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.
@@ -30,7 +30,7 @@ jobs:
30
30
  id: changesets
31
31
  uses: changesets/action@v1
32
32
  with:
33
- publish: pnpm run release --access public
33
+ publish: pnpm run release
34
34
  env:
35
35
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
36
36
  NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
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
@@ -1,5 +1,11 @@
1
1
  # trpc-to-mcp
2
2
 
3
+ ## 1.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - a9f1c69: Implement @vercel/mcp-handler adapter for trpc-to-mcp
8
+
3
9
  ## 1.0.0
4
10
 
5
11
  ### Major Changes
package/package.json CHANGED
@@ -1,25 +1,72 @@
1
1
  {
2
2
  "name": "trpc-to-mcp",
3
3
  "license": "MIT",
4
- "version": "1.0.0",
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 ./src/index.ts --format cjs,esm --dts",
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 createMcpServer<
19
- TRoot extends AnyRootTypes,
20
- TRecord extends RouterRecord
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
@@ -0,0 +1,12 @@
1
+ import { defineConfig } from "tsup";
2
+
3
+ export default defineConfig({
4
+ entry: [
5
+ "src/index.ts",
6
+ "src/server.ts",
7
+ "src/tools.ts",
8
+ "src/adapters/vercel-mcp-adapter.ts",
9
+ ],
10
+ format: ["esm", "cjs"],
11
+ dts: true,
12
+ });
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