Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions .changeset/published-readme-symbol-claims-9544.md
Original file line numberDiff line numberDiff line change
@@ -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.
6 changes: 3 additions & 3 deletions packages/drivers/driver-sql/README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -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
Expand Down
166 changes: 83 additions & 83 deletions packages/mcp/README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,42 +37,45 @@ 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,
}),
],
});
```

## 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
Expand DownExpand Up@@ -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
// `<project>/.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
Expand DownExpand Up@@ -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:
Expand All@@ -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).
Expand Down
8 changes: 5 additions & 3 deletions packages/objectql/README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -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'
Expand Down
Loading
Loading