-
Notifications
You must be signed in to change notification settings - Fork 745
Inconsistent handling of inputSchema
when schema is {}
vs undefined
#458
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I am seeing the same behavior for {} and undefined now. Possibly related to #453 |
Just pushed a fix to #453, would you mind checking to see how it affects this issue? (And if it still happens, a repro would be super helpful :) Thanks! |
The 1.11.1 release does fix the issue when the schema is defined as {} (cool) but when you omit the schema definition from the tool it gets defined as EMPTY_OBJECT_JSON_SCHEMA. You can verify this behavior with inspector by running the server below ,connecting over SSE, and running See screenshots showing different behavior when schema is {} vs undefined. Good tool: server.tool(
"crashtest",
`Some Description`,
{},
async (_extra) => {
return {
content: [{ type: "text", text: "did it work?" }]
};
}
); Bad tool: server.tool(
"crashtest",
`Some Description`,
async (_extra) => {
return {
content: [{ type: "text", text: "did it work?" }]
};
}
); test mcp server: import express from "express";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
import { z } from "zod";
const server = new McpServer({
name: "crashtest",
version: "1.0.0"
});
server.tool(
"crashtest",
`Some Description`,
{}, // remove this line to trigger bug
async (_extra) => {
return {
content: [{ type: "text", text: "did it work?" }]
};
}
);
const app = express();
app.use(express.json());
app.use((req, res, next) => {
next();
});
const transports = {
streamable: {} as Record<string, StreamableHTTPServerTransport>,
sse: {} as Record<string, SSEServerTransport>
};
// Streamable HTTP endpoint placeholder
app.all('/mcp', async (req, res) => {
console.log(`[MCP HTTP] ${req.method} ${req.originalUrl}`);
});
// SSE endpoint
app.get('/sse', async (req, res) => {
console.log(`[SSE] New connection from ${req.ip}`);
const transport = new SSEServerTransport('/messages', res);
transports.sse[transport.sessionId] = transport;
res.on("close", () => {
delete transports.sse[transport.sessionId];
});
await server.connect(transport);
});
// Message endpoint
app.post('/messages', async (req, res) => {
const sessionId = req.query.sessionId as string;
const transport = transports.sse[sessionId];
if (transport) {
await transport.handlePostMessage(req, res, req.body);
} else {
res.status(400).send('No transport found for sessionId');
}
});
// Start server
app.listen(8080, () => {
console.log(`Server listening on port 8080`);
}); |
There's a significant and subtle difference in behavior when explicitly defining an empty schema
{}
compared to leaving the schema undefined (undefined
) in tool registration.Current Behavior
When defining a tool, the following two definitions produce distinctly different outcomes:
Case 1: Explicit empty schema (
{}
)EDIT: Seeing same behavior for
{}
andundefined
Case 2: Undefined schema (
undefined
) (supported by overload)Client sees a minimal, non-strict schema:
Explanation
This behavior difference is unexpected because the SDK explicitly supports tool definitions without schemas via the following overload:
The root cause is the current logic in the SDK:
With
EMPTY_OBJECT_JSON_SCHEMA
defined as:Relevant code
The text was updated successfully, but these errors were encountered: