From 82ecef68c971cd38f117df4feec26dfa5c422cb5 Mon Sep 17 00:00:00 2001 From: Shawn Kuang Date: Thu, 6 Aug 2026 18:52:54 -0700 Subject: [PATCH 1/2] feat: add outputSchema support for local MCP tools ### Description Introduced the `outputSchema` property to the MCP `ServerTool` interface and the `tool()` builder function, enabling local tools to declare typed output schemas. Since the `@modelcontextprotocol/sdk` natively supports `outputSchema`, remote server schemas are automatically validated and forwarded. ### Scenarios Tested - Verified that local tools constructed using `tool()` builder accept and compile with `outputSchema`. - Verified that `outputSchema` gets processed and cleaned correctly in unit tests. - Verified that `OneMcpServer.listTools()` successfully parses and retains the `outputSchema` returned by remote servers. ### Sample Commands npx mocha src/mcp/tool.spec.ts src/mcp/onemcp/onemcp_server.spec.ts --- CHANGELOG.md | 1 + src/mcp/onemcp/onemcp_server.spec.ts | 2 ++ src/mcp/tool.spec.ts | 3 +++ src/mcp/tool.ts | 20 ++++++++++++++++---- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0752cf767f3..a7682cfdb30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ +- Added `outputSchema` support for local MCP tools. - Added `appcheck:providers:list`, `appcheck:providers:get` and `appcheck:providers:set` to configure App Check attestation providers for an app. - Added `appcheck:apps:list` to show every app with its configured App Check providers. - Added web app support for Crashlytics MCP tools and prompts. diff --git a/src/mcp/onemcp/onemcp_server.spec.ts b/src/mcp/onemcp/onemcp_server.spec.ts index 5f82b1d9145..19ce8e9b66f 100644 --- a/src/mcp/onemcp/onemcp_server.spec.ts +++ b/src/mcp/onemcp/onemcp_server.spec.ts @@ -33,6 +33,7 @@ describe("OneMcpServer", () => { name: "test_tool", description: "A test tool", inputSchema: { type: "object", properties: {} }, + outputSchema: { type: "object", properties: { status: { type: "string" } } }, }; clientRequestStub.resolves({ body: { @@ -47,6 +48,7 @@ describe("OneMcpServer", () => { expect(tools).to.have.length(1); expect(tools[0].mcp.name).to.equal("auth_test_tool"); expect(tools[0].mcp.description).to.equal(mockMcpTool.description); + expect(tools[0].mcp.outputSchema).to.deep.equal(mockMcpTool.outputSchema); expect(tools[0].mcp._meta).to.deep.equal({ requiresAuth: false, requiresProject: true, diff --git a/src/mcp/tool.spec.ts b/src/mcp/tool.spec.ts index 5e4457cf9d8..eb3f2cb8653 100644 --- a/src/mcp/tool.spec.ts +++ b/src/mcp/tool.spec.ts @@ -33,12 +33,15 @@ describe("tool", () => { name: "test_tool", description: "A test tool", inputSchema: z.object({}), + outputSchema: z.object({ result: z.string() }), }, testFn, ); expect(testTool.mcp.name).to.equal("test_tool"); expect(testTool.mcp.description).to.equal("A test tool"); + expect(testTool.mcp.outputSchema).to.not.be.undefined; + expect(testTool.mcp.outputSchema.properties.result.type).to.equal("string"); expect(testTool.fn).to.equal(testFn); }); diff --git a/src/mcp/tool.ts b/src/mcp/tool.ts index 99af0298d8e..779d049eef2 100644 --- a/src/mcp/tool.ts +++ b/src/mcp/tool.ts @@ -19,11 +19,15 @@ export type ServerToolMeta = { }; }; -export interface ServerTool { +export interface ServerTool< + InputSchema extends ZodTypeAny = z.ZodAny, + OutputSchema extends ZodTypeAny = z.ZodAny, +> { mcp: { name: string; description?: string; inputSchema: any; + outputSchema?: any; annotations?: { title?: string; @@ -47,13 +51,14 @@ export interface ServerTool { isAvailable: (ctx: McpContext) => Promise; } -export function tool( +export function tool( feature: ServerFeature, - options: Omit["mcp"], "inputSchema"> & { + options: Omit["mcp"], "inputSchema" | "outputSchema"> & { inputSchema: InputSchema; + outputSchema?: OutputSchema; isAvailable?: (ctx: McpContext) => Promise; }, - fn: ServerTool["fn"], + fn: ServerTool["fn"], ): ServerTool { const { isAvailable, ...mcpOptions } = options; @@ -63,6 +68,13 @@ export function tool( inputSchema: cleanSchema( z.toJSONSchema(options.inputSchema, { target: "draft-7", io: "input" }), ), + ...(options.outputSchema + ? { + outputSchema: cleanSchema( + z.toJSONSchema(options.outputSchema, { target: "draft-7", io: "output" }), + ), + } + : {}), }, fn, isAvailable: (ctx: McpContext) => { From bbc3ad6e4fe9e3389798c32a4a9b0538ee7ffa97 Mon Sep 17 00:00:00 2001 From: Shawn Kuang Date: Fri, 7 Aug 2026 10:29:43 -0700 Subject: [PATCH 2/2] refactor: remove unused OutputSchema from ServerTool interface --- src/mcp/tool.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/mcp/tool.ts b/src/mcp/tool.ts index 779d049eef2..1cef8f58cbb 100644 --- a/src/mcp/tool.ts +++ b/src/mcp/tool.ts @@ -19,10 +19,7 @@ export type ServerToolMeta = { }; }; -export interface ServerTool< - InputSchema extends ZodTypeAny = z.ZodAny, - OutputSchema extends ZodTypeAny = z.ZodAny, -> { +export interface ServerTool { mcp: { name: string; description?: string; @@ -53,12 +50,12 @@ export interface ServerTool< export function tool( feature: ServerFeature, - options: Omit["mcp"], "inputSchema" | "outputSchema"> & { + options: Omit["mcp"], "inputSchema" | "outputSchema"> & { inputSchema: InputSchema; outputSchema?: OutputSchema; isAvailable?: (ctx: McpContext) => Promise; }, - fn: ServerTool["fn"], + fn: ServerTool["fn"], ): ServerTool { const { isAvailable, ...mcpOptions } = options;