diff --git a/.changeset/published-readme-symbol-claims-9544.md b/.changeset/published-readme-symbol-claims-9544.md new file mode 100644 index 0000000000..c245f552c3 --- /dev/null +++ b/.changeset/published-readme-symbol-claims-9544.md @@ -0,0 +1,43 @@ +--- +"@objectstack/driver-sql": patch +"@objectstack/mcp": patch +"@objectstack/objectql": patch +"@objectstack/spec": patch +--- + +docs: four published READMEs stop documenting symbols and call sites that do not exist (#9544) + +All four packages ship `README.md` in their `files` array with `private` unset, so these +are the pages npm renders. Each finding was re-measured against the **built `.d.ts`**, not +against source, because that is what a consumer resolves through the `exports` map. + +- **`@objectstack/driver-sql`** — `import type { IDriver } from '@objectstack/spec'` named + a type that exists **nowhere in the repository** (0 hits across every package's `src` + and `dist`). The real contract is `IDataDriver` on `@objectstack/spec/contracts` — the + one `SqlDriver` actually declares (`export class SqlDriver implements IDataDriver`). The + adjacent operation list was corrected too: the method is `create`, not `insert`. + +- **`@objectstack/mcp`** — `DriverSql` has never existed (the export is `SqlDriver`), and + the README then called `DriverSql.configure({...})` on it. Renaming alone would have + been wrong twice over: `SqlDriver` has **no static `configure` either**, and `driver:` + is not a key of `defineStack` at all. The example now declares a datasource the way the + shipped templates do. `MCPServerPlugin.configure({...})` — five call sites — becomes + `new MCPServerPlugin({...})`, the form the class's own JSDoc and every in-repo caller + use. The documented options block claimed `serverName`, `autoRegisterTools`, + `autoExposeObjects`, `enableStreaming`, `port` and `debug`; the real + `MCPServerPluginOptions` is `name`, `version`, `transport`, `autoStart`, `instructions`, + and the env switches are named instead. + +- **`@objectstack/objectql`** — `registerObject` is an **instance** method, so + `SchemaRegistry.registerObject(...)` on the class could never run. The example now + reaches it through the engine's registry and states the real parameter order + (`schema, packageId, namespace?`). + +- **`@objectstack/spec`** — the protocol package's own front page imported + `MCPServerConfigSchema` from `@objectstack/spec/ai`, which exports `MCPServerRefSchema`. + A rename by itself would have swapped a broken import for a broken **parse**: the + documented payload was built for a schema that does not exist, and + `MCPServerRefSchema.safeParse` rejects it (`transport` is an enum of + `stdio | http | websocket`, not an object, and `endpoint` is required and was absent). + The example is now a payload that parses green, and the page says plainly that tools, + resources and prompts are derived from metadata at runtime rather than authored there. diff --git a/packages/drivers/driver-sql/README.md b/packages/drivers/driver-sql/README.md index 9eb84814e3..4d41357300 100644 --- a/packages/drivers/driver-sql/README.md +++ b/packages/drivers/driver-sql/README.md @@ -134,10 +134,10 @@ interface SQLDriverConfig { The SQL driver implements the standard ObjectStack driver interface: ```typescript -import type { IDriver } from '@objectstack/spec'; +import type { IDataDriver } from '@objectstack/spec/contracts'; -// All standard operations are supported: -// find, findOne, insert, update, delete, count +// `SqlDriver implements IDataDriver` — all standard operations are supported: +// find, findOne, create, update, delete, count ``` ### Advanced Queries diff --git a/packages/mcp/README.md b/packages/mcp/README.md index c868108f16..343ac1b549 100644 --- a/packages/mcp/README.md +++ b/packages/mcp/README.md @@ -37,10 +37,9 @@ import { MCPServerPlugin } from '@objectstack/mcp'; const stack = defineStack({ plugins: [ - MCPServerPlugin.configure({ - serverName: 'objectstack-server', + new MCPServerPlugin({ + name: 'objectstack-server', version: '1.0.0', - autoRegisterTools: true, }), ], }); @@ -48,31 +47,35 @@ const stack = defineStack({ ## Configuration +The constructor takes `MCPServerPluginOptions`: + ```typescript -interface MCPServerConfig { - /** Server name (shown to AI clients) */ - serverName?: string; +interface MCPServerPluginOptions { + /** Override MCP server name. Defaults to 'objectstack'. */ + name?: string; - /** Server version */ + /** Override MCP server version. Defaults to package version. */ version?: string; - /** Auto-register tools from actions and flows */ - autoRegisterTools?: boolean; - - /** Auto-expose objects as resources */ - autoExposeObjects?: boolean; - - /** Enable streaming for large responses */ - enableStreaming?: boolean; - - /** Transport mechanism ('stdio' | 'http') */ + /** Transport mode: 'stdio' (default). */ transport?: 'stdio' | 'http'; - /** HTTP port (if transport is 'http') */ - port?: number; + /** Whether to auto-start the MCP server. Defaults to false. */ + autoStart?: boolean; + + /** Custom instructions for the MCP server. */ + instructions?: string; } ``` +Tools and resources are **not** opted into per-option — the plugin bridges the +AI tool registry, metadata service and data engine automatically when it +starts. The HTTP surface needs no start at all: it is served per-request at +`/api/v1/mcp` (default-on; `OS_MCP_SERVER_ENABLED=false` opts out). + +Environment overrides: `OS_MCP_SERVER_NAME`, `OS_MCP_SERVER_TRANSPORT`, +`OS_MCP_SERVER_ENABLED`. + ## MCP Tools ### Auto-Generated Tools @@ -389,43 +392,57 @@ Configure in Cline settings: ### Stdio Transport (Default) ```typescript -// server.ts +// objectstack.config.ts import { defineStack } from '@objectstack/spec'; +import { defineDatasource } from '@objectstack/spec/data'; import { MCPServerPlugin } from '@objectstack/mcp'; -import { DriverSql } from '@objectstack/driver-sql'; -const stack = defineStack({ - driver: DriverSql.configure({ - client: 'better-sqlite3', - connection: { filename: process.env.DATABASE_URL ?? './data/app.db' }, - }), +export default defineStack({ + manifest: { + id: 'com.example.crm', + namespace: 'crm', + version: '0.1.0', + type: 'app', + name: 'My CRM', + engines: { protocol: '^17' }, + }, + // Optional: the CLI already anchors a persistent SQLite database at + // `/.objectstack/data/standalone.db`. Declare a datasource only + // to point somewhere else. + datasources: [ + defineDatasource({ + name: 'primary', + label: 'Primary', + driver: 'sqlite', + config: { filename: '.objectstack/data/app.db' }, + }), + ], plugins: [ - MCPServerPlugin.configure({ - serverName: 'my-crm', + new MCPServerPlugin({ + name: 'my-crm', transport: 'stdio', // Claude Desktop, Cursor, Cline + autoStart: true, // stdio is a long-lived transport, so start it }), ], }); - -await stack.boot(); ``` +Run it with the CLI (`os dev` / `os serve`) — `defineStack()` returns the +metadata definition; the CLI boots the kernel from it. + ### HTTP Transport ```typescript -const stack = defineStack({ - driver: DriverSql.configure({ /* ... */ }), +export default defineStack({ + manifest: { /* ... */ }, plugins: [ - MCPServerPlugin.configure({ - serverName: 'my-crm', + new MCPServerPlugin({ + name: 'my-crm', transport: 'http', - port: 3100, }), ], }); - -await stack.boot(); -// MCP server running on http://localhost:3100 +// Served per-request by the running server at /api/v1/mcp ``` ## Advanced Features @@ -549,13 +566,13 @@ The MCP server exposes these capabilities: ## Debugging -Enable debug logging: +The plugin logs through the kernel logger — there is no `debug` option. The +MCP surface is controlled by environment variables: -```typescript -MCPServerPlugin.configure({ - serverName: 'my-crm', - debug: true, // Log all MCP messages -}); +```bash +OS_MCP_SERVER_ENABLED=true # explicit true also auto-starts the stdio transport +OS_MCP_SERVER_NAME=my-crm # override the server name +OS_MCP_SERVER_TRANSPORT=http # override the transport ``` View MCP messages in client: @@ -566,51 +583,34 @@ View MCP messages in client: ## Example: Complete CRM Server ```typescript -import { defineStack, defineTool } from '@objectstack/spec'; +// objectstack.config.ts +import { defineStack } from '@objectstack/spec'; import { MCPServerPlugin } from '@objectstack/mcp'; -const stack = defineStack({ - driver: /* ... */, - plugins: [ - MCPServerPlugin.configure({ - serverName: 'crm-assistant', - autoRegisterTools: true, - }), - ], -}); - -await stack.boot(); - -const mcp = stack.kernel.getService('mcp'); - -// Register custom tools -mcp.registerTool(defineTool({ - name: 'forecast_revenue', - description: 'Forecast revenue based on pipeline', - async execute() { - // Implementation - }, -})); - -// Register custom resources -mcp.registerResource({ - uri: 'objectstack://dashboards/sales', - name: 'Sales Dashboard', - async read() { - // Implementation - }, -}); - -// Register prompts -mcp.registerPrompt({ - name: 'weekly_report', - description: 'Generate weekly sales report', - async render() { - // Implementation +import * as objects from './src/objects/index.js'; +import { allActions } from './src/actions/index.js'; + +export default defineStack({ + manifest: { + id: 'com.example.crm', + namespace: 'crm', + version: '0.1.0', + type: 'app', + name: 'CRM Assistant', + engines: { protocol: '^17' }, }, + objects: Object.values(objects), + // Your actions become MCP tools — the plugin bridges them at start. + actions: allActions, + plugins: [new MCPServerPlugin({ name: 'crm-assistant' })], }); ``` +There is no imperative "register a tool" call to make: the plugin derives the +tool set from your metadata. The bridging helpers it uses — +`registerObjectTools`, `registerActionTools` and `registerSkillPrompts` — are +exported for hosts that drive an `MCPServerRuntime` directly. + ## License Apache-2.0. See [LICENSING.md](../../LICENSING.md). diff --git a/packages/objectql/README.md b/packages/objectql/README.md index 5b5ebb3b3b..c2e2b58e74 100644 --- a/packages/objectql/README.md +++ b/packages/objectql/README.md @@ -60,10 +60,12 @@ for (const obj of objects) { ### Schema Registry ```typescript -import { SchemaRegistry, computeFQN } from '@objectstack/objectql'; +import { computeFQN, type SchemaRegistry } from '@objectstack/objectql'; -// Register an object under a namespace -SchemaRegistry.registerObject(taskDef, 'com.acme.todo', 'todo'); +// `registerObject` is an INSTANCE method — reach the engine's registry. +// Signature: (schema, packageId, namespace?, ownership?, priority?) +const registry: SchemaRegistry = engine.registry; +registry.registerObject(taskDef, 'com.acme.todo', 'todo'); // Resolve FQN computeFQN('todo', 'task'); // => 'todo__task' diff --git a/packages/spec/README.md b/packages/spec/README.md index bce44161f4..ebd9c7f86d 100644 --- a/packages/spec/README.md +++ b/packages/spec/README.md @@ -63,135 +63,25 @@ if (result.success) { ## MCP (Model Context Protocol) Integration -Define MCP servers to connect AI agents to your ObjectStack data and tools: +Declare the MCP servers your agents may reach. `MCPServerRefSchema` is a +**reference** to a server — where it lives and how to authenticate — not a +description of what it serves: ```typescript -import { MCPServerConfigSchema } from '@objectstack/spec/ai'; +import { MCPServerRefSchema } from '@objectstack/spec/ai'; -// Define an MCP server exposing ObjectStack data -export const objectStackMCP = MCPServerConfigSchema.parse({ +// A reference to an MCP server an agent may call +export const objectStackMCP = MCPServerRefSchema.parse({ name: 'objectstack_mcp', label: 'ObjectStack MCP Server', - description: 'Connects AI agents to ObjectStack data and workflows', - - serverInfo: { - name: 'ObjectStack MCP', - version: '1.0.0', - capabilities: { - resources: true, - resourceTemplates: true, - tools: true, - prompts: true, - }, - }, - - transport: { - type: 'http', - url: 'https://api.objectstack.ai/mcp', - auth: { - type: 'bearer', - secretRef: 'system:mcp_api_key', - }, - }, - - // Expose data as resources - resourceTemplates: [ - { - uriPattern: 'objectstack://objects/{objectName}', - name: 'Object Data', - description: 'Access object records', - parameters: [ - { - name: 'objectName', - type: 'string', - required: true, - description: 'Name of the object to access', - }, - ], - handler: 'resources.getObjectData', - }, - ], - - // Expose workflows as tools - tools: [ - { - name: 'create_record', - description: 'Create a new record in any object', - parameters: [ - { - name: 'object', - type: 'string', - description: 'Object name (e.g., "account", "contact")', - required: true, - }, - { - name: 'data', - type: 'object', - description: 'Record data as key-value pairs', - required: true, - }, - ], - handler: 'flows.create_record', - sideEffects: 'write', - // NOTE: an MCP capability-descriptor hint — surfaced to the client, but - // nothing server-side pauses on it. (The `ToolSchema` field of the same - // name was removed in 16.x — #3715, ADR-0033 §2.) A real human-in-the-loop - // gate is `ai.requiresConfirmation` on the underlying action (+ the - // approval queue), or `approval: 'always'` on an MCP binding. - requiresConfirmation: true, - }, - { - name: 'search_records', - description: 'Search for records using natural language or filters', - parameters: [ - { - name: 'object', - type: 'string', - description: 'Object to search in', - required: true, - }, - { - name: 'query', - type: 'string', - description: 'Search query', - required: true, - }, - ], - handler: 'data.search', - sideEffects: 'read', - }, - ], - - // Provide prompt templates - prompts: [ - { - name: 'analyze_customer_data', - description: 'Analyze customer data and generate insights', - messages: [ - { - role: 'system', - content: 'You are a data analyst specializing in customer insights.', - }, - { - role: 'user', - content: 'Analyze the following customer data and provide insights: {{customer_data}}', - }, - ], - arguments: [ - { - name: 'customer_data', - type: 'string', - required: true, - description: 'Customer data in JSON format', - }, - ], - }, - ], - - autoStart: true, - healthCheck: { - enabled: true, - interval: 60000, - }, + transport: 'http', // 'stdio' | 'http' | 'websocket' + endpoint: 'https://api.objectstack.ai/mcp', + secretRef: 'system:mcp_api_key', // optional + active: true, // defaults to true }); ``` + +The tools, resources and prompts an ObjectStack server exposes are **not +authored here** — they are derived from your metadata at runtime by the +`MCPServerPlugin` in `@objectstack/mcp`, which bridges the metadata and data +engines to any connected MCP client. diff --git a/scripts/published-readme-exports.baseline.json b/scripts/published-readme-exports.baseline.json index f4701de11e..e9dfb37ce0 100644 --- a/scripts/published-readme-exports.baseline.json +++ b/scripts/published-readme-exports.baseline.json @@ -22,26 +22,5 @@ "Key format: `|||[|]`. Run the checker to see the", "exact key it computes for a finding." ], - "entries": [ - { - "id": "@objectstack/driver-sql|packages/drivers/driver-sql/README.md|import|@objectstack/spec|IDriver", - "why": "IDriver is not on @objectstack/spec's root entry — it is exported from @objectstack/spec/contracts. Wrong subpath, not a missing export." - }, - { - "id": "@objectstack/mcp|packages/mcp/README.md|member|@objectstack/mcp|MCPServerPlugin.configure", - "why": "MCPServerPlugin is a REAL exported class (packages/mcp/src/plugin.ts:96) with no static `configure`. The #9532 shape at its worst: the import resolves, so only the call-site half can see it." - }, - { - "id": "@objectstack/mcp|packages/mcp/README.md|import|@objectstack/driver-sql|DriverSql", - "why": "@objectstack/driver-sql exports `SqlDriver`. `DriverSql` has never existed, and the README then calls `DriverSql.configure({...})` on it." - }, - { - "id": "@objectstack/objectql|packages/objectql/README.md|member|@objectstack/objectql|SchemaRegistry.registerObject", - "why": "registerObject is an INSTANCE method (`engine.registry.registerObject(...)`); the README calls it on the class. The import resolves, so only the call-site half can see it." - }, - { - "id": "@objectstack/spec|packages/spec/README.md|import|@objectstack/spec/ai|MCPServerConfigSchema", - "why": "@objectstack/spec/ai exports `MCPServerRefSchema`; there is no `MCPServerConfigSchema`. This is the protocol package's own front page." - } - ] + "entries": [] }