trpc-to-mcp 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/publish.yml +1 -1
- package/.prettierrc +12 -0
- package/CHANGELOG.md +6 -0
- package/package.json +52 -5
- package/src/adapters/vercel-mcp-adapter.ts +53 -0
- package/src/server.ts +32 -22
- package/src/tools.ts +2 -2
- package/tsup.config.ts +12 -0
- package/dist/index.d.mts +0 -17
- package/dist/index.d.ts +0 -17
- package/dist/index.js +0 -113
- package/dist/index.mjs +0 -87
- package/src/adapters/better-auth.ts +0 -0
package/.prettierrc
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"importOrder": [
|
|
3
|
+
"<BUILTIN_MODULES>",
|
|
4
|
+
"<THIRD_PARTY_MODULES>",
|
|
5
|
+
"",
|
|
6
|
+
"^[../]",
|
|
7
|
+
"^[./]"
|
|
8
|
+
],
|
|
9
|
+
"importOrderParserPlugins": ["typescript", "jsx", "decorators-legacy"],
|
|
10
|
+
"importOrderCaseSensitive": true,
|
|
11
|
+
"plugins": ["@ianvs/prettier-plugin-sort-imports"]
|
|
12
|
+
}
|
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -1,25 +1,72 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "trpc-to-mcp",
|
|
3
3
|
"license": "MIT",
|
|
4
|
-
"version": "1.
|
|
5
|
-
"main": "dist/index.js",
|
|
6
|
-
"module": "dist/index.mjs",
|
|
7
|
-
"types": "dist/index.d.ts",
|
|
4
|
+
"version": "1.1.0",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.mjs"
|
|
13
|
+
},
|
|
14
|
+
"require": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"default": "./dist/index.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"./server": {
|
|
20
|
+
"import": {
|
|
21
|
+
"types": "./dist/server.d.ts",
|
|
22
|
+
"default": "./dist/server.mjs"
|
|
23
|
+
},
|
|
24
|
+
"require": {
|
|
25
|
+
"types": "./dist/server.d.ts",
|
|
26
|
+
"default": "./dist/server.js"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"./tools": {
|
|
30
|
+
"import": {
|
|
31
|
+
"types": "./dist/tools.d.ts",
|
|
32
|
+
"default": "./dist/tools.mjs"
|
|
33
|
+
},
|
|
34
|
+
"require": {
|
|
35
|
+
"types": "./dist/tools.d.ts",
|
|
36
|
+
"default": "./dist/tools.js"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"./adapter/vercel-mcp-adapter": {
|
|
40
|
+
"import": {
|
|
41
|
+
"types": "./dist/adapter/vercel-mcp-adapter.d.ts",
|
|
42
|
+
"default": "./dist/adapter/vercel-mcp-adapter.mjs"
|
|
43
|
+
},
|
|
44
|
+
"require": {
|
|
45
|
+
"types": "./dist/adapter/vercel-mcp-adapter.d.ts",
|
|
46
|
+
"default": "./dist/adapter/vercel-mcp-adapter.js"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
},
|
|
8
50
|
"devDependencies": {
|
|
9
51
|
"@changesets/cli": "^2.29.5",
|
|
52
|
+
"@ianvs/prettier-plugin-sort-imports": "^4.6.0",
|
|
53
|
+
"prettier": "^3.6.2",
|
|
10
54
|
"tsup": "^8.5.0",
|
|
11
55
|
"typescript": "^5.9.2"
|
|
12
56
|
},
|
|
13
57
|
"peerDependencies": {
|
|
14
58
|
"@trpc/server": "^11.4.4",
|
|
59
|
+
"better-auth": "^1.3.4",
|
|
60
|
+
"mcp-handler": "^1.0.1",
|
|
15
61
|
"zod": "^4.0.15"
|
|
16
62
|
},
|
|
17
63
|
"dependencies": {
|
|
18
64
|
"@modelcontextprotocol/sdk": "^1.17.2"
|
|
19
65
|
},
|
|
20
66
|
"scripts": {
|
|
21
|
-
"build": "tsup
|
|
67
|
+
"build": "tsup --config tsup.config.ts",
|
|
22
68
|
"release": "pnpm run build && changeset publish",
|
|
69
|
+
"format": "prettier --write \"**/*.{ts,tsx,css,md}\"",
|
|
23
70
|
"lint": "tsc"
|
|
24
71
|
}
|
|
25
72
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
+
import type {
|
|
3
|
+
AnyRootTypes,
|
|
4
|
+
MaybePromise,
|
|
5
|
+
Router,
|
|
6
|
+
RouterRecord,
|
|
7
|
+
} from "@trpc/server/unstable-core-do-not-import";
|
|
8
|
+
import { createMcpHandler } from "mcp-handler";
|
|
9
|
+
|
|
10
|
+
import { setRequestHandler } from "../server";
|
|
11
|
+
import { extractToolsFromProcedures } from "../tools";
|
|
12
|
+
|
|
13
|
+
export type VercelMcpHandler = ReturnType<typeof createMcpHandler>;
|
|
14
|
+
export type McpServerOptions = Parameters<typeof createMcpHandler>[1];
|
|
15
|
+
export type McpHandlerConfig = Parameters<typeof createMcpHandler>[2];
|
|
16
|
+
|
|
17
|
+
export function trpcToMcpHandler<
|
|
18
|
+
TRoot extends AnyRootTypes,
|
|
19
|
+
TRecord extends RouterRecord,
|
|
20
|
+
>(
|
|
21
|
+
appRouter: Router<TRoot, TRecord>,
|
|
22
|
+
ctx: TRoot["ctx"] | (() => MaybePromise<TRoot["ctx"]>),
|
|
23
|
+
handlerOptions: {
|
|
24
|
+
config: McpHandlerConfig;
|
|
25
|
+
serverOptions?: McpServerOptions;
|
|
26
|
+
callback?: (server: Server) => unknown;
|
|
27
|
+
},
|
|
28
|
+
) {
|
|
29
|
+
const { serverOptions, config, callback } = handlerOptions;
|
|
30
|
+
|
|
31
|
+
const tools = extractToolsFromProcedures(appRouter);
|
|
32
|
+
const trpcCaller = appRouter.createCaller(ctx);
|
|
33
|
+
|
|
34
|
+
const handler = createMcpHandler(
|
|
35
|
+
(server) => {
|
|
36
|
+
setRequestHandler(server.server, tools, trpcCaller);
|
|
37
|
+
|
|
38
|
+
if (typeof callback === "function") {
|
|
39
|
+
callback(server.server);
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
// Leave it empty because we list tools manually
|
|
44
|
+
capabilities: {
|
|
45
|
+
tools: {},
|
|
46
|
+
},
|
|
47
|
+
...serverOptions,
|
|
48
|
+
},
|
|
49
|
+
config,
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
return handler;
|
|
53
|
+
}
|
package/src/server.ts
CHANGED
|
@@ -1,38 +1,25 @@
|
|
|
1
1
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
2
|
import {
|
|
3
3
|
CallToolRequestSchema,
|
|
4
|
-
type Implementation,
|
|
5
4
|
ListToolsRequestSchema,
|
|
5
|
+
type Implementation,
|
|
6
6
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
7
7
|
import type {
|
|
8
8
|
AnyProcedure,
|
|
9
9
|
AnyRootTypes,
|
|
10
|
+
DecorateRouterRecord,
|
|
11
|
+
MaybePromise,
|
|
10
12
|
Router,
|
|
11
13
|
RouterRecord,
|
|
12
14
|
} from "@trpc/server/unstable-core-do-not-import";
|
|
13
15
|
|
|
14
|
-
import { extractToolsFromProcedures } from "./tools";
|
|
15
|
-
|
|
16
|
-
type MaybePromise<T> = Promise<T> | T;
|
|
16
|
+
import { extractToolsFromProcedures, type McpTool } from "./tools";
|
|
17
17
|
|
|
18
|
-
export function
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
implementation: Implementation,
|
|
23
|
-
appRouter: Router<TRoot, TRecord>,
|
|
24
|
-
ctx: TRoot["ctx"] | (() => MaybePromise<TRoot["ctx"]>)
|
|
18
|
+
export function setRequestHandler<TRecord extends RouterRecord>(
|
|
19
|
+
server: Server,
|
|
20
|
+
tools: McpTool[],
|
|
21
|
+
trpcCaller: DecorateRouterRecord<TRecord>,
|
|
25
22
|
) {
|
|
26
|
-
const tools = extractToolsFromProcedures(appRouter);
|
|
27
|
-
const trpcCaller = appRouter.createCaller(ctx);
|
|
28
|
-
|
|
29
|
-
const server = new Server(implementation, {
|
|
30
|
-
capabilities: {
|
|
31
|
-
// Leave it empty because we list tools manually
|
|
32
|
-
tools: {},
|
|
33
|
-
},
|
|
34
|
-
});
|
|
35
|
-
|
|
36
23
|
// List all of the available tools
|
|
37
24
|
server.setRequestHandler(ListToolsRequestSchema, () => ({ tools }));
|
|
38
25
|
|
|
@@ -50,7 +37,7 @@ export function createMcpServer<
|
|
|
50
37
|
const procedure: AnyProcedure = tool.pathInRouter.reduce(
|
|
51
38
|
// @ts-expect-error path in router
|
|
52
39
|
(acc, part) => acc?.[part],
|
|
53
|
-
trpcCaller
|
|
40
|
+
trpcCaller,
|
|
54
41
|
);
|
|
55
42
|
|
|
56
43
|
// @ts-expect-error path in router
|
|
@@ -61,3 +48,26 @@ export function createMcpServer<
|
|
|
61
48
|
};
|
|
62
49
|
});
|
|
63
50
|
}
|
|
51
|
+
|
|
52
|
+
export function createMcpServer<
|
|
53
|
+
TRoot extends AnyRootTypes,
|
|
54
|
+
TRecord extends RouterRecord,
|
|
55
|
+
>(
|
|
56
|
+
implementation: Implementation,
|
|
57
|
+
appRouter: Router<TRoot, TRecord>,
|
|
58
|
+
ctx: TRoot["ctx"] | (() => MaybePromise<TRoot["ctx"]>),
|
|
59
|
+
) {
|
|
60
|
+
const tools = extractToolsFromProcedures(appRouter);
|
|
61
|
+
const trpcCaller = appRouter.createCaller(ctx);
|
|
62
|
+
|
|
63
|
+
const server = new Server(implementation, {
|
|
64
|
+
capabilities: {
|
|
65
|
+
// Leave it empty because we list tools manually
|
|
66
|
+
tools: {},
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
setRequestHandler(server, tools, trpcCaller);
|
|
71
|
+
|
|
72
|
+
return server;
|
|
73
|
+
}
|
package/src/tools.ts
CHANGED
|
@@ -24,7 +24,7 @@ export function mergeInputs(inputs: z.ZodObject[]) {
|
|
|
24
24
|
|
|
25
25
|
export function extractToolsFromProcedures<
|
|
26
26
|
TRoot extends AnyRootTypes,
|
|
27
|
-
TRecord extends RouterRecord
|
|
27
|
+
TRecord extends RouterRecord,
|
|
28
28
|
>(appRouter: Router<TRoot, TRecord>, currentPath: string[] = []) {
|
|
29
29
|
const tools: McpTool[] = [];
|
|
30
30
|
const procedures = Object.entries(appRouter._def.procedures);
|
|
@@ -57,7 +57,7 @@ export function extractToolsFromProcedures<
|
|
|
57
57
|
} else {
|
|
58
58
|
console.error(
|
|
59
59
|
"[TRPC-TO-MCP] Procedure has no object schema",
|
|
60
|
-
pathInRouter
|
|
60
|
+
pathInRouter,
|
|
61
61
|
);
|
|
62
62
|
}
|
|
63
63
|
} else {
|
package/tsup.config.ts
ADDED
package/dist/index.d.mts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { Implementation } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
-
import { AnyRootTypes, RouterRecord, Router } from '@trpc/server/unstable-core-do-not-import';
|
|
3
|
-
import { z } from 'zod/v4';
|
|
4
|
-
|
|
5
|
-
type MaybePromise<T> = Promise<T> | T;
|
|
6
|
-
declare function createMcpServer<TRoot extends AnyRootTypes, TRecord extends RouterRecord>(implementation: Implementation, appRouter: Router<TRoot, TRecord>, ctx: TRoot["ctx"] | (() => MaybePromise<TRoot["ctx"]>)): void;
|
|
7
|
-
|
|
8
|
-
type McpTool = {
|
|
9
|
-
name: string;
|
|
10
|
-
description: string;
|
|
11
|
-
pathInRouter: string[];
|
|
12
|
-
inputSchema?: z.core.JSONSchema.JSONSchema;
|
|
13
|
-
};
|
|
14
|
-
declare function mergeInputs(inputs: z.ZodObject[]): z.ZodObject<z.core.$ZodLooseShape, z.core.$strip>;
|
|
15
|
-
declare function extractToolsFromProcedures<TRoot extends AnyRootTypes, TRecord extends RouterRecord>(appRouter: Router<TRoot, TRecord>, currentPath?: string[]): McpTool[];
|
|
16
|
-
|
|
17
|
-
export { type McpTool, createMcpServer, extractToolsFromProcedures, mergeInputs };
|
package/dist/index.d.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { Implementation } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
-
import { AnyRootTypes, RouterRecord, Router } from '@trpc/server/unstable-core-do-not-import';
|
|
3
|
-
import { z } from 'zod/v4';
|
|
4
|
-
|
|
5
|
-
type MaybePromise<T> = Promise<T> | T;
|
|
6
|
-
declare function createMcpServer<TRoot extends AnyRootTypes, TRecord extends RouterRecord>(implementation: Implementation, appRouter: Router<TRoot, TRecord>, ctx: TRoot["ctx"] | (() => MaybePromise<TRoot["ctx"]>)): void;
|
|
7
|
-
|
|
8
|
-
type McpTool = {
|
|
9
|
-
name: string;
|
|
10
|
-
description: string;
|
|
11
|
-
pathInRouter: string[];
|
|
12
|
-
inputSchema?: z.core.JSONSchema.JSONSchema;
|
|
13
|
-
};
|
|
14
|
-
declare function mergeInputs(inputs: z.ZodObject[]): z.ZodObject<z.core.$ZodLooseShape, z.core.$strip>;
|
|
15
|
-
declare function extractToolsFromProcedures<TRoot extends AnyRootTypes, TRecord extends RouterRecord>(appRouter: Router<TRoot, TRecord>, currentPath?: string[]): McpTool[];
|
|
16
|
-
|
|
17
|
-
export { type McpTool, createMcpServer, extractToolsFromProcedures, mergeInputs };
|
package/dist/index.js
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
|
|
20
|
-
// src/index.ts
|
|
21
|
-
var index_exports = {};
|
|
22
|
-
__export(index_exports, {
|
|
23
|
-
createMcpServer: () => createMcpServer,
|
|
24
|
-
extractToolsFromProcedures: () => extractToolsFromProcedures,
|
|
25
|
-
mergeInputs: () => mergeInputs
|
|
26
|
-
});
|
|
27
|
-
module.exports = __toCommonJS(index_exports);
|
|
28
|
-
|
|
29
|
-
// src/server.ts
|
|
30
|
-
var import_server = require("@modelcontextprotocol/sdk/server/index.js");
|
|
31
|
-
var import_types = require("@modelcontextprotocol/sdk/types.js");
|
|
32
|
-
|
|
33
|
-
// src/tools.ts
|
|
34
|
-
var import_v4 = require("zod/v4");
|
|
35
|
-
function mergeInputs(inputs) {
|
|
36
|
-
return inputs.reduce((acc, input) => {
|
|
37
|
-
return acc.extend(input.shape);
|
|
38
|
-
}, import_v4.z.object());
|
|
39
|
-
}
|
|
40
|
-
function extractToolsFromProcedures(appRouter, currentPath = []) {
|
|
41
|
-
const tools = [];
|
|
42
|
-
const procedures = Object.entries(appRouter._def.procedures);
|
|
43
|
-
for (const [name, procedure] of procedures) {
|
|
44
|
-
if (procedure._def && "inputs" in procedure._def) {
|
|
45
|
-
const inputs = procedure._def.inputs;
|
|
46
|
-
const schema = inputs.length > 1 ? mergeInputs(inputs) : inputs[0];
|
|
47
|
-
const meta = procedure._def.meta;
|
|
48
|
-
if (!meta || !meta?.mcp?.enabled) {
|
|
49
|
-
continue;
|
|
50
|
-
}
|
|
51
|
-
const pathInRouter = [...currentPath, ...name.split(".")];
|
|
52
|
-
const tool = {
|
|
53
|
-
name: meta?.mcp?.name ?? name.replace(/\./g, "_"),
|
|
54
|
-
description: meta?.mcp?.description ?? "",
|
|
55
|
-
pathInRouter
|
|
56
|
-
};
|
|
57
|
-
if (schema) {
|
|
58
|
-
const jsonSchema = import_v4.z.toJSONSchema(schema, {
|
|
59
|
-
unrepresentable: "any"
|
|
60
|
-
});
|
|
61
|
-
if (jsonSchema.type === "object") {
|
|
62
|
-
const { type, properties = {}, required = [] } = jsonSchema;
|
|
63
|
-
tool.inputSchema = { type, properties, required };
|
|
64
|
-
} else {
|
|
65
|
-
console.error(
|
|
66
|
-
"[TRPC-TO-MCP] Procedure has no object schema",
|
|
67
|
-
pathInRouter
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
} else {
|
|
71
|
-
const jsonSchema = import_v4.z.toJSONSchema(import_v4.z.object());
|
|
72
|
-
tool.inputSchema = jsonSchema;
|
|
73
|
-
}
|
|
74
|
-
tools.push(tool);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
return tools;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// src/server.ts
|
|
81
|
-
function createMcpServer(implementation, appRouter, ctx) {
|
|
82
|
-
const tools = extractToolsFromProcedures(appRouter);
|
|
83
|
-
const trpcCaller = appRouter.createCaller(ctx);
|
|
84
|
-
const server = new import_server.Server(implementation, {
|
|
85
|
-
capabilities: {
|
|
86
|
-
// Leave it empty because we list tools manually
|
|
87
|
-
tools: {}
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
server.setRequestHandler(import_types.ListToolsRequestSchema, () => ({ tools }));
|
|
91
|
-
server.setRequestHandler(import_types.CallToolRequestSchema, async (request) => {
|
|
92
|
-
const { name, arguments: args } = request.params;
|
|
93
|
-
const tool = tools.find((t) => t.name === name);
|
|
94
|
-
if (!tool) {
|
|
95
|
-
return { content: [{ type: "text", text: "Could not find tool" }] };
|
|
96
|
-
}
|
|
97
|
-
const procedure = tool.pathInRouter.reduce(
|
|
98
|
-
// @ts-expect-error path in router
|
|
99
|
-
(acc, part) => acc?.[part],
|
|
100
|
-
trpcCaller
|
|
101
|
-
);
|
|
102
|
-
const result = await procedure(args);
|
|
103
|
-
return {
|
|
104
|
-
content: [{ type: "text", text: JSON.stringify(result) }]
|
|
105
|
-
};
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
109
|
-
0 && (module.exports = {
|
|
110
|
-
createMcpServer,
|
|
111
|
-
extractToolsFromProcedures,
|
|
112
|
-
mergeInputs
|
|
113
|
-
});
|
package/dist/index.mjs
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
// src/server.ts
|
|
2
|
-
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
|
-
import {
|
|
4
|
-
CallToolRequestSchema,
|
|
5
|
-
ListToolsRequestSchema
|
|
6
|
-
} from "@modelcontextprotocol/sdk/types.js";
|
|
7
|
-
|
|
8
|
-
// src/tools.ts
|
|
9
|
-
import { z } from "zod/v4";
|
|
10
|
-
function mergeInputs(inputs) {
|
|
11
|
-
return inputs.reduce((acc, input) => {
|
|
12
|
-
return acc.extend(input.shape);
|
|
13
|
-
}, z.object());
|
|
14
|
-
}
|
|
15
|
-
function extractToolsFromProcedures(appRouter, currentPath = []) {
|
|
16
|
-
const tools = [];
|
|
17
|
-
const procedures = Object.entries(appRouter._def.procedures);
|
|
18
|
-
for (const [name, procedure] of procedures) {
|
|
19
|
-
if (procedure._def && "inputs" in procedure._def) {
|
|
20
|
-
const inputs = procedure._def.inputs;
|
|
21
|
-
const schema = inputs.length > 1 ? mergeInputs(inputs) : inputs[0];
|
|
22
|
-
const meta = procedure._def.meta;
|
|
23
|
-
if (!meta || !meta?.mcp?.enabled) {
|
|
24
|
-
continue;
|
|
25
|
-
}
|
|
26
|
-
const pathInRouter = [...currentPath, ...name.split(".")];
|
|
27
|
-
const tool = {
|
|
28
|
-
name: meta?.mcp?.name ?? name.replace(/\./g, "_"),
|
|
29
|
-
description: meta?.mcp?.description ?? "",
|
|
30
|
-
pathInRouter
|
|
31
|
-
};
|
|
32
|
-
if (schema) {
|
|
33
|
-
const jsonSchema = z.toJSONSchema(schema, {
|
|
34
|
-
unrepresentable: "any"
|
|
35
|
-
});
|
|
36
|
-
if (jsonSchema.type === "object") {
|
|
37
|
-
const { type, properties = {}, required = [] } = jsonSchema;
|
|
38
|
-
tool.inputSchema = { type, properties, required };
|
|
39
|
-
} else {
|
|
40
|
-
console.error(
|
|
41
|
-
"[TRPC-TO-MCP] Procedure has no object schema",
|
|
42
|
-
pathInRouter
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
} else {
|
|
46
|
-
const jsonSchema = z.toJSONSchema(z.object());
|
|
47
|
-
tool.inputSchema = jsonSchema;
|
|
48
|
-
}
|
|
49
|
-
tools.push(tool);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
return tools;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// src/server.ts
|
|
56
|
-
function createMcpServer(implementation, appRouter, ctx) {
|
|
57
|
-
const tools = extractToolsFromProcedures(appRouter);
|
|
58
|
-
const trpcCaller = appRouter.createCaller(ctx);
|
|
59
|
-
const server = new Server(implementation, {
|
|
60
|
-
capabilities: {
|
|
61
|
-
// Leave it empty because we list tools manually
|
|
62
|
-
tools: {}
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
server.setRequestHandler(ListToolsRequestSchema, () => ({ tools }));
|
|
66
|
-
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
67
|
-
const { name, arguments: args } = request.params;
|
|
68
|
-
const tool = tools.find((t) => t.name === name);
|
|
69
|
-
if (!tool) {
|
|
70
|
-
return { content: [{ type: "text", text: "Could not find tool" }] };
|
|
71
|
-
}
|
|
72
|
-
const procedure = tool.pathInRouter.reduce(
|
|
73
|
-
// @ts-expect-error path in router
|
|
74
|
-
(acc, part) => acc?.[part],
|
|
75
|
-
trpcCaller
|
|
76
|
-
);
|
|
77
|
-
const result = await procedure(args);
|
|
78
|
-
return {
|
|
79
|
-
content: [{ type: "text", text: JSON.stringify(result) }]
|
|
80
|
-
};
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
export {
|
|
84
|
-
createMcpServer,
|
|
85
|
-
extractToolsFromProcedures,
|
|
86
|
-
mergeInputs
|
|
87
|
-
};
|
|
File without changes
|