@tinycloud/mcp 0.5.4 → 0.6.0-beta.1

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/server.ts","../src/tools.ts","../src/results.ts","../package.json","../src/version.ts"],"sourcesContent":["import { McpServer } from \"@modelcontextprotocol/server\";\nimport { serveStdio, type StdioServerHandle } from \"@modelcontextprotocol/server/stdio\";\n\nimport { createJsonSchemaValidator, registerTinyCloudTools, type McpStartupSelection } from \"./tools.js\";\nimport { MCP_VERSION } from \"./version.js\";\n\nexport const MCP_SERVER_NAME = \"tinycloud-mcp\";\nexport { MCP_VERSION } from \"./version.js\";\n/** The stdio server is always the local surface. */\nexport type LocalMcpSelection = Omit<McpStartupSelection, \"surface\">;\n\nexport function createTinyCloudMcpServer(selection: LocalMcpSelection): McpServer {\n const validator = createJsonSchemaValidator();\n const server = new McpServer(\n { name: MCP_SERVER_NAME, version: MCP_VERSION },\n { jsonSchemaValidator: validator },\n );\n registerTinyCloudTools(server, { ...selection, surface: \"local\" }, validator);\n return server;\n}\n\n/** Start the only supported MCP transport: local stdio. */\nexport function serveTinyCloudMcp(selection: LocalMcpSelection): StdioServerHandle {\n return serveStdio(\n () => createTinyCloudMcpServer(selection),\n { onerror: () => writeBoundedDiagnostic(\"MCP transport error\") },\n );\n}\n\nfunction writeBoundedDiagnostic(message: string): void {\n process.stderr.write(`[tinycloud-mcp] ${message}\\n`);\n}\n","import { createRequire } from \"node:module\";\nimport { join } from \"node:path\";\n\nimport { fromJsonSchema, type McpServer, type ToolAnnotations } from \"@modelcontextprotocol/server\";\nimport { addFormats, Ajv, AjvJsonSchemaValidator } from \"@modelcontextprotocol/server/validators/ajv\";\nimport { invokeOperation } from \"@tinycloud/operations\";\n\nimport { toMcpToolResult, type McpToolResult } from \"./results.js\";\n\nexport const TOOL_NAMES = [\n \"tinycloud_status\",\n \"tinycloud_auth_status\",\n \"tinycloud_auth_capabilities\",\n \"tinycloud_auth_request\",\n \"tinycloud_auth_import\",\n \"tinycloud_account_spaces_list\",\n \"tinycloud_account_applications_list\",\n \"tinycloud_kv_list\",\n \"tinycloud_kv_get\",\n \"tinycloud_kv_head\",\n \"tinycloud_kv_put\",\n \"tinycloud_kv_delete\",\n \"tinycloud_sql_schema_inspect\",\n \"tinycloud_sql_query\",\n \"tinycloud_sql_execute\",\n \"tinycloud_secrets_get\",\n \"tinycloud_secrets_status\",\n] as const;\n\nexport type ToolName = (typeof TOOL_NAMES)[number];\n\n/** MCP server surfaces: local stdio and the hosted OAuth HTTP server. */\nexport type McpSurface = \"local\" | \"hosted\";\n\nexport interface McpStartupSelection {\n /** Which server registers the tools; bindings not on this surface are skipped. */\n readonly surface: McpSurface;\n readonly profile: string;\n readonly explicitProfile: boolean;\n readonly allowOwnerProfile: boolean;\n /** Absolute TinyCloud home used to isolate one hosted OAuth principal. */\n readonly stateRoot?: string;\n /** Hosted transports may attach a browser approval URL to canonical results. */\n readonly transformOperationResult?: (result: unknown) => Promise<unknown>;\n}\n\nexport interface McpInvocationTarget {\n readonly profile: string;\n readonly allowOwnerProfile?: true;\n readonly stateRoot?: string;\n}\n\n/** Project one startup selection into the only owner-sensitive target shape. */\nexport function invocationTargetForMcp(\n selection: Omit<McpStartupSelection, \"surface\">,\n): McpInvocationTarget {\n return {\n profile: selection.profile,\n ...(selection.explicitProfile && selection.allowOwnerProfile\n ? { allowOwnerProfile: true }\n : {}),\n ...(selection.stateRoot === undefined ? {} : { stateRoot: selection.stateRoot }),\n };\n}\n\ninterface CatalogOperation {\n readonly id: string;\n readonly version: number;\n readonly title: string;\n readonly description: string;\n readonly input: Record<string, unknown>;\n readonly result: Record<string, unknown>;\n}\n\ninterface OperationsCatalog {\n readonly operations: readonly CatalogOperation[];\n}\n\n// The require anchor is this module, never the consumer entrypoint. In ESM\n// tsup preserves import.meta.url; in CJS it rewrites the same module-relative\n// anchor to the generated __filename, so both formats stay in MCP's package\n// dependency boundary.\nconst packageRequire = createRequire(\n typeof __dirname === \"string\" ? join(__dirname, \"tools.cjs\") : import.meta.url,\n);\nconst generatedCatalog = packageRequire(\n \"@tinycloud/operations/operations.json\",\n) as OperationsCatalog;\n\nexport interface ToolBinding {\n readonly name: ToolName;\n readonly operationId: string;\n readonly operationVersion: number;\n readonly readOnlyHint: boolean;\n readonly idempotentHint: boolean;\n readonly destructiveHint: boolean;\n readonly openWorldHint: boolean;\n /** Surfaces that register this tool; omitted means every surface. */\n readonly surfaces?: readonly McpSurface[];\n}\n\nconst ALL_SURFACES: readonly McpSurface[] = [\"local\", \"hosted\"];\n\n/** The surfaces a binding is registered on. */\nexport function bindingSurfaces(binding: ToolBinding): readonly McpSurface[] {\n return binding.surfaces ?? ALL_SURFACES;\n}\n\nexport const TOOL_BINDINGS: readonly ToolBinding[] = [\n {\n name: \"tinycloud_status\",\n operationId: \"tinycloud.status.get\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: false,\n },\n {\n name: \"tinycloud_auth_status\",\n operationId: \"tinycloud.auth.status\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: false,\n },\n {\n name: \"tinycloud_auth_capabilities\",\n operationId: \"tinycloud.auth.capabilities\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: false,\n },\n {\n name: \"tinycloud_auth_request\",\n operationId: \"tinycloud.auth.request\",\n operationVersion: 1,\n readOnlyHint: false,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: false,\n },\n {\n name: \"tinycloud_auth_import\",\n operationId: \"tinycloud.auth.import\",\n operationVersion: 1,\n readOnlyHint: false,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: false,\n // Hosted delegations must arrive through the owner/request-bound OpenKey callback,\n // not a caller-supplied import artifact.\n surfaces: [\"local\"],\n },\n {\n name: \"tinycloud_account_spaces_list\",\n operationId: \"tinycloud.account.spaces.list\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_account_applications_list\",\n operationId: \"tinycloud.account.applications.list\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_kv_list\",\n operationId: \"tinycloud.kv.list\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_kv_get\",\n operationId: \"tinycloud.kv.get\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_kv_head\",\n operationId: \"tinycloud.kv.head\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_kv_put\",\n operationId: \"tinycloud.kv.put\",\n operationVersion: 1,\n readOnlyHint: false,\n idempotentHint: true,\n destructiveHint: true,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_kv_delete\",\n operationId: \"tinycloud.kv.delete\",\n operationVersion: 1,\n readOnlyHint: false,\n idempotentHint: true,\n destructiveHint: true,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_sql_schema_inspect\",\n operationId: \"tinycloud.sql.schema.inspect\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_sql_query\",\n operationId: \"tinycloud.sql.query\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_sql_execute\",\n operationId: \"tinycloud.sql.execute\",\n operationVersion: 1,\n readOnlyHint: false,\n idempotentHint: false,\n destructiveHint: true,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_secrets_get\",\n operationId: \"tinycloud.secrets.get\",\n operationVersion: 1,\n readOnlyHint: false,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_secrets_status\",\n operationId: \"tinycloud.secrets.status\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n // Hosted has no persistent reauthorization path for a revoked session\n // yet (TC-896), so status is local/stdio only.\n surfaces: [\"local\"],\n },\n] as const;\n\nexport function createJsonSchemaValidator(): AjvJsonSchemaValidator {\n const ajv = new Ajv({ strict: false });\n addFormats(ajv);\n return new AjvJsonSchemaValidator(ajv);\n}\n\nexport function registerTinyCloudTools(\n server: McpServer,\n selection: McpStartupSelection,\n validator: AjvJsonSchemaValidator,\n): void {\n const definitions = new Map(\n generatedCatalog.operations.map((operation) => [\n `${operation.id}@${operation.version}`,\n operation,\n ]),\n );\n\n for (const binding of TOOL_BINDINGS) {\n if (!bindingSurfaces(binding).includes(selection.surface)) continue;\n const operation = definitions.get(`${binding.operationId}@${binding.operationVersion}`);\n if (operation === undefined) {\n throw new Error(`Generated operations catalog is missing ${binding.operationId}@${binding.operationVersion}.`);\n }\n\n const inputSchema = fromJsonSchema(\n operation.input as Parameters<typeof fromJsonSchema>[0],\n validator,\n );\n const outputSchema = fromJsonSchema(\n operation.result as unknown as Parameters<typeof fromJsonSchema>[0],\n validator,\n );\n const annotations: ToolAnnotations = {\n readOnlyHint: binding.readOnlyHint,\n idempotentHint: binding.idempotentHint,\n destructiveHint: binding.destructiveHint,\n openWorldHint: binding.openWorldHint,\n };\n\n server.registerTool(\n binding.name,\n {\n title: operation.title,\n description: operation.description,\n inputSchema,\n outputSchema,\n annotations,\n },\n async (input: unknown): Promise<McpToolResult> => {\n const result = await invokeOperation(\n binding.operationId,\n binding.operationVersion,\n invocationTargetForMcp(selection),\n input,\n );\n const projected = selection.transformOperationResult === undefined\n ? result\n : await selection.transformOperationResult(result);\n return toMcpToolResult(projected, TOOL_BINDINGS);\n },\n );\n }\n}\n\nexport function toolBindingsForTest(): readonly ToolBinding[] {\n return TOOL_BINDINGS;\n}\n","/**\n * MCP has one structured result channel for a TinyCloud operation. Text is a\n * fixed, non-sensitive status line; it never serializes the operation result.\n */\nexport interface CanonicalOperationResult {\n readonly status: \"ok\" | \"authority_required\" | \"setup_required\" | \"error\";\n readonly [key: string]: unknown;\n}\n\nexport interface McpToolResult extends CallToolResult {\n readonly content: [{ readonly type: \"text\"; readonly text: string }];\n readonly structuredContent: CanonicalOperationResult;\n}\n\n/** The binding fields needed to name the tool that runs an operation. */\nexport interface RecoveryToolBinding {\n readonly name: string;\n readonly operationId: string;\n}\n\nexport function toMcpToolResult(\n result: unknown,\n bindings: readonly RecoveryToolBinding[] = [],\n): McpToolResult {\n const canonical: CanonicalOperationResult = isCanonicalOperationResult(result)\n ? withRecoveryTool(result, bindings)\n : {\n status: \"error\",\n operation: {},\n context: {},\n error: { code: \"INTERNAL_ERROR\" },\n };\n\n return {\n content: [{ type: \"text\", text: resultSummary(canonical.status) }],\n structuredContent: canonical,\n };\n}\n\n/**\n * A redacted `complete_migration` recovery names an operation; MCP clients\n * call tools, so name the bound tool. `tool` comes from the code-owned binding\n * table only, never from operation data, and is added after redaction. An\n * operationId with no binding gets no `tool`.\n */\nfunction withRecoveryTool(\n result: CanonicalOperationResult,\n bindings: readonly RecoveryToolBinding[],\n): CanonicalOperationResult {\n if (result.status !== \"error\") return result;\n // The kernel's redaction already constrained `error.details.recovery` to a\n // safe recovery object; only its discriminant and operationId are read here.\n const error = result.error as\n | { readonly details?: { readonly recovery?: { readonly action?: unknown; readonly operationId?: unknown } } }\n | undefined;\n const recovery = error?.details?.recovery;\n if (recovery?.action !== \"complete_migration\") return result;\n const binding = bindings.find((candidate) => candidate.operationId === recovery.operationId);\n if (binding === undefined) return result;\n return {\n ...result,\n error: { ...error, details: { ...error?.details, recovery: { ...recovery, tool: binding.name } } },\n };\n}\n\n/** The canonical envelope immediately before MCP protocol serialization. */\nexport function canonicalMcpAdapterResult(result: unknown): CanonicalOperationResult {\n return toMcpToolResult(result).structuredContent;\n}\n\nfunction isCanonicalOperationResult(value: unknown): value is CanonicalOperationResult {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) return false;\n const status = (value as { status?: unknown }).status;\n return status === \"ok\" ||\n status === \"authority_required\" ||\n status === \"setup_required\" ||\n status === \"error\";\n}\n\nfunction resultSummary(status: CanonicalOperationResult[\"status\"]): string {\n switch (status) {\n case \"ok\":\n return \"TinyCloud operation completed; use the structured result.\";\n case \"authority_required\":\n return \"TinyCloud authority is required; use the structured request and approval action.\";\n case \"setup_required\":\n return \"TinyCloud setup is required; use the structured setup action.\";\n case \"error\":\n return \"TinyCloud operation failed; use the structured error.\";\n }\n}\nimport type { CallToolResult } from \"@modelcontextprotocol/server\";\n","{\n \"name\": \"@tinycloud/mcp\",\n \"version\": \"0.5.4\",\n \"description\": \"TinyCloud delegated operations MCP server\",\n \"keywords\": [\n \"tinycloud\",\n \"mcp\",\n \"model-context-protocol\",\n \"agents\",\n \"delegation\",\n \"ucan\",\n \"kv\",\n \"sqlite\"\n ],\n \"author\": \"TinyCloud, Inc.\",\n \"license\": \"EGPL\",\n \"type\": \"module\",\n \"main\": \"dist/index.cjs\",\n \"module\": \"dist/index.js\",\n \"types\": \"dist/index.d.ts\",\n \"bin\": {\n \"tinycloud-mcp\": \"./bin/tinycloud-mcp\",\n \"tinycloud-mcp-http\": \"./bin/tinycloud-mcp-http\"\n },\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n },\n \"./server\": {\n \"types\": \"./dist/server.d.ts\",\n \"import\": \"./dist/server.js\",\n \"require\": \"./dist/server.cjs\"\n },\n \"./tools\": {\n \"types\": \"./dist/tools.d.ts\",\n \"import\": \"./dist/tools.js\",\n \"require\": \"./dist/tools.cjs\"\n },\n \"./results\": {\n \"types\": \"./dist/results.d.ts\",\n \"import\": \"./dist/results.js\",\n \"require\": \"./dist/results.cjs\"\n },\n \"./http\": {\n \"types\": \"./dist/http.d.ts\",\n \"import\": \"./dist/http.js\",\n \"require\": \"./dist/http.cjs\"\n }\n },\n \"files\": [\n \"dist\",\n \"bin\",\n \"generated\",\n \"skills\"\n ],\n \"engines\": {\n \"node\": \">=20\"\n },\n \"scripts\": {\n \"build\": \"tsup\",\n \"clean\": \"rm -rf dist\",\n \"test\": \"bun run build && bun scripts/test.ts && bun run check:generated\",\n \"test:stdio\": \"bun run build && bun test src/stdio.test.ts\",\n \"typecheck\": \"tsc -p tsconfig.json\",\n \"start:http\": \"node dist/http-cli.js\",\n \"generate\": \"bun scripts/generate.ts\",\n \"check:generated\": \"bun scripts/generate.ts --check\"\n },\n \"dependencies\": {\n \"@modelcontextprotocol/node\": \"2.0.0-beta.4\",\n \"@modelcontextprotocol/server\": \"2.0.0-beta.4\",\n \"@tinycloud/node-sdk\": \"3.2.4\",\n \"@tinycloud/node-sdk-wasm\": \"1.7.7\",\n \"@tinycloud/operations\": \"0.5.4\",\n \"jose\": \"6.1.3\"\n },\n \"devDependencies\": {\n \"@modelcontextprotocol/client\": \"2.0.0-beta.4\",\n \"@types/node\": \"^20\",\n \"tsup\": \"^8.0.0\",\n \"typescript\": \"^5.9.3\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/TinyCloudLabs/js-sdk\"\n },\n \"homepage\": \"https://docs.tinycloud.xyz/cli/mcp\"\n}\n","import packageMetadata from \"../package.json\";\n\nexport const MCP_VERSION = packageMetadata.version;\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/server.ts","../src/tools.ts","../src/results.ts","../src/logging.ts","../package.json","../src/version.ts"],"sourcesContent":["import { McpServer } from \"@modelcontextprotocol/server\";\nimport { serveStdio, type StdioServerHandle } from \"@modelcontextprotocol/server/stdio\";\n\nimport { createJsonSchemaValidator, registerTinyCloudTools, type McpStartupSelection } from \"./tools.js\";\nimport { MCP_VERSION } from \"./version.js\";\n\nexport const MCP_SERVER_NAME = \"tinycloud-mcp\";\nexport { MCP_VERSION } from \"./version.js\";\n/** The stdio server is always the local surface. */\nexport type LocalMcpSelection = Omit<McpStartupSelection, \"surface\">;\n\nexport function createTinyCloudMcpServer(selection: LocalMcpSelection): McpServer {\n const validator = createJsonSchemaValidator();\n const server = new McpServer(\n { name: MCP_SERVER_NAME, version: MCP_VERSION },\n { jsonSchemaValidator: validator },\n );\n registerTinyCloudTools(server, { ...selection, surface: \"local\" }, validator);\n return server;\n}\n\n/** Start the only supported MCP transport: local stdio. */\nexport function serveTinyCloudMcp(selection: LocalMcpSelection): StdioServerHandle {\n return serveStdio(\n () => createTinyCloudMcpServer(selection),\n { onerror: () => writeBoundedDiagnostic(\"MCP transport error\") },\n );\n}\n\nfunction writeBoundedDiagnostic(message: string): void {\n process.stderr.write(`[tinycloud-mcp] ${message}\\n`);\n}\n","import { createRequire } from \"node:module\";\nimport { join } from \"node:path\";\n\nimport { fromJsonSchema, type McpServer, type ToolAnnotations } from \"@modelcontextprotocol/server\";\nimport { addFormats, Ajv, AjvJsonSchemaValidator } from \"@modelcontextprotocol/server/validators/ajv\";\nimport { invokeOperation } from \"@tinycloud/operations\";\n\nimport { toMcpToolResult, type McpToolResult } from \"./results.js\";\nimport { logToolCall } from \"./logging.js\";\n\nexport const TOOL_NAMES = [\n \"tinycloud_status\",\n \"tinycloud_auth_status\",\n \"tinycloud_auth_capabilities\",\n \"tinycloud_auth_request\",\n \"tinycloud_auth_import\",\n \"tinycloud_account_spaces_list\",\n \"tinycloud_account_applications_list\",\n \"tinycloud_kv_list\",\n \"tinycloud_kv_get\",\n \"tinycloud_kv_head\",\n \"tinycloud_kv_put\",\n \"tinycloud_kv_delete\",\n \"tinycloud_sql_schema_inspect\",\n \"tinycloud_sql_query\",\n \"tinycloud_sql_execute\",\n \"tinycloud_secrets_get\",\n \"tinycloud_secrets_status\",\n \"tinycloud_apps_context\",\n \"tinycloud_apps_read\",\n \"tinycloud_apps_write\",\n] as const;\n\nexport type ToolName = (typeof TOOL_NAMES)[number];\n\n/** MCP server surfaces: local stdio and the hosted OAuth HTTP server. */\nexport type McpSurface = \"local\" | \"hosted\";\n\nexport interface McpStartupSelection {\n /** Which server registers the tools; bindings not on this surface are skipped. */\n readonly surface: McpSurface;\n readonly profile: string;\n readonly explicitProfile: boolean;\n readonly allowOwnerProfile: boolean;\n /** Absolute TinyCloud home used to isolate one hosted OAuth principal. */\n readonly stateRoot?: string;\n /** Hosted transports may attach a browser approval URL to canonical results. */\n readonly transformOperationResult?: (result: unknown) => Promise<unknown>;\n}\n\nexport interface McpInvocationTarget {\n readonly profile: string;\n readonly allowOwnerProfile?: true;\n readonly stateRoot?: string;\n}\n\n/** Project one startup selection into the only owner-sensitive target shape. */\nexport function invocationTargetForMcp(\n selection: Omit<McpStartupSelection, \"surface\">,\n): McpInvocationTarget {\n return {\n profile: selection.profile,\n ...(selection.explicitProfile && selection.allowOwnerProfile\n ? { allowOwnerProfile: true }\n : {}),\n ...(selection.stateRoot === undefined ? {} : { stateRoot: selection.stateRoot }),\n };\n}\n\ninterface CatalogOperation {\n readonly id: string;\n readonly version: number;\n readonly title: string;\n readonly description: string;\n readonly input: Record<string, unknown>;\n readonly result: Record<string, unknown>;\n}\n\ninterface OperationsCatalog {\n readonly stableErrors: readonly string[];\n readonly operations: readonly CatalogOperation[];\n}\n\n// The require anchor is this module, never the consumer entrypoint. In ESM\n// tsup preserves import.meta.url; in CJS it rewrites the same module-relative\n// anchor to the generated __filename, so both formats stay in MCP's package\n// dependency boundary.\nconst packageRequire = createRequire(\n typeof __dirname === \"string\" ? join(__dirname, \"tools.cjs\") : import.meta.url,\n);\nconst generatedCatalog = packageRequire(\n \"@tinycloud/operations/operations.json\",\n) as OperationsCatalog;\nconst stableErrorCodes: Readonly<Record<string, true>> = Object.fromEntries(\n generatedCatalog.stableErrors.map((code) => [code, true as const]),\n);\n\nexport interface ToolBinding {\n readonly name: ToolName;\n readonly operationId: string;\n readonly operationVersion: number;\n readonly readOnlyHint: boolean;\n readonly idempotentHint: boolean;\n readonly destructiveHint: boolean;\n readonly openWorldHint: boolean;\n /** Surfaces that register this tool; omitted means every surface. */\n readonly surfaces?: readonly McpSurface[];\n}\n\nconst ALL_SURFACES: readonly McpSurface[] = [\"local\", \"hosted\"];\n\n/** The surfaces a binding is registered on. */\nexport function bindingSurfaces(binding: ToolBinding): readonly McpSurface[] {\n return binding.surfaces ?? ALL_SURFACES;\n}\n\nexport const TOOL_BINDINGS: readonly ToolBinding[] = [\n {\n name: \"tinycloud_status\",\n operationId: \"tinycloud.status.get\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: false,\n },\n {\n name: \"tinycloud_auth_status\",\n operationId: \"tinycloud.auth.status\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: false,\n },\n {\n name: \"tinycloud_auth_capabilities\",\n operationId: \"tinycloud.auth.capabilities\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: false,\n },\n {\n name: \"tinycloud_auth_request\",\n operationId: \"tinycloud.auth.request\",\n operationVersion: 1,\n readOnlyHint: false,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: false,\n },\n {\n name: \"tinycloud_auth_import\",\n operationId: \"tinycloud.auth.import\",\n operationVersion: 1,\n readOnlyHint: false,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: false,\n // Hosted delegations must arrive through the owner/request-bound OpenKey callback,\n // not a caller-supplied import artifact.\n surfaces: [\"local\"],\n },\n {\n name: \"tinycloud_account_spaces_list\",\n operationId: \"tinycloud.account.spaces.list\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_account_applications_list\",\n operationId: \"tinycloud.account.applications.list\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_kv_list\",\n operationId: \"tinycloud.kv.list\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_kv_get\",\n operationId: \"tinycloud.kv.get\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_kv_head\",\n operationId: \"tinycloud.kv.head\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_kv_put\",\n operationId: \"tinycloud.kv.put\",\n operationVersion: 1,\n readOnlyHint: false,\n idempotentHint: true,\n destructiveHint: true,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_kv_delete\",\n operationId: \"tinycloud.kv.delete\",\n operationVersion: 1,\n readOnlyHint: false,\n idempotentHint: true,\n destructiveHint: true,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_sql_schema_inspect\",\n operationId: \"tinycloud.sql.schema.inspect\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_sql_query\",\n operationId: \"tinycloud.sql.query\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_sql_execute\",\n operationId: \"tinycloud.sql.execute\",\n operationVersion: 1,\n readOnlyHint: false,\n idempotentHint: false,\n destructiveHint: true,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_secrets_get\",\n operationId: \"tinycloud.secrets.get\",\n operationVersion: 1,\n readOnlyHint: false,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_secrets_status\",\n operationId: \"tinycloud.secrets.status\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n // Hosted has no persistent reauthorization path for a revoked session\n // yet (TC-896), so status is local/stdio only.\n surfaces: [\"local\"],\n },\n {\n name: \"tinycloud_apps_context\",\n operationId: \"tinycloud.apps.context\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n surfaces: [\"hosted\"],\n },\n {\n name: \"tinycloud_apps_read\",\n operationId: \"tinycloud.apps.read\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n surfaces: [\"hosted\"],\n },\n {\n name: \"tinycloud_apps_write\",\n operationId: \"tinycloud.apps.write\",\n operationVersion: 1,\n readOnlyHint: false,\n idempotentHint: false,\n destructiveHint: true,\n openWorldHint: true,\n surfaces: [\"hosted\"],\n },\n] as const;\n\nexport function createJsonSchemaValidator(): AjvJsonSchemaValidator {\n const ajv = new Ajv({ strict: false });\n addFormats(ajv);\n return new AjvJsonSchemaValidator(ajv);\n}\n\nexport function registerTinyCloudTools(\n server: McpServer,\n selection: McpStartupSelection,\n validator: AjvJsonSchemaValidator,\n): void {\n const definitions = new Map(\n generatedCatalog.operations.map((operation) => [\n `${operation.id}@${operation.version}`,\n operation,\n ]),\n );\n\n for (const binding of TOOL_BINDINGS) {\n if (!bindingSurfaces(binding).includes(selection.surface)) continue;\n const operation = definitions.get(`${binding.operationId}@${binding.operationVersion}`);\n if (operation === undefined) {\n throw new Error(`Generated operations catalog is missing ${binding.operationId}@${binding.operationVersion}.`);\n }\n\n const inputSchema = fromJsonSchema(\n operation.input as Parameters<typeof fromJsonSchema>[0],\n validator,\n );\n const outputSchema = fromJsonSchema(\n operation.result as unknown as Parameters<typeof fromJsonSchema>[0],\n validator,\n );\n const annotations: ToolAnnotations = {\n readOnlyHint: binding.readOnlyHint,\n idempotentHint: binding.idempotentHint,\n destructiveHint: binding.destructiveHint,\n openWorldHint: binding.openWorldHint,\n };\n\n server.registerTool(\n binding.name,\n {\n title: operation.title,\n description: operation.description,\n inputSchema,\n outputSchema,\n annotations,\n },\n async (input: unknown): Promise<McpToolResult> => {\n const startedAt = performance.now();\n const metrics = { replayedGrants: 0 };\n let code = \"INTERNAL_ERROR\";\n try {\n const result = await invokeOperation(\n binding.operationId,\n binding.operationVersion,\n invocationTargetForMcp(selection),\n input,\n metrics,\n );\n const projected = selection.transformOperationResult === undefined\n ? result\n : await selection.transformOperationResult(result);\n const response = toMcpToolResult(projected, TOOL_BINDINGS, {\n surface: selection.surface,\n readOnly: binding.readOnlyHint,\n operationId: binding.operationId,\n });\n code = outcomeCode(response.structuredContent);\n return response;\n } finally {\n if (selection.surface === \"hosted\") {\n logToolCall(binding.name, code, startedAt, metrics.replayedGrants);\n }\n }\n },\n );\n }\n}\n\nfunction outcomeCode(result: McpToolResult[\"structuredContent\"]): string {\n if (result.status === \"error\") {\n const error = result.error as { code?: unknown } | undefined;\n return typeof error?.code === \"string\" && Object.hasOwn(stableErrorCodes, error.code) ? error.code : \"INTERNAL_ERROR\";\n }\n if (result.status !== \"ok\") return result.status;\n const output = result.output as { outcome?: unknown; ops?: readonly { outcome?: unknown }[] } | undefined;\n if (output?.outcome === \"COPY_PARTIAL\") return \"COPY_PARTIAL\";\n if (Array.isArray(output?.ops) && output.ops.some((op) => op.outcome !== \"ok\")) return \"PARTIAL\";\n return \"ok\";\n}\n\nexport function toolBindingsForTest(): readonly ToolBinding[] {\n return TOOL_BINDINGS;\n}\n","/** MCP preserves the canonical envelope; hosted clients also receive readable JSON. */\nexport interface CanonicalOperationResult {\n readonly status: \"ok\" | \"authority_required\" | \"setup_required\" | \"error\";\n readonly [key: string]: unknown;\n}\n\nexport interface McpToolResult extends CallToolResult {\n readonly content: [{ readonly type: \"text\"; readonly text: string }];\n readonly structuredContent: CanonicalOperationResult;\n}\n\n/** The binding fields needed to name the tool that runs an operation. */\nexport interface RecoveryToolBinding {\n readonly name: string;\n readonly operationId: string;\n}\n\nexport interface McpToolResultOptions {\n readonly surface?: \"hosted\" | \"local\";\n readonly readOnly?: boolean;\n /** Trusted operation identity from the tool binding, not operation output. */\n readonly operationId?: string;\n}\n\nexport function toMcpToolResult(\n result: unknown,\n bindings: readonly RecoveryToolBinding[] = [],\n options: McpToolResultOptions = {},\n): McpToolResult {\n let canonical: CanonicalOperationResult = isCanonicalOperationResult(result)\n ? withRecoveryTool(result, bindings)\n : {\n status: \"error\",\n operation: {},\n context: {},\n error: { code: \"INTERNAL_ERROR\" },\n };\n let serialized: string | undefined;\n if (options.surface === \"hosted\") {\n serialized = JSON.stringify(canonical);\n if (options.readOnly === true && serialized.length > 100_000) {\n const sql = options.operationId?.startsWith(\"tinycloud.sql.\") ||\n options.operationId === \"tinycloud.apps.query\";\n canonical = {\n status: \"error\",\n operation: canonical.operation,\n context: canonical.context,\n error: {\n code: sql ? \"SQL_RESULT_LIMIT_EXCEEDED\" : \"KV_RESPONSE_TOO_LARGE\",\n message: sql\n ? \"The result exceeds 100,000 characters. Select fewer columns or rows, add a WHERE filter or a smaller LIMIT, or aggregate the data.\"\n : \"The result exceeds 100,000 characters. Request fewer keys, narrow the prefix, or use a smaller page size.\",\n retryable: false,\n },\n };\n serialized = JSON.stringify(canonical);\n }\n }\n\n return {\n content: [{\n type: \"text\",\n text: resultSummary(canonical.status) +\n (serialized !== undefined && !(options.operationId === \"tinycloud.secrets.get\" && canonical.status === \"ok\")\n ? `\\n${serialized}` : \"\"),\n }],\n structuredContent: canonical,\n };\n}\n\n/**\n * A redacted `complete_migration` recovery names an operation; MCP clients\n * call tools, so name the bound tool. `tool` comes from the code-owned binding\n * table only, never from operation data, and is added after redaction. An\n * operationId with no binding gets no `tool`.\n */\nfunction withRecoveryTool(\n result: CanonicalOperationResult,\n bindings: readonly RecoveryToolBinding[],\n): CanonicalOperationResult {\n if (result.status !== \"error\") return result;\n // The kernel's redaction already constrained `error.details.recovery` to a\n // safe recovery object; only its discriminant and operationId are read here.\n const error = result.error as\n | { readonly details?: { readonly recovery?: { readonly action?: unknown; readonly operationId?: unknown } } }\n | undefined;\n const recovery = error?.details?.recovery;\n if (recovery?.action !== \"complete_migration\") return result;\n const binding = bindings.find((candidate) => candidate.operationId === recovery.operationId);\n if (binding === undefined) return result;\n return {\n ...result,\n error: { ...error, details: { ...error?.details, recovery: { ...recovery, tool: binding.name } } },\n };\n}\n\n/** The canonical envelope immediately before MCP protocol serialization. */\nexport function canonicalMcpAdapterResult(result: unknown): CanonicalOperationResult {\n return toMcpToolResult(result).structuredContent;\n}\n\nfunction isCanonicalOperationResult(value: unknown): value is CanonicalOperationResult {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) return false;\n const status = (value as { status?: unknown }).status;\n return status === \"ok\" ||\n status === \"authority_required\" ||\n status === \"setup_required\" ||\n status === \"error\";\n}\n\nfunction resultSummary(status: CanonicalOperationResult[\"status\"]): string {\n switch (status) {\n case \"ok\":\n return \"TinyCloud operation completed; use the structured result.\";\n case \"authority_required\":\n return \"TinyCloud authority is required; use the structured request and approval action.\";\n case \"setup_required\":\n return \"TinyCloud setup is required; use the structured setup action.\";\n case \"error\":\n return \"TinyCloud operation failed; use the structured error.\";\n }\n}\nimport type { CallToolResult } from \"@modelcontextprotocol/server\";\n","/** Only code-owned tool names/codes and numeric counters reach this sink. */\nexport function logToolCall(\n tool: string,\n code: string,\n startedAt: number,\n replayedGrants: number,\n): void {\n process.stderr.write(`${JSON.stringify({\n tool,\n code,\n durationMs: Math.max(0, Math.round(performance.now() - startedAt)),\n replayedGrants,\n })}\\n`);\n}\n","{\n \"name\": \"@tinycloud/mcp\",\n \"version\": \"0.6.0-beta.1\",\n \"description\": \"TinyCloud delegated operations MCP server\",\n \"keywords\": [\n \"tinycloud\",\n \"mcp\",\n \"model-context-protocol\",\n \"agents\",\n \"delegation\",\n \"ucan\",\n \"kv\",\n \"sqlite\"\n ],\n \"author\": \"TinyCloud, Inc.\",\n \"license\": \"EGPL\",\n \"type\": \"module\",\n \"main\": \"dist/index.cjs\",\n \"module\": \"dist/index.js\",\n \"types\": \"dist/index.d.ts\",\n \"bin\": {\n \"tinycloud-mcp\": \"./bin/tinycloud-mcp\",\n \"tinycloud-mcp-http\": \"./bin/tinycloud-mcp-http\"\n },\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n },\n \"./server\": {\n \"types\": \"./dist/server.d.ts\",\n \"import\": \"./dist/server.js\",\n \"require\": \"./dist/server.cjs\"\n },\n \"./tools\": {\n \"types\": \"./dist/tools.d.ts\",\n \"import\": \"./dist/tools.js\",\n \"require\": \"./dist/tools.cjs\"\n },\n \"./results\": {\n \"types\": \"./dist/results.d.ts\",\n \"import\": \"./dist/results.js\",\n \"require\": \"./dist/results.cjs\"\n },\n \"./http\": {\n \"types\": \"./dist/http.d.ts\",\n \"import\": \"./dist/http.js\",\n \"require\": \"./dist/http.cjs\"\n }\n },\n \"files\": [\n \"dist\",\n \"bin\",\n \"generated\",\n \"skills\"\n ],\n \"engines\": {\n \"node\": \">=20\"\n },\n \"scripts\": {\n \"build\": \"tsup\",\n \"clean\": \"rm -rf dist\",\n \"test\": \"bun run build && bun scripts/test.ts && bun run check:generated\",\n \"test:stdio\": \"bun run build && bun test src/stdio.test.ts\",\n \"typecheck\": \"tsc -p tsconfig.json\",\n \"start:http\": \"node dist/http-cli.js\",\n \"generate\": \"bun scripts/generate.ts\",\n \"check:generated\": \"bun scripts/generate.ts --check\"\n },\n \"dependencies\": {\n \"@modelcontextprotocol/node\": \"2.0.0-beta.4\",\n \"@modelcontextprotocol/server\": \"2.0.0-beta.4\",\n \"@tinycloud/node-sdk\": \"3.2.5-beta.0\",\n \"@tinycloud/node-sdk-wasm\": \"1.7.7\",\n \"@tinycloud/operations\": \"0.6.0-beta.1\",\n \"jose\": \"6.1.3\"\n },\n \"devDependencies\": {\n \"@modelcontextprotocol/client\": \"2.0.0-beta.4\",\n \"@types/node\": \"^20\",\n \"tsup\": \"^8.0.0\",\n \"typescript\": \"^5.9.3\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/TinyCloudLabs/js-sdk\"\n },\n \"homepage\": \"https://docs.tinycloud.xyz/cli/mcp\"\n}\n","import packageMetadata from \"../package.json\";\n\nexport const MCP_VERSION = packageMetadata.version;\n"],"mappings":"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","names":[]}
package/dist/tools.cjs CHANGED
@@ -36,15 +36,37 @@ var import_ajv = require("@modelcontextprotocol/server/validators/ajv");
36
36
  var import_operations = require("@tinycloud/operations");
