@objectstack/mcp 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +93 -0
- package/README.md +528 -0
- package/dist/index.cjs +817 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +284 -0
- package/dist/index.d.ts +284 -0
- package/dist/index.js +785 -0
- package/dist/index.js.map +1 -0
- package/package.json +58 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/plugin.ts","../src/mcp-server-runtime.ts","../src/mcp-http-tools.ts","../src/skill.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Plugin, PluginContext } from '@objectstack/core';\nimport { readEnvWithDeprecation } from '@objectstack/types';\nimport type { IAIService, IDataEngine, IMetadataService } from '@objectstack/spec/contracts';\nimport { MCPServerRuntime } from './mcp-server-runtime.js';\nimport type { MCPServerRuntimeConfig } from './mcp-server-runtime.js';\nimport type { ToolRegistry } from './types.js';\n\n/**\n * Configuration options for the MCPServerPlugin.\n */\nexport interface MCPServerPluginOptions {\n /** Override MCP server name. Defaults to 'objectstack'. */\n name?: string;\n /** Override MCP server version. Defaults to package version. */\n version?: string;\n /** Transport mode: 'stdio' (default). */\n transport?: 'stdio' | 'http';\n /** Whether to auto-start the MCP server. Defaults to false (manual start via env var). */\n autoStart?: boolean;\n /** Custom instructions for the MCP server. */\n instructions?: string;\n}\n\n/**\n * MCPServerPlugin — Kernel plugin that exposes ObjectStack as an MCP server.\n *\n * Lifecycle:\n * 1. **init** — Creates {@link MCPServerRuntime} and registers as `'mcp'` service.\n * 2. **start** — Bridges ToolRegistry, MetadataService, DataEngine, and Agents\n * to the MCP server. Starts the transport if `autoStart` is enabled or\n * the `OS_MCP_SERVER_ENABLED` environment variable is set.\n * 3. **destroy** — Stops the MCP transport.\n *\n * Environment Variables:\n * - `OS_MCP_SERVER_ENABLED=true` — Enable MCP server at startup\n * - `OS_MCP_SERVER_NAME` — Override server name\n * - `OS_MCP_SERVER_TRANSPORT` — Override transport ('stdio' | 'http')\n * (legacy `MCP_SERVER_*` names still honoured with a deprecation warning)\n *\n * @example\n * ```ts\n * import { LiteKernel } from '@objectstack/core';\n * import { MCPServerPlugin } from '@objectstack/mcp';\n *\n * const kernel = new LiteKernel();\n * kernel.use(new MCPServerPlugin({ autoStart: true }));\n * await kernel.bootstrap();\n * ```\n */\nexport class MCPServerPlugin implements Plugin {\n name = 'com.objectstack.mcp';\n version = '1.0.0';\n type = 'standard' as const;\n dependencies: string[] = [];\n\n private runtime?: MCPServerRuntime;\n private readonly options: MCPServerPluginOptions;\n\n constructor(options: MCPServerPluginOptions = {}) {\n this.options = options;\n }\n\n async init(ctx: PluginContext): Promise<void> {\n const config: MCPServerRuntimeConfig = {\n name: readEnvWithDeprecation('OS_MCP_SERVER_NAME', 'MCP_SERVER_NAME') ?? this.options.name ?? 'objectstack',\n version: this.options.version ?? '1.0.0',\n transport: (readEnvWithDeprecation('OS_MCP_SERVER_TRANSPORT', 'MCP_SERVER_TRANSPORT') as 'stdio' | 'http') ?? this.options.transport ?? 'stdio',\n instructions: this.options.instructions,\n logger: ctx.logger,\n };\n\n this.runtime = new MCPServerRuntime(config);\n ctx.registerService('mcp', this.runtime);\n\n ctx.logger.info('[MCP] Plugin initialized');\n }\n\n async start(ctx: PluginContext): Promise<void> {\n if (!this.runtime) return;\n\n // ── Bridge tools from AIService ──\n // The IAIService contract does not formally include `toolRegistry` because\n // it is an implementation detail of AIService. We use duck-typing here to\n // avoid a hard dependency on @objectstack/service-ai while still bridging\n // tools when the full AIService implementation is present.\n try {\n const aiService = ctx.getService<IAIService & { toolRegistry?: ToolRegistry }>('ai');\n if (aiService?.toolRegistry) {\n this.runtime.bridgeTools(aiService.toolRegistry);\n } else {\n ctx.logger.debug('[MCP] AI service does not expose a toolRegistry, skipping tool bridging');\n }\n } catch {\n ctx.logger.debug('[MCP] AI service not available, skipping tool bridging');\n }\n\n // ── Bridge resources from MetadataService & DataEngine ──\n let metadataService: IMetadataService | undefined;\n let dataEngine: IDataEngine | undefined;\n\n try {\n metadataService = ctx.getService<IMetadataService>('metadata');\n } catch {\n ctx.logger.debug('[MCP] Metadata service not available, skipping resource bridging');\n }\n\n try {\n dataEngine = ctx.getService<IDataEngine>('data');\n } catch {\n ctx.logger.debug('[MCP] Data engine not available, skipping record resources');\n }\n\n if (metadataService) {\n this.runtime.bridgeResources(metadataService, dataEngine);\n this.runtime.bridgePrompts(metadataService);\n }\n\n // ── Auto-start if configured ──\n const shouldStart = this.options.autoStart || readEnvWithDeprecation('OS_MCP_SERVER_ENABLED', 'MCP_SERVER_ENABLED') === 'true';\n if (shouldStart) {\n await this.runtime.start();\n ctx.logger.info('[MCP] Server started automatically');\n } else {\n ctx.logger.info(\n '[MCP] Server ready but not started. Set OS_MCP_SERVER_ENABLED=true or use autoStart option.',\n );\n }\n\n // Trigger hook for other plugins to extend MCP\n await ctx.trigger('mcp:ready', this.runtime);\n }\n\n async destroy(): Promise<void> {\n if (this.runtime?.isStarted) {\n await this.runtime.stop();\n }\n this.runtime = undefined;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { WebStandardStreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js';\nimport type { Logger, IMetadataService, IDataEngine, AIToolDefinition } from '@objectstack/spec/contracts';\nimport type { Agent } from '@objectstack/spec/ai';\nimport type { ToolRegistry, ToolExecutionResult } from './types.js';\nimport { registerObjectTools } from './mcp-http-tools.js';\nimport type { McpDataBridge, RegisterObjectToolsOptions } from './mcp-http-tools.js';\nimport { z } from 'zod';\n\n/**\n * Configuration for the MCP Server Runtime.\n */\nexport interface MCPServerRuntimeConfig {\n /** Human-readable server name. */\n name?: string;\n /** Server version (semver). */\n version?: string;\n /** Optional instructions describing how to use the server. */\n instructions?: string;\n /** Transport mode: 'stdio' (default) or 'http'. */\n transport?: 'stdio' | 'http';\n /** Logger instance. */\n logger?: Logger;\n}\n\n/**\n * Minimal shape of an object definition returned by IMetadataService.\n */\ninterface ObjectDef {\n name: string;\n label?: string;\n fields?: Record<string, { name?: string; type?: string; label?: string; required?: boolean }>;\n enable?: Record<string, boolean>;\n}\n\n/**\n * Names of tools that are read-only (no side effects).\n * Kept as a module-level constant for easy extension.\n */\nconst READ_ONLY_TOOLS = new Set([\n 'list_objects',\n 'describe_object',\n 'query_records',\n 'get_record',\n 'aggregate_data',\n]);\n\n/**\n * Names of tools that perform destructive mutations.\n */\nconst DESTRUCTIVE_TOOLS = new Set([\n 'delete_field',\n]);\n\n/**\n * MCPServerRuntime — Bridges ObjectStack kernel services to the Model Context Protocol.\n *\n * Responsibilities:\n * 1. Bridge ToolRegistry → MCP tools (all registered AI tools)\n * 2. Bridge IMetadataService → MCP resources (object schemas, metadata types)\n * 3. Bridge IDataEngine → MCP resources (record access by URI)\n * 4. Bridge Agent definitions → MCP prompts (agent instructions)\n *\n * Architecture:\n * ```\n * ToolRegistry (service-ai) ──┐\n * IMetadataService (metadata) ─┼──→ MCPServerRuntime ──→ McpServer (SDK)\n * IDataEngine (objectql) ──┤ │\n * Agent definitions ──┘ ├── stdio transport\n * └── http transport (future)\n * ```\n */\nexport class MCPServerRuntime {\n private readonly mcpServer: McpServer;\n private readonly config: Required<Pick<MCPServerRuntimeConfig, 'name' | 'version'>> & MCPServerRuntimeConfig;\n private transport: StdioServerTransport | undefined;\n private started = false;\n\n constructor(config: MCPServerRuntimeConfig = {}) {\n this.config = {\n name: 'objectstack',\n version: '1.0.0',\n transport: 'stdio',\n ...config,\n };\n\n this.mcpServer = new McpServer(\n {\n name: this.config.name,\n version: this.config.version,\n },\n {\n capabilities: {\n resources: {},\n tools: {},\n prompts: {},\n logging: {},\n },\n instructions: this.config.instructions ?? 'ObjectStack MCP Server — access data objects, AI tools, and agent prompts.',\n },\n );\n }\n\n /** The underlying McpServer instance (for advanced use cases). */\n get server(): McpServer {\n return this.mcpServer;\n }\n\n /** Whether the server is currently connected and running. */\n get isStarted(): boolean {\n return this.started;\n }\n\n // ── Helpers ─────────────────────────────────────────────────────\n\n /**\n * Extract the text value from a ToolExecutionResult's output.\n *\n * The output may be a `{ type: 'text', value: string }` object (from the\n * Vercel AI SDK ToolResultPart) or any serialisable value.\n */\n private static formatToolOutput(result: ToolExecutionResult): string {\n const output = result.output;\n if (output && typeof output === 'object' && 'value' in output) {\n return String((output as { value: unknown }).value);\n }\n return JSON.stringify(output ?? '');\n }\n\n // ── Tool Bridge ────────────────────────────────────────────────\n\n /**\n * Bridge all tools from the ToolRegistry to MCP tools.\n *\n * Each registered tool becomes an MCP tool with the same name, description,\n * and JSON Schema parameters. The handler delegates to the ToolRegistry's\n * execute path.\n */\n bridgeTools(toolRegistry: ToolRegistry): void {\n const tools = toolRegistry.getAll();\n const logger = this.config.logger;\n\n for (const tool of tools) {\n this.registerToolFromDefinition(tool, toolRegistry);\n }\n\n logger?.info(`[MCP] Bridged ${tools.length} tools from ToolRegistry`);\n }\n\n /**\n * Register a single tool on the MCP server from an AIToolDefinition.\n */\n private registerToolFromDefinition(tool: AIToolDefinition, toolRegistry: ToolRegistry): void {\n const logger = this.config.logger;\n\n // Convert JSON Schema parameters to Zod-compatible format for MCP SDK\n // The MCP SDK registerTool with inputSchema expects a Zod raw shape or AnySchema.\n // Since our tools use JSON Schema, we use the low-level .tool() with a raw callback\n // and pass the JSON Schema as annotations metadata.\n this.mcpServer.registerTool(\n tool.name,\n {\n description: tool.description,\n annotations: {\n // Mark tools with write side-effects for destructive operations\n destructiveHint: this.isDestructiveTool(tool.name),\n readOnlyHint: this.isReadOnlyTool(tool.name),\n openWorldHint: false,\n },\n },\n async (extra) => {\n // The MCP SDK passes tool arguments via the extra.arguments property\n // when registerTool is called without an inputSchema.\n const rawExtra = extra as Record<string, unknown>;\n const args = (rawExtra.arguments ?? {}) as Record<string, unknown>;\n\n try {\n const result = await toolRegistry.execute({\n type: 'tool-call',\n toolCallId: `mcp-${tool.name}-${Date.now()}`,\n toolName: tool.name,\n input: args,\n });\n\n const outputText = MCPServerRuntime.formatToolOutput(result);\n\n if (result.isError) {\n return {\n content: [{ type: 'text' as const, text: outputText }],\n isError: true,\n };\n }\n\n return {\n content: [{ type: 'text' as const, text: outputText }],\n };\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n logger?.warn(`[MCP] Tool \"${tool.name}\" execution failed:`, { error: message });\n return {\n content: [{ type: 'text' as const, text: message }],\n isError: true,\n };\n }\n },\n );\n }\n\n /**\n * Check if a tool is read-only (data query tools).\n */\n private isReadOnlyTool(name: string): boolean {\n return READ_ONLY_TOOLS.has(name);\n }\n\n /**\n * Check if a tool performs destructive operations.\n */\n private isDestructiveTool(name: string): boolean {\n return DESTRUCTIVE_TOOLS.has(name);\n }\n\n // ── Resource Bridge ────────────────────────────────────────────\n\n /**\n * Bridge metadata service and data engine to MCP resources.\n *\n * Exposes:\n * - `objectstack://objects` — List all data objects\n * - `objectstack://objects/{objectName}` — Get object schema\n * - `objectstack://objects/{objectName}/records/{recordId}` — Get a specific record\n * - `objectstack://metadata/types` — List all metadata types\n */\n bridgeResources(metadataService: IMetadataService, dataEngine?: IDataEngine): void {\n const logger = this.config.logger;\n let resourceCount = 0;\n\n // ── Static resource: List all objects ──\n this.mcpServer.registerResource(\n 'object_list',\n 'objectstack://objects',\n {\n description: 'List all data objects (tables) in the ObjectStack instance',\n mimeType: 'application/json',\n },\n async () => {\n const objects = await metadataService.listObjects();\n const summary = (objects as ObjectDef[]).map(o => ({\n name: o.name,\n label: o.label ?? o.name,\n fieldCount: o.fields ? Object.keys(o.fields).length : 0,\n }));\n\n return {\n contents: [{\n uri: 'objectstack://objects',\n mimeType: 'application/json',\n text: JSON.stringify({ objects: summary, totalCount: summary.length }, null, 2),\n }],\n };\n },\n );\n resourceCount++;\n\n // ── Template resource: Object schema ──\n this.mcpServer.registerResource(\n 'object_schema',\n new ResourceTemplate('objectstack://objects/{objectName}', { list: undefined }),\n {\n description: 'Get the full schema of a specific data object including fields and features',\n mimeType: 'application/json',\n },\n async (_uri, variables) => {\n const objectName = String(variables.objectName);\n const objectDef = await metadataService.getObject(objectName);\n\n if (!objectDef) {\n return {\n contents: [{\n uri: `objectstack://objects/${objectName}`,\n mimeType: 'application/json',\n text: JSON.stringify({ error: `Object \"${objectName}\" not found` }),\n }],\n };\n }\n\n const def = objectDef as ObjectDef;\n const fields = def.fields ?? {};\n const fieldSummary = Object.entries(fields).map(([key, f]) => ({\n name: key,\n type: f.type,\n label: f.label ?? key,\n required: f.required ?? false,\n }));\n\n return {\n contents: [{\n uri: `objectstack://objects/${objectName}`,\n mimeType: 'application/json',\n text: JSON.stringify({\n name: def.name,\n label: def.label ?? def.name,\n fields: fieldSummary,\n enableFeatures: def.enable ?? {},\n }, null, 2),\n }],\n };\n },\n );\n resourceCount++;\n\n // ── Template resource: Record by ID ──\n if (dataEngine) {\n this.mcpServer.registerResource(\n 'record_by_id',\n new ResourceTemplate('objectstack://objects/{objectName}/records/{recordId}', { list: undefined }),\n {\n description: 'Get a specific record by ID from a data object',\n mimeType: 'application/json',\n },\n async (_uri, variables) => {\n const objectName = String(variables.objectName);\n const recordId = String(variables.recordId);\n\n try {\n const record = await dataEngine.findOne(objectName, {\n where: { id: recordId },\n });\n\n if (!record) {\n return {\n contents: [{\n uri: `objectstack://objects/${objectName}/records/${recordId}`,\n mimeType: 'application/json',\n text: JSON.stringify({ error: `Record \"${recordId}\" not found in \"${objectName}\"` }),\n }],\n };\n }\n\n return {\n contents: [{\n uri: `objectstack://objects/${objectName}/records/${recordId}`,\n mimeType: 'application/json',\n text: JSON.stringify(record, null, 2),\n }],\n };\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n contents: [{\n uri: `objectstack://objects/${objectName}/records/${recordId}`,\n mimeType: 'application/json',\n text: JSON.stringify({ error: message }),\n }],\n };\n }\n },\n );\n resourceCount++;\n }\n\n // ── Static resource: Metadata types ──\n if (metadataService.getRegisteredTypes) {\n this.mcpServer.registerResource(\n 'metadata_types',\n 'objectstack://metadata/types',\n {\n description: 'List all registered metadata types (object, app, view, agent, tool, etc.)',\n mimeType: 'application/json',\n },\n async () => {\n const types = await metadataService.getRegisteredTypes!();\n return {\n contents: [{\n uri: 'objectstack://metadata/types',\n mimeType: 'application/json',\n text: JSON.stringify({ types, totalCount: types.length }, null, 2),\n }],\n };\n },\n );\n resourceCount++;\n }\n\n logger?.info(`[MCP] Bridged ${resourceCount} resource endpoints`);\n }\n\n // ── Prompt Bridge ──────────────────────────────────────────────\n\n /**\n * Bridge registered agents to MCP prompts.\n *\n * Each active agent becomes an MCP prompt with:\n * - Name matching the agent name\n * - System message from agent instructions\n * - Optional context arguments (objectName, recordId, viewName)\n */\n bridgePrompts(metadataService: IMetadataService): void {\n const logger = this.config.logger;\n\n // Register a dynamic prompt that loads agents at call time\n this.mcpServer.registerPrompt(\n 'agent_prompt',\n {\n description: 'Load an agent\\'s system prompt with optional UI context. ' +\n 'Use the agentName argument to select which agent\\'s instructions to use.',\n argsSchema: {\n agentName: z.string().describe('Name of the agent to load (e.g. \"data_chat\", \"metadata_assistant\")'),\n objectName: z.string().optional().describe('Current object the user is viewing'),\n recordId: z.string().optional().describe('Currently selected record ID'),\n viewName: z.string().optional().describe('Current view name'),\n },\n },\n async (args) => {\n const agentName = String(args.agentName ?? '');\n if (!agentName) {\n return {\n messages: [{\n role: 'user' as const,\n content: { type: 'text' as const, text: 'Error: agentName argument is required' },\n }],\n };\n }\n\n const raw = await metadataService.get('agent', agentName);\n if (!raw) {\n return {\n messages: [{\n role: 'user' as const,\n content: { type: 'text' as const, text: `Error: Agent \"${agentName}\" not found` },\n }],\n };\n }\n\n const agent = raw as Agent;\n\n // Build system prompt from agent instructions + context\n const parts: string[] = [];\n parts.push(agent.instructions ?? '');\n\n const contextHints: string[] = [];\n if (args.objectName) contextHints.push(`Current object: ${args.objectName}`);\n if (args.recordId) contextHints.push(`Selected record ID: ${args.recordId}`);\n if (args.viewName) contextHints.push(`Current view: ${args.viewName}`);\n if (contextHints.length > 0) {\n parts.push('\\n--- Current Context ---\\n' + contextHints.join('\\n'));\n }\n\n return {\n messages: [{\n role: 'assistant' as const,\n content: { type: 'text' as const, text: parts.join('\\n') },\n }],\n };\n },\n );\n\n logger?.info('[MCP] Agent prompts bridged');\n }\n\n // ── Lifecycle ──────────────────────────────────────────────────\n\n /**\n * Start the MCP server with the configured transport.\n *\n * For stdio transport, this connects to process stdin/stdout.\n */\n async start(): Promise<void> {\n if (this.started) return;\n\n const logger = this.config.logger;\n\n if (this.config.transport === 'stdio') {\n this.transport = new StdioServerTransport();\n await this.mcpServer.connect(this.transport);\n this.started = true;\n logger?.info(`[MCP] Server started (transport: stdio, name: ${this.config.name})`);\n } else {\n // HTTP is served per-request via `handleHttpRequest()` (mounted by the\n // runtime dispatcher at `/api/v1/mcp`), not through a long-lived\n // `connect()` like stdio — so there is nothing to start here.\n logger?.info('[MCP] HTTP transport ready (served per-request at /api/v1/mcp).');\n }\n }\n\n /**\n * Stop the MCP server and disconnect the transport.\n */\n async stop(): Promise<void> {\n if (!this.started) return;\n\n await this.mcpServer.close();\n this.transport = undefined;\n this.started = false;\n this.config.logger?.info('[MCP] Server stopped');\n }\n\n // ── HTTP (Streamable HTTP) transport ───────────────────────────\n\n /**\n * Handle one MCP request over the **Streamable HTTP** transport (Web Standard\n * `Request`/`Response`), the network-reachable surface for external agents.\n *\n * Stateless by design: a fresh {@link McpServer} + transport is built per\n * request (the SDK-recommended pattern for stateless HTTP — it avoids any\n * cross-request session/request-id collision and keeps each call isolated).\n * The tool set is the object-CRUD bridge, bound to the **caller's principal**\n * via `bridge`; the runtime wires that bridge to the existing permission +\n * RLS path, so an external agent can never exceed the key's authority.\n *\n * Only the object-CRUD tools are exposed here — the internal AI/authoring\n * toolRegistry (which can mutate metadata) is deliberately NOT bridged onto\n * the external surface.\n *\n * @param request The inbound Web `Request` (headers/method/url).\n * @param opts.bridge Principal-bound data accessor (required to expose tools).\n * @param opts.parsedBody Pre-parsed JSON-RPC body (the dispatcher already read it).\n * @param opts.authInfo Optional auth info forwarded to message handlers.\n * @param opts.toolOptions Object-tool exposure options (system objects, limits).\n */\n async handleHttpRequest(\n request: Request,\n opts: {\n bridge?: McpDataBridge;\n parsedBody?: unknown;\n authInfo?: unknown;\n toolOptions?: RegisterObjectToolsOptions;\n } = {},\n ): Promise<Response> {\n // Fresh, isolated server per request (stateless).\n const server = new McpServer(\n { name: this.config.name, version: this.config.version },\n {\n capabilities: { tools: {} },\n instructions:\n this.config.instructions ??\n 'ObjectStack MCP Server — query and modify your app\\'s data objects as tools.',\n },\n );\n\n if (opts.bridge) {\n registerObjectTools(server, opts.bridge, opts.toolOptions);\n }\n\n const transport = new WebStandardStreamableHTTPServerTransport({\n // Stateless: no session id, single request/response.\n sessionIdGenerator: undefined,\n // Return a buffered JSON response (no long-lived SSE) — fits the\n // Worker→container hop without streaming pass-through concerns.\n enableJsonResponse: true,\n });\n\n await server.connect(transport);\n try {\n // JSON-response mode fully materialises the Response before resolving,\n // so it is safe to close the per-request server in `finally`.\n return await transport.handleRequest(request, {\n parsedBody: opts.parsedBody,\n authInfo: opts.authInfo as any,\n });\n } finally {\n await server.close().catch(() => {});\n }\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * mcp-http-tools — object CRUD exposed as MCP tools for the HTTP transport.\n *\n * These are the tools an external agent (Claude Desktop / Cursor) drives over\n * the network. Unlike the stdio bridge — which is a trusted local process —\n * the HTTP surface is reached by arbitrary callers, so every operation MUST\n * run under the caller's resolved principal. We never touch the data engine\n * directly here: all reads/writes go through an injected {@link McpDataBridge}\n * that the runtime wires to the SAME permission/RLS-enforcing path the REST\n * API uses (`callData` with the request's ExecutionContext). This module owns\n * the tool *shape*; the bridge owns *execution + security*.\n *\n * SECURITY (zero-tolerance):\n * - System objects (`sys_*`) are NOT exposed by default — fail-closed guard on\n * every tool that takes an object name, independent of the bridge.\n * - The bridge is bound to the caller's principal; tools cannot widen it.\n * - Errors are returned as tool errors (text), never thrown across the wire,\n * and never include secrets.\n */\n\nimport { z } from 'zod';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\n\nexport interface McpObjectSummary {\n name: string;\n label?: string;\n fieldCount?: number;\n}\n\n/**\n * Data access seam for the HTTP MCP tools. Implemented by the runtime/dispatcher\n * so execution flows through the existing permission + RLS path bound to the\n * caller's ExecutionContext. Every method runs AS the authenticated principal.\n */\nexport interface McpDataBridge {\n listObjects(): Promise<McpObjectSummary[]>;\n describeObject(name: string): Promise<unknown | null>;\n query(\n object: string,\n opts: {\n where?: Record<string, unknown>;\n fields?: string[];\n limit?: number;\n offset?: number;\n orderBy?: Array<{ field: string; order: 'asc' | 'desc' }>;\n },\n ): Promise<unknown>;\n get(object: string, id: string): Promise<unknown>;\n create(object: string, data: Record<string, unknown>): Promise<unknown>;\n update(object: string, id: string, data: Record<string, unknown>): Promise<unknown>;\n remove(object: string, id: string): Promise<unknown>;\n}\n\nexport interface RegisterObjectToolsOptions {\n /** Expose `sys_*` system objects too. Default false (fail-closed). */\n allowSystemObjects?: boolean;\n /** Hard cap on `query_records` page size. Default 50. */\n maxQueryLimit?: number;\n}\n\nconst DEFAULT_MAX_LIMIT = 50;\n\n/** A `sys_`-prefixed object is a system table — off-limits to external agents. */\nfunction isSystemObject(name: string): boolean {\n return /^sys_/i.test(name);\n}\n\nfunction textResult(value: unknown) {\n return { content: [{ type: 'text' as const, text: jsonText(value) }] };\n}\n\nfunction errorResult(message: string) {\n return { content: [{ type: 'text' as const, text: message }], isError: true as const };\n}\n\nfunction jsonText(value: unknown): string {\n try {\n return JSON.stringify(value, null, 2);\n } catch {\n return String(value);\n }\n}\n\n/**\n * Register the object-CRUD tool set on a fresh per-request {@link McpServer}.\n * All execution is delegated to `bridge`, which is bound to the caller's\n * principal by the runtime.\n */\nexport function registerObjectTools(\n server: McpServer,\n bridge: McpDataBridge,\n options: RegisterObjectToolsOptions = {},\n): void {\n const allowSystem = options.allowSystemObjects === true;\n const maxLimit = options.maxQueryLimit ?? DEFAULT_MAX_LIMIT;\n\n /** Fail-closed object-name guard shared by every object-scoped tool. */\n const guard = (objectName: string): string | undefined => {\n if (!objectName || typeof objectName !== 'string') return 'objectName is required';\n if (!allowSystem && isSystemObject(objectName)) {\n return `Object \"${objectName}\" is a system object and is not exposed via MCP`;\n }\n return undefined;\n };\n\n server.registerTool(\n 'list_objects',\n {\n description:\n 'List the data objects (tables) available in this app. Returns each object\\'s name, label and field count.',\n inputSchema: {},\n annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false },\n },\n async () => {\n try {\n const objects = await bridge.listObjects();\n const visible = allowSystem ? objects : objects.filter((o) => !isSystemObject(o.name));\n return textResult({ objects: visible, totalCount: visible.length });\n } catch (err) {\n return errorResult(messageOf(err));\n }\n },\n );\n\n server.registerTool(\n 'describe_object',\n {\n description:\n 'Get the schema of a data object: its fields (name, type, label, required) and enabled features.',\n inputSchema: { objectName: z.string().describe('The object/table name, e.g. \"task\"') },\n annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false },\n },\n async ({ objectName }) => {\n const bad = guard(objectName);\n if (bad) return errorResult(bad);\n try {\n const def = await bridge.describeObject(objectName);\n if (!def) return errorResult(`Object \"${objectName}\" not found`);\n return textResult(def);\n } catch (err) {\n return errorResult(messageOf(err));\n }\n },\n );\n\n server.registerTool(\n 'query_records',\n {\n description:\n 'Query records from an object with optional filter, field selection, sorting and pagination. ' +\n 'Runs under the caller\\'s permissions and row-level security.',\n inputSchema: {\n objectName: z.string().describe('The object/table name'),\n where: z\n .record(z.string(), z.unknown())\n .optional()\n .describe('Filter conditions, e.g. {\"status\":\"open\"}'),\n fields: z.array(z.string()).optional().describe('Field names to return (defaults to all)'),\n limit: z.number().int().positive().max(maxLimit).optional().describe(`Max rows (≤ ${maxLimit})`),\n offset: z.number().int().nonnegative().optional().describe('Rows to skip'),\n orderBy: z\n .array(z.object({ field: z.string(), order: z.enum(['asc', 'desc']) }))\n .optional()\n .describe('Sort order'),\n },\n annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false },\n },\n async ({ objectName, where, fields, limit, offset, orderBy }) => {\n const bad = guard(objectName);\n if (bad) return errorResult(bad);\n try {\n const result = await bridge.query(objectName, {\n where,\n fields,\n limit: Math.min(limit ?? maxLimit, maxLimit),\n offset,\n orderBy,\n });\n return textResult(result);\n } catch (err) {\n return errorResult(messageOf(err));\n }\n },\n );\n\n server.registerTool(\n 'get_record',\n {\n description: 'Fetch a single record by id.',\n inputSchema: {\n objectName: z.string().describe('The object/table name'),\n recordId: z.string().describe('The record id'),\n },\n annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false },\n },\n async ({ objectName, recordId }) => {\n const bad = guard(objectName);\n if (bad) return errorResult(bad);\n try {\n const record = await bridge.get(objectName, recordId);\n if (record == null) return errorResult(`Record \"${recordId}\" not found in \"${objectName}\"`);\n return textResult(record);\n } catch (err) {\n return errorResult(messageOf(err));\n }\n },\n );\n\n server.registerTool(\n 'create_record',\n {\n description: 'Create a new record. Runs under the caller\\'s permissions and validations.',\n inputSchema: {\n objectName: z.string().describe('The object/table name'),\n data: z.record(z.string(), z.unknown()).describe('Field values for the new record'),\n },\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },\n },\n async ({ objectName, data }) => {\n const bad = guard(objectName);\n if (bad) return errorResult(bad);\n try {\n return textResult(await bridge.create(objectName, data));\n } catch (err) {\n return errorResult(messageOf(err));\n }\n },\n );\n\n server.registerTool(\n 'update_record',\n {\n description: 'Update fields on an existing record by id.',\n inputSchema: {\n objectName: z.string().describe('The object/table name'),\n recordId: z.string().describe('The record id'),\n data: z.record(z.string(), z.unknown()).describe('Field values to change'),\n },\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },\n },\n async ({ objectName, recordId, data }) => {\n const bad = guard(objectName);\n if (bad) return errorResult(bad);\n try {\n return textResult(await bridge.update(objectName, recordId, data));\n } catch (err) {\n return errorResult(messageOf(err));\n }\n },\n );\n\n server.registerTool(\n 'delete_record',\n {\n description: 'Delete a record by id. This is destructive.',\n inputSchema: {\n objectName: z.string().describe('The object/table name'),\n recordId: z.string().describe('The record id'),\n },\n annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false },\n },\n async ({ objectName, recordId }) => {\n const bad = guard(objectName);\n if (bad) return errorResult(bad);\n try {\n return textResult(await bridge.remove(objectName, recordId));\n } catch (err) {\n return errorResult(messageOf(err));\n }\n },\n );\n}\n\nfunction messageOf(err: unknown): string {\n if (err instanceof Error) return err.message;\n if (err && typeof err === 'object' && 'message' in err) return String((err as any).message);\n return String(err);\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * skill — the generic, portable ObjectStack Agent Skill.\n *\n * Per ADR-0036 (Amendment C): the cross-agent distributable is ONE generic\n * Skill, not per-app artifacts and not hand-maintained vendor config snippets.\n * Agent Skills (`SKILL.md`) is an open, cross-platform standard (Claude Code,\n * OpenAI Codex, Gemini CLI, Copilot, Cursor, …), so this single skill teaches\n * any skills-capable agent how to drive an ObjectStack environment over MCP.\n *\n * The skill content is GENERIC — it never enumerates a tenant's schema (that is\n * discovered live via the `list_objects` / `describe_object` MCP tools). Only\n * the connection URL is environment-specific, slotted in by\n * {@link renderSkillMarkdown}. So one skill install works for every env and\n * every app the caller's key can reach; building a new app needs no reinstall.\n *\n * This module is the single source of truth for the skill; serve it (objectui /\n * cloud) by calling {@link renderSkillMarkdown} with the env's MCP URL.\n */\n\n/** Skill identity (mirrors the `SKILL.md` YAML frontmatter). */\nexport const OBJECTSTACK_SKILL_NAME = 'objectstack';\nexport const OBJECTSTACK_SKILL_DESCRIPTION =\n 'Query and modify data in an ObjectStack app over MCP — discover objects, ' +\n 'read and filter records, and create/update/delete under your own ' +\n 'permissions and row-level security. Use when the user wants to inspect or ' +\n 'change data in their ObjectStack environment.';\n\nexport interface RenderSkillOptions {\n /**\n * The environment's MCP endpoint, e.g. `https://acme.objectos.app/api/v1/mcp`.\n * When omitted a clearly-marked placeholder is used so the skill is still\n * valid and self-explanatory.\n */\n mcpUrl?: string;\n /** Optional human label for the environment, shown in the intro. */\n envName?: string;\n}\n\nconst URL_PLACEHOLDER = '<YOUR_ENV_MCP_URL>'; // e.g. https://<env>.objectos.app/api/v1/mcp\n\n/**\n * Render the full `SKILL.md` (YAML frontmatter + body). Pass the env's MCP URL\n * to produce a ready-to-install skill; the body is otherwise generic.\n */\nexport function renderSkillMarkdown(options: RenderSkillOptions = {}): string {\n const url = options.mcpUrl?.trim() || URL_PLACEHOLDER;\n const envLabel = options.envName?.trim();\n const intro = envLabel\n ? `This skill connects you to the **${envLabel}** ObjectStack environment.`\n : 'This skill connects you to an ObjectStack environment.';\n\n return `---\nname: ${OBJECTSTACK_SKILL_NAME}\ndescription: ${OBJECTSTACK_SKILL_DESCRIPTION}\n---\n\n# ObjectStack\n\n${intro} An ObjectStack environment exposes its data **objects** (tables) as\ntools over the Model Context Protocol (MCP). Every operation runs **as you** —\nunder your account's permissions and row-level security — so you may see a\nsubset of rows, or get a permission error on a write. That is expected\ngovernance, not a failure.\n\n## When to use\n\nUse these tools whenever the user wants to **inspect or change data** in their\nObjectStack app: look up records, filter/report, create or update entries, or\nclean up data. Prefer these tools over guessing — the environment is the source\nof truth.\n\n## Connect\n\nThis skill drives the MCP server at:\n\n\\`\\`\\`\n${url}\n\\`\\`\\`\n\nAuthenticate with an ObjectStack API key sent as a request header (the key is\nshown to you once when created; treat it like a password):\n\n\\`\\`\\`\nx-api-key: <YOUR_API_KEY>\n\\`\\`\\`\n\n(The header \\`Authorization: ApiKey <YOUR_API_KEY>\\` is also accepted.) If your\nMCP client supports custom headers on a remote server, set the header there.\n\n## Discover before you act\n\nThe schema is **not** baked into this skill — it is discovered live, so it is\nalways current even as the app evolves:\n\n1. \\`list_objects\\` — see what objects exist.\n2. \\`describe_object({ objectName })\\` — get an object's fields (name, type,\n required) before querying or writing it.\n\nAlways discover the relevant object's shape before constructing a filter or a\ncreate/update payload.\n\n## Tools\n\n- **list_objects()** — list available objects (system \\`sys_*\\` objects are hidden).\n- **describe_object({ objectName })** — an object's fields and features.\n- **query_records({ objectName, where?, fields?, limit?, offset?, orderBy? })** —\n read records. \\`where\\` is a field→value match, e.g. \\`{ \"status\": \"open\" }\\`.\n Results are page-capped; use \\`limit\\`/\\`offset\\` to page.\n- **get_record({ objectName, recordId })** — fetch one record by id.\n- **create_record({ objectName, data })** — create a record.\n- **update_record({ objectName, recordId, data })** — change fields on a record.\n- **delete_record({ objectName, recordId })** — delete a record (destructive —\n confirm with the user first).\n\n## Conventions & gotchas\n\n- **Permissions/RLS apply to every call.** Fewer rows than expected, or a\n write that's rejected, usually means your key isn't authorized — don't retry\n blindly; tell the user.\n- **Discover, don't assume.** Object and field names vary per app; always\n \\`list_objects\\` / \\`describe_object\\` first.\n- **Writes are real and immediate.** There is no implicit dry-run. Confirm\n destructive actions (\\`delete_record\\`, bulk updates) with the user.\n- **Page large reads.** Use \\`limit\\`/\\`offset\\` rather than asking for everything.\n\n## Recommended workflow\n\n1. \\`list_objects\\` to orient.\n2. \\`describe_object\\` on the target object.\n3. \\`query_records\\` to read / verify current state.\n4. \\`create_record\\` / \\`update_record\\` / \\`delete_record\\` to make changes,\n confirming destructive steps with the user.\n`;\n}\n"],"mappings":"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","names":["z"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@objectstack/mcp",
|
|
3
|
+
"version": "8.0.0",
|
|
4
|
+
"license": "Apache-2.0",
|
|
5
|
+
"description": "ObjectStack as an MCP server — exposes your app's objects (and AI tools) over the Model Context Protocol (stdio + Streamable HTTP)",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
18
|
+
"zod": "^4.4.3",
|
|
19
|
+
"@objectstack/core": "8.0.0",
|
|
20
|
+
"@objectstack/spec": "8.0.0",
|
|
21
|
+
"@objectstack/types": "8.0.0"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/node": "^25.9.1",
|
|
25
|
+
"typescript": "^6.0.3",
|
|
26
|
+
"vitest": "^4.1.8"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"objectstack",
|
|
30
|
+
"plugin",
|
|
31
|
+
"mcp",
|
|
32
|
+
"ai",
|
|
33
|
+
"llm",
|
|
34
|
+
"tools"
|
|
35
|
+
],
|
|
36
|
+
"author": "ObjectStack",
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "https://github.com/objectstack-ai/framework.git",
|
|
40
|
+
"directory": "packages/mcp"
|
|
41
|
+
},
|
|
42
|
+
"homepage": "https://objectstack.ai/docs",
|
|
43
|
+
"bugs": "https://github.com/objectstack-ai/framework/issues",
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public"
|
|
46
|
+
},
|
|
47
|
+
"files": [
|
|
48
|
+
"dist",
|
|
49
|
+
"README.md"
|
|
50
|
+
],
|
|
51
|
+
"engines": {
|
|
52
|
+
"node": ">=18.0.0"
|
|
53
|
+
},
|
|
54
|
+
"scripts": {
|
|
55
|
+
"build": "tsup --config ../../tsup.config.ts",
|
|
56
|
+
"test": "vitest run"
|
|
57
|
+
}
|
|
58
|
+
}
|