From fbbc477dd62fbf84a19b2020f40cea90bc36c7e9 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 18 Aug 2026 11:56:53 +0000 Subject: [PATCH 1/2] docs: four published READMEs stop documenting symbols that do not exist (#9544) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit driver-sql, mcp, objectql and spec each ship README.md in their `files` array with `private` unset, so these are the pages npm renders. Every claim was re-measured against the built `.d.ts`, which is what a consumer resolves through the `exports` map. Two of the five findings could not be fixed by renaming the symbol: - `IDriver` (driver-sql) exists nowhere in the repository, so the card's own "it lives on @objectstack/spec/contracts" was itself wrong. The real contract is `IDataDriver` — the one `SqlDriver` declares. - `MCPServerConfigSchema` -> `MCPServerRefSchema` (spec) fixes the import but leaves `.parse()` throwing: the documented payload was built for a schema that does not exist. The example is now one that parses green. The two `.configure` call sites are fixed at the call site, not the import: neither `MCPServerPlugin` nor `SqlDriver` has a static `configure`, and `driver:` is not a key of `defineStack` at all. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01XqDQYVU5smx29ts9pAErja --- .../published-readme-symbol-claims-9544.md | 43 +++++ packages/drivers/driver-sql/README.md | 6 +- packages/mcp/README.md | 166 +++++++++--------- packages/objectql/README.md | 8 +- packages/spec/README.md | 140 ++------------- 5 files changed, 149 insertions(+), 214 deletions(-) create mode 100644 .changeset/published-readme-symbol-claims-9544.md 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. From e8a80574926212698fdb8ed8e5446208f33eb79a Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 18 Aug 2026 13:56:14 +0000 Subject: [PATCH 2/2] chore(ci): drop the five now-resolved published-README baseline entries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The gate and its baseline reached `main` after this branch was written, so the reconciliation this branch's report named as an ordering constraint now falls here. The four READMEs on this branch already make these five claims resolve, so their baseline entries are stale text and the shrink-only gate refuses them. Measured against the real gate on `main` (not the untracked copy the earlier run had to use): before the deletion it reports exactly these 5 as stale and exits 1; after, it is green with 5 known instances left — the `packages/spec/prompts/` group, which a separate card carries. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01XqDQYVU5smx29ts9pAErja --- .../published-readme-exports.baseline.json | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/scripts/published-readme-exports.baseline.json b/scripts/published-readme-exports.baseline.json index d876a11611..a7c9931656 100644 --- a/scripts/published-readme-exports.baseline.json +++ b/scripts/published-readme-exports.baseline.json @@ -23,26 +23,6 @@ "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." - }, { "id": "@objectstack/spec|packages/spec/prompts/create-new-project.md|import|@objectstack/spec/data|Object", "why": "@objectstack/spec/data exports `ObjectSchema`. `Object` resolves to the JS global instead of failing loudly — the worst shape for a published AGENT-AUTHORING prompt."