37
37
 
38
38
  // src/results.ts
39
- function toMcpToolResult(result, bindings = []) {
40
- const canonical = isCanonicalOperationResult(result) ? withRecoveryTool(result, bindings) : {
39
+ function toMcpToolResult(result, bindings = [], options = {}) {
40
+ let canonical = isCanonicalOperationResult(result) ? withRecoveryTool(result, bindings) : {
41
41
  status: "error",
42
42
  operation: {},
43
43
  context: {},
44
44
  error: { code: "INTERNAL_ERROR" }
45
45
  };
46
+ let serialized;
47
+ if (options.surface === "hosted") {
48
+ serialized = JSON.stringify(canonical);
49
+ if (options.readOnly === true && serialized.length > 1e5) {
50
+ const sql = options.operationId?.startsWith("tinycloud.sql.") || options.operationId === "tinycloud.apps.query";
51
+ canonical = {
52
+ status: "error",
53
+ operation: canonical.operation,
54
+ context: canonical.context,
55
+ error: {
56
+ code: sql ? "SQL_RESULT_LIMIT_EXCEEDED" : "KV_RESPONSE_TOO_LARGE",
57
+ message: sql ? "The result exceeds 100,000 characters. Select fewer columns or rows, add a WHERE filter or a smaller LIMIT, or aggregate the data." : "The result exceeds 100,000 characters. Request fewer keys, narrow the prefix, or use a smaller page size.",
58
+ retryable: false
59
+ }
60
+ };
61
+ serialized = JSON.stringify(canonical);
62
+ }
63
+ }
46
64
  return {
47
- content: [{ type: "text", text: resultSummary(canonical.status) }],
65
+ content: [{
66
+ type: "text",
67
+ text: resultSummary(canonical.status) + (serialized !== void 0 && !(options.operationId === "tinycloud.secrets.get" && canonical.status === "ok") ? `
68
+ ${serialized}` : "")
69
+ }],
48
70
  structuredContent: canonical
49
71
  };
50
72
  }
@@ -78,6 +100,17 @@ function resultSummary(status) {
78
100
  }
79
101
  }
80
102
 
103
+ // src/logging.ts
104
+ function logToolCall(tool, code, startedAt, replayedGrants) {
105
+ process.stderr.write(`${JSON.stringify({
106
+ tool,
107
+ code,
108
+ durationMs: Math.max(0, Math.round(performance.now() - startedAt)),
109
+ replayedGrants
110
+ })}
111
+ `);
112
+ }
113
+
81
114
  // src/tools.ts
82
115
  var import_meta = {};
83
116
  var TOOL_NAMES = [
@@ -97,7 +130,10 @@ var TOOL_NAMES = [
97
130
  "tinycloud_sql_query",
98
131
  "tinycloud_sql_execute",
99
132
  "tinycloud_secrets_get",
100
- "tinycloud_secrets_status"
133
+ "tinycloud_secrets_status",
134
+ "tinycloud_apps_context",
135
+ "tinycloud_apps_read",
136
+ "tinycloud_apps_write"
101
137
  ];
102
138
  function invocationTargetForMcp(selection) {
103
139
  return {
@@ -112,6 +148,9 @@ var packageRequire = (0, import_node_module.createRequire)(
112
148
  var generatedCatalog = packageRequire(
113
149
  "@tinycloud/operations/operations.json"
114
150
  );
151
+ var stableErrorCodes = Object.fromEntries(
152
+ generatedCatalog.stableErrors.map((code) => [code, true])
153
+ );
115
154
  var ALL_SURFACES = ["local", "hosted"];
116
155
  function bindingSurfaces(binding) {
117
156
  return binding.surfaces ?? ALL_SURFACES;
@@ -275,6 +314,36 @@ var TOOL_BINDINGS = [
275
314
  // Hosted has no persistent reauthorization path for a revoked session
276
315
  // yet (TC-896), so status is local/stdio only.
277
316
  surfaces: ["local"]
317
+ },
318
+ {
319
+ name: "tinycloud_apps_context",
320
+ operationId: "tinycloud.apps.context",
321
+ operationVersion: 1,
322
+ readOnlyHint: true,
323
+ idempotentHint: true,
324
+ destructiveHint: false,
325
+ openWorldHint: true,
326
+ surfaces: ["hosted"]
327
+ },
328
+ {
329
+ name: "tinycloud_apps_read",
330
+ operationId: "tinycloud.apps.read",
331
+ operationVersion: 1,
332
+ readOnlyHint: true,
333
+ idempotentHint: true,
334
+ destructiveHint: false,
335
+ openWorldHint: true,
336
+ surfaces: ["hosted"]
337
+ },
338
+ {
339
+ name: "tinycloud_apps_write",
340
+ operationId: "tinycloud.apps.write",
341
+ operationVersion: 1,
342
+ readOnlyHint: false,
343
+ idempotentHint: false,
344
+ destructiveHint: true,
345
+ openWorldHint: true,
346
+ surfaces: ["hosted"]
278
347
  }
279
348
  ];
280
349
  function createJsonSchemaValidator() {
@@ -319,18 +388,45 @@ function registerTinyCloudTools(server, selection, validator) {
319
388
  annotations
320
389
  },
321
390
  async (input) => {
322
- const result = await (0, import_operations.invokeOperation)(
323
- binding.operationId,
324
- binding.operationVersion,
325
- invocationTargetForMcp(selection),
326
- input
327
- );
328
- const projected = selection.transformOperationResult === void 0 ? result : await selection.transformOperationResult(result);
329
- return toMcpToolResult(projected, TOOL_BINDINGS);
391
+ const startedAt = performance.now();
392
+ const metrics = { replayedGrants: 0 };
393
+ let code = "INTERNAL_ERROR";
394
+ try {
395
+ const result = await (0, import_operations.invokeOperation)(
396
+ binding.operationId,
397
+ binding.operationVersion,
398
+ invocationTargetForMcp(selection),
399
+ input,
400
+ metrics
401
+ );
402
+ const projected = selection.transformOperationResult === void 0 ? result : await selection.transformOperationResult(result);
403
+ const response = toMcpToolResult(projected, TOOL_BINDINGS, {
404
+ surface: selection.surface,
405
+ readOnly: binding.readOnlyHint,
406
+ operationId: binding.operationId
407
+ });
408
+ code = outcomeCode(response.structuredContent);
409
+ return response;
410
+ } finally {
411
+ if (selection.surface === "hosted") {
412
+ logToolCall(binding.name, code, startedAt, metrics.replayedGrants);
413
+ }
414
+ }
330
415
  }
331
416
  );
332
417
  }
333
418
  }
419
+ function outcomeCode(result) {
420
+ if (result.status === "error") {
421
+ const error = result.error;
422
+ return typeof error?.code === "string" && Object.hasOwn(stableErrorCodes, error.code) ? error.code : "INTERNAL_ERROR";
423
+ }
424
+ if (result.status !== "ok") return result.status;
425
+ const output = result.output;
426
+ if (output?.outcome === "COPY_PARTIAL") return "COPY_PARTIAL";
427
+ if (Array.isArray(output?.ops) && output.ops.some((op) => op.outcome !== "ok")) return "PARTIAL";
428
+ return "ok";
429
+ }
334
430
  function toolBindingsForTest() {
335
431
  return TOOL_BINDINGS;
336
432
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/tools.ts","../src/results.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\nimport { join } from \"node:path\";\n\nimport { fromJsonSchema, type McpServer, type ToolAnnotations } from \"@modelcontextprotocol/server\";\nimport { addFormats, Ajv, AjvJsonSchemaValidator } from \"@modelcontextprotocol/server/validators/ajv\";\nimport { invokeOperation } from \"@tinycloud/operations\";\n\nimport { toMcpToolResult, type McpToolResult } from \"./results.js\";\n\nexport const TOOL_NAMES = [\n \"tinycloud_status\",\n \"tinycloud_auth_status\",\n \"tinycloud_auth_capabilities\",\n \"tinycloud_auth_request\",\n \"tinycloud_auth_import\",\n \"tinycloud_account_spaces_list\",\n \"tinycloud_account_applications_list\",\n \"tinycloud_kv_list\",\n \"tinycloud_kv_get\",\n \"tinycloud_kv_head\",\n \"tinycloud_kv_put\",\n \"tinycloud_kv_delete\",\n \"tinycloud_sql_schema_inspect\",\n \"tinycloud_sql_query\",\n \"tinycloud_sql_execute\",\n \"tinycloud_secrets_get\",\n \"tinycloud_secrets_status\",\n] as const;\n\nexport type ToolName = (typeof TOOL_NAMES)[number];\n\n/** MCP server surfaces: local stdio and the hosted OAuth HTTP server. */\nexport type McpSurface = \"local\" | \"hosted\";\n\nexport interface McpStartupSelection {\n /** Which server registers the tools; bindings not on this surface are skipped. */\n readonly surface: McpSurface;\n readonly profile: string;\n readonly explicitProfile: boolean;\n readonly allowOwnerProfile: boolean;\n /** Absolute TinyCloud home used to isolate one hosted OAuth principal. */\n readonly stateRoot?: string;\n /** Hosted transports may attach a browser approval URL to canonical results. */\n readonly transformOperationResult?: (result: unknown) => Promise<unknown>;\n}\n\nexport interface McpInvocationTarget {\n readonly profile: string;\n readonly allowOwnerProfile?: true;\n readonly stateRoot?: string;\n}\n\n/** Project one startup selection into the only owner-sensitive target shape. */\nexport function invocationTargetForMcp(\n selection: Omit<McpStartupSelection, \"surface\">,\n): McpInvocationTarget {\n return {\n profile: selection.profile,\n ...(selection.explicitProfile && selection.allowOwnerProfile\n ? { allowOwnerProfile: true }\n : {}),\n ...(selection.stateRoot === undefined ? {} : { stateRoot: selection.stateRoot }),\n };\n}\n\ninterface CatalogOperation {\n readonly id: string;\n readonly version: number;\n readonly title: string;\n readonly description: string;\n readonly input: Record<string, unknown>;\n readonly result: Record<string, unknown>;\n}\n\ninterface OperationsCatalog {\n readonly operations: readonly CatalogOperation[];\n}\n\n// The require anchor is this module, never the consumer entrypoint. In ESM\n// tsup preserves import.meta.url; in CJS it rewrites the same module-relative\n// anchor to the generated __filename, so both formats stay in MCP's package\n// dependency boundary.\nconst packageRequire = createRequire(\n typeof __dirname === \"string\" ? join(__dirname, \"tools.cjs\") : import.meta.url,\n);\nconst generatedCatalog = packageRequire(\n \"@tinycloud/operations/operations.json\",\n) as OperationsCatalog;\n\nexport interface ToolBinding {\n readonly name: ToolName;\n readonly operationId: string;\n readonly operationVersion: number;\n readonly readOnlyHint: boolean;\n readonly idempotentHint: boolean;\n readonly destructiveHint: boolean;\n readonly openWorldHint: boolean;\n /** Surfaces that register this tool; omitted means every surface. */\n readonly surfaces?: readonly McpSurface[];\n}\n\nconst ALL_SURFACES: readonly McpSurface[] = [\"local\", \"hosted\"];\n\n/** The surfaces a binding is registered on. */\nexport function bindingSurfaces(binding: ToolBinding): readonly McpSurface[] {\n return binding.surfaces ?? ALL_SURFACES;\n}\n\nexport const TOOL_BINDINGS: readonly ToolBinding[] = [\n {\n name: \"tinycloud_status\",\n operationId: \"tinycloud.status.get\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: false,\n },\n {\n name: \"tinycloud_auth_status\",\n operationId: \"tinycloud.auth.status\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: false,\n },\n {\n name: \"tinycloud_auth_capabilities\",\n operationId: \"tinycloud.auth.capabilities\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: false,\n },\n {\n name: \"tinycloud_auth_request\",\n operationId: \"tinycloud.auth.request\",\n operationVersion: 1,\n readOnlyHint: false,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: false,\n },\n {\n name: \"tinycloud_auth_import\",\n operationId: \"tinycloud.auth.import\",\n operationVersion: 1,\n readOnlyHint: false,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: false,\n // Hosted delegations must arrive through the owner/request-bound OpenKey callback,\n // not a caller-supplied import artifact.\n surfaces: [\"local\"],\n },\n {\n name: \"tinycloud_account_spaces_list\",\n operationId: \"tinycloud.account.spaces.list\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_account_applications_list\",\n operationId: \"tinycloud.account.applications.list\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_kv_list\",\n operationId: \"tinycloud.kv.list\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_kv_get\",\n operationId: \"tinycloud.kv.get\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_kv_head\",\n operationId: \"tinycloud.kv.head\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_kv_put\",\n operationId: \"tinycloud.kv.put\",\n operationVersion: 1,\n readOnlyHint: false,\n idempotentHint: true,\n destructiveHint: true,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_kv_delete\",\n operationId: \"tinycloud.kv.delete\",\n operationVersion: 1,\n readOnlyHint: false,\n idempotentHint: true,\n destructiveHint: true,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_sql_schema_inspect\",\n operationId: \"tinycloud.sql.schema.inspect\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_sql_query\",\n operationId: \"tinycloud.sql.query\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_sql_execute\",\n operationId: \"tinycloud.sql.execute\",\n operationVersion: 1,\n readOnlyHint: false,\n idempotentHint: false,\n destructiveHint: true,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_secrets_get\",\n operationId: \"tinycloud.secrets.get\",\n operationVersion: 1,\n readOnlyHint: false,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_secrets_status\",\n operationId: \"tinycloud.secrets.status\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n // Hosted has no persistent reauthorization path for a revoked session\n // yet (TC-896), so status is local/stdio only.\n surfaces: [\"local\"],\n },\n] as const;\n\nexport function createJsonSchemaValidator(): AjvJsonSchemaValidator {\n const ajv = new Ajv({ strict: false });\n addFormats(ajv);\n return new AjvJsonSchemaValidator(ajv);\n}\n\nexport function registerTinyCloudTools(\n server: McpServer,\n selection: McpStartupSelection,\n validator: AjvJsonSchemaValidator,\n): void {\n const definitions = new Map(\n generatedCatalog.operations.map((operation) => [\n `${operation.id}@${operation.version}`,\n operation,\n ]),\n );\n\n for (const binding of TOOL_BINDINGS) {\n if (!bindingSurfaces(binding).includes(selection.surface)) continue;\n const operation = definitions.get(`${binding.operationId}@${binding.operationVersion}`);\n if (operation === undefined) {\n throw new Error(`Generated operations catalog is missing ${binding.operationId}@${binding.operationVersion}.`);\n }\n\n const inputSchema = fromJsonSchema(\n operation.input as Parameters<typeof fromJsonSchema>[0],\n validator,\n );\n const outputSchema = fromJsonSchema(\n operation.result as unknown as Parameters<typeof fromJsonSchema>[0],\n validator,\n );\n const annotations: ToolAnnotations = {\n readOnlyHint: binding.readOnlyHint,\n idempotentHint: binding.idempotentHint,\n destructiveHint: binding.destructiveHint,\n openWorldHint: binding.openWorldHint,\n };\n\n server.registerTool(\n binding.name,\n {\n title: operation.title,\n description: operation.description,\n inputSchema,\n outputSchema,\n annotations,\n },\n async (input: unknown): Promise<McpToolResult> => {\n const result = await invokeOperation(\n binding.operationId,\n binding.operationVersion,\n invocationTargetForMcp(selection),\n input,\n );\n const projected = selection.transformOperationResult === undefined\n ? result\n : await selection.transformOperationResult(result);\n return toMcpToolResult(projected, TOOL_BINDINGS);\n },\n );\n }\n}\n\nexport function toolBindingsForTest(): readonly ToolBinding[] {\n return TOOL_BINDINGS;\n}\n","/**\n * MCP has one structured result channel for a TinyCloud operation. Text is a\n * fixed, non-sensitive status line; it never serializes the operation result.\n */\nexport interface CanonicalOperationResult {\n readonly status: \"ok\" | \"authority_required\" | \"setup_required\" | \"error\";\n readonly [key: string]: unknown;\n}\n\nexport interface McpToolResult extends CallToolResult {\n readonly content: [{ readonly type: \"text\"; readonly text: string }];\n readonly structuredContent: CanonicalOperationResult;\n}\n\n/** The binding fields needed to name the tool that runs an operation. */\nexport interface RecoveryToolBinding {\n readonly name: string;\n readonly operationId: string;\n}\n\nexport function toMcpToolResult(\n result: unknown,\n bindings: readonly RecoveryToolBinding[] = [],\n): McpToolResult {\n const canonical: CanonicalOperationResult = isCanonicalOperationResult(result)\n ? withRecoveryTool(result, bindings)\n : {\n status: \"error\",\n operation: {},\n context: {},\n error: { code: \"INTERNAL_ERROR\" },\n };\n\n return {\n content: [{ type: \"text\", text: resultSummary(canonical.status) }],\n structuredContent: canonical,\n };\n}\n\n/**\n * A redacted `complete_migration` recovery names an operation; MCP clients\n * call tools, so name the bound tool. `tool` comes from the code-owned binding\n * table only, never from operation data, and is added after redaction. An\n * operationId with no binding gets no `tool`.\n */\nfunction withRecoveryTool(\n result: CanonicalOperationResult,\n bindings: readonly RecoveryToolBinding[],\n): CanonicalOperationResult {\n if (result.status !== \"error\") return result;\n // The kernel's redaction already constrained `error.details.recovery` to a\n // safe recovery object; only its discriminant and operationId are read here.\n const error = result.error as\n | { readonly details?: { readonly recovery?: { readonly action?: unknown; readonly operationId?: unknown } } }\n | undefined;\n const recovery = error?.details?.recovery;\n if (recovery?.action !== \"complete_migration\") return result;\n const binding = bindings.find((candidate) => candidate.operationId === recovery.operationId);\n if (binding === undefined) return result;\n return {\n ...result,\n error: { ...error, details: { ...error?.details, recovery: { ...recovery, tool: binding.name } } },\n };\n}\n\n/** The canonical envelope immediately before MCP protocol serialization. */\nexport function canonicalMcpAdapterResult(result: unknown): CanonicalOperationResult {\n return toMcpToolResult(result).structuredContent;\n}\n\nfunction isCanonicalOperationResult(value: unknown): value is CanonicalOperationResult {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) return false;\n const status = (value as { status?: unknown }).status;\n return status === \"ok\" ||\n status === \"authority_required\" ||\n status === \"setup_required\" ||\n status === \"error\";\n}\n\nfunction resultSummary(status: CanonicalOperationResult[\"status\"]): string {\n switch (status) {\n case \"ok\":\n return \"TinyCloud operation completed; use the structured result.\";\n case \"authority_required\":\n return \"TinyCloud authority is required; use the structured request and approval action.\";\n case \"setup_required\":\n return \"TinyCloud setup is required; use the structured setup action.\";\n case \"error\":\n return \"TinyCloud operation failed; use the structured error.\";\n }\n}\nimport type { CallToolResult } from \"@modelcontextprotocol/server\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAA8B;AAC9B,uBAAqB;AAErB,oBAAqE;AACrE,iBAAwD;AACxD,wBAAgC;;;ACezB,SAAS,gBACd,QACA,WAA2C,CAAC,GAC7B;AACf,QAAM,YAAsC,2BAA2B,MAAM,IACzE,iBAAiB,QAAQ,QAAQ,IACjC;AAAA,IACA,QAAQ;AAAA,IACR,WAAW,CAAC;AAAA,IACZ,SAAS,CAAC;AAAA,IACV,OAAO,EAAE,MAAM,iBAAiB;AAAA,EAClC;AAEF,SAAO;AAAA,IACL,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,cAAc,UAAU,MAAM,EAAE,CAAC;AAAA,IACjE,mBAAmB;AAAA,EACrB;AACF;AAQA,SAAS,iBACP,QACA,UAC0B;AAC1B,MAAI,OAAO,WAAW,QAAS,QAAO;AAGtC,QAAM,QAAQ,OAAO;AAGrB,QAAM,WAAW,OAAO,SAAS;AACjC,MAAI,UAAU,WAAW,qBAAsB,QAAO;AACtD,QAAM,UAAU,SAAS,KAAK,CAAC,cAAc,UAAU,gBAAgB,SAAS,WAAW;AAC3F,MAAI,YAAY,OAAW,QAAO;AAClC,SAAO;AAAA,IACL,GAAG;AAAA,IACH,OAAO,EAAE,GAAG,OAAO,SAAS,EAAE,GAAG,OAAO,SAAS,UAAU,EAAE,GAAG,UAAU,MAAM,QAAQ,KAAK,EAAE,EAAE;AAAA,EACnG;AACF;AAOA,SAAS,2BAA2B,OAAmD;AACrF,MAAI,UAAU,QAAQ,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,EAAG,QAAO;AAChF,QAAM,SAAU,MAA+B;AAC/C,SAAO,WAAW,QAChB,WAAW,wBACX,WAAW,oBACX,WAAW;AACf;AAEA,SAAS,cAAc,QAAoD;AACzE,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,EACX;AACF;;;AD1FA;AASO,IAAM,aAAa;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AA0BO,SAAS,uBACd,WACqB;AACrB,SAAO;AAAA,IACL,SAAS,UAAU;AAAA,IACnB,GAAI,UAAU,mBAAmB,UAAU,oBACvC,EAAE,mBAAmB,KAAK,IAC1B,CAAC;AAAA,IACL,GAAI,UAAU,cAAc,SAAY,CAAC,IAAI,EAAE,WAAW,UAAU,UAAU;AAAA,EAChF;AACF;AAmBA,IAAM,qBAAiB;AAAA,EACrB,OAAO,cAAc,eAAW,uBAAK,WAAW,WAAW,IAAI,YAAY;AAC7E;AACA,IAAM,mBAAmB;AAAA,EACvB;AACF;AAcA,IAAM,eAAsC,CAAC,SAAS,QAAQ;AAGvD,SAAS,gBAAgB,SAA6C;AAC3E,SAAO,QAAQ,YAAY;AAC7B;AAEO,IAAM,gBAAwC;AAAA,EACnD;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,kBAAkB;AAAA,IAClB,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,IACjB,eAAe;AAAA,EACjB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,kBAAkB;AAAA,IAClB,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,IACjB,eAAe;AAAA,EACjB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,kBAAkB;AAAA,IAClB,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,IACjB,eAAe;AAAA,EACjB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,kBAAkB;AAAA,IAClB,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,IACjB,eAAe;AAAA,EACjB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,kBAAkB;AAAA,IAClB,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,IACjB,eAAe;AAAA;AAAA;AAAA,IAGf,UAAU,CAAC,OAAO;AAAA,EACpB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,kBAAkB;AAAA,IAClB,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,IACjB,eAAe;AAAA,EACjB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,kBAAkB;AAAA,IAClB,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,IACjB,eAAe;AAAA,EACjB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,kBAAkB;AAAA,IAClB,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,IACjB,eAAe;AAAA,EACjB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,kBAAkB;AAAA,IAClB,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,IACjB,eAAe;AAAA,EACjB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,kBAAkB;AAAA,IAClB,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,IACjB,eAAe;AAAA,EACjB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,kBAAkB;AAAA,IAClB,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,IACjB,eAAe;AAAA,EACjB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,kBAAkB;AAAA,IAClB,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,IACjB,eAAe;AAAA,EACjB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,kBAAkB;AAAA,IAClB,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,IACjB,eAAe;AAAA,EACjB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,kBAAkB;AAAA,IAClB,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,IACjB,eAAe;AAAA,EACjB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,kBAAkB;AAAA,IAClB,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,IACjB,eAAe;AAAA,EACjB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,kBAAkB;AAAA,IAClB,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,IACjB,eAAe;AAAA,EACjB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,kBAAkB;AAAA,IAClB,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,IACjB,eAAe;AAAA;AAAA;AAAA,IAGf,UAAU,CAAC,OAAO;AAAA,EACpB;AACF;AAEO,SAAS,4BAAoD;AAClE,QAAM,MAAM,IAAI,eAAI,EAAE,QAAQ,MAAM,CAAC;AACrC,6BAAW,GAAG;AACd,SAAO,IAAI,kCAAuB,GAAG;AACvC;AAEO,SAAS,uBACd,QACA,WACA,WACM;AACN,QAAM,cAAc,IAAI;AAAA,IACtB,iBAAiB,WAAW,IAAI,CAAC,cAAc;AAAA,MAC7C,GAAG,UAAU,EAAE,IAAI,UAAU,OAAO;AAAA,MACpC;AAAA,IACF,CAAC;AAAA,EACH;AAEA,aAAW,WAAW,eAAe;AACnC,QAAI,CAAC,gBAAgB,OAAO,EAAE,SAAS,UAAU,OAAO,EAAG;AAC3D,UAAM,YAAY,YAAY,IAAI,GAAG,QAAQ,WAAW,IAAI,QAAQ,gBAAgB,EAAE;AACtF,QAAI,cAAc,QAAW;AAC3B,YAAM,IAAI,MAAM,2CAA2C,QAAQ,WAAW,IAAI,QAAQ,gBAAgB,GAAG;AAAA,IAC/G;AAEA,UAAM,kBAAc;AAAA,MAClB,UAAU;AAAA,MACV;AAAA,IACF;AACA,UAAM,mBAAe;AAAA,MACnB,UAAU;AAAA,MACV;AAAA,IACF;AACA,UAAM,cAA+B;AAAA,MACnC,cAAc,QAAQ;AAAA,MACtB,gBAAgB,QAAQ;AAAA,MACxB,iBAAiB,QAAQ;AAAA,MACzB,eAAe,QAAQ;AAAA,IACzB;AAEA,WAAO;AAAA,MACL,QAAQ;AAAA,MACR;AAAA,QACE,OAAO,UAAU;AAAA,QACjB,aAAa,UAAU;AAAA,QACvB;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA,OAAO,UAA2C;AAChD,cAAM,SAAS,UAAM;AAAA,UACnB,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR,uBAAuB,SAAS;AAAA,UAChC;AAAA,QACF;AACA,cAAM,YAAY,UAAU,6BAA6B,SACrD,SACA,MAAM,UAAU,yBAAyB,MAAM;AACnD,eAAO,gBAAgB,WAAW,aAAa;AAAA,MACjD;AAAA,IACF;AAAA,EACF;AACF;AAEO,SAAS,sBAA8C;AAC5D,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../src/tools.ts","../src/results.ts","../src/logging.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\nimport { join } from \"node:path\";\n\nimport { fromJsonSchema, type McpServer, type ToolAnnotations } from \"@modelcontextprotocol/server\";\nimport { addFormats, Ajv, AjvJsonSchemaValidator } from \"@modelcontextprotocol/server/validators/ajv\";\nimport { invokeOperation } from \"@tinycloud/operations\";\n\nimport { toMcpToolResult, type McpToolResult } from \"./results.js\";\nimport { logToolCall } from \"./logging.js\";\n\nexport const TOOL_NAMES = [\n \"tinycloud_status\",\n \"tinycloud_auth_status\",\n \"tinycloud_auth_capabilities\",\n \"tinycloud_auth_request\",\n \"tinycloud_auth_import\",\n \"tinycloud_account_spaces_list\",\n \"tinycloud_account_applications_list\",\n \"tinycloud_kv_list\",\n \"tinycloud_kv_get\",\n \"tinycloud_kv_head\",\n \"tinycloud_kv_put\",\n \"tinycloud_kv_delete\",\n \"tinycloud_sql_schema_inspect\",\n \"tinycloud_sql_query\",\n \"tinycloud_sql_execute\",\n \"tinycloud_secrets_get\",\n \"tinycloud_secrets_status\",\n \"tinycloud_apps_context\",\n \"tinycloud_apps_read\",\n \"tinycloud_apps_write\",\n] as const;\n\nexport type ToolName = (typeof TOOL_NAMES)[number];\n\n/** MCP server surfaces: local stdio and the hosted OAuth HTTP server. */\nexport type McpSurface = \"local\" | \"hosted\";\n\nexport interface McpStartupSelection {\n /** Which server registers the tools; bindings not on this surface are skipped. */\n readonly surface: McpSurface;\n readonly profile: string;\n readonly explicitProfile: boolean;\n readonly allowOwnerProfile: boolean;\n /** Absolute TinyCloud home used to isolate one hosted OAuth principal. */\n readonly stateRoot?: string;\n /** Hosted transports may attach a browser approval URL to canonical results. */\n readonly transformOperationResult?: (result: unknown) => Promise<unknown>;\n}\n\nexport interface McpInvocationTarget {\n readonly profile: string;\n readonly allowOwnerProfile?: true;\n readonly stateRoot?: string;\n}\n\n/** Project one startup selection into the only owner-sensitive target shape. */\nexport function invocationTargetForMcp(\n selection: Omit<McpStartupSelection, \"surface\">,\n): McpInvocationTarget {\n return {\n profile: selection.profile,\n ...(selection.explicitProfile && selection.allowOwnerProfile\n ? { allowOwnerProfile: true }\n : {}),\n ...(selection.stateRoot === undefined ? {} : { stateRoot: selection.stateRoot }),\n };\n}\n\ninterface CatalogOperation {\n readonly id: string;\n readonly version: number;\n readonly title: string;\n readonly description: string;\n readonly input: Record<string, unknown>;\n readonly result: Record<string, unknown>;\n}\n\ninterface OperationsCatalog {\n readonly stableErrors: readonly string[];\n readonly operations: readonly CatalogOperation[];\n}\n\n// The require anchor is this module, never the consumer entrypoint. In ESM\n// tsup preserves import.meta.url; in CJS it rewrites the same module-relative\n// anchor to the generated __filename, so both formats stay in MCP's package\n// dependency boundary.\nconst packageRequire = createRequire(\n typeof __dirname === \"string\" ? join(__dirname, \"tools.cjs\") : import.meta.url,\n);\nconst generatedCatalog = packageRequire(\n \"@tinycloud/operations/operations.json\",\n) as OperationsCatalog;\nconst stableErrorCodes: Readonly<Record<string, true>> = Object.fromEntries(\n generatedCatalog.stableErrors.map((code) => [code, true as const]),\n);\n\nexport interface ToolBinding {\n readonly name: ToolName;\n readonly operationId: string;\n readonly operationVersion: number;\n readonly readOnlyHint: boolean;\n readonly idempotentHint: boolean;\n readonly destructiveHint: boolean;\n readonly openWorldHint: boolean;\n /** Surfaces that register this tool; omitted means every surface. */\n readonly surfaces?: readonly McpSurface[];\n}\n\nconst ALL_SURFACES: readonly McpSurface[] = [\"local\", \"hosted\"];\n\n/** The surfaces a binding is registered on. */\nexport function bindingSurfaces(binding: ToolBinding): readonly McpSurface[] {\n return binding.surfaces ?? ALL_SURFACES;\n}\n\nexport const TOOL_BINDINGS: readonly ToolBinding[] = [\n {\n name: \"tinycloud_status\",\n operationId: \"tinycloud.status.get\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: false,\n },\n {\n name: \"tinycloud_auth_status\",\n operationId: \"tinycloud.auth.status\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: false,\n },\n {\n name: \"tinycloud_auth_capabilities\",\n operationId: \"tinycloud.auth.capabilities\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: false,\n },\n {\n name: \"tinycloud_auth_request\",\n operationId: \"tinycloud.auth.request\",\n operationVersion: 1,\n readOnlyHint: false,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: false,\n },\n {\n name: \"tinycloud_auth_import\",\n operationId: \"tinycloud.auth.import\",\n operationVersion: 1,\n readOnlyHint: false,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: false,\n // Hosted delegations must arrive through the owner/request-bound OpenKey callback,\n // not a caller-supplied import artifact.\n surfaces: [\"local\"],\n },\n {\n name: \"tinycloud_account_spaces_list\",\n operationId: \"tinycloud.account.spaces.list\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_account_applications_list\",\n operationId: \"tinycloud.account.applications.list\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_kv_list\",\n operationId: \"tinycloud.kv.list\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_kv_get\",\n operationId: \"tinycloud.kv.get\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_kv_head\",\n operationId: \"tinycloud.kv.head\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_kv_put\",\n operationId: \"tinycloud.kv.put\",\n operationVersion: 1,\n readOnlyHint: false,\n idempotentHint: true,\n destructiveHint: true,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_kv_delete\",\n operationId: \"tinycloud.kv.delete\",\n operationVersion: 1,\n readOnlyHint: false,\n idempotentHint: true,\n destructiveHint: true,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_sql_schema_inspect\",\n operationId: \"tinycloud.sql.schema.inspect\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_sql_query\",\n operationId: \"tinycloud.sql.query\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_sql_execute\",\n operationId: \"tinycloud.sql.execute\",\n operationVersion: 1,\n readOnlyHint: false,\n idempotentHint: false,\n destructiveHint: true,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_secrets_get\",\n operationId: \"tinycloud.secrets.get\",\n operationVersion: 1,\n readOnlyHint: false,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n },\n {\n name: \"tinycloud_secrets_status\",\n operationId: \"tinycloud.secrets.status\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n // Hosted has no persistent reauthorization path for a revoked session\n // yet (TC-896), so status is local/stdio only.\n surfaces: [\"local\"],\n },\n {\n name: \"tinycloud_apps_context\",\n operationId: \"tinycloud.apps.context\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n surfaces: [\"hosted\"],\n },\n {\n name: \"tinycloud_apps_read\",\n operationId: \"tinycloud.apps.read\",\n operationVersion: 1,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n surfaces: [\"hosted\"],\n },\n {\n name: \"tinycloud_apps_write\",\n operationId: \"tinycloud.apps.write\",\n operationVersion: 1,\n readOnlyHint: false,\n idempotentHint: false,\n destructiveHint: true,\n openWorldHint: true,\n surfaces: [\"hosted\"],\n },\n] as const;\n\nexport function createJsonSchemaValidator(): AjvJsonSchemaValidator {\n const ajv = new Ajv({ strict: false });\n addFormats(ajv);\n return new AjvJsonSchemaValidator(ajv);\n}\n\nexport function registerTinyCloudTools(\n server: McpServer,\n selection: McpStartupSelection,\n validator: AjvJsonSchemaValidator,\n): void {\n const definitions = new Map(\n generatedCatalog.operations.map((operation) => [\n `${operation.id}@${operation.version}`,\n operation,\n ]),\n );\n\n for (const binding of TOOL_BINDINGS) {\n if (!bindingSurfaces(binding).includes(selection.surface)) continue;\n const operation = definitions.get(`${binding.operationId}@${binding.operationVersion}`);\n if (operation === undefined) {\n throw new Error(`Generated operations catalog is missing ${binding.operationId}@${binding.operationVersion}.`);\n }\n\n const inputSchema = fromJsonSchema(\n operation.input as Parameters<typeof fromJsonSchema>[0],\n validator,\n );\n const outputSchema = fromJsonSchema(\n operation.result as unknown as Parameters<typeof fromJsonSchema>[0],\n validator,\n );\n const annotations: ToolAnnotations = {\n readOnlyHint: binding.readOnlyHint,\n idempotentHint: binding.idempotentHint,\n destructiveHint: binding.destructiveHint,\n openWorldHint: binding.openWorldHint,\n };\n\n server.registerTool(\n binding.name,\n {\n title: operation.title,\n description: operation.description,\n inputSchema,\n outputSchema,\n annotations,\n },\n async (input: unknown): Promise<McpToolResult> => {\n const startedAt = performance.now();\n const metrics = { replayedGrants: 0 };\n let code = \"INTERNAL_ERROR\";\n try {\n const result = await invokeOperation(\n binding.operationId,\n binding.operationVersion,\n invocationTargetForMcp(selection),\n input,\n metrics,\n );\n const projected = selection.transformOperationResult === undefined\n ? result\n : await selection.transformOperationResult(result);\n const response = toMcpToolResult(projected, TOOL_BINDINGS, {\n surface: selection.surface,\n readOnly: binding.readOnlyHint,\n operationId: binding.operationId,\n });\n code = outcomeCode(response.structuredContent);\n return response;\n } finally {\n if (selection.surface === \"hosted\") {\n logToolCall(binding.name, code, startedAt, metrics.replayedGrants);\n }\n }\n },\n );\n }\n}\n\nfunction outcomeCode(result: McpToolResult[\"structuredContent\"]): string {\n if (result.status === \"error\") {\n const error = result.error as { code?: unknown } | undefined;\n return typeof error?.code === \"string\" && Object.hasOwn(stableErrorCodes, error.code) ? error.code : \"INTERNAL_ERROR\";\n }\n if (result.status !== \"ok\") return result.status;\n const output = result.output as { outcome?: unknown; ops?: readonly { outcome?: unknown }[] } | undefined;\n if (output?.outcome === \"COPY_PARTIAL\") return \"COPY_PARTIAL\";\n if (Array.isArray(output?.ops) && output.ops.some((op) => op.outcome !== \"ok\")) return \"PARTIAL\";\n return \"ok\";\n}\n\nexport function toolBindingsForTest(): readonly ToolBinding[] {\n return TOOL_BINDINGS;\n}\n","/** MCP preserves the canonical envelope; hosted clients also receive readable JSON. */\nexport interface CanonicalOperationResult {\n readonly status: \"ok\" | \"authority_required\" | \"setup_required\" | \"error\";\n readonly [key: string]: unknown;\n}\n\nexport interface McpToolResult extends CallToolResult {\n readonly content: [{ readonly type: \"text\"; readonly text: string }];\n readonly structuredContent: CanonicalOperationResult;\n}\n\n/** The binding fields needed to name the tool that runs an operation. */\nexport interface RecoveryToolBinding {\n readonly name: string;\n readonly operationId: string;\n}\n\nexport interface McpToolResultOptions {\n readonly surface?: \"hosted\" | \"local\";\n readonly readOnly?: boolean;\n /** Trusted operation identity from the tool binding, not operation output. */\n readonly operationId?: string;\n}\n\nexport function toMcpToolResult(\n result: unknown,\n bindings: readonly RecoveryToolBinding[] = [],\n options: McpToolResultOptions = {},\n): McpToolResult {\n let canonical: CanonicalOperationResult = isCanonicalOperationResult(result)\n ? withRecoveryTool(result, bindings)\n : {\n status: \"error\",\n operation: {},\n context: {},\n error: { code: \"INTERNAL_ERROR\" },\n };\n let serialized: string | undefined;\n if (options.surface === \"hosted\") {\n serialized = JSON.stringify(canonical);\n if (options.readOnly === true && serialized.length > 100_000) {\n const sql = options.operationId?.startsWith(\"tinycloud.sql.\") ||\n options.operationId === \"tinycloud.apps.query\";\n canonical = {\n status: \"error\",\n operation: canonical.operation,\n context: canonical.context,\n error: {\n code: sql ? \"SQL_RESULT_LIMIT_EXCEEDED\" : \"KV_RESPONSE_TOO_LARGE\",\n message: sql\n ? \"The result exceeds 100,000 characters. Select fewer columns or rows, add a WHERE filter or a smaller LIMIT, or aggregate the data.\"\n : \"The result exceeds 100,000 characters. Request fewer keys, narrow the prefix, or use a smaller page size.\",\n retryable: false,\n },\n };\n serialized = JSON.stringify(canonical);\n }\n }\n\n return {\n content: [{\n type: \"text\",\n text: resultSummary(canonical.status) +\n (serialized !== undefined && !(options.operationId === \"tinycloud.secrets.get\" && canonical.status === \"ok\")\n ? `\\n${serialized}` : \"\"),\n }],\n structuredContent: canonical,\n };\n}\n\n/**\n * A redacted `complete_migration` recovery names an operation; MCP clients\n * call tools, so name the bound tool. `tool` comes from the code-owned binding\n * table only, never from operation data, and is added after redaction. An\n * operationId with no binding gets no `tool`.\n */\nfunction withRecoveryTool(\n result: CanonicalOperationResult,\n bindings: readonly RecoveryToolBinding[],\n): CanonicalOperationResult {\n if (result.status !== \"error\") return result;\n // The kernel's redaction already constrained `error.details.recovery` to a\n // safe recovery object; only its discriminant and operationId are read here.\n const error = result.error as\n | { readonly details?: { readonly recovery?: { readonly action?: unknown; readonly operationId?: unknown } } }\n | undefined;\n const recovery = error?.details?.recovery;\n if (recovery?.action !== \"complete_migration\") return result;\n const binding = bindings.find((candidate) => candidate.operationId === recovery.operationId);\n if (binding === undefined) return result;\n return {\n ...result,\n error: { ...error, details: { ...error?.details, recovery: { ...recovery, tool: binding.name } } },\n };\n}\n\n/** The canonical envelope immediately before MCP protocol serialization. */\nexport function canonicalMcpAdapterResult(result: unknown): CanonicalOperationResult {\n return toMcpToolResult(result).structuredContent;\n}\n\nfunction isCanonicalOperationResult(value: unknown): value is CanonicalOperationResult {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) return false;\n const status = (value as { status?: unknown }).status;\n return status === \"ok\" ||\n status === \"authority_required\" ||\n status === \"setup_required\" ||\n status === \"error\";\n}\n\nfunction resultSummary(status: CanonicalOperationResult[\"status\"]): string {\n switch (status) {\n case \"ok\":\n return \"TinyCloud operation completed; use the structured result.\";\n case \"authority_required\":\n return \"TinyCloud authority is required; use the structured request and approval action.\";\n case \"setup_required\":\n return \"TinyCloud setup is required; use the structured setup action.\";\n case \"error\":\n return \"TinyCloud operation failed; use the structured error.\";\n }\n}\nimport type { CallToolResult } from \"@modelcontextprotocol/server\";\n","/** Only code-owned tool names/codes and numeric counters reach this sink. */\nexport function logToolCall(\n tool: string,\n code: string,\n startedAt: number,\n replayedGrants: number,\n): void {\n process.stderr.write(`${JSON.stringify({\n tool,\n code,\n durationMs: Math.max(0, Math.round(performance.now() - startedAt)),\n replayedGrants,\n })}\\n`);\n}\n"],"mappings":"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","names":[]}
package/dist/tools.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { McpServer } from '@modelcontextprotocol/server';
2
2
  import { AjvJsonSchemaValidator } from '@modelcontextprotocol/server/validators/ajv';
3
3
 
4
- declare const TOOL_NAMES: readonly ["tinycloud_status", "tinycloud_auth_status", "tinycloud_auth_capabilities", "tinycloud_auth_request", "tinycloud_auth_import", "tinycloud_account_spaces_list", "tinycloud_account_applications_list", "tinycloud_kv_list", "tinycloud_kv_get", "tinycloud_kv_head", "tinycloud_kv_put", "tinycloud_kv_delete", "tinycloud_sql_schema_inspect", "tinycloud_sql_query", "tinycloud_sql_execute", "tinycloud_secrets_get", "tinycloud_secrets_status"];
4
+ declare const TOOL_NAMES: readonly ["tinycloud_status", "tinycloud_auth_status", "tinycloud_auth_capabilities", "tinycloud_auth_request", "tinycloud_auth_import", "tinycloud_account_spaces_list", "tinycloud_account_applications_list", "tinycloud_kv_list", "tinycloud_kv_get", "tinycloud_kv_head", "tinycloud_kv_put", "tinycloud_kv_delete", "tinycloud_sql_schema_inspect", "tinycloud_sql_query", "tinycloud_sql_execute", "tinycloud_secrets_get", "tinycloud_secrets_status", "tinycloud_apps_context", "tinycloud_apps_read", "tinycloud_apps_write"];
5
5
  type ToolName = (typeof TOOL_NAMES)[number];
6
6
  /** MCP server surfaces: local stdio and the hosted OAuth HTTP server. */
7
7
  type McpSurface = "local" | "hosted";
package/dist/tools.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { McpServer } from '@modelcontextprotocol/server';
2
2
  import { AjvJsonSchemaValidator } from '@modelcontextprotocol/server/validators/ajv';
3
3
 
4
- declare const TOOL_NAMES: readonly ["tinycloud_status", "tinycloud_auth_status", "tinycloud_auth_capabilities", "tinycloud_auth_request", "tinycloud_auth_import", "tinycloud_account_spaces_list", "tinycloud_account_applications_list", "tinycloud_kv_list", "tinycloud_kv_get", "tinycloud_kv_head", "tinycloud_kv_put", "tinycloud_kv_delete", "tinycloud_sql_schema_inspect", "tinycloud_sql_query", "tinycloud_sql_execute", "tinycloud_secrets_get", "tinycloud_secrets_status"];
4
+ declare const TOOL_NAMES: readonly ["tinycloud_status", "tinycloud_auth_status", "tinycloud_auth_capabilities", "tinycloud_auth_request", "tinycloud_auth_import", "tinycloud_account_spaces_list", "tinycloud_account_applications_list", "tinycloud_kv_list", "tinycloud_kv_get", "tinycloud_kv_head", "tinycloud_kv_put", "tinycloud_kv_delete", "tinycloud_sql_schema_inspect", "tinycloud_sql_query", "tinycloud_sql_execute", "tinycloud_secrets_get", "tinycloud_secrets_status", "tinycloud_apps_context", "tinycloud_apps_read", "tinycloud_apps_write"];
5
5
  type ToolName = (typeof TOOL_NAMES)[number];
6
6
  /** MCP server surfaces: local stdio and the hosted OAuth HTTP server. */
7
7
  type McpSurface = "local" | "hosted";
package/dist/tools.js CHANGED
@@ -6,15 +6,37 @@ import { addFormats, Ajv, AjvJsonSchemaValidator } from "@modelcontextprotocol/s
6
6
  import { invokeOperation } from "@tinycloud/operations";
7
7
 
8
8
  // src/results.ts
9
- function toMcpToolResult(result, bindings = []) {
10
- const canonical = isCanonicalOperationResult(result) ? withRecoveryTool(result, bindings) : {
9
+ function toMcpToolResult(result, bindings = [], options = {}) {
10
+ let canonical = isCanonicalOperationResult(result) ? withRecoveryTool(result, bindings) : {
11
11
  status: "error",
12
12
  operation: {},
13
13
  context: {},
14
14
  error: { code: "INTERNAL_ERROR" }
15
15
  };
16
+ let serialized;
17
+ if (options.surface === "hosted") {
18
+ serialized = JSON.stringify(canonical);
19
+ if (options.readOnly === true && serialized.length > 1e5) {
20
+ const sql = options.operationId?.startsWith("tinycloud.sql.") || options.operationId === "tinycloud.apps.query";
21
+ canonical = {
22
+ status: "error",
23
+ operation: canonical.operation,
24
+ context: canonical.context,
25
+ error: {
26
+ code: sql ? "SQL_RESULT_LIMIT_EXCEEDED" : "KV_RESPONSE_TOO_LARGE",
27
+ message: sql ? "The result exceeds 100,000 characters. Select fewer columns or rows, add a WHERE filter or a smaller LIMIT, or aggregate the data." : "The result exceeds 100,000 characters. Request fewer keys, narrow the prefix, or use a smaller page size.",
28
+ retryable: false
29
+ }
30
+ };
31
+ serialized = JSON.stringify(canonical);
32
+ }
33
+ }
16
34
  return {
17
- content: [{ type: "text", text: resultSummary(canonical.status) }],
35
+ content: [{
36
+ type: "text",
37
+ text: resultSummary(canonical.status) + (serialized !== void 0 && !(options.operationId === "tinycloud.secrets.get" && canonical.status === "ok") ? `
38
+ ${serialized}` : "")
39
+ }],
18
40
  structuredContent: canonical
19
41
  };
20
42
  }
@@ -48,6 +70,17 @@ function resultSummary(status) {
48
70
  }
49
71
  }
50
72
 
73
+ // src/logging.ts
74
+ function logToolCall(tool, code, startedAt, replayedGrants) {
75
+ process.stderr.write(`${JSON.stringify({
76
+ tool,
77
+ code,
78
+ durationMs: Math.max(0, Math.round(performance.now() - startedAt)),
79
+ replayedGrants
80
+ })}
81
+ `);
82
+ }
83
+
51
84
  // src/tools.ts
52
85
  var TOOL_NAMES = [
53
86
  "tinycloud_status",
@@ -66,7 +99,10 @@ var TOOL_NAMES = [
66
99
  "tinycloud_sql_query",
67
100
  "tinycloud_sql_execute",
68
101
  "tinycloud_secrets_get",
69
- "tinycloud_secrets_status"
102
+ "tinycloud_secrets_status",
103
+ "tinycloud_apps_context",
104
+ "tinycloud_apps_read",
105
+ "tinycloud_apps_write"
70
106
  ];
71
107
  function invocationTargetForMcp(selection) {
72
108
  return {
@@ -81,6 +117,9 @@ var packageRequire = createRequire(
81
117
  var generatedCatalog = packageRequire(
82
118
  "@tinycloud/operations/operations.json"
83
119
  );
120
+ var stableErrorCodes = Object.fromEntries(
121
+ generatedCatalog.stableErrors.map((code) => [code, true])
122
+ );
84
123
  var ALL_SURFACES = ["local", "hosted"];
85
124
  function bindingSurfaces(binding) {
86
125
  return binding.surfaces ?? ALL_SURFACES;
@@ -244,6 +283,36 @@ var TOOL_BINDINGS = [
244
283
  // Hosted has no persistent reauthorization path for a revoked session
245
284
  // yet (TC-896), so status is local/stdio only.
246
285
  surfaces: ["local"]
286
+ },
287
+ {
288
+ name: "tinycloud_apps_context",
289
+ operationId: "tinycloud.apps.context",
290
+ operationVersion: 1,
291
+ readOnlyHint: true,
292
+ idempotentHint: true,
293
+ destructiveHint: false,
294
+ openWorldHint: true,
295
+ surfaces: ["hosted"]
296
+ },
297
+ {
298
+ name: "tinycloud_apps_read",
299
+ operationId: "tinycloud.apps.read",
300
+ operationVersion: 1,
301
+ readOnlyHint: true,
302
+ idempotentHint: true,
303
+ destructiveHint: false,
304
+ openWorldHint: true,
305
+ surfaces: ["hosted"]
306
+ },
307
+ {
308
+ name: "tinycloud_apps_write",
309
+ operationId: "tinycloud.apps.write",
310
+ operationVersion: 1,
311
+ readOnlyHint: false,
312
+ idempotentHint: false,
313
+ destructiveHint: true,
314
+ openWorldHint: true,
315
+ surfaces: ["hosted"]
247
316
  }
248
317
  ];
249
318
  function createJsonSchemaValidator() {
@@ -288,18 +357,45 @@ function registerTinyCloudTools(server, selection, validator) {
288
357
  annotations
289
358
  },
290
359
  async (input) => {
291
- const result = await invokeOperation(
292
- binding.operationId,
293
- binding.operationVersion,
294
- invocationTargetForMcp(selection),
295
- input
296
- );
297
- const projected = selection.transformOperationResult === void 0 ? result : await selection.transformOperationResult(result);
298
- return toMcpToolResult(projected, TOOL_BINDINGS);
360
+ const startedAt = performance.now();
361
+ const metrics = { replayedGrants: 0 };
362
+ let code = "INTERNAL_ERROR";
363
+ try {
364
+ const result = await invokeOperation(
365
+ binding.operationId,
366
+ binding.operationVersion,
367
+ invocationTargetForMcp(selection),
368
+ input,
369
+ metrics
370
+ );
371
+ const projected = selection.transformOperationResult === void 0 ? result : await selection.transformOperationResult(result);
372
+ const response = toMcpToolResult(projected, TOOL_BINDINGS, {
373
+ surface: selection.surface,
374
+ readOnly: binding.readOnlyHint,
375
+ operationId: binding.operationId
376
+ });
377
+ code = outcomeCode(response.structuredContent);
378
+ return response;
379
+ } finally {
380
+ if (selection.surface === "hosted") {
381
+ logToolCall(binding.name, code, startedAt, metrics.replayedGrants);
382
+ }
383
+ }
299
384
  }
300
385
  );
301
386
  }
302
387
  }
388
+ function outcomeCode(result) {
389
+ if (result.status === "error") {
390
+ const error = result.error;
391
+ return typeof error?.code === "string" && Object.hasOwn(stableErrorCodes, error.code) ? error.code : "INTERNAL_ERROR";
392
+ }
393
+ if (result.status !== "ok") return result.status;
394
+ const output = result.output;
395
+ if (output?.outcome === "COPY_PARTIAL") return "COPY_PARTIAL";
396
+ if (Array.isArray(output?.ops) && output.ops.some((op) => op.outcome !== "ok")) return "PARTIAL";
397
+ return "ok";
398
+ }
303
399
  function toolBindingsForTest() {
304
400
  return TOOL_BINDINGS;
305
401
  }