@capixjs/transport-mcp 0.1.0-alpha.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Capix Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,8 @@
1
+ /**
2
+ * index.ts — public API for capix-transport-mcp
3
+ */
4
+ export { mcpTransport } from './transport.js';
5
+ export type { McpTransportOptions } from './transport.js';
6
+ export { buildMcpServer, buildTools, toToolName } from './server-builder.js';
7
+ export type { McpServerOptions } from './server-builder.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC7E,YAAY,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ /**
2
+ * index.ts — public API for capix-transport-mcp
3
+ */
4
+ export { mcpTransport } from './transport.js';
5
+ export { buildMcpServer, buildTools, toToolName } from './server-builder.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * server-builder.ts — converts a Capix registry into an MCP server.
3
+ *
4
+ * Every capability becomes an MCP tool:
5
+ * - Dot-path names become underscore-separated tool names (users.getUser → users_getUser)
6
+ * - Zod input schema → tool inputSchema (JSON Schema, input side)
7
+ * - Zod object output schema → tool outputSchema + structuredContent
8
+ * - intent → tool annotations (query → readOnlyHint, delete → destructiveHint)
9
+ *
10
+ * Requests run through the execution engine's invoke() — guards, input
11
+ * validation, and typed errors behave exactly as on every other transport.
12
+ */
13
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
14
+ import type { Tool } from '@modelcontextprotocol/sdk/types.js';
15
+ import type { CapabilityRegistry, InvokeFn } from '@capixjs/core';
16
+ export type McpServerOptions = {
17
+ /** Server name reported during the MCP handshake. Default: 'capix'. */
18
+ readonly name?: string;
19
+ /** Server version reported during the MCP handshake. Default: '0.0.0'. */
20
+ readonly version?: string;
21
+ /** Per-call timeout in milliseconds. Default: 30 000. */
22
+ readonly timeoutMs?: number;
23
+ };
24
+ /** users.getUser → users_getUser (MCP tool names allow [a-zA-Z0-9_-] only). */
25
+ export declare function toToolName(dotPath: string): string;
26
+ /** Builds the tools/list payload from a compiled registry. */
27
+ export declare function buildTools(registry: CapabilityRegistry): {
28
+ tools: Tool[];
29
+ byName: Map<string, string>;
30
+ };
31
+ /**
32
+ * Builds an MCP Server serving every capability in the registry as a tool.
33
+ * One Server instance per MCP connection — call this once per stdio session
34
+ * or per stateless HTTP request.
35
+ */
36
+ export declare function buildMcpServer(registry: CapabilityRegistry, invoke: InvokeFn, options?: McpServerOptions): Server;
37
+ //# sourceMappingURL=server-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-builder.d.ts","sourceRoot":"","sources":["../src/server-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAKnE,OAAO,KAAK,EAAkB,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAG/E,OAAO,KAAK,EAAE,kBAAkB,EAAE,QAAQ,EAAmB,MAAM,eAAe,CAAC;AAEnF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,uEAAuE;IACvE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,0EAA0E;IAC1E,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,yDAAyD;IACzD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B,CAAC;AAIF,+EAA+E;AAC/E,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAElD;AAiBD,8DAA8D;AAC9D,wBAAgB,UAAU,CAAC,QAAQ,EAAE,kBAAkB,GAAG;IAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CA2CvG;AAcD;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,kBAAkB,EAC5B,MAAM,EAAE,QAAQ,EAChB,OAAO,GAAE,gBAAqB,GAC7B,MAAM,CAgDR"}
@@ -0,0 +1,126 @@
1
+ /**
2
+ * server-builder.ts — converts a Capix registry into an MCP server.
3
+ *
4
+ * Every capability becomes an MCP tool:
5
+ * - Dot-path names become underscore-separated tool names (users.getUser → users_getUser)
6
+ * - Zod input schema → tool inputSchema (JSON Schema, input side)
7
+ * - Zod object output schema → tool outputSchema + structuredContent
8
+ * - intent → tool annotations (query → readOnlyHint, delete → destructiveHint)
9
+ *
10
+ * Requests run through the execution engine's invoke() — guards, input
11
+ * validation, and typed errors behave exactly as on every other transport.
12
+ */
13
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
14
+ import { ListToolsRequestSchema, CallToolRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
15
+ import { z } from 'zod';
16
+ import { inferIntent } from '@capixjs/core';
17
+ const EMPTY_INPUT_SCHEMA = { type: 'object', properties: {} };
18
+ /** users.getUser → users_getUser (MCP tool names allow [a-zA-Z0-9_-] only). */
19
+ export function toToolName(dotPath) {
20
+ return dotPath.replaceAll('.', '_');
21
+ }
22
+ /** Converts a Zod schema to JSON Schema; null when conversion fails. */
23
+ function toJsonSchema(schema, io) {
24
+ try {
25
+ const js = z.toJSONSchema(schema, {
26
+ io,
27
+ reused: 'inline',
28
+ unrepresentable: 'any',
29
+ });
30
+ delete js['$schema'];
31
+ return js;
32
+ }
33
+ catch {
34
+ return null;
35
+ }
36
+ }
37
+ /** Builds the tools/list payload from a compiled registry. */
38
+ export function buildTools(registry) {
39
+ const tools = [];
40
+ const byName = new Map();
41
+ for (const [dotPath, cap] of registry) {
42
+ const name = toToolName(dotPath);
43
+ byName.set(name, dotPath);
44
+ // Same rule as the REST router: explicit intent wins, otherwise infer
45
+ // from the capability's key name (getUser → query, deleteUser → delete).
46
+ const key = dotPath.split('.').pop() ?? dotPath;
47
+ const intent = cap._intentExplicit ? cap.intent : inferIntent(key);
48
+ const inputJs = cap.inputSchema !== null ? toJsonSchema(cap.inputSchema, 'input') : null;
49
+ // MCP requires inputSchema to be an object schema. Non-object inputs
50
+ // (z.record works; z.string() does not decompose) fall back to a
51
+ // permissive object — the engine still validates the real schema.
52
+ const inputSchema = inputJs !== null && inputJs['type'] === 'object'
53
+ ? inputJs
54
+ : EMPTY_INPUT_SCHEMA;
55
+ const outputJs = cap.outputSchema !== null ? toJsonSchema(cap.outputSchema, 'output') : null;
56
+ const outputSchema = outputJs !== null && outputJs['type'] === 'object'
57
+ ? outputJs
58
+ : undefined;
59
+ tools.push({
60
+ name,
61
+ description: `Capix capability '${dotPath}' (intent: ${intent})`,
62
+ inputSchema,
63
+ ...(outputSchema !== undefined ? { outputSchema } : {}),
64
+ annotations: {
65
+ title: dotPath,
66
+ readOnlyHint: intent === 'query',
67
+ destructiveHint: intent === 'delete',
68
+ idempotentHint: intent === 'query' || intent === 'replace' || intent === 'delete',
69
+ },
70
+ });
71
+ }
72
+ return { tools, byName };
73
+ }
74
+ function errorResult(error) {
75
+ const issues = Array.isArray(error.meta?.['issues']) ? error.meta['issues'] : null;
76
+ const text = `${error.error}: ${error.message}` +
77
+ (issues !== null ? `\n${issues.map((i) => `- ${String(i)}`).join('\n')}` : '');
78
+ return { content: [{ type: 'text', text }], isError: true };
79
+ }
80
+ function isPlainObject(v) {
81
+ return typeof v === 'object' && v !== null && !Array.isArray(v);
82
+ }
83
+ /**
84
+ * Builds an MCP Server serving every capability in the registry as a tool.
85
+ * One Server instance per MCP connection — call this once per stdio session
86
+ * or per stateless HTTP request.
87
+ */
88
+ export function buildMcpServer(registry, invoke, options = {}) {
89
+ const { tools, byName } = buildTools(registry);
90
+ const timeoutMs = options.timeoutMs ?? 30_000;
91
+ const server = new Server({ name: options.name ?? 'capix', version: options.version ?? '0.0.0' }, { capabilities: { tools: {} } });
92
+ server.setRequestHandler(ListToolsRequestSchema, () => ({ tools }));
93
+ server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
94
+ const dotPath = byName.get(request.params.name);
95
+ if (dotPath === undefined) {
96
+ return {
97
+ content: [{ type: 'text', text: `NotFound: unknown tool '${request.params.name}'` }],
98
+ isError: true,
99
+ };
100
+ }
101
+ // Headers reach context builders on HTTP connections; stdio has none.
102
+ const rawHeaders = extra.requestInfo?.headers ?? {};
103
+ const headers = {};
104
+ for (const [key, val] of Object.entries(rawHeaders)) {
105
+ if (val !== undefined)
106
+ headers[key] = Array.isArray(val) ? val.join(', ') : val;
107
+ }
108
+ const signal = typeof AbortSignal.any === 'function'
109
+ ? AbortSignal.any([extra.signal, AbortSignal.timeout(timeoutMs)])
110
+ : AbortSignal.timeout(timeoutMs);
111
+ const response = await invoke({
112
+ capability: dotPath,
113
+ input: request.params.arguments ?? {},
114
+ headers,
115
+ signal,
116
+ });
117
+ if (!response.ok)
118
+ return errorResult(response.error);
119
+ return {
120
+ content: [{ type: 'text', text: JSON.stringify(response.data) }],
121
+ ...(isPlainObject(response.data) ? { structuredContent: response.data } : {}),
122
+ };
123
+ });
124
+ return server;
125
+ }
126
+ //# sourceMappingURL=server-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-builder.js","sourceRoot":"","sources":["../src/server-builder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * transport.ts — MCP transport for Capix.
3
+ *
4
+ * Two modes:
5
+ * - stdio: the process becomes an MCP server over stdin/stdout. For local
6
+ * use with MCP clients (Claude Code, editors). Diagnostics go to stderr —
7
+ * stdout belongs to the protocol.
8
+ * - http: serves the MCP Streamable HTTP transport (stateless) on a port,
9
+ * mountable alongside the other Capix transports. Request headers are
10
+ * forwarded to the context builder like on the REST transport.
11
+ *
12
+ * Mode is inferred: pass `port` for http, omit it for stdio.
13
+ */
14
+ import type { GroupTree, TransportWithCapabilities } from '@capixjs/core';
15
+ import type { McpServerOptions } from './server-builder.js';
16
+ export type McpTransportOptions = McpServerOptions & {
17
+ /** Listen port. When set, serves Streamable HTTP; when omitted, serves stdio. */
18
+ readonly port?: number;
19
+ readonly host?: string;
20
+ /** URL path for the MCP endpoint in http mode. Default: '/mcp'. */
21
+ readonly path?: string;
22
+ /** Capability registry for this transport only. Overrides the server-level default. */
23
+ readonly capabilities?: GroupTree;
24
+ };
25
+ export declare function mcpTransport(options?: McpTransportOptions): TransportWithCapabilities;
26
+ //# sourceMappingURL=transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH,OAAO,KAAK,EAAqC,SAAS,EAAE,yBAAyB,EAAE,MAAM,eAAe,CAAC;AAE7G,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAS5D,MAAM,MAAM,mBAAmB,GAAG,gBAAgB,GAAG;IACnD,iFAAiF;IACjF,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,mEAAmE;IACnE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,uFAAuF;IACvF,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,CAAC;CACnC,CAAC;AAEF,wBAAgB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,yBAAyB,CAmFzF"}
@@ -0,0 +1,95 @@
1
+ /**
2
+ * transport.ts — MCP transport for Capix.
3
+ *
4
+ * Two modes:
5
+ * - stdio: the process becomes an MCP server over stdin/stdout. For local
6
+ * use with MCP clients (Claude Code, editors). Diagnostics go to stderr —
7
+ * stdout belongs to the protocol.
8
+ * - http: serves the MCP Streamable HTTP transport (stateless) on a port,
9
+ * mountable alongside the other Capix transports. Request headers are
10
+ * forwarded to the context builder like on the REST transport.
11
+ *
12
+ * Mode is inferred: pass `port` for http, omit it for stdio.
13
+ */
14
+ import * as http from 'node:http';
15
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
16
+ import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
17
+ import { buildMcpServer } from './server-builder.js';
18
+ export function mcpTransport(options = {}) {
19
+ const isHttp = options.port !== undefined;
20
+ const mcpPath = options.path ?? '/mcp';
21
+ let httpServer = null;
22
+ let stdioServer = null;
23
+ const serverOptions = {
24
+ ...(options.name !== undefined ? { name: options.name } : {}),
25
+ ...(options.version !== undefined ? { version: options.version } : {}),
26
+ ...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),
27
+ };
28
+ return {
29
+ ...(options.capabilities !== undefined ? { _capabilities: options.capabilities } : {}),
30
+ async mount(invoke, mountOptions) {
31
+ if (!isHttp) {
32
+ // stdio — single long-lived server bound to this process's stdin/stdout
33
+ stdioServer = buildMcpServer(mountOptions.registry, invoke, serverOptions);
34
+ const transport = new StdioServerTransport();
35
+ await stdioServer.connect(transport);
36
+ console.error('[capix:mcp] serving MCP over stdio');
37
+ return;
38
+ }
39
+ // http — stateless Streamable HTTP: a fresh Server + transport pair per
40
+ // request, so concurrent clients never share JSON-RPC id space.
41
+ const handler = (req, res) => {
42
+ const pathname = (req.url ?? '/').split('?')[0] ?? '';
43
+ if (pathname !== mcpPath && pathname !== `${mcpPath}/`) {
44
+ res.writeHead(404, { 'Content-Type': 'application/json' });
45
+ res.end('{"error":"NotFound","message":"MCP endpoint is ' + mcpPath + '"}');
46
+ return;
47
+ }
48
+ const server = buildMcpServer(mountOptions.registry, invoke, serverOptions);
49
+ // No sessionIdGenerator — stateless mode, one transport per request.
50
+ const transport = new StreamableHTTPServerTransport({
51
+ enableJsonResponse: true,
52
+ });
53
+ res.on('close', () => {
54
+ void transport.close();
55
+ void server.close();
56
+ });
57
+ server
58
+ .connect(transport)
59
+ .then(() => transport.handleRequest(req, res))
60
+ .catch((err) => {
61
+ console.error('[capix:mcp] Handler error:', err);
62
+ if (!res.headersSent) {
63
+ res.writeHead(500, { 'Content-Type': 'application/json' });
64
+ res.end('{"error":"Internal","message":"Internal server error"}');
65
+ }
66
+ });
67
+ };
68
+ console.log('\nCapix MCP transport starting...');
69
+ console.log(` ✓ MCP (Streamable HTTP) http://localhost:${options.port}${mcpPath}`);
70
+ return new Promise((resolve, reject) => {
71
+ httpServer = http.createServer(handler);
72
+ httpServer.on('error', reject);
73
+ httpServer.listen(options.port, options.host ?? '0.0.0.0', () => resolve());
74
+ });
75
+ },
76
+ async unmount() {
77
+ if (stdioServer !== null) {
78
+ await stdioServer.close();
79
+ stdioServer = null;
80
+ }
81
+ return new Promise((resolve, reject) => {
82
+ if (!httpServer)
83
+ return resolve();
84
+ httpServer.close((err) => {
85
+ if (err)
86
+ reject(err);
87
+ else
88
+ resolve();
89
+ });
90
+ httpServer = null;
91
+ });
92
+ },
93
+ };
94
+ }
95
+ //# sourceMappingURL=transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@capixjs/transport-mcp",
3
+ "version": "0.1.0-alpha.15",
4
+ "description": "Capix MCP transport — expose capabilities as Model Context Protocol tools",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "!dist/**/*.test.*",
18
+ "LICENSE"
19
+ ],
20
+ "keywords": [
21
+ "capix",
22
+ "mcp",
23
+ "model-context-protocol",
24
+ "transport",
25
+ "typescript"
26
+ ],
27
+ "engines": {
28
+ "node": ">=20"
29
+ },
30
+ "dependencies": {
31
+ "@modelcontextprotocol/sdk": "^1.29.0",
32
+ "zod": "^4.0.0"
33
+ },
34
+ "peerDependencies": {
35
+ "@capixjs/core": ">=0.1.0-0"
36
+ },
37
+ "devDependencies": {
38
+ "@types/node": "^20.0.0",
39
+ "typescript": "^5.5.0",
40
+ "vitest": "^1.6.0",
41
+ "@capixjs/core": "0.1.0-alpha.15"
42
+ },
43
+ "scripts": {
44
+ "build": "tsc",
45
+ "test": "vitest run",
46
+ "typecheck": "tsc --noEmit"
47
+ }
48
+ }