trpc-to-mcp 1.3.2 → 2.0.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.
Files changed (70) hide show
  1. package/README.md +138 -178
  2. package/dist/adapters/vercel-mcp-adapter.cjs +19 -0
  3. package/dist/adapters/vercel-mcp-adapter.cjs.map +1 -0
  4. package/dist/adapters/vercel-mcp-adapter.d.cts +17 -0
  5. package/dist/adapters/vercel-mcp-adapter.d.mts +16 -13
  6. package/dist/adapters/vercel-mcp-adapter.mjs +15 -27
  7. package/dist/adapters/vercel-mcp-adapter.mjs.map +1 -1
  8. package/dist/helpers.cjs +20 -0
  9. package/dist/helpers.cjs.map +1 -0
  10. package/dist/helpers.d.cts +13 -0
  11. package/dist/helpers.d.mts +13 -6
  12. package/dist/helpers.mjs +17 -2
  13. package/dist/helpers.mjs.map +1 -1
  14. package/dist/index.cjs +9 -0
  15. package/dist/index.d.cts +5 -0
  16. package/dist/index.d.mts +5 -10
  17. package/dist/index.mjs +5 -6
  18. package/dist/server.cjs +18 -0
  19. package/dist/server.cjs.map +1 -0
  20. package/dist/server.d.cts +12 -0
  21. package/dist/server.d.mts +12 -12
  22. package/dist/server.mjs +16 -3
  23. package/dist/server.mjs.map +1 -1
  24. package/dist/tools.cjs +121 -0
  25. package/dist/tools.cjs.map +1 -0
  26. package/dist/tools.d.cts +23 -0
  27. package/dist/tools.d.mts +22 -15
  28. package/dist/tools.mjs +118 -2
  29. package/dist/tools.mjs.map +1 -1
  30. package/dist/types.cjs +0 -0
  31. package/dist/types.d.cts +31 -0
  32. package/dist/types.d.mts +30 -13
  33. package/dist/types.mjs +1 -3
  34. package/package.json +55 -73
  35. package/dist/adapters/vercel-mcp-adapter.d.ts +0 -14
  36. package/dist/adapters/vercel-mcp-adapter.js +0 -32
  37. package/dist/adapters/vercel-mcp-adapter.js.map +0 -1
  38. package/dist/chunk-55J6XMHW.js +0 -4
  39. package/dist/chunk-55J6XMHW.js.map +0 -1
  40. package/dist/chunk-7GYUHEUD.mjs +0 -47
  41. package/dist/chunk-7GYUHEUD.mjs.map +0 -1
  42. package/dist/chunk-BTXMEL6M.js +0 -55
  43. package/dist/chunk-BTXMEL6M.js.map +0 -1
  44. package/dist/chunk-FIQIIJAT.mjs +0 -11
  45. package/dist/chunk-FIQIIJAT.mjs.map +0 -1
  46. package/dist/chunk-FT3KTYAU.js +0 -13
  47. package/dist/chunk-FT3KTYAU.js.map +0 -1
  48. package/dist/chunk-KIQOUUEZ.mjs +0 -3
  49. package/dist/chunk-KIQOUUEZ.mjs.map +0 -1
  50. package/dist/chunk-RJJMUGXY.js +0 -50
  51. package/dist/chunk-RJJMUGXY.js.map +0 -1
  52. package/dist/chunk-ULLXW6IN.mjs +0 -52
  53. package/dist/chunk-ULLXW6IN.mjs.map +0 -1
  54. package/dist/helpers.d.ts +0 -6
  55. package/dist/helpers.js +0 -12
  56. package/dist/helpers.js.map +0 -1
  57. package/dist/index.d.ts +0 -10
  58. package/dist/index.js +0 -31
  59. package/dist/index.js.map +0 -1
  60. package/dist/index.mjs.map +0 -1
  61. package/dist/server.d.ts +0 -12
  62. package/dist/server.js +0 -17
  63. package/dist/server.js.map +0 -1
  64. package/dist/tools.d.ts +0 -16
  65. package/dist/tools.js +0 -16
  66. package/dist/tools.js.map +0 -1
  67. package/dist/types.d.ts +0 -14
  68. package/dist/types.js +0 -6
  69. package/dist/types.js.map +0 -1
  70. package/dist/types.mjs.map +0 -1
package/README.md CHANGED
@@ -1,257 +1,217 @@
1
- ## Introduction
1
+ # trpc-to-mcp
2
2
 
3
- You can skip this part if you know exactly why you're turning your tRPC endpoints into MCP tools.
3
+ Turn the tRPC procedures you choose into MCP tools.
4
4
 
