Skip to content

Commit 07d4aa0

Browse files
committed
derive MCP output schema from SDK
1 parent 445ae35 commit 07d4aa0

4 files changed

Lines changed: 52 additions & 24 deletions

File tree

bun.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/plugins/mcp/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@
6666
"@executor-js/config": "workspace:*",
6767
"@executor-js/sdk": "workspace:*",
6868
"@modelcontextprotocol/sdk": "^1.29.0",
69-
"effect": "catalog:"
69+
"effect": "catalog:",
70+
"zod": "^4.3.6"
7071
},
7172
"devDependencies": {
7273
"@effect/atom-react": "catalog:",
@@ -78,8 +79,7 @@
7879
"bun-types": "catalog:",
7980
"react": "catalog:",
8081
"tsup": "catalog:",
81-
"vitest": "catalog:",
82-
"zod": "^4.3.6"
82+
"vitest": "catalog:"
8383
},
8484
"peerDependencies": {
8585
"@effect/atom-react": "catalog:",

packages/plugins/mcp/src/sdk/elicitation.test.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,30 @@ describe("MCP elicitation (end-to-end)", () => {
161161
},
162162
required: ["content"],
163163
});
164-
expect(schema?.outputTypeScript).toContain("content: unknown[]");
165-
expect(schema?.outputTypeScript).toContain("structuredContent?: unknown");
164+
const outputSchema = schema?.outputSchema as {
165+
readonly properties: {
166+
readonly content: {
167+
readonly items: {
168+
readonly anyOf: readonly unknown[];
169+
};
170+
};
171+
};
172+
};
173+
expect(outputSchema.properties.content.items.anyOf).toEqual(
174+
expect.arrayContaining([
175+
expect.objectContaining({
176+
properties: expect.objectContaining({
177+
type: { const: "text", type: "string" },
178+
text: { type: "string" },
179+
}),
180+
required: ["type", "text"],
181+
}),
182+
]),
183+
);
184+
expect(schema?.outputTypeScript).toContain('type: "text"');
185+
expect(schema?.outputTypeScript).toContain(
186+
"structuredContent?: { [k: string]: unknown; }",
187+
);
166188

167189
const result = yield* executor.tools.invoke(
168190
simpleEcho.id,

packages/plugins/mcp/src/sdk/plugin.ts

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import {
1414
import type { HttpClient } from "effect/unstable/http";
1515

1616
import type { OAuthClientProvider } from "@modelcontextprotocol/sdk/client/auth.js";
17+
import { CallToolResultSchema } from "@modelcontextprotocol/sdk/types.js";
18+
import * as z from "zod/v4";
1719

1820
import {
1921
type CredentialBindingRef,
@@ -319,25 +321,29 @@ const normalizeNamespace = (config: McpSourceConfig): string =>
319321
command: config.transport === "stdio" ? config.command : undefined,
320322
});
321323

322-
const mcpCallToolResultOutputSchema = (
323-
structuredContentSchema?: unknown,
324-
): Record<string, unknown> => ({
325-
type: "object",
326-
properties: {
327-
content: {
328-
type: "array",
329-
items: {},
330-
},
331-
structuredContent: structuredContentSchema ?? {},
332-
isError: { const: false },
333-
_meta: {
334-
type: "object",
335-
additionalProperties: {},
324+
type JsonSchemaObject = Record<string, unknown> & {
325+
readonly properties?: Record<string, unknown>;
326+
};
327+
328+
const McpCallToolResultJsonSchema = z.toJSONSchema(CallToolResultSchema) as JsonSchemaObject;
329+
330+
const mcpCallToolResultOutputSchema = (structuredContentSchema?: unknown): JsonSchemaObject => {
331+
const defaultStructuredContentSchema =
332+
McpCallToolResultJsonSchema.properties?.structuredContent ?? {};
333+
334+
return {
335+
...McpCallToolResultJsonSchema,
336+
properties: {
337+
...McpCallToolResultJsonSchema.properties,
338+
structuredContent:
339+
structuredContentSchema === undefined
340+
? defaultStructuredContentSchema
341+
: structuredContentSchema,
342+
isError: { const: false },
336343
},
337-
},
338-
required: structuredContentSchema === undefined ? ["content"] : ["content", "structuredContent"],
339-
additionalProperties: {},
340-
});
344+
required: structuredContentSchema === undefined ? ["content"] : ["content", "structuredContent"],
345+
};
346+
};
341347

342348
const toBinding = (entry: McpToolManifestEntry): McpToolBinding =>
343349
McpToolBinding.make({

0 commit comments

Comments
 (0)