@objectstack/mcp 11.0.0 → 11.1.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/dist/index.cjs CHANGED
@@ -714,9 +714,9 @@ var MCPServerPlugin = class {
714
714
  }
715
715
  async init(ctx) {
716
716
  const config = {
717
- name: (0, import_types.readEnvWithDeprecation)("OS_MCP_SERVER_NAME", "MCP_SERVER_NAME") ?? this.options.name ?? "objectstack",
717
+ name: (0, import_types.readEnvWithDeprecation)("OS_MCP_SERVER_NAME", "MCP_SERVER_NAME", { silent: true }) ?? this.options.name ?? "objectstack",
718
718
  version: this.options.version ?? "1.0.0",
719
- transport: (0, import_types.readEnvWithDeprecation)("OS_MCP_SERVER_TRANSPORT", "MCP_SERVER_TRANSPORT") ?? this.options.transport ?? "stdio",
719
+ transport: (0, import_types.readEnvWithDeprecation)("OS_MCP_SERVER_TRANSPORT", "MCP_SERVER_TRANSPORT", { silent: true }) ?? this.options.transport ?? "stdio",
720
720
  instructions: this.options.instructions,
721
721
  logger: ctx.logger
722
722
  };
@@ -752,7 +752,7 @@ var MCPServerPlugin = class {
752
752
  this.runtime.bridgeResources(metadataService, dataEngine);
753
753
  this.runtime.bridgePrompts(metadataService);
754
754
  }
755
- const shouldStart = this.options.autoStart || (0, import_types.readEnvWithDeprecation)("OS_MCP_SERVER_ENABLED", "MCP_SERVER_ENABLED") === "true";
755
+ const shouldStart = this.options.autoStart || (0, import_types.readEnvWithDeprecation)("OS_MCP_SERVER_ENABLED", "MCP_SERVER_ENABLED", { silent: true }) === "true";
756
756
  if (shouldStart) {
757
757
  await this.runtime.start();
758
758
  ctx.logger.info("[MCP] Server started automatically");
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../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\n/**\n * @objectstack/mcp\n *\n * ObjectStack as an MCP server. Exposes your app's objects (and registered AI\n * tools, data resources, agent prompts) over the Model Context Protocol — via\n * stdio (local) and Streamable HTTP (remote agents: Claude, Cursor, Codex,\n * Gemini, Copilot, …). The inbound sibling (consuming external MCP servers) is\n * `@objectstack/connector-mcp`.\n */\n\nexport { MCPServerPlugin } from './plugin.js';\nexport type { MCPServerPluginOptions } from './plugin.js';\nexport { MCPServerRuntime } from './mcp-server-runtime.js';\nexport type { MCPServerRuntimeConfig } from './mcp-server-runtime.js';\nexport { registerObjectTools, registerActionTools } from './mcp-http-tools.js';\nexport type {\n McpDataBridge,\n McpObjectSummary,\n RegisterObjectToolsOptions,\n McpActionBridge,\n McpActionSummary,\n McpActionParamSummary,\n RegisterActionToolsOptions,\n} from './mcp-http-tools.js';\nexport {\n renderSkillMarkdown,\n OBJECTSTACK_SKILL_NAME,\n OBJECTSTACK_SKILL_DESCRIPTION,\n} from './skill.js';\nexport type { RenderSkillOptions } from './skill.js';\n","// 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, registerActionTools } from './mcp-http-tools.js';\nimport type {\n McpDataBridge,\n McpActionBridge,\n RegisterObjectToolsOptions,\n RegisterActionToolsOptions,\n} 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 plus — when the bridge can resolve\n * the framework's action mechanism — the business-action tools\n * (`list_actions` / `run_action`), all 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 these native 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 (+ optional action) 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 Tool exposure options (system objects, query limits).\n */\n async handleHttpRequest(\n request: Request,\n opts: {\n bridge?: McpDataBridge & Partial<McpActionBridge>;\n parsedBody?: unknown;\n authInfo?: unknown;\n toolOptions?: RegisterObjectToolsOptions & RegisterActionToolsOptions;\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 // The action surface is wired by capability: only when the runtime's\n // bridge can resolve + dispatch the framework's actions. A host with no\n // action mechanism keeps serving object tools unchanged (graceful\n // degradation, mirroring how record resources need a dataEngine).\n if (\n typeof opts.bridge.listActions === 'function' &&\n typeof opts.bridge.runAction === 'function'\n ) {\n registerActionTools(server, opts.bridge as McpActionBridge, opts.toolOptions);\n }\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\n/** One declared input parameter of a business action, LLM-facing. */\nexport interface McpActionParamSummary {\n name: string;\n type?: 'string' | 'number' | 'boolean' | 'array';\n required?: boolean;\n description?: string;\n /** Allowed values, when the param (or its backing field) is an enum. */\n enum?: string[];\n}\n\n/**\n * A business action the caller may invoke, as surfaced by `list_actions`.\n * Mirrors {@link McpObjectSummary} for the action surface: enough for an agent\n * to decide whether and how to call `run_action`, nothing engine-internal.\n */\nexport interface McpActionSummary {\n /** Declarative action name — the identifier passed to `run_action`. */\n name: string;\n /** The object the action operates on (omitted for object-less actions). */\n objectName?: string;\n /** Human label. */\n label?: string;\n /** What the action does (the authored `ai.description` when present). */\n description?: string;\n /** Dispatch kind: `script` | `flow` | `api`. */\n type?: string;\n /** True when the action acts on a row and so needs a `recordId`. */\n requiresRecord?: boolean;\n /** True when the action is destructive / an author flagged it for confirmation. */\n requiresConfirmation?: boolean;\n /** Declared input parameters. */\n params?: McpActionParamSummary[];\n}\n\n/**\n * Action-execution seam for the HTTP MCP tools. Implemented by the runtime so\n * resolution + dispatch flows through the framework's own action mechanism\n * (`IDataEngine.executeAction` / automation flow runner) bound to the caller's\n * ExecutionContext — the SAME permission + RLS path the REST `/actions/...`\n * endpoint uses. Every method runs AS the authenticated principal.\n *\n * Deliberately decoupled from {@link McpDataBridge}: a runtime that cannot\n * resolve the action mechanism simply does not implement this, and the action\n * tools are then not registered (graceful degradation — see\n * `registerActionTools`). Bridging here is direct framework-contract access; it\n * does NOT depend on `@objectstack/service-ai`.\n */\nexport interface McpActionBridge {\n /** Actions the caller may run, already filtered by permission + visibility. */\n listActions(): Promise<McpActionSummary[]>;\n /**\n * Invoke an action by its declarative name. Resolves the action (optionally\n * scoped by `objectName` to disambiguate), enforces its `requiredPermissions`\n * as the caller, loads the subject record under RLS when row-context, then\n * dispatches through the framework action runner. Throws on\n * denial / not-found / handler failure so the tool surfaces a tool-error.\n */\n runAction(\n name: string,\n input: { objectName?: string; recordId?: string; params?: Record<string, unknown> },\n ): Promise<unknown>;\n}\n\nexport interface RegisterActionToolsOptions {\n /** Expose actions on `sys_*` system objects too. Default false (fail-closed). */\n allowSystemObjects?: boolean;\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\n/**\n * Register the business-action tool set (`list_actions`, `run_action`) on a\n * fresh per-request {@link McpServer}. This is the action analogue of\n * {@link registerObjectTools}: it owns the tool *shape* and delegates all\n * resolution + dispatch + security to `bridge`, which the runtime binds to the\n * caller's principal.\n *\n * Symmetry with the object tools is deliberate — like `list_objects`/CRUD, the\n * action surface exposes the *mechanism* and relies on the bridge's\n * permission + RLS enforcement (not a separate AI opt-in flag) for safety,\n * with `sys_*`-scoped actions held back fail-closed by default.\n */\nexport function registerActionTools(\n server: McpServer,\n bridge: McpActionBridge,\n options: RegisterActionToolsOptions = {},\n): void {\n const allowSystem = options.allowSystemObjects === true;\n\n server.registerTool(\n 'list_actions',\n {\n description:\n 'List the business actions you can invoke in this app (e.g. \"complete task\", \"convert lead\"). ' +\n 'Returns each action\\'s name, the object it operates on, a description, whether it needs a record id, ' +\n 'whether it is destructive, and its input parameters. Only actions the caller is permitted to run are returned. ' +\n 'Use run_action to invoke one.',\n inputSchema: {},\n annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false },\n },\n async () => {\n try {\n const actions = await bridge.listActions();\n const visible = allowSystem\n ? actions\n : actions.filter((a) => !a.objectName || !isSystemObject(a.objectName));\n return textResult({ actions: visible, totalCount: visible.length });\n } catch (err) {\n return errorResult(messageOf(err));\n }\n },\n );\n\n server.registerTool(\n 'run_action',\n {\n description:\n 'Invoke a business action by name (see list_actions). Runs the app\\'s registered business logic ' +\n 'under the caller\\'s permissions and row-level security — this can mutate data or trigger flows. ' +\n 'Supply recordId for actions that operate on a specific record, and params for any declared inputs.',\n inputSchema: {\n actionName: z.string().describe('The action name from list_actions, e.g. \"complete_task\"'),\n objectName: z\n .string()\n .optional()\n .describe('The object the action belongs to. Optional; required only to disambiguate a name shared by multiple objects.'),\n recordId: z\n .string()\n .optional()\n .describe('The id of the record to act on (for record-scoped actions).'),\n params: z\n .record(z.string(), z.unknown())\n .optional()\n .describe('Input parameters declared by the action.'),\n },\n // Actions execute app-defined business logic with side effects (writes,\n // flows, outbound calls), so we mark the tool destructive + open-world:\n // MCP clients should confirm before invoking. Per-action destructiveness\n // is further surfaced via `requiresConfirmation` in list_actions.\n annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: true },\n },\n async ({ actionName, objectName, recordId, params }) => {\n if (!actionName || typeof actionName !== 'string') {\n return errorResult('actionName is required');\n }\n if (objectName && !allowSystem && isSystemObject(objectName)) {\n return errorResult(`Object \"${objectName}\" is a system object and its actions are not exposed via MCP`);\n }\n try {\n const result = await bridge.runAction(actionName, { objectName, recordId, params });\n return textResult(result);\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":["import_zod"]}
1
+ {"version":3,"sources":["../src/index.ts","../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\n/**\n * @objectstack/mcp\n *\n * ObjectStack as an MCP server. Exposes your app's objects (and registered AI\n * tools, data resources, agent prompts) over the Model Context Protocol — via\n * stdio (local) and Streamable HTTP (remote agents: Claude, Cursor, Codex,\n * Gemini, Copilot, …). The inbound sibling (consuming external MCP servers) is\n * `@objectstack/connector-mcp`.\n */\n\nexport { MCPServerPlugin } from './plugin.js';\nexport type { MCPServerPluginOptions } from './plugin.js';\nexport { MCPServerRuntime } from './mcp-server-runtime.js';\nexport type { MCPServerRuntimeConfig } from './mcp-server-runtime.js';\nexport { registerObjectTools, registerActionTools } from './mcp-http-tools.js';\nexport type {\n McpDataBridge,\n McpObjectSummary,\n RegisterObjectToolsOptions,\n McpActionBridge,\n McpActionSummary,\n McpActionParamSummary,\n RegisterActionToolsOptions,\n} from './mcp-http-tools.js';\nexport {\n renderSkillMarkdown,\n OBJECTSTACK_SKILL_NAME,\n OBJECTSTACK_SKILL_DESCRIPTION,\n} from './skill.js';\nexport type { RenderSkillOptions } from './skill.js';\n","// 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', { silent: true }) ?? this.options.name ?? 'objectstack',\n version: this.options.version ?? '1.0.0',\n transport: (readEnvWithDeprecation('OS_MCP_SERVER_TRANSPORT', 'MCP_SERVER_TRANSPORT', { silent: true }) 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', { silent: true }) === '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, registerActionTools } from './mcp-http-tools.js';\nimport type {\n McpDataBridge,\n McpActionBridge,\n RegisterObjectToolsOptions,\n RegisterActionToolsOptions,\n} 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 plus — when the bridge can resolve\n * the framework's action mechanism — the business-action tools\n * (`list_actions` / `run_action`), all 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 these native 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 (+ optional action) 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 Tool exposure options (system objects, query limits).\n */\n async handleHttpRequest(\n request: Request,\n opts: {\n bridge?: McpDataBridge & Partial<McpActionBridge>;\n parsedBody?: unknown;\n authInfo?: unknown;\n toolOptions?: RegisterObjectToolsOptions & RegisterActionToolsOptions;\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 // The action surface is wired by capability: only when the runtime's\n // bridge can resolve + dispatch the framework's actions. A host with no\n // action mechanism keeps serving object tools unchanged (graceful\n // degradation, mirroring how record resources need a dataEngine).\n if (\n typeof opts.bridge.listActions === 'function' &&\n typeof opts.bridge.runAction === 'function'\n ) {\n registerActionTools(server, opts.bridge as McpActionBridge, opts.toolOptions);\n }\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\n/** One declared input parameter of a business action, LLM-facing. */\nexport interface McpActionParamSummary {\n name: string;\n type?: 'string' | 'number' | 'boolean' | 'array';\n required?: boolean;\n description?: string;\n /** Allowed values, when the param (or its backing field) is an enum. */\n enum?: string[];\n}\n\n/**\n * A business action the caller may invoke, as surfaced by `list_actions`.\n * Mirrors {@link McpObjectSummary} for the action surface: enough for an agent\n * to decide whether and how to call `run_action`, nothing engine-internal.\n */\nexport interface McpActionSummary {\n /** Declarative action name — the identifier passed to `run_action`. */\n name: string;\n /** The object the action operates on (omitted for object-less actions). */\n objectName?: string;\n /** Human label. */\n label?: string;\n /** What the action does (the authored `ai.description` when present). */\n description?: string;\n /** Dispatch kind: `script` | `flow` | `api`. */\n type?: string;\n /** True when the action acts on a row and so needs a `recordId`. */\n requiresRecord?: boolean;\n /** True when the action is destructive / an author flagged it for confirmation. */\n requiresConfirmation?: boolean;\n /** Declared input parameters. */\n params?: McpActionParamSummary[];\n}\n\n/**\n * Action-execution seam for the HTTP MCP tools. Implemented by the runtime so\n * resolution + dispatch flows through the framework's own action mechanism\n * (`IDataEngine.executeAction` / automation flow runner) bound to the caller's\n * ExecutionContext — the SAME permission + RLS path the REST `/actions/...`\n * endpoint uses. Every method runs AS the authenticated principal.\n *\n * Deliberately decoupled from {@link McpDataBridge}: a runtime that cannot\n * resolve the action mechanism simply does not implement this, and the action\n * tools are then not registered (graceful degradation — see\n * `registerActionTools`). Bridging here is direct framework-contract access; it\n * does NOT depend on `@objectstack/service-ai`.\n */\nexport interface McpActionBridge {\n /** Actions the caller may run, already filtered by permission + visibility. */\n listActions(): Promise<McpActionSummary[]>;\n /**\n * Invoke an action by its declarative name. Resolves the action (optionally\n * scoped by `objectName` to disambiguate), enforces its `requiredPermissions`\n * as the caller, loads the subject record under RLS when row-context, then\n * dispatches through the framework action runner. Throws on\n * denial / not-found / handler failure so the tool surfaces a tool-error.\n */\n runAction(\n name: string,\n input: { objectName?: string; recordId?: string; params?: Record<string, unknown> },\n ): Promise<unknown>;\n}\n\nexport interface RegisterActionToolsOptions {\n /** Expose actions on `sys_*` system objects too. Default false (fail-closed). */\n allowSystemObjects?: boolean;\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\n/**\n * Register the business-action tool set (`list_actions`, `run_action`) on a\n * fresh per-request {@link McpServer}. This is the action analogue of\n * {@link registerObjectTools}: it owns the tool *shape* and delegates all\n * resolution + dispatch + security to `bridge`, which the runtime binds to the\n * caller's principal.\n *\n * Symmetry with the object tools is deliberate — like `list_objects`/CRUD, the\n * action surface exposes the *mechanism* and relies on the bridge's\n * permission + RLS enforcement (not a separate AI opt-in flag) for safety,\n * with `sys_*`-scoped actions held back fail-closed by default.\n */\nexport function registerActionTools(\n server: McpServer,\n bridge: McpActionBridge,\n options: RegisterActionToolsOptions = {},\n): void {\n const allowSystem = options.allowSystemObjects === true;\n\n server.registerTool(\n 'list_actions',\n {\n description:\n 'List the business actions you can invoke in this app (e.g. \"complete task\", \"convert lead\"). ' +\n 'Returns each action\\'s name, the object it operates on, a description, whether it needs a record id, ' +\n 'whether it is destructive, and its input parameters. Only actions the caller is permitted to run are returned. ' +\n 'Use run_action to invoke one.',\n inputSchema: {},\n annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false },\n },\n async () => {\n try {\n const actions = await bridge.listActions();\n const visible = allowSystem\n ? actions\n : actions.filter((a) => !a.objectName || !isSystemObject(a.objectName));\n return textResult({ actions: visible, totalCount: visible.length });\n } catch (err) {\n return errorResult(messageOf(err));\n }\n },\n );\n\n server.registerTool(\n 'run_action',\n {\n description:\n 'Invoke a business action by name (see list_actions). Runs the app\\'s registered business logic ' +\n 'under the caller\\'s permissions and row-level security — this can mutate data or trigger flows. ' +\n 'Supply recordId for actions that operate on a specific record, and params for any declared inputs.',\n inputSchema: {\n actionName: z.string().describe('The action name from list_actions, e.g. \"complete_task\"'),\n objectName: z\n .string()\n .optional()\n .describe('The object the action belongs to. Optional; required only to disambiguate a name shared by multiple objects.'),\n recordId: z\n .string()\n .optional()\n .describe('The id of the record to act on (for record-scoped actions).'),\n params: z\n .record(z.string(), z.unknown())\n .optional()\n .describe('Input parameters declared by the action.'),\n },\n // Actions execute app-defined business logic with side effects (writes,\n // flows, outbound calls), so we mark the tool destructive + open-world:\n // MCP clients should confirm before invoking. Per-action destructiveness\n // is further surfaced via `requiresConfirmation` in list_actions.\n annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: true },\n },\n async ({ actionName, objectName, recordId, params }) => {\n if (!actionName || typeof actionName !== 'string') {\n return errorResult('actionName is required');\n }\n if (objectName && !allowSystem && isSystemObject(objectName)) {\n return errorResult(`Object \"${objectName}\" is a system object and its actions are not exposed via MCP`);\n }\n try {\n const result = await bridge.runAction(actionName, { objectName, recordId, params });\n return textResult(result);\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":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACGA,mBAAuC;;;ACDvC,iBAA4C;AAC5C,mBAAqC;AACrC,uCAAyD;;;ACkBzD,iBAAkB;AA4GlB,IAAM,oBAAoB;AAG1B,SAAS,eAAe,MAAuB;AAC7C,SAAO,SAAS,KAAK,IAAI;AAC3B;AAEA,SAAS,WAAW,OAAgB;AAClC,SAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,SAAS,KAAK,EAAE,CAAC,EAAE;AACvE;AAEA,SAAS,YAAY,SAAiB;AACpC,SAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,QAAQ,CAAC,GAAG,SAAS,KAAc;AACvF;AAEA,SAAS,SAAS,OAAwB;AACxC,MAAI;AACF,WAAO,KAAK,UAAU,OAAO,MAAM,CAAC;AAAA,EACtC,QAAQ;AACN,WAAO,OAAO,KAAK;AAAA,EACrB;AACF;AAOO,SAAS,oBACd,QACA,QACA,UAAsC,CAAC,GACjC;AACN,QAAM,cAAc,QAAQ,uBAAuB;AACnD,QAAM,WAAW,QAAQ,iBAAiB;AAG1C,QAAM,QAAQ,CAAC,eAA2C;AACxD,QAAI,CAAC,cAAc,OAAO,eAAe,SAAU,QAAO;AAC1D,QAAI,CAAC,eAAe,eAAe,UAAU,GAAG;AAC9C,aAAO,WAAW,UAAU;AAAA,IAC9B;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,aACE;AAAA,MACF,aAAa,CAAC;AAAA,MACd,aAAa,EAAE,cAAc,MAAM,iBAAiB,OAAO,eAAe,MAAM;AAAA,IAClF;AAAA,IACA,YAAY;AACV,UAAI;AACF,cAAM,UAAU,MAAM,OAAO,YAAY;AACzC,cAAM,UAAU,cAAc,UAAU,QAAQ,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,IAAI,CAAC;AACrF,eAAO,WAAW,EAAE,SAAS,SAAS,YAAY,QAAQ,OAAO,CAAC;AAAA,MACpE,SAAS,KAAK;AACZ,eAAO,YAAY,UAAU,GAAG,CAAC;AAAA,MACnC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,aACE;AAAA,MACF,aAAa,EAAE,YAAY,aAAE,OAAO,EAAE,SAAS,oCAAoC,EAAE;AAAA,MACrF,aAAa,EAAE,cAAc,MAAM,iBAAiB,OAAO,eAAe,MAAM;AAAA,IAClF;AAAA,IACA,OAAO,EAAE,WAAW,MAAM;AACxB,YAAM,MAAM,MAAM,UAAU;AAC5B,UAAI,IAAK,QAAO,YAAY,GAAG;AAC/B,UAAI;AACF,cAAM,MAAM,MAAM,OAAO,eAAe,UAAU;AAClD,YAAI,CAAC,IAAK,QAAO,YAAY,WAAW,UAAU,aAAa;AAC/D,eAAO,WAAW,GAAG;AAAA,MACvB,SAAS,KAAK;AACZ,eAAO,YAAY,UAAU,GAAG,CAAC;AAAA,MACnC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,aACE;AAAA,MAEF,aAAa;AAAA,QACX,YAAY,aAAE,OAAO,EAAE,SAAS,uBAAuB;AAAA,QACvD,OAAO,aACJ,OAAO,aAAE,OAAO,GAAG,aAAE,QAAQ,CAAC,EAC9B,SAAS,EACT,SAAS,2CAA2C;AAAA,QACvD,QAAQ,aAAE,MAAM,aAAE,OAAO,CAAC,EAAE,SAAS,EAAE,SAAS,yCAAyC;AAAA,QACzF,OAAO,aAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,QAAQ,EAAE,SAAS,EAAE,SAAS,oBAAe,QAAQ,GAAG;AAAA,QAC/F,QAAQ,aAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,SAAS,cAAc;AAAA,QACzE,SAAS,aACN,MAAM,aAAE,OAAO,EAAE,OAAO,aAAE,OAAO,GAAG,OAAO,aAAE,KAAK,CAAC,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC,EACrE,SAAS,EACT,SAAS,YAAY;AAAA,MAC1B;AAAA,MACA,aAAa,EAAE,cAAc,MAAM,iBAAiB,OAAO,eAAe,MAAM;AAAA,IAClF;AAAA,IACA,OAAO,EAAE,YAAY,OAAO,QAAQ,OAAO,QAAQ,QAAQ,MAAM;AAC/D,YAAM,MAAM,MAAM,UAAU;AAC5B,UAAI,IAAK,QAAO,YAAY,GAAG;AAC/B,UAAI;AACF,cAAM,SAAS,MAAM,OAAO,MAAM,YAAY;AAAA,UAC5C;AAAA,UACA;AAAA,UACA,OAAO,KAAK,IAAI,SAAS,UAAU,QAAQ;AAAA,UAC3C;AAAA,UACA;AAAA,QACF,CAAC;AACD,eAAO,WAAW,MAAM;AAAA,MAC1B,SAAS,KAAK;AACZ,eAAO,YAAY,UAAU,GAAG,CAAC;AAAA,MACnC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,aAAa;AAAA,QACX,YAAY,aAAE,OAAO,EAAE,SAAS,uBAAuB;AAAA,QACvD,UAAU,aAAE,OAAO,EAAE,SAAS,eAAe;AAAA,MAC/C;AAAA,MACA,aAAa,EAAE,cAAc,MAAM,iBAAiB,OAAO,eAAe,MAAM;AAAA,IAClF;AAAA,IACA,OAAO,EAAE,YAAY,SAAS,MAAM;AAClC,YAAM,MAAM,MAAM,UAAU;AAC5B,UAAI,IAAK,QAAO,YAAY,GAAG;AAC/B,UAAI;AACF,cAAM,SAAS,MAAM,OAAO,IAAI,YAAY,QAAQ;AACpD,YAAI,UAAU,KAAM,QAAO,YAAY,WAAW,QAAQ,mBAAmB,UAAU,GAAG;AAC1F,eAAO,WAAW,MAAM;AAAA,MAC1B,SAAS,KAAK;AACZ,eAAO,YAAY,UAAU,GAAG,CAAC;AAAA,MACnC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,aAAa;AAAA,QACX,YAAY,aAAE,OAAO,EAAE,SAAS,uBAAuB;AAAA,QACvD,MAAM,aAAE,OAAO,aAAE,OAAO,GAAG,aAAE,QAAQ,CAAC,EAAE,SAAS,iCAAiC;AAAA,MACpF;AAAA,MACA,aAAa,EAAE,cAAc,OAAO,iBAAiB,OAAO,eAAe,MAAM;AAAA,IACnF;AAAA,IACA,OAAO,EAAE,YAAY,KAAK,MAAM;AAC9B,YAAM,MAAM,MAAM,UAAU;AAC5B,UAAI,IAAK,QAAO,YAAY,GAAG;AAC/B,UAAI;AACF,eAAO,WAAW,MAAM,OAAO,OAAO,YAAY,IAAI,CAAC;AAAA,MACzD,SAAS,KAAK;AACZ,eAAO,YAAY,UAAU,GAAG,CAAC;AAAA,MACnC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,aAAa;AAAA,QACX,YAAY,aAAE,OAAO,EAAE,SAAS,uBAAuB;AAAA,QACvD,UAAU,aAAE,OAAO,EAAE,SAAS,eAAe;AAAA,QAC7C,MAAM,aAAE,OAAO,aAAE,OAAO,GAAG,aAAE,QAAQ,CAAC,EAAE,SAAS,wBAAwB;AAAA,MAC3E;AAAA,MACA,aAAa,EAAE,cAAc,OAAO,iBAAiB,OAAO,eAAe,MAAM;AAAA,IACnF;AAAA,IACA,OAAO,EAAE,YAAY,UAAU,KAAK,MAAM;AACxC,YAAM,MAAM,MAAM,UAAU;AAC5B,UAAI,IAAK,QAAO,YAAY,GAAG;AAC/B,UAAI;AACF,eAAO,WAAW,MAAM,OAAO,OAAO,YAAY,UAAU,IAAI,CAAC;AAAA,MACnE,SAAS,KAAK;AACZ,eAAO,YAAY,UAAU,GAAG,CAAC;AAAA,MACnC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,aAAa;AAAA,QACX,YAAY,aAAE,OAAO,EAAE,SAAS,uBAAuB;AAAA,QACvD,UAAU,aAAE,OAAO,EAAE,SAAS,eAAe;AAAA,MAC/C;AAAA,MACA,aAAa,EAAE,cAAc,OAAO,iBAAiB,MAAM,eAAe,MAAM;AAAA,IAClF;AAAA,IACA,OAAO,EAAE,YAAY,SAAS,MAAM;AAClC,YAAM,MAAM,MAAM,UAAU;AAC5B,UAAI,IAAK,QAAO,YAAY,GAAG;AAC/B,UAAI;AACF,eAAO,WAAW,MAAM,OAAO,OAAO,YAAY,QAAQ,CAAC;AAAA,MAC7D,SAAS,KAAK;AACZ,eAAO,YAAY,UAAU,GAAG,CAAC;AAAA,MACnC;AAAA,IACF;AAAA,EACF;AACF;AAcO,SAAS,oBACd,QACA,QACA,UAAsC,CAAC,GACjC;AACN,QAAM,cAAc,QAAQ,uBAAuB;AAEnD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,aACE;AAAA,MAIF,aAAa,CAAC;AAAA,MACd,aAAa,EAAE,cAAc,MAAM,iBAAiB,OAAO,eAAe,MAAM;AAAA,IAClF;AAAA,IACA,YAAY;AACV,UAAI;AACF,cAAM,UAAU,MAAM,OAAO,YAAY;AACzC,cAAM,UAAU,cACZ,UACA,QAAQ,OAAO,CAAC,MAAM,CAAC,EAAE,cAAc,CAAC,eAAe,EAAE,UAAU,CAAC;AACxE,eAAO,WAAW,EAAE,SAAS,SAAS,YAAY,QAAQ,OAAO,CAAC;AAAA,MACpE,SAAS,KAAK;AACZ,eAAO,YAAY,UAAU,GAAG,CAAC;AAAA,MACnC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,aACE;AAAA,MAGF,aAAa;AAAA,QACX,YAAY,aAAE,OAAO,EAAE,SAAS,yDAAyD;AAAA,QACzF,YAAY,aACT,OAAO,EACP,SAAS,EACT,SAAS,8GAA8G;AAAA,QAC1H,UAAU,aACP,OAAO,EACP,SAAS,EACT,SAAS,6DAA6D;AAAA,QACzE,QAAQ,aACL,OAAO,aAAE,OAAO,GAAG,aAAE,QAAQ,CAAC,EAC9B,SAAS,EACT,SAAS,0CAA0C;AAAA,MACxD;AAAA;AAAA;AAAA;AAAA;AAAA,MAKA,aAAa,EAAE,cAAc,OAAO,iBAAiB,MAAM,eAAe,KAAK;AAAA,IACjF;AAAA,IACA,OAAO,EAAE,YAAY,YAAY,UAAU,OAAO,MAAM;AACtD,UAAI,CAAC,cAAc,OAAO,eAAe,UAAU;AACjD,eAAO,YAAY,wBAAwB;AAAA,MAC7C;AACA,UAAI,cAAc,CAAC,eAAe,eAAe,UAAU,GAAG;AAC5D,eAAO,YAAY,WAAW,UAAU,8DAA8D;AAAA,MACxG;AACA,UAAI;AACF,cAAM,SAAS,MAAM,OAAO,UAAU,YAAY,EAAE,YAAY,UAAU,OAAO,CAAC;AAClF,eAAO,WAAW,MAAM;AAAA,MAC1B,SAAS,KAAK;AACZ,eAAO,YAAY,UAAU,GAAG,CAAC;AAAA,MACnC;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,UAAU,KAAsB;AACvC,MAAI,eAAe,MAAO,QAAO,IAAI;AACrC,MAAI,OAAO,OAAO,QAAQ,YAAY,aAAa,IAAK,QAAO,OAAQ,IAAY,OAAO;AAC1F,SAAO,OAAO,GAAG;AACnB;;;ADpaA,IAAAA,cAAkB;AAgClB,IAAM,kBAAkB,oBAAI,IAAI;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAKD,IAAM,oBAAoB,oBAAI,IAAI;AAAA,EAChC;AACF,CAAC;AAoBM,IAAM,mBAAN,MAAM,kBAAiB;AAAA,EAM5B,YAAY,SAAiC,CAAC,GAAG;AAFjD,SAAQ,UAAU;AAGhB,SAAK,SAAS;AAAA,MACZ,MAAM;AAAA,MACN,SAAS;AAAA,MACT,WAAW;AAAA,MACX,GAAG;AAAA,IACL;AAEA,SAAK,YAAY,IAAI;AAAA,MACnB;AAAA,QACE,MAAM,KAAK,OAAO;AAAA,QAClB,SAAS,KAAK,OAAO;AAAA,MACvB;AAAA,MACA;AAAA,QACE,cAAc;AAAA,UACZ,WAAW,CAAC;AAAA,UACZ,OAAO,CAAC;AAAA,UACR,SAAS,CAAC;AAAA,UACV,SAAS,CAAC;AAAA,QACZ;AAAA,QACA,cAAc,KAAK,OAAO,gBAAgB;AAAA,MAC5C;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,IAAI,SAAoB;AACtB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,IAAI,YAAqB;AACvB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,OAAe,iBAAiB,QAAqC;AACnE,UAAM,SAAS,OAAO;AACtB,QAAI,UAAU,OAAO,WAAW,YAAY,WAAW,QAAQ;AAC7D,aAAO,OAAQ,OAA8B,KAAK;AAAA,IACpD;AACA,WAAO,KAAK,UAAU,UAAU,EAAE;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,YAAY,cAAkC;AAC5C,UAAM,QAAQ,aAAa,OAAO;AAClC,UAAM,SAAS,KAAK,OAAO;AAE3B,eAAW,QAAQ,OAAO;AACxB,WAAK,2BAA2B,MAAM,YAAY;AAAA,IACpD;AAEA,YAAQ,KAAK,iBAAiB,MAAM,MAAM,0BAA0B;AAAA,EACtE;AAAA;AAAA;AAAA;AAAA,EAKQ,2BAA2B,MAAwB,cAAkC;AAC3F,UAAM,SAAS,KAAK,OAAO;AAM3B,SAAK,UAAU;AAAA,MACb,KAAK;AAAA,MACL;AAAA,QACE,aAAa,KAAK;AAAA,QAClB,aAAa;AAAA;AAAA,UAEX,iBAAiB,KAAK,kBAAkB,KAAK,IAAI;AAAA,UACjD,cAAc,KAAK,eAAe,KAAK,IAAI;AAAA,UAC3C,eAAe;AAAA,QACjB;AAAA,MACF;AAAA,MACA,OAAO,UAAU;AAGf,cAAM,WAAW;AACjB,cAAM,OAAQ,SAAS,aAAa,CAAC;AAErC,YAAI;AACF,gBAAM,SAAS,MAAM,aAAa,QAAQ;AAAA,YACxC,MAAM;AAAA,YACN,YAAY,OAAO,KAAK,IAAI,IAAI,KAAK,IAAI,CAAC;AAAA,YAC1C,UAAU,KAAK;AAAA,YACf,OAAO;AAAA,UACT,CAAC;AAED,gBAAM,aAAa,kBAAiB,iBAAiB,MAAM;AAE3D,cAAI,OAAO,SAAS;AAClB,mBAAO;AAAA,cACL,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,WAAW,CAAC;AAAA,cACrD,SAAS;AAAA,YACX;AAAA,UACF;AAEA,iBAAO;AAAA,YACL,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,WAAW,CAAC;AAAA,UACvD;AAAA,QACF,SAAS,KAAK;AACZ,gBAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,kBAAQ,KAAK,eAAe,KAAK,IAAI,uBAAuB,EAAE,OAAO,QAAQ,CAAC;AAC9E,iBAAO;AAAA,YACL,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,QAAQ,CAAC;AAAA,YAClD,SAAS;AAAA,UACX;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,eAAe,MAAuB;AAC5C,WAAO,gBAAgB,IAAI,IAAI;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKQ,kBAAkB,MAAuB;AAC/C,WAAO,kBAAkB,IAAI,IAAI;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,gBAAgB,iBAAmC,YAAgC;AACjF,UAAM,SAAS,KAAK,OAAO;AAC3B,QAAI,gBAAgB;AAGpB,SAAK,UAAU;AAAA,MACb;AAAA,MACA;AAAA,MACA;AAAA,QACE,aAAa;AAAA,QACb,UAAU;AAAA,MACZ;AAAA,MACA,YAAY;AACV,cAAM,UAAU,MAAM,gBAAgB,YAAY;AAClD,cAAM,UAAW,QAAwB,IAAI,QAAM;AAAA,UACjD,MAAM,EAAE;AAAA,UACR,OAAO,EAAE,SAAS,EAAE;AAAA,UACpB,YAAY,EAAE,SAAS,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS;AAAA,QACxD,EAAE;AAEF,eAAO;AAAA,UACL,UAAU,CAAC;AAAA,YACT,KAAK;AAAA,YACL,UAAU;AAAA,YACV,MAAM,KAAK,UAAU,EAAE,SAAS,SAAS,YAAY,QAAQ,OAAO,GAAG,MAAM,CAAC;AAAA,UAChF,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AACA;AAGA,SAAK,UAAU;AAAA,MACb;AAAA,MACA,IAAI,4BAAiB,sCAAsC,EAAE,MAAM,OAAU,CAAC;AAAA,MAC9E;AAAA,QACE,aAAa;AAAA,QACb,UAAU;AAAA,MACZ;AAAA,MACA,OAAO,MAAM,cAAc;AACzB,cAAM,aAAa,OAAO,UAAU,UAAU;AAC9C,cAAM,YAAY,MAAM,gBAAgB,UAAU,UAAU;AAE5D,YAAI,CAAC,WAAW;AACd,iBAAO;AAAA,YACL,UAAU,CAAC;AAAA,cACT,KAAK,yBAAyB,UAAU;AAAA,cACxC,UAAU;AAAA,cACV,MAAM,KAAK,UAAU,EAAE,OAAO,WAAW,UAAU,cAAc,CAAC;AAAA,YACpE,CAAC;AAAA,UACH;AAAA,QACF;AAEA,cAAM,MAAM;AACZ,cAAM,SAAS,IAAI,UAAU,CAAC;AAC9B,cAAM,eAAe,OAAO,QAAQ,MAAM,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO;AAAA,UAC7D,MAAM;AAAA,UACN,MAAM,EAAE;AAAA,UACR,OAAO,EAAE,SAAS;AAAA,UAClB,UAAU,EAAE,YAAY;AAAA,QAC1B,EAAE;AAEF,eAAO;AAAA,UACL,UAAU,CAAC;AAAA,YACT,KAAK,yBAAyB,UAAU;AAAA,YACxC,UAAU;AAAA,YACV,MAAM,KAAK,UAAU;AAAA,cACnB,MAAM,IAAI;AAAA,cACV,OAAO,IAAI,SAAS,IAAI;AAAA,cACxB,QAAQ;AAAA,cACR,gBAAgB,IAAI,UAAU,CAAC;AAAA,YACjC,GAAG,MAAM,CAAC;AAAA,UACZ,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AACA;AAGA,QAAI,YAAY;AACd,WAAK,UAAU;AAAA,QACb;AAAA,QACA,IAAI,4BAAiB,yDAAyD,EAAE,MAAM,OAAU,CAAC;AAAA,QACjG;AAAA,UACE,aAAa;AAAA,UACb,UAAU;AAAA,QACZ;AAAA,QACA,OAAO,MAAM,cAAc;AACzB,gBAAM,aAAa,OAAO,UAAU,UAAU;AAC9C,gBAAM,WAAW,OAAO,UAAU,QAAQ;AAE1C,cAAI;AACF,kBAAM,SAAS,MAAM,WAAW,QAAQ,YAAY;AAAA,cAClD,OAAO,EAAE,IAAI,SAAS;AAAA,YACxB,CAAC;AAED,gBAAI,CAAC,QAAQ;AACX,qBAAO;AAAA,gBACL,UAAU,CAAC;AAAA,kBACT,KAAK,yBAAyB,UAAU,YAAY,QAAQ;AAAA,kBAC5D,UAAU;AAAA,kBACV,MAAM,KAAK,UAAU,EAAE,OAAO,WAAW,QAAQ,mBAAmB,UAAU,IAAI,CAAC;AAAA,gBACrF,CAAC;AAAA,cACH;AAAA,YACF;AAEA,mBAAO;AAAA,cACL,UAAU,CAAC;AAAA,gBACT,KAAK,yBAAyB,UAAU,YAAY,QAAQ;AAAA,gBAC5D,UAAU;AAAA,gBACV,MAAM,KAAK,UAAU,QAAQ,MAAM,CAAC;AAAA,cACtC,CAAC;AAAA,YACH;AAAA,UACF,SAAS,KAAK;AACZ,kBAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,mBAAO;AAAA,cACL,UAAU,CAAC;AAAA,gBACT,KAAK,yBAAyB,UAAU,YAAY,QAAQ;AAAA,gBAC5D,UAAU;AAAA,gBACV,MAAM,KAAK,UAAU,EAAE,OAAO,QAAQ,CAAC;AAAA,cACzC,CAAC;AAAA,YACH;AAAA,UACF;AAAA,QACF;AAAA,MACF;AACA;AAAA,IACF;AAGA,QAAI,gBAAgB,oBAAoB;AACtC,WAAK,UAAU;AAAA,QACb;AAAA,QACA;AAAA,QACA;AAAA,UACE,aAAa;AAAA,UACb,UAAU;AAAA,QACZ;AAAA,QACA,YAAY;AACV,gBAAM,QAAQ,MAAM,gBAAgB,mBAAoB;AACxD,iBAAO;AAAA,YACL,UAAU,CAAC;AAAA,cACT,KAAK;AAAA,cACL,UAAU;AAAA,cACV,MAAM,KAAK,UAAU,EAAE,OAAO,YAAY,MAAM,OAAO,GAAG,MAAM,CAAC;AAAA,YACnE,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AACA;AAAA,IACF;AAEA,YAAQ,KAAK,iBAAiB,aAAa,qBAAqB;AAAA,EAClE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,cAAc,iBAAyC;AACrD,UAAM,SAAS,KAAK,OAAO;AAG3B,SAAK,UAAU;AAAA,MACb;AAAA,MACA;AAAA,QACE,aAAa;AAAA,QAEb,YAAY;AAAA,UACV,WAAW,cAAE,OAAO,EAAE,SAAS,oEAAoE;AAAA,UACnG,YAAY,cAAE,OAAO,EAAE,SAAS,EAAE,SAAS,oCAAoC;AAAA,UAC/E,UAAU,cAAE,OAAO,EAAE,SAAS,EAAE,SAAS,8BAA8B;AAAA,UACvE,UAAU,cAAE,OAAO,EAAE,SAAS,EAAE,SAAS,mBAAmB;AAAA,QAC9D;AAAA,MACF;AAAA,MACA,OAAO,SAAS;AACd,cAAM,YAAY,OAAO,KAAK,aAAa,EAAE;AAC7C,YAAI,CAAC,WAAW;AACd,iBAAO;AAAA,YACL,UAAU,CAAC;AAAA,cACT,MAAM;AAAA,cACN,SAAS,EAAE,MAAM,QAAiB,MAAM,wCAAwC;AAAA,YAClF,CAAC;AAAA,UACH;AAAA,QACF;AAEA,cAAM,MAAM,MAAM,gBAAgB,IAAI,SAAS,SAAS;AACxD,YAAI,CAAC,KAAK;AACR,iBAAO;AAAA,YACL,UAAU,CAAC;AAAA,cACT,MAAM;AAAA,cACN,SAAS,EAAE,MAAM,QAAiB,MAAM,iBAAiB,SAAS,cAAc;AAAA,YAClF,CAAC;AAAA,UACH;AAAA,QACF;AAEA,cAAM,QAAQ;AAGd,cAAM,QAAkB,CAAC;AACzB,cAAM,KAAK,MAAM,gBAAgB,EAAE;AAEnC,cAAM,eAAyB,CAAC;AAChC,YAAI,KAAK,WAAY,cAAa,KAAK,mBAAmB,KAAK,UAAU,EAAE;AAC3E,YAAI,KAAK,SAAU,cAAa,KAAK,uBAAuB,KAAK,QAAQ,EAAE;AAC3E,YAAI,KAAK,SAAU,cAAa,KAAK,iBAAiB,KAAK,QAAQ,EAAE;AACrE,YAAI,aAAa,SAAS,GAAG;AAC3B,gBAAM,KAAK,gCAAgC,aAAa,KAAK,IAAI,CAAC;AAAA,QACpE;AAEA,eAAO;AAAA,UACL,UAAU,CAAC;AAAA,YACT,MAAM;AAAA,YACN,SAAS,EAAE,MAAM,QAAiB,MAAM,MAAM,KAAK,IAAI,EAAE;AAAA,UAC3D,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAEA,YAAQ,KAAK,6BAA6B;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,QAAuB;AAC3B,QAAI,KAAK,QAAS;AAElB,UAAM,SAAS,KAAK,OAAO;AAE3B,QAAI,KAAK,OAAO,cAAc,SAAS;AACrC,WAAK,YAAY,IAAI,kCAAqB;AAC1C,YAAM,KAAK,UAAU,QAAQ,KAAK,SAAS;AAC3C,WAAK,UAAU;AACf,cAAQ,KAAK,iDAAiD,KAAK,OAAO,IAAI,GAAG;AAAA,IACnF,OAAO;AAIL,cAAQ,KAAK,iEAAiE;AAAA,IAChF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAsB;AAC1B,QAAI,CAAC,KAAK,QAAS;AAEnB,UAAM,KAAK,UAAU,MAAM;AAC3B,SAAK,YAAY;AACjB,SAAK,UAAU;AACf,SAAK,OAAO,QAAQ,KAAK,sBAAsB;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA2BA,MAAM,kBACJ,SACA,OAKI,CAAC,GACc;AAEnB,UAAM,SAAS,IAAI;AAAA,MACjB,EAAE,MAAM,KAAK,OAAO,MAAM,SAAS,KAAK,OAAO,QAAQ;AAAA,MACvD;AAAA,QACE,cAAc,EAAE,OAAO,CAAC,EAAE;AAAA,QAC1B,cACE,KAAK,OAAO,gBACZ;AAAA,MACJ;AAAA,IACF;AAEA,QAAI,KAAK,QAAQ;AACf,0BAAoB,QAAQ,KAAK,QAAQ,KAAK,WAAW;AAKzD,UACE,OAAO,KAAK,OAAO,gBAAgB,cACnC,OAAO,KAAK,OAAO,cAAc,YACjC;AACA,4BAAoB,QAAQ,KAAK,QAA2B,KAAK,WAAW;AAAA,MAC9E;AAAA,IACF;AAEA,UAAM,YAAY,IAAI,0EAAyC;AAAA;AAAA,MAE7D,oBAAoB;AAAA;AAAA;AAAA,MAGpB,oBAAoB;AAAA,IACtB,CAAC;AAED,UAAM,OAAO,QAAQ,SAAS;AAC9B,QAAI;AAGF,aAAO,MAAM,UAAU,cAAc,SAAS;AAAA,QAC5C,YAAY,KAAK;AAAA,QACjB,UAAU,KAAK;AAAA,MACjB,CAAC;AAAA,IACH,UAAE;AACA,YAAM,OAAO,MAAM,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AAAA,IACrC;AAAA,EACF;AACF;;;ADrhBO,IAAM,kBAAN,MAAwC;AAAA,EAS7C,YAAY,UAAkC,CAAC,GAAG;AARlD,gBAAO;AACP,mBAAU;AACV,gBAAO;AACP,wBAAyB,CAAC;AAMxB,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,MAAM,KAAK,KAAmC;AAC5C,UAAM,SAAiC;AAAA,MACrC,UAAM,qCAAuB,sBAAsB,mBAAmB,EAAE,QAAQ,KAAK,CAAC,KAAK,KAAK,QAAQ,QAAQ;AAAA,MAChH,SAAS,KAAK,QAAQ,WAAW;AAAA,MACjC,eAAY,qCAAuB,2BAA2B,wBAAwB,EAAE,QAAQ,KAAK,CAAC,KAA0B,KAAK,QAAQ,aAAa;AAAA,MAC1J,cAAc,KAAK,QAAQ;AAAA,MAC3B,QAAQ,IAAI;AAAA,IACd;AAEA,SAAK,UAAU,IAAI,iBAAiB,MAAM;AAC1C,QAAI,gBAAgB,OAAO,KAAK,OAAO;AAEvC,QAAI,OAAO,KAAK,0BAA0B;AAAA,EAC5C;AAAA,EAEA,MAAM,MAAM,KAAmC;AAC7C,QAAI,CAAC,KAAK,QAAS;AAOnB,QAAI;AACF,YAAM,YAAY,IAAI,WAAyD,IAAI;AACnF,UAAI,WAAW,cAAc;AAC3B,aAAK,QAAQ,YAAY,UAAU,YAAY;AAAA,MACjD,OAAO;AACL,YAAI,OAAO,MAAM,yEAAyE;AAAA,MAC5F;AAAA,IACF,QAAQ;AACN,UAAI,OAAO,MAAM,wDAAwD;AAAA,IAC3E;AAGA,QAAI;AACJ,QAAI;AAEJ,QAAI;AACF,wBAAkB,IAAI,WAA6B,UAAU;AAAA,IAC/D,QAAQ;AACN,UAAI,OAAO,MAAM,kEAAkE;AAAA,IACrF;AAEA,QAAI;AACF,mBAAa,IAAI,WAAwB,MAAM;AAAA,IACjD,QAAQ;AACN,UAAI,OAAO,MAAM,4DAA4D;AAAA,IAC/E;AAEA,QAAI,iBAAiB;AACnB,WAAK,QAAQ,gBAAgB,iBAAiB,UAAU;AACxD,WAAK,QAAQ,cAAc,eAAe;AAAA,IAC5C;AAGA,UAAM,cAAc,KAAK,QAAQ,iBAAa,qCAAuB,yBAAyB,sBAAsB,EAAE,QAAQ,KAAK,CAAC,MAAM;AAC1I,QAAI,aAAa;AACf,YAAM,KAAK,QAAQ,MAAM;AACzB,UAAI,OAAO,KAAK,oCAAoC;AAAA,IACtD,OAAO;AACL,UAAI,OAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAGA,UAAM,IAAI,QAAQ,aAAa,KAAK,OAAO;AAAA,EAC7C;AAAA,EAEA,MAAM,UAAyB;AAC7B,QAAI,KAAK,SAAS,WAAW;AAC3B,YAAM,KAAK,QAAQ,KAAK;AAAA,IAC1B;AACA,SAAK,UAAU;AAAA,EACjB;AACF;;;AGtHO,IAAM,yBAAyB;AAC/B,IAAM,gCACX;AAgBF,IAAM,kBAAkB;AAMjB,SAAS,oBAAoB,UAA8B,CAAC,GAAW;AAC5E,QAAM,MAAM,QAAQ,QAAQ,KAAK,KAAK;AACtC,QAAM,WAAW,QAAQ,SAAS,KAAK;AACvC,QAAM,QAAQ,WACV,oCAAoC,QAAQ,gCAC5C;AAEJ,SAAO;AAAA,QACD,sBAAsB;AAAA,eACf,6BAA6B;AAAA;AAAA;AAAA;AAAA;AAAA,EAK1C,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBL,GAAG;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyDL;","names":["import_zod"]}
package/dist/index.js CHANGED
@@ -682,9 +682,9 @@ var MCPServerPlugin = class {
682
682
  }
683
683
  async init(ctx) {
684
684
  const config = {
685
- name: readEnvWithDeprecation("OS_MCP_SERVER_NAME", "MCP_SERVER_NAME") ?? this.options.name ?? "objectstack",
685
+ name: readEnvWithDeprecation("OS_MCP_SERVER_NAME", "MCP_SERVER_NAME", { silent: true }) ?? this.options.name ?? "objectstack",
686
686
  version: this.options.version ?? "1.0.0",
687
- transport: readEnvWithDeprecation("OS_MCP_SERVER_TRANSPORT", "MCP_SERVER_TRANSPORT") ?? this.options.transport ?? "stdio",
687
+ transport: readEnvWithDeprecation("OS_MCP_SERVER_TRANSPORT", "MCP_SERVER_TRANSPORT", { silent: true }) ?? this.options.transport ?? "stdio",
688
688
  instructions: this.options.instructions,
689
689
  logger: ctx.logger
690
690
  };
@@ -720,7 +720,7 @@ var MCPServerPlugin = class {
720
720
  this.runtime.bridgeResources(metadataService, dataEngine);
721
721
  this.runtime.bridgePrompts(metadataService);
722
722
  }
723
- const shouldStart = this.options.autoStart || readEnvWithDeprecation("OS_MCP_SERVER_ENABLED", "MCP_SERVER_ENABLED") === "true";
723
+ const shouldStart = this.options.autoStart || readEnvWithDeprecation("OS_MCP_SERVER_ENABLED", "MCP_SERVER_ENABLED", { silent: true }) === "true";
724
724
  if (shouldStart) {
725
725
  await this.runtime.start();
726
726
  ctx.logger.info("[MCP] Server started automatically");
package/dist/index.js.map CHANGED
@@ -1 +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, registerActionTools } from './mcp-http-tools.js';\nimport type {\n McpDataBridge,\n McpActionBridge,\n RegisterObjectToolsOptions,\n RegisterActionToolsOptions,\n} 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 plus — when the bridge can resolve\n * the framework's action mechanism — the business-action tools\n * (`list_actions` / `run_action`), all 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 these native 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 (+ optional action) 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 Tool exposure options (system objects, query limits).\n */\n async handleHttpRequest(\n request: Request,\n opts: {\n bridge?: McpDataBridge & Partial<McpActionBridge>;\n parsedBody?: unknown;\n authInfo?: unknown;\n toolOptions?: RegisterObjectToolsOptions & RegisterActionToolsOptions;\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 // The action surface is wired by capability: only when the runtime's\n // bridge can resolve + dispatch the framework's actions. A host with no\n // action mechanism keeps serving object tools unchanged (graceful\n // degradation, mirroring how record resources need a dataEngine).\n if (\n typeof opts.bridge.listActions === 'function' &&\n typeof opts.bridge.runAction === 'function'\n ) {\n registerActionTools(server, opts.bridge as McpActionBridge, opts.toolOptions);\n }\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\n/** One declared input parameter of a business action, LLM-facing. */\nexport interface McpActionParamSummary {\n name: string;\n type?: 'string' | 'number' | 'boolean' | 'array';\n required?: boolean;\n description?: string;\n /** Allowed values, when the param (or its backing field) is an enum. */\n enum?: string[];\n}\n\n/**\n * A business action the caller may invoke, as surfaced by `list_actions`.\n * Mirrors {@link McpObjectSummary} for the action surface: enough for an agent\n * to decide whether and how to call `run_action`, nothing engine-internal.\n */\nexport interface McpActionSummary {\n /** Declarative action name — the identifier passed to `run_action`. */\n name: string;\n /** The object the action operates on (omitted for object-less actions). */\n objectName?: string;\n /** Human label. */\n label?: string;\n /** What the action does (the authored `ai.description` when present). */\n description?: string;\n /** Dispatch kind: `script` | `flow` | `api`. */\n type?: string;\n /** True when the action acts on a row and so needs a `recordId`. */\n requiresRecord?: boolean;\n /** True when the action is destructive / an author flagged it for confirmation. */\n requiresConfirmation?: boolean;\n /** Declared input parameters. */\n params?: McpActionParamSummary[];\n}\n\n/**\n * Action-execution seam for the HTTP MCP tools. Implemented by the runtime so\n * resolution + dispatch flows through the framework's own action mechanism\n * (`IDataEngine.executeAction` / automation flow runner) bound to the caller's\n * ExecutionContext — the SAME permission + RLS path the REST `/actions/...`\n * endpoint uses. Every method runs AS the authenticated principal.\n *\n * Deliberately decoupled from {@link McpDataBridge}: a runtime that cannot\n * resolve the action mechanism simply does not implement this, and the action\n * tools are then not registered (graceful degradation — see\n * `registerActionTools`). Bridging here is direct framework-contract access; it\n * does NOT depend on `@objectstack/service-ai`.\n */\nexport interface McpActionBridge {\n /** Actions the caller may run, already filtered by permission + visibility. */\n listActions(): Promise<McpActionSummary[]>;\n /**\n * Invoke an action by its declarative name. Resolves the action (optionally\n * scoped by `objectName` to disambiguate), enforces its `requiredPermissions`\n * as the caller, loads the subject record under RLS when row-context, then\n * dispatches through the framework action runner. Throws on\n * denial / not-found / handler failure so the tool surfaces a tool-error.\n */\n runAction(\n name: string,\n input: { objectName?: string; recordId?: string; params?: Record<string, unknown> },\n ): Promise<unknown>;\n}\n\nexport interface RegisterActionToolsOptions {\n /** Expose actions on `sys_*` system objects too. Default false (fail-closed). */\n allowSystemObjects?: boolean;\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\n/**\n * Register the business-action tool set (`list_actions`, `run_action`) on a\n * fresh per-request {@link McpServer}. This is the action analogue of\n * {@link registerObjectTools}: it owns the tool *shape* and delegates all\n * resolution + dispatch + security to `bridge`, which the runtime binds to the\n * caller's principal.\n *\n * Symmetry with the object tools is deliberate — like `list_objects`/CRUD, the\n * action surface exposes the *mechanism* and relies on the bridge's\n * permission + RLS enforcement (not a separate AI opt-in flag) for safety,\n * with `sys_*`-scoped actions held back fail-closed by default.\n */\nexport function registerActionTools(\n server: McpServer,\n bridge: McpActionBridge,\n options: RegisterActionToolsOptions = {},\n): void {\n const allowSystem = options.allowSystemObjects === true;\n\n server.registerTool(\n 'list_actions',\n {\n description:\n 'List the business actions you can invoke in this app (e.g. \"complete task\", \"convert lead\"). ' +\n 'Returns each action\\'s name, the object it operates on, a description, whether it needs a record id, ' +\n 'whether it is destructive, and its input parameters. Only actions the caller is permitted to run are returned. ' +\n 'Use run_action to invoke one.',\n inputSchema: {},\n annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false },\n },\n async () => {\n try {\n const actions = await bridge.listActions();\n const visible = allowSystem\n ? actions\n : actions.filter((a) => !a.objectName || !isSystemObject(a.objectName));\n return textResult({ actions: visible, totalCount: visible.length });\n } catch (err) {\n return errorResult(messageOf(err));\n }\n },\n );\n\n server.registerTool(\n 'run_action',\n {\n description:\n 'Invoke a business action by name (see list_actions). Runs the app\\'s registered business logic ' +\n 'under the caller\\'s permissions and row-level security — this can mutate data or trigger flows. ' +\n 'Supply recordId for actions that operate on a specific record, and params for any declared inputs.',\n inputSchema: {\n actionName: z.string().describe('The action name from list_actions, e.g. \"complete_task\"'),\n objectName: z\n .string()\n .optional()\n .describe('The object the action belongs to. Optional; required only to disambiguate a name shared by multiple objects.'),\n recordId: z\n .string()\n .optional()\n .describe('The id of the record to act on (for record-scoped actions).'),\n params: z\n .record(z.string(), z.unknown())\n .optional()\n .describe('Input parameters declared by the action.'),\n },\n // Actions execute app-defined business logic with side effects (writes,\n // flows, outbound calls), so we mark the tool destructive + open-world:\n // MCP clients should confirm before invoking. Per-action destructiveness\n // is further surfaced via `requiresConfirmation` in list_actions.\n annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: true },\n },\n async ({ actionName, objectName, recordId, params }) => {\n if (!actionName || typeof actionName !== 'string') {\n return errorResult('actionName is required');\n }\n if (objectName && !allowSystem && isSystemObject(objectName)) {\n return errorResult(`Object \"${objectName}\" is a system object and its actions are not exposed via MCP`);\n }\n try {\n const result = await bridge.runAction(actionName, { objectName, recordId, params });\n return textResult(result);\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"]}
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', { silent: true }) ?? this.options.name ?? 'objectstack',\n version: this.options.version ?? '1.0.0',\n transport: (readEnvWithDeprecation('OS_MCP_SERVER_TRANSPORT', 'MCP_SERVER_TRANSPORT', { silent: true }) 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', { silent: true }) === '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, registerActionTools } from './mcp-http-tools.js';\nimport type {\n McpDataBridge,\n McpActionBridge,\n RegisterObjectToolsOptions,\n RegisterActionToolsOptions,\n} 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 plus — when the bridge can resolve\n * the framework's action mechanism — the business-action tools\n * (`list_actions` / `run_action`), all 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 these native 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 (+ optional action) 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 Tool exposure options (system objects, query limits).\n */\n async handleHttpRequest(\n request: Request,\n opts: {\n bridge?: McpDataBridge & Partial<McpActionBridge>;\n parsedBody?: unknown;\n authInfo?: unknown;\n toolOptions?: RegisterObjectToolsOptions & RegisterActionToolsOptions;\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 // The action surface is wired by capability: only when the runtime's\n // bridge can resolve + dispatch the framework's actions. A host with no\n // action mechanism keeps serving object tools unchanged (graceful\n // degradation, mirroring how record resources need a dataEngine).\n if (\n typeof opts.bridge.listActions === 'function' &&\n typeof opts.bridge.runAction === 'function'\n ) {\n registerActionTools(server, opts.bridge as McpActionBridge, opts.toolOptions);\n }\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\n/** One declared input parameter of a business action, LLM-facing. */\nexport interface McpActionParamSummary {\n name: string;\n type?: 'string' | 'number' | 'boolean' | 'array';\n required?: boolean;\n description?: string;\n /** Allowed values, when the param (or its backing field) is an enum. */\n enum?: string[];\n}\n\n/**\n * A business action the caller may invoke, as surfaced by `list_actions`.\n * Mirrors {@link McpObjectSummary} for the action surface: enough for an agent\n * to decide whether and how to call `run_action`, nothing engine-internal.\n */\nexport interface McpActionSummary {\n /** Declarative action name — the identifier passed to `run_action`. */\n name: string;\n /** The object the action operates on (omitted for object-less actions). */\n objectName?: string;\n /** Human label. */\n label?: string;\n /** What the action does (the authored `ai.description` when present). */\n description?: string;\n /** Dispatch kind: `script` | `flow` | `api`. */\n type?: string;\n /** True when the action acts on a row and so needs a `recordId`. */\n requiresRecord?: boolean;\n /** True when the action is destructive / an author flagged it for confirmation. */\n requiresConfirmation?: boolean;\n /** Declared input parameters. */\n params?: McpActionParamSummary[];\n}\n\n/**\n * Action-execution seam for the HTTP MCP tools. Implemented by the runtime so\n * resolution + dispatch flows through the framework's own action mechanism\n * (`IDataEngine.executeAction` / automation flow runner) bound to the caller's\n * ExecutionContext — the SAME permission + RLS path the REST `/actions/...`\n * endpoint uses. Every method runs AS the authenticated principal.\n *\n * Deliberately decoupled from {@link McpDataBridge}: a runtime that cannot\n * resolve the action mechanism simply does not implement this, and the action\n * tools are then not registered (graceful degradation — see\n * `registerActionTools`). Bridging here is direct framework-contract access; it\n * does NOT depend on `@objectstack/service-ai`.\n */\nexport interface McpActionBridge {\n /** Actions the caller may run, already filtered by permission + visibility. */\n listActions(): Promise<McpActionSummary[]>;\n /**\n * Invoke an action by its declarative name. Resolves the action (optionally\n * scoped by `objectName` to disambiguate), enforces its `requiredPermissions`\n * as the caller, loads the subject record under RLS when row-context, then\n * dispatches through the framework action runner. Throws on\n * denial / not-found / handler failure so the tool surfaces a tool-error.\n */\n runAction(\n name: string,\n input: { objectName?: string; recordId?: string; params?: Record<string, unknown> },\n ): Promise<unknown>;\n}\n\nexport interface RegisterActionToolsOptions {\n /** Expose actions on `sys_*` system objects too. Default false (fail-closed). */\n allowSystemObjects?: boolean;\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\n/**\n * Register the business-action tool set (`list_actions`, `run_action`) on a\n * fresh per-request {@link McpServer}. This is the action analogue of\n * {@link registerObjectTools}: it owns the tool *shape* and delegates all\n * resolution + dispatch + security to `bridge`, which the runtime binds to the\n * caller's principal.\n *\n * Symmetry with the object tools is deliberate — like `list_objects`/CRUD, the\n * action surface exposes the *mechanism* and relies on the bridge's\n * permission + RLS enforcement (not a separate AI opt-in flag) for safety,\n * with `sys_*`-scoped actions held back fail-closed by default.\n */\nexport function registerActionTools(\n server: McpServer,\n bridge: McpActionBridge,\n options: RegisterActionToolsOptions = {},\n): void {\n const allowSystem = options.allowSystemObjects === true;\n\n server.registerTool(\n 'list_actions',\n {\n description:\n 'List the business actions you can invoke in this app (e.g. \"complete task\", \"convert lead\"). ' +\n 'Returns each action\\'s name, the object it operates on, a description, whether it needs a record id, ' +\n 'whether it is destructive, and its input parameters. Only actions the caller is permitted to run are returned. ' +\n 'Use run_action to invoke one.',\n inputSchema: {},\n annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false },\n },\n async () => {\n try {\n const actions = await bridge.listActions();\n const visible = allowSystem\n ? actions\n : actions.filter((a) => !a.objectName || !isSystemObject(a.objectName));\n return textResult({ actions: visible, totalCount: visible.length });\n } catch (err) {\n return errorResult(messageOf(err));\n }\n },\n );\n\n server.registerTool(\n 'run_action',\n {\n description:\n 'Invoke a business action by name (see list_actions). Runs the app\\'s registered business logic ' +\n 'under the caller\\'s permissions and row-level security — this can mutate data or trigger flows. ' +\n 'Supply recordId for actions that operate on a specific record, and params for any declared inputs.',\n inputSchema: {\n actionName: z.string().describe('The action name from list_actions, e.g. \"complete_task\"'),\n objectName: z\n .string()\n .optional()\n .describe('The object the action belongs to. Optional; required only to disambiguate a name shared by multiple objects.'),\n recordId: z\n .string()\n .optional()\n .describe('The id of the record to act on (for record-scoped actions).'),\n params: z\n .record(z.string(), z.unknown())\n .optional()\n .describe('Input parameters declared by the action.'),\n },\n // Actions execute app-defined business logic with side effects (writes,\n // flows, outbound calls), so we mark the tool destructive + open-world:\n // MCP clients should confirm before invoking. Per-action destructiveness\n // is further surfaced via `requiresConfirmation` in list_actions.\n annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: true },\n },\n async ({ actionName, objectName, recordId, params }) => {\n if (!actionName || typeof actionName !== 'string') {\n return errorResult('actionName is required');\n }\n if (objectName && !allowSystem && isSystemObject(objectName)) {\n return errorResult(`Object \"${objectName}\" is a system object and its actions are not exposed via MCP`);\n }\n try {\n const result = await bridge.runAction(actionName, { objectName, recordId, params });\n return textResult(result);\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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@objectstack/mcp",
3
- "version": "11.0.0",
3
+ "version": "11.1.0",
4
4
  "license": "Apache-2.0",
5
5
  "description": "ObjectStack as an MCP server — exposes your app's objects (and AI tools) over the Model Context Protocol (stdio + Streamable HTTP)",
6
6
  "type": "module",
@@ -16,9 +16,9 @@
16
16
  "dependencies": {
17
17
  "@modelcontextprotocol/sdk": "^1.29.0",
18
18
  "zod": "^4.4.3",
19
- "@objectstack/core": "11.0.0",
20
- "@objectstack/spec": "11.0.0",
21
- "@objectstack/types": "11.0.0"
19
+ "@objectstack/core": "11.1.0",
20
+ "@objectstack/spec": "11.1.0",
21
+ "@objectstack/types": "11.1.0"
22
22
  },
23
23
  "devDependencies": {
24
24
  "@types/node": "^26.0.0",