5
- <details>
6
- <summary>How to think of MCPs</summary>
7
-
8
- At its core, the Model Context Protocol (MCP) gives language models a context to interact with external systems by exposing well-defined tools. This isn't about wrapping API endpoints- it's about enabling AI to perform tasks with clarity and purpose.
5
+ - Works with tRPC v11 and `@modelcontextprotocol/server` v2, the MCP TypeScript SDK
6
+ - [Serve tools over stdio or HTTP](#serve-your-tools)
7
+ - [Use the tRPC context and middlewares on every tool call](#context)
8
+ - [Transform outputs into text, images, or other MCP content](#transform-outputs)
9
+ - [Return structured content from procedures with an output schema](#structured-output)
10
+ - [Mount on Next.js and other frameworks with mcp-handler](#mcp-handler)
9
11
 
10
- This library was created to convert only the tRPC procedures you explicitly choose into MCP tools. By doing so, it ensures that only the functionalities intended for controlled AI interaction are exposed, rather than indiscriminately converting all endpoints.
12
+ <details>
13
+ <summary>Why only the procedures you choose?</summary>
11
14
 
12
- Remember, for an endpoint to be effectively transformed into an MCP tool, it should be meticulously documented with clear descriptions, meaningful names, and well-defined inputs/outputs. This careful design is crucial because MCP tools are more than mere API endpoints - they form the operational contexts that enable language models to function reliably.
15
+ An MCP tool is something a language model decides to call on its own, so expose only the procedures you want a model to use. A model picks a tool based on its name, description, and input schema. Give each exposed procedure a clear name, a description of what it does and when to use it, and a `.describe()` on each input field.
13
16
 
14
17
  </details>
15
18
 
16
- ## tRPC to MCP
17
-
18
- - Support for tRPC v11
19
- - [Transform your JSON outputs into human-language with custom helpers](#transform-output)
20
- - [Turn your tRPC router into MCP tools](#to-mcp-tools)
21
- - [Turn your tRPC router into MCP server](#to-mcp-server)
22
- - [Turn your tRPC router into @vercel/mcp-adapter handler](#to-vercel-mcp-adapter)
23
-
24
- ## Usage
25
-
26
- 1. Install trpc-to-mcp
19
+ ## Install
27
20
 
28
21
  ```bash
29
- npm install trpc-to-mcp
30
-
31
- pnpm add trpc-to-mcp
22
+ pnpm add trpc-to-mcp @modelcontextprotocol/server
23
+ ```
32
24
 
33
- bun add trpc-to-mcp
25
+ `@trpc/server` 11 and `@modelcontextprotocol/server` 2 are peer dependencies. Node.js 20 or later is required.
34
26
 
35
- yarn add trpc-to-mcp
36
- ```
27
+ ## Usage
37
28
 
38
- 2. Add `McpMeta` to your tRPC instance
29
+ 1. Add `McpMeta` to your tRPC instance.
39
30
 
40
31
  ```typescript
41
32
  import { initTRPC } from "@trpc/server";
42
33
  import { type McpMeta } from "trpc-to-mcp";
43
34
 
44
- const t = initTRPC.meta<McpMeta>().create();
35
+ const t = initTRPC.context<Context>().meta<McpMeta>().create();
45
36
  ```
46
37
 
47
- 3. Enable `mcp` support for a procedure
38
+ 2. Enable `mcp` on the procedures you want as tools.
48
39
 
49
40
  ```typescript
41
+ import { z } from "zod";
42
+
50
43
  export const appRouter = t.router({
51
44
  hello: t.procedure
52
45
  .meta({
53
46
  mcp: {
54
47
  enabled: true,
55
- description: "Say hello to a name",
56
- // You can leave it empty, it'll be converted to "hello"
57
- // If you have subrouters, then subrouter_procedure_name
48
+ description: "Say hello to someone",
49
+ // Optional. Defaults to the procedure path with dots replaced by
50
+ // underscores, e.g. "hello" or "user_byId".
58
51
  name: "say_hello",
59
52
  },
60
53
  })
61
- .input(
62
- z.object({
63
- name: z.string(),
64
- }),
65
- )
66
- .query(({ input }) => {
67
- return { greeting: `Hello ${input.name}` };
68
- }),
54
+ .input(z.object({ name: z.string().describe("Who to greet") }))
55
+ .query(({ input }) => `Hello ${input.name}`),
69
56
  });
70
57
  ```
71
58
 
72
- ## Transform Outputs
59
+ Inputs must be object schemas from a validator that implements [Standard JSON Schema](https://standardschema.dev), such as zod 4.2 or later, ArkType, or Valibot with `toStandardJsonSchema()`. Chained `.input()` calls are merged into one tool input schema. Subscriptions can't be tools.
73
60
 
74
- If you need a human-language outputs for LLMs to have a better context, you can use `transformMcpProcedure`
61
+ tRPC validates input on every call, so your zod transforms and refinements run as usual. Errors thrown by a procedure, including `TRPCError`, come back to the client as a tool result with `isError: true`.
75
62
 
76
- You simply wrap your procedure with the helper function, and provide a transformer callback function that turns your procedure output into `ContentBlock[]` array compatible with MCP content output.
63
+ `meta.mcp` also takes `title` and `annotations`. Queries get `readOnlyHint: true` unless you set it yourself.
77
64
 
78
- ```typescript
79
- import { initTRPC } from "@trpc/server";
80
- import { z } from "zod";
65
+ ## Serve your tools
81
66
 
82
- import { transformMcpProcedure, type McpMeta } from "../src";
67
+ `createMcpServer` returns an `McpServer` with your tools registered. You can register more tools, prompts, and resources on it.
83
68
 
84
- const t = initTRPC.meta<McpMeta>().create();
69
+ Over stdio:
85
70
 
86
- export const appRouter = t.router({
87
- procedure: transformMcpProcedure(
88
- t.procedure
89
- .meta({
90
- mcp: {
91
- enabled: true,
92
- description: "Send a message",
93
- name: "send_message",
94
- },
95
- })
96
- .input(
97
- z.object({
98
- message: z.string(),
99
- }),
100
- )
101
- .query(({ input }) => {
102
- return {
103
- payload: {
104
- from: "trpc",
105
- message: input.message,
106
- array: [{ a: 1 }, { b: 2 }],
107
- },
108
- };
109
- }),
110
- (output) => {
111
- return [
112
- ...output.payload.array.map((item) => {
113
- const [name, value] = Object.entries(item);
114
- return {
115
- type: "text" as const,
116
- text: `${name} is ${value} letter of alphabet`,
117
- };
118
- }),
119
- {
120
- type: "image",
121
- data: "...",
122
- mimeType: "",
123
- },
124
- {
125
- type: "audio", // or even "resource" | "resource_link"
126
- data: "...",
127
- mimeType: "",
128
- },
129
- ];
130
- },
131
- ),
132
- });
133
- ```
71
+ ```typescript
72
+ import { serveStdio } from "@modelcontextprotocol/server/stdio";
73
+ import { createMcpServer } from "trpc-to-mcp";
134
74
 
135
- ## To MCP tools
75
+ serveStdio(() =>
76
+ createMcpServer({ name: "my-app", version: "1.0.0" }, appRouter, { db }),
77
+ );
78
+ ```
136
79
 
137
- 4. You can turn a router into tools
80
+ Over HTTP, with the SDK's `createMcpHandler` on any runtime with web-standard `Request` and `Response`:
138
81
 
139
82
  ```typescript
140
- import { appRouter } from "@/server/trpc/root.ts";
141
- import { extractToolsFromProcedures } from "trpc-to-mcp";
83
+ import { createMcpHandler } from "@modelcontextprotocol/server";
84
+ import { createMcpServer } from "trpc-to-mcp";
142
85
 
143
- const tools = extractToolsFromProcedures(appRouter);
86
+ const handler = createMcpHandler(() =>
87
+ createMcpServer({ name: "my-app", version: "1.0.0" }, appRouter, { db }),
88
+ );
144
89
 
145
- /*
90
+ export default { fetch: handler.fetch };
91
+ ```
146
92
 
147
- [
148
- {
149
- name: "Tool name",
150
- description: "Description of the tool",
151
- pathInRouter: [...],
152
- inputSchema: JSONSchema // this if full JSON schema from your zod schema
153
- },
154
- ...
155
- ]
93
+ To add tools to an `McpServer` you created yourself, call `registerTrpcTools(server, appRouter, ctx)`.
156
94
 
157
- */
95
+ ## Context
96
+
97
+ The third argument is the tRPC context. Pass a value, or a function that creates the context on each tool call. The function receives the MCP request context, so it can read the HTTP request and the auth info from your auth middleware.
98
+
99
+ ```typescript
100
+ createMcpServer({ name: "my-app", version: "1.0.0" }, appRouter, (ctx) => ({
101
+ db,
102
+ headers: ctx.http?.req?.headers,
103
+ auth: ctx.http?.authInfo,
104
+ }));
158
105
  ```
159
106
 
160
- ## To MCP server
107
+ Tool calls run through your tRPC middlewares, so auth checks in a `protectedProcedure` apply to MCP clients too.
161
108
 
162
- 5. You can turn a router into an MCP server
109
+ ## Transform outputs
110
+
111
+ By default a tool returns the procedure output as JSON text. To return something easier for a model to read, wrap the procedure with `transformMcpProcedure` and return MCP content blocks. The `output` argument is typed from the procedure.
163
112
 
164
113
  ```typescript
165
- import { appRouter } from "@/server/trpc/root.ts";
166
- import { createMcpServer } from "trpc-to-mcp";
114
+ import { transformMcpProcedure } from "trpc-to-mcp";
167
115
 
168
- const ctx = {
169
- session: {
170
- // ...
171
- },
172
- };
116
+ export const appRouter = t.router({
117
+ weather: transformMcpProcedure(
118
+ t.procedure
119
+ .meta({
120
+ mcp: { enabled: true, description: "Current weather in a city" },
121
+ })
122
+ .input(z.object({ city: z.string() }))
123
+ .query(({ input }) => getWeather(input.city)),
124
+ (output) => [
125
+ { type: "text", text: `${output.city}: ${output.temperature}°C` },
126
+ { type: "image", data: output.radarPng, mimeType: "image/png" },
127
+ ],
128
+ ),
129
+ });
130
+ ```
173
131
 
174
- // Returns high-level McpServer instance
175
- const mcpServer = createMcpServer(
176
- implementation, // Pass your Implementation instance
177
- appRouter,
178
- ctx, // Pass your tRPC context
179
- );
132
+ The content types are `text`, `image`, `audio`, `resource`, and `resource_link`. The procedure still returns its normal output to tRPC clients.
133
+
134
+ ## Structured output
135
+
136
+ If a procedure has an `.output()` validator that describes an object, the tool advertises it as an `outputSchema` and returns the output as `structuredContent` next to the text content.
137
+
138
+ ```typescript
139
+ t.procedure
140
+ .meta({ mcp: { enabled: true, description: "Look up a user" } })
141
+ .input(z.object({ id: z.string() }))
142
+ .output(z.object({ id: z.string(), name: z.string() }))
143
+ .query(({ input }) => db.user.find(input.id));
180
144
  ```
181
145
 
182
- ## To Vercel MCP adapter
146
+ ## mcp-handler
183
147
 
184
- 6. You can turn a router into `@vercel/mcp-adapter` handler
148
+ [mcp-handler](https://github.com/vercel/mcp-handler) turns an MCP server into a `(Request) => Promise<Response>` handler for Next.js, Nuxt, SvelteKit, Hono, and other frameworks. Install `mcp-handler` 2, then:
185
149
 
186
150
  ```typescript
187
- // app/api/[transport]/route.ts
151
+ // app/api/mcp/route.ts
188
152
  import { trpcToMcpHandler } from "trpc-to-mcp/adapters/vercel-mcp-adapter";
189
153
 
190
- const handler = trpcToHandler(appRouter, ctx, {
191
- // @vercel/mcp-adapter config options
192
- config: {
193
- basePath: "/api",
194
- // Disable in production
195
- verboseLogs: true,
196
- maxDuration: 60,
154
+ const handler = trpcToMcpHandler(appRouter, createContext, {
155
+ // mcp-handler options
156
+ serverOptions: {
157
+ serverInfo: { name: "my-app", version: "1.0.0" },
158
+ verboseLogs: process.env.NODE_ENV === "development",
197
159
  },
198
- // @vercel/mcp-adapter server options
199
- serverOptions: { ... },
200
- callback: (server) => {
201
- // You can modify the McpServer instance
202
- }
160
+ // Register extra tools, prompts, or resources
161
+ callback: (server) => {},
203
162
  });
204
163
 
205
- export { handler as DELETE, handler as GET, handler as POST };
164
+ export { handler as GET, handler as POST };
206
165
  ```
207
166
 
167
+ mcp-handler serves requests without sessions, so there is no Redis setup and no `basePath`. Mount the handler at any route.
168
+
208
169
  ## Use with better-auth
209
170
 
210
- 7. You can use it with better-auth
171
+ The [`@better-auth/mcp`](https://www.better-auth.com/docs/plugins/mcp) plugin makes your better-auth app an OAuth authorization server for MCP clients. Put your handler behind `requireMcpAuth`, and read the user ID from the access token claims.
211
172
 
212
173
  ```typescript
213
- // app/api/[transport]/route.ts
214
-
215
- import { withMcpAuth } from "better-auth/plugins";
216
- import { trpcToMcpHandler } from "trpc-to-mcp/adapters/vercel-mcp-adapter";
174
+ // app/api/mcp/route.ts
175
+ import { requireMcpAuth } from "@better-auth/mcp";
176
+ import { createMcpHandler } from "@modelcontextprotocol/server";
177
+ import { createMcpServer } from "trpc-to-mcp";
217
178
 
218
- // Define a function to retrieve user session from database
219
- async function getSession(mcpSession: McpSession): Promise<Session | null> {
220
- // You can use mcpSession.userId to fetch session
221
- // await db.query.session.findFirst({
222
- // where: (table, { eq }) => eq(table.userId, mcpSession.userId)
223
- // })
224
- }
225
-
226
- const handler = withMcpAuth(auth, async (request, mcpSession) => {
227
- // Retrieve the session from database via userId inside mcpSession
228
- const session = await getSession(mcpSession);
229
-
230
- const handler = trpcToMcpHandler(
231
- appRouter,
232
- // Pass your tRPC context here
233
- {
234
- db,
235
- headers: request.headers,
236
- session: session?.session,
237
- user: session?.user,
238
- },
239
- {
240
- config: {
241
- basePath: "/api",
242
- // Disable in production
243
- verboseLogs: true,
244
- maxDuration: 60,
245
- },
246
- },
179
+ export const POST = requireMcpAuth(auth, (request, claims) => {
180
+ const handler = createMcpHandler(
181
+ () =>
182
+ createMcpServer({ name: "my-app", version: "1.0.0" }, appRouter, {
183
+ db,
184
+ userId: claims.sub,
185
+ }),
186
+ // @better-auth/mcp recommends serving only the 2026-07-28 protocol.
187
+ { legacy: "reject" },
247
188
  );
248
189
 
249
- return await handler(request);
190
+ return handler.fetch(request);
250
191
  });
192
+ ```
193
+
194
+ ## List tools without a server
251
195
 
252
- export { handler as DELETE, handler as GET, handler as POST };
196
+ `extractToolsFromProcedures` returns the tool definitions, including JSON input schemas, without creating a server.
197
+
198
+ ```typescript
199
+ import { extractToolsFromProcedures } from "trpc-to-mcp";
200
+
201
+ const tools = extractToolsFromProcedures(appRouter);
202
+ // [{ name: "say_hello", description: "...", path: "hello", type: "query", inputSchema: {...} }]
253
203
  ```
254
204
 
205
+ ## Upgrading from 1.x
206
+
207
+ - Replace `@modelcontextprotocol/sdk` with `@modelcontextprotocol/server` 2, and upgrade `mcp-handler` to 2 if you use the adapter.
208
+ - In `trpcToMcpHandler`, remove `config`. Move `verboseLogs` into `serverOptions`, and mount the handler at the route you want.
209
+ - Use zod 4.2 or later, or another validator with Standard JSON Schema support.
210
+ - Replace `setRequestHandler(server.server, tools, caller)` with `registerTrpcTools(server, appRouter, ctx)`.
211
+ - `McpTool.pathInRouter` is now `McpTool.path`, a dotted string.
212
+
213
+ See [CHANGELOG.md](./CHANGELOG.md) for the full list.
214
+
255
215
  ## Result
256
216
 
257
217
  Now you can chill and add MCP to your VC-backed startup so your investors won't worry, and profit
@@ -0,0 +1,19 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_tools = require("../tools.cjs");
3
+ let mcp_handler = require("mcp-handler");
4
+ //#region src/adapters/vercel-mcp-adapter.ts
5
+ /**
6
+ * Creates an `mcp-handler` request handler, a `(Request) => Promise<Response>`
7
+ * you can mount as a Next.js route or in any Fetch-compatible framework.
8
+ * Use `callback` to register extra tools, prompts, or resources.
9
+ */
10
+ function trpcToMcpHandler(router, ctx, options = {}) {
11
+ return (0, mcp_handler.createMcpHandler)(async (server) => {
12
+ require_tools.registerTrpcTools(server, router, ctx);
13
+ await options.callback?.(server);
14
+ }, options.serverOptions);
15
+ }
16
+ //#endregion
17
+ exports.trpcToMcpHandler = trpcToMcpHandler;
18
+
19
+ //# sourceMappingURL=vercel-mcp-adapter.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vercel-mcp-adapter.cjs","names":["createMcpHandler"],"sources":["../../src/adapters/vercel-mcp-adapter.ts"],"sourcesContent":["import type { McpServer } from \"@modelcontextprotocol/server\";\nimport type { AnyTRPCRouter } from \"@trpc/server\";\nimport { createMcpHandler, type McpHandlerOptions } from \"mcp-handler\";\n\nimport { registerTrpcTools } from \"../tools\";\nimport type { MaybePromise, McpContext } from \"../types\";\n\nexport type { McpHandlerOptions };\n\n/**\n * Creates an `mcp-handler` request handler, a `(Request) => Promise<Response>`\n * you can mount as a Next.js route or in any Fetch-compatible framework.\n * Use `callback` to register extra tools, prompts, or resources.\n */\nexport function trpcToMcpHandler<TRouter extends AnyTRPCRouter>(\n router: TRouter,\n ctx: McpContext<TRouter>,\n options: {\n serverOptions?: McpHandlerOptions;\n callback?: (server: McpServer) => MaybePromise<void>;\n } = {},\n) {\n return createMcpHandler(async (server) => {\n registerTrpcTools(server, router, ctx);\n await options.callback?.(server);\n }, options.serverOptions);\n}\n"],"mappings":";;;;;;;;;AAcA,SAAgB,iBACd,QACA,KACA,UAGI,CAAC,GACL;CACA,QAAA,GAAOA,YAAAA,iBAAAA,CAAiB,OAAO,WAAW;EACxC,cAAA,kBAAkB,QAAQ,QAAQ,GAAG;EACrC,MAAM,QAAQ,WAAW,MAAM;CACjC,GAAG,QAAQ,aAAa;AAC1B"}
@@ -0,0 +1,17 @@
1
+ import { MaybePromise, McpContext } from "../types.cjs";
2
+ import { McpServer } from "@modelcontextprotocol/server";
3
+ import { AnyTRPCRouter } from "@trpc/server";
4
+ import { McpHandlerOptions } from "mcp-handler";
5
+ //#region src/adapters/vercel-mcp-adapter.d.ts
6
+ /**
7
+ * Creates an `mcp-handler` request handler, a `(Request) => Promise<Response>`
8
+ * you can mount as a Next.js route or in any Fetch-compatible framework.
9
+ * Use `callback` to register extra tools, prompts, or resources.
10
+ */
11
+ export declare function trpcToMcpHandler<TRouter extends AnyTRPCRouter>(router: TRouter, ctx: McpContext<TRouter>, options?: {
12
+ serverOptions?: McpHandlerOptions;
13
+ callback?: (server: McpServer) => MaybePromise<void>;
14
+ }): (request: Request) => Promise<Response>;
15
+ //#endregion
16
+ export type { McpHandlerOptions };
17
+ //# sourceMappingURL=vercel-mcp-adapter.d.cts.map
@@ -1,14 +1,17 @@
1
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp';
2
- import { AnyRootTypes, RouterRecord, Router, MaybePromise } from '@trpc/server/unstable-core-do-not-import';
3
- import { createMcpHandler } from 'mcp-handler';
4
-
5
- type VercelMcpHandler = ReturnType<typeof createMcpHandler>;
6
- type McpServerOptions = Parameters<typeof createMcpHandler>[1];
7
- type McpHandlerConfig = Parameters<typeof createMcpHandler>[2];
8
- declare function trpcToMcpHandler<TRoot extends AnyRootTypes, TRecord extends RouterRecord>(appRouter: Router<TRoot, TRecord>, ctx: TRoot["ctx"] | (() => MaybePromise<TRoot["ctx"]>), handlerOptions: {
9
- config: McpHandlerConfig;
10
- serverOptions?: McpServerOptions;
11
- callback?: (server: McpServer) => unknown;
1
+ import { MaybePromise, McpContext } from "../types.mjs";
2
+ import { McpServer } from "@modelcontextprotocol/server";
3
+ import { AnyTRPCRouter } from "@trpc/server";
4
+ import { McpHandlerOptions } from "mcp-handler";
5
+ //#region src/adapters/vercel-mcp-adapter.d.ts
6
+ /**
7
+ * Creates an `mcp-handler` request handler, a `(Request) => Promise<Response>`
8
+ * you can mount as a Next.js route or in any Fetch-compatible framework.
9
+ * Use `callback` to register extra tools, prompts, or resources.
10
+ */
11
+ export declare function trpcToMcpHandler<TRouter extends AnyTRPCRouter>(router: TRouter, ctx: McpContext<TRouter>, options?: {
12
+ serverOptions?: McpHandlerOptions;
13
+ callback?: (server: McpServer) => MaybePromise<void>;
12
14
  }): (request: Request) => Promise<Response>;
13
-
14
- export { type McpHandlerConfig, type McpServerOptions, type VercelMcpHandler, trpcToMcpHandler };
15
+ //#endregion
16
+ export type { McpHandlerOptions };
17
+ //# sourceMappingURL=vercel-mcp-adapter.d.mts.map
@@ -1,30 +1,18 @@
1
- import { setRequestHandler } from '../chunk-7GYUHEUD.mjs';
2
- import { extractToolsFromProcedures } from '../chunk-ULLXW6IN.mjs';
3
- import { createMcpHandler } from 'mcp-handler';
4
-
5
- function trpcToMcpHandler(appRouter, ctx, handlerOptions) {
6
- const { serverOptions, config, callback } = handlerOptions;
7
- const tools = extractToolsFromProcedures(appRouter);
8
- const trpcCaller = appRouter.createCaller(ctx);
9
- const handler = createMcpHandler(
10
- (server) => {
11
- setRequestHandler(server.server, tools, trpcCaller);
12
- if (typeof callback === "function") {
13
- callback(server);
14
- }
15
- },
16
- {
17
- // Leave it empty because we list tools manually
18
- capabilities: {
19
- tools: {}
20
- },
21
- ...serverOptions
22
- },
23
- config
24
- );
25
- return handler;
1
+ import { registerTrpcTools } from "../tools.mjs";
2
+ import { createMcpHandler } from "mcp-handler";
3
+ //#region src/adapters/vercel-mcp-adapter.ts
4
+ /**
5
+ * Creates an `mcp-handler` request handler, a `(Request) => Promise<Response>`
6
+ * you can mount as a Next.js route or in any Fetch-compatible framework.
7
+ * Use `callback` to register extra tools, prompts, or resources.
8
+ */
9
+ function trpcToMcpHandler(router, ctx, options = {}) {
10
+ return createMcpHandler(async (server) => {
11
+ registerTrpcTools(server, router, ctx);
12
+ await options.callback?.(server);
13
+ }, options.serverOptions);
26
14
  }
27
-
15
+ //#endregion
28
16
  export { trpcToMcpHandler };
29
- //# sourceMappingURL=vercel-mcp-adapter.mjs.map
17
+
30
18
  //# sourceMappingURL=vercel-mcp-adapter.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/adapters/vercel-mcp-adapter.ts"],"names":[],"mappings":";;;;AAgBO,SAAS,gBAAA,CAId,SAAA,EACA,GAAA,EACA,cAAA,EAKA;AACA,EAAA,MAAM,EAAE,aAAA,EAAe,MAAA,EAAQ,QAAA,EAAS,GAAI,cAAA;AAE5C,EAAA,MAAM,KAAA,GAAQ,2BAA2B,SAAS,CAAA;AAClD,EAAA,MAAM,UAAA,GAAa,SAAA,CAAU,YAAA,CAAa,GAAG,CAAA;AAE7C,EAAA,MAAM,OAAA,GAAU,gBAAA;AAAA,IACd,CAAC,MAAA,KAAW;AACV,MAAA,iBAAA,CAAkB,MAAA,CAAO,MAAA,EAAQ,KAAA,EAAO,UAAU,CAAA;AAElD,MAAA,IAAI,OAAO,aAAa,UAAA,EAAY;AAClC,QAAA,QAAA,CAAS,MAAM,CAAA;AAAA,MACjB;AAAA,IACF,CAAA;AAAA,IACA;AAAA;AAAA,MAEE,YAAA,EAAc;AAAA,QACZ,OAAO;AAAC,OACV;AAAA,MACA,GAAG;AAAA,KACL;AAAA,IACA;AAAA,GACF;AAEA,EAAA,OAAO,OAAA;AACT","file":"vercel-mcp-adapter.mjs","sourcesContent":["import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp\";\nimport type {\n AnyRootTypes,\n MaybePromise,\n Router,\n RouterRecord,\n} from \"@trpc/server/unstable-core-do-not-import\";\nimport { createMcpHandler } from \"mcp-handler\";\n\nimport { setRequestHandler } from \"../server\";\nimport { extractToolsFromProcedures } from \"../tools\";\n\nexport type VercelMcpHandler = ReturnType<typeof createMcpHandler>;\nexport type McpServerOptions = Parameters<typeof createMcpHandler>[1];\nexport type McpHandlerConfig = Parameters<typeof createMcpHandler>[2];\n\nexport function trpcToMcpHandler<\n TRoot extends AnyRootTypes,\n TRecord extends RouterRecord,\n>(\n appRouter: Router<TRoot, TRecord>,\n ctx: TRoot[\"ctx\"] | (() => MaybePromise<TRoot[\"ctx\"]>),\n handlerOptions: {\n config: McpHandlerConfig;\n serverOptions?: McpServerOptions;\n callback?: (server: McpServer) => unknown;\n },\n) {\n const { serverOptions, config, callback } = handlerOptions;\n\n const tools = extractToolsFromProcedures(appRouter);\n const trpcCaller = appRouter.createCaller(ctx);\n\n const handler = createMcpHandler(\n (server) => {\n setRequestHandler(server.server, tools, trpcCaller);\n\n if (typeof callback === \"function\") {\n callback(server);\n }\n },\n {\n // Leave it empty because we list tools manually\n capabilities: {\n tools: {},\n },\n ...serverOptions,\n },\n config,\n );\n\n return handler;\n}\n"]}
1
+ {"version":3,"file":"vercel-mcp-adapter.mjs","names":[],"sources":["../../src/adapters/vercel-mcp-adapter.ts"],"sourcesContent":["import type { McpServer } from \"@modelcontextprotocol/server\";\nimport type { AnyTRPCRouter } from \"@trpc/server\";\nimport { createMcpHandler, type McpHandlerOptions } from \"mcp-handler\";\n\nimport { registerTrpcTools } from \"../tools\";\nimport type { MaybePromise, McpContext } from \"../types\";\n\nexport type { McpHandlerOptions };\n\n/**\n * Creates an `mcp-handler` request handler, a `(Request) => Promise<Response>`\n * you can mount as a Next.js route or in any Fetch-compatible framework.\n * Use `callback` to register extra tools, prompts, or resources.\n */\nexport function trpcToMcpHandler<TRouter extends AnyTRPCRouter>(\n router: TRouter,\n ctx: McpContext<TRouter>,\n options: {\n serverOptions?: McpHandlerOptions;\n callback?: (server: McpServer) => MaybePromise<void>;\n } = {},\n) {\n return createMcpHandler(async (server) => {\n registerTrpcTools(server, router, ctx);\n await options.callback?.(server);\n }, options.serverOptions);\n}\n"],"mappings":";;;;;;;;AAcA,SAAgB,iBACd,QACA,KACA,UAGI,CAAC,GACL;CACA,OAAO,iBAAiB,OAAO,WAAW;EACxC,kBAAkB,QAAQ,QAAQ,GAAG;EACrC,MAAM,QAAQ,WAAW,MAAM;CACjC,GAAG,QAAQ,aAAa;AAC1B"}
@@ -0,0 +1,20 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/helpers.ts
3
+ const transforms = /* @__PURE__ */ new WeakMap();
4
+ /**
5
+ * Wraps a procedure so its MCP tool returns `transform(output)` as content
6
+ * instead of the JSON-serialized output. The procedure itself is unchanged.
7
+ */
8
+ function transformMcpProcedure(procedure, transform) {
9
+ transforms.set(procedure, transform);
10
+ return procedure;
11
+ }
12
+ /** @internal Used by `extractToolsFromProcedures`. */
13
+ function getMcpTransform(procedure) {
14
+ return transforms.get(procedure);
15
+ }
16
+ //#endregion
17
+ exports.getMcpTransform = getMcpTransform;
18
+ exports.transformMcpProcedure = transformMcpProcedure;
19
+
20
+ //# sourceMappingURL=helpers.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.cjs","names":[],"sources":["../src/helpers.ts"],"sourcesContent":["import type { ContentBlock } from \"@modelcontextprotocol/server\";\nimport type { AnyTRPCProcedure, inferProcedureOutput } from \"@trpc/server\";\n\nimport type { MaybePromise, McpToolTransform } from \"./types\";\n\n// Keyed by procedure instead of stored in meta: procedures built from the same\n// base procedure share one `meta.mcp` object, so writing to it would leak the\n// transform into sibling procedures.\nconst transforms = new WeakMap<AnyTRPCProcedure, McpToolTransform>();\n\n/**\n * Wraps a procedure so its MCP tool returns `transform(output)` as content\n * instead of the JSON-serialized output. The procedure itself is unchanged.\n */\nexport function transformMcpProcedure<TProcedure extends AnyTRPCProcedure>(\n procedure: TProcedure,\n transform: (\n output: inferProcedureOutput<TProcedure>,\n ) => MaybePromise<ContentBlock[]>,\n): TProcedure {\n // The map only hands this transform the output of `procedure`.\n transforms.set(procedure, transform as McpToolTransform);\n return procedure;\n}\n\n/** @internal Used by `extractToolsFromProcedures`. */\nexport function getMcpTransform(procedure: AnyTRPCProcedure) {\n return transforms.get(procedure);\n}\n"],"mappings":";;AAQA,MAAM,6BAAa,IAAI,QAA4C;;;;;AAMnE,SAAgB,sBACd,WACA,WAGY;CAEZ,WAAW,IAAI,WAAW,SAA6B;CACvD,OAAO;AACT;;AAGA,SAAgB,gBAAgB,WAA6B;CAC3D,OAAO,WAAW,IAAI,SAAS;AACjC"}
@@ -0,0 +1,13 @@
1
+ import { MaybePromise, McpToolTransform } from "./types.cjs";
2
+ import { ContentBlock } from "@modelcontextprotocol/server";
3
+ import { AnyTRPCProcedure, inferProcedureOutput } from "@trpc/server";
4
+ //#region src/helpers.d.ts
5
+ /**
6
+ * Wraps a procedure so its MCP tool returns `transform(output)` as content
7
+ * instead of the JSON-serialized output. The procedure itself is unchanged.
8
+ */
9
+ export declare function transformMcpProcedure<TProcedure extends AnyTRPCProcedure>(procedure: TProcedure, transform: (output: inferProcedureOutput<TProcedure>) => MaybePromise<ContentBlock[]>): TProcedure;
10
+ /** @internal Used by `extractToolsFromProcedures`. */
11
+ export declare function getMcpTransform(procedure: AnyTRPCProcedure): McpToolTransform | undefined;
12
+ //#endregion
13
+ //# sourceMappingURL=helpers.d.cts.map
@@ -1,6 +1,13 @@
1
- import { ContentBlock } from '@modelcontextprotocol/sdk/types';
2
- import { AnyProcedure, inferProcedureOutput, MaybePromise } from '@trpc/server/unstable-core-do-not-import';
3
-
4
- declare function transformMcpProcedure<TProcedure extends AnyProcedure>(procedure: TProcedure, callback: (output: inferProcedureOutput<TProcedure>) => MaybePromise<ContentBlock[]>): TProcedure;
5
-
6
- export { transformMcpProcedure };
1
+ import { MaybePromise, McpToolTransform } from "./types.mjs";
2
+ import { ContentBlock } from "@modelcontextprotocol/server";
3
+ import { AnyTRPCProcedure, inferProcedureOutput } from "@trpc/server";
4
+ //#region src/helpers.d.ts
5
+ /**
6
+ * Wraps a procedure so its MCP tool returns `transform(output)` as content
7
+ * instead of the JSON-serialized output. The procedure itself is unchanged.
8
+ */
9
+ export declare function transformMcpProcedure<TProcedure extends AnyTRPCProcedure>(procedure: TProcedure, transform: (output: inferProcedureOutput<TProcedure>) => MaybePromise<ContentBlock[]>): TProcedure;
10
+ /** @internal Used by `extractToolsFromProcedures`. */
11
+ export declare function getMcpTransform(procedure: AnyTRPCProcedure): McpToolTransform | undefined;
12
+ //#endregion
13
+ //# sourceMappingURL=helpers.d.mts.map
package/dist/helpers.mjs CHANGED
@@ -1,3 +1,18 @@
1
- export { transformMcpProcedure } from './chunk-FIQIIJAT.mjs';
2
- //# sourceMappingURL=helpers.mjs.map
1
+ //#region src/helpers.ts
2
+ const transforms = /* @__PURE__ */ new WeakMap();
3
+ /**
4
+ * Wraps a procedure so its MCP tool returns `transform(output)` as content
5
+ * instead of the JSON-serialized output. The procedure itself is unchanged.
6
+ */
7
+ function transformMcpProcedure(procedure, transform) {
8
+ transforms.set(procedure, transform);
9
+ return procedure;
10
+ }
11
+ /** @internal Used by `extractToolsFromProcedures`. */
12
+ function getMcpTransform(procedure) {
13
+ return transforms.get(procedure);
14
+ }
15
+ //#endregion
16
+ export { getMcpTransform, transformMcpProcedure };
17
+
3
18
  //# sourceMappingURL=helpers.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"helpers.mjs"}
1
+ {"version":3,"file":"helpers.mjs","names":[],"sources":["../src/helpers.ts"],"sourcesContent":["import type { ContentBlock } from \"@modelcontextprotocol/server\";\nimport type { AnyTRPCProcedure, inferProcedureOutput } from \"@trpc/server\";\n\nimport type { MaybePromise, McpToolTransform } from \"./types\";\n\n// Keyed by procedure instead of stored in meta: procedures built from the same\n// base procedure share one `meta.mcp` object, so writing to it would leak the\n// transform into sibling procedures.\nconst transforms = new WeakMap<AnyTRPCProcedure, McpToolTransform>();\n\n/**\n * Wraps a procedure so its MCP tool returns `transform(output)` as content\n * instead of the JSON-serialized output. The procedure itself is unchanged.\n */\nexport function transformMcpProcedure<TProcedure extends AnyTRPCProcedure>(\n procedure: TProcedure,\n transform: (\n output: inferProcedureOutput<TProcedure>,\n ) => MaybePromise<ContentBlock[]>,\n): TProcedure {\n // The map only hands this transform the output of `procedure`.\n transforms.set(procedure, transform as McpToolTransform);\n return procedure;\n}\n\n/** @internal Used by `extractToolsFromProcedures`. */\nexport function getMcpTransform(procedure: AnyTRPCProcedure) {\n return transforms.get(procedure);\n}\n"],"mappings":";AAQA,MAAM,6BAAa,IAAI,QAA4C;;;;;AAMnE,SAAgB,sBACd,WACA,WAGY;CAEZ,WAAW,IAAI,WAAW,SAA6B;CACvD,OAAO;AACT;;AAGA,SAAgB,gBAAgB,WAA6B;CAC3D,OAAO,WAAW,IAAI,SAAS;AACjC"}
package/dist/index.cjs ADDED
@@ -0,0 +1,9 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_helpers = require("./helpers.cjs");
3
+ const require_tools = require("./tools.cjs");
4
+ const require_server = require("./server.cjs");
5
+ require("./types.cjs");
6
+ exports.createMcpServer = require_server.createMcpServer;
7
+ exports.extractToolsFromProcedures = require_tools.extractToolsFromProcedures;
8
+ exports.registerTrpcTools = require_tools.registerTrpcTools;
9
+ exports.transformMcpProcedure = require_helpers.transformMcpProcedure;