What version of Effect is running?
4.0.0-rc.115 (also current main, packages/effect/src/unstable/ai/McpServer.ts and Toolkit.ts)
What steps can reproduce the bug?
Register a tool with a struct parameter schema through McpServer.toolkit and call it with an extra, unknown key (for example a misspelled parameter).
import { Effect, Layer, Schema } from "effect"
import { McpServer, Tool, Toolkit } from "effect/unstable/ai"
const Echo = Tool.make("echo", {
parameters: { text: Schema.String, limit: Schema.optionalKey(Schema.Number) },
success: Schema.String
})
const toolkit = Toolkit.make(Echo)
const ToolkitLayer = toolkit.toLayer({
echo: ({ text }) => Effect.succeed(text)
})
// Serve over stdio with McpServer.layerStdio and call:
// { "method": "tools/call", "params": { "name": "echo",
// "arguments": { "text": "hi", "limti": 5 } } }
What is the expected behavior?
Some way for the server to reject the call, since limti is not an accepted parameter. Either:
McpServer honours the existing Tool.StrictJsonSchema annotation: when a tool is strict, tools/list serves additionalProperties: false on every object level of inputSchema, and tools/call decodes with onExcessProperty: "error" and returns the same InvalidParams / isError path used for a wrong type; or
McpServer.toolkit (or Toolkit.toLayer) accepts Schema parse options so a server can opt in.
What do you see instead?
The call succeeds. Toolkit.ts decodes parameters with a bare Schema.decodeUnknownEffect(tool.parametersSchema) (line 254), so Schema's default onExcessProperty: "ignore" silently drops limti, and the handler runs with limit unset. The served inputSchema has no additionalProperties, so clients cannot detect the problem either.
Tool.StrictJsonSchema exists but is only consulted by LLM provider clients (it maps to OpenAI's strict: true); McpServer never reads it.
Additional information
This matters more for an MCP server than for an ordinary API: the caller is a model that cannot see that a key was dropped, so a typo turns into a silently different tool call with a default value. We worked around it with a custom registration over McpServer.McpServer.addTool that walks the raw payload for unknown keys and rewrites the served schema with additionalProperties: false; happy to upstream that shape if option 1 is the preferred direction.
Related but distinct: #6355 is about a client rejecting additionalProperties in a served schema; this issue is about the server accepting keys it never declared.
What version of Effect is running?
4.0.0-rc.115 (also current
main,packages/effect/src/unstable/ai/McpServer.tsandToolkit.ts)What steps can reproduce the bug?
Register a tool with a struct parameter schema through
McpServer.toolkitand call it with an extra, unknown key (for example a misspelled parameter).What is the expected behavior?
Some way for the server to reject the call, since
limtiis not an accepted parameter. Either:McpServerhonours the existingTool.StrictJsonSchemaannotation: when a tool is strict,tools/listservesadditionalProperties: falseon every object level ofinputSchema, andtools/calldecodes withonExcessProperty: "error"and returns the sameInvalidParams/isErrorpath used for a wrong type; orMcpServer.toolkit(orToolkit.toLayer) acceptsSchemaparse options so a server can opt in.What do you see instead?
The call succeeds.
Toolkit.tsdecodes parameters with a bareSchema.decodeUnknownEffect(tool.parametersSchema)(line 254), so Schema's defaultonExcessProperty: "ignore"silently dropslimti, and the handler runs withlimitunset. The servedinputSchemahas noadditionalProperties, so clients cannot detect the problem either.Tool.StrictJsonSchemaexists but is only consulted by LLM provider clients (it maps to OpenAI'sstrict: true);McpServernever reads it.Additional information
This matters more for an MCP server than for an ordinary API: the caller is a model that cannot see that a key was dropped, so a typo turns into a silently different tool call with a default value. We worked around it with a custom registration over
McpServer.McpServer.addToolthat walks the raw payload for unknown keys and rewrites the served schema withadditionalProperties: false; happy to upstream that shape if option 1 is the preferred direction.Related but distinct: #6355 is about a client rejecting
additionalPropertiesin a served schema; this issue is about the server accepting keys it never declared.