Skip to content

handlePostMessage fails when reqBody is not passed #223

Open
@Rajesh-Narayanappa87

Description

@Rajesh-Narayanappa87

Describe the bug
When creating mcp using SSE server, await transport.handlePostMessage(req, res); expects reqbody. Not providing is failing run

Machine config:
Tried with node 20 and 22.
Mac M3
@modelcontextprotocol/sdk - 1.7.0

To Reproduce
Steps to reproduce the behavior:

  1. Run node index.js to run mcp server
  2. Run node client.js to run mcp client

index.js


  // Create an MCP server
  const server = new McpServer({
    name: "Demo",
    version: "1.0.0",
    });
  
  // Add an addition tool
  server.tool("add", { a: z.number(), b: z.number() }, async ({ a, b}) => ({
    content: [{ type: "text", text: String(a + b) }],
  }));
  
  
  const axiosInstance = axios.create({
      httpsAgent: new https.Agent({
        rejectUnauthorized: false,
      }),
    });
  
  server.tool("pullTestResults", { a: z.number() }, async ({ a }) => {
    let result = await axiosInstance.get(`https://xyz/test-case/api-result?count=${a}`);
    return {
      content: [{ type: "text", text: JSON.stringify(result.data) }],
    };
  });
  
  
  const app = express();
  app.use(express.json());
  
  const transports = {};


  app.get("/sse", async (req, res) => {
    const transport = new SSEServerTransport('/messages', res);
    transports[transport.sessionId] = transport;
    res.on("close", () => {
      delete transports[transport.sessionId];
    });
    await server.connect(transport);
  });
  
  app.post("/messages", async (req, res) => {
    const sessionId = req.query.sessionId;
    const transport = transports[sessionId];
    if (transport) {
      await transport.handlePostMessage(req, res);
    } else {
      res.status(400).send('No transport found for sessionId');
    }
  });
  
  const port = 3000;
  app.listen(port, () => {
    console.log(`HTTP server listening on port ${port}`);
  });

client.js


// Create an MCP client
const client = new Client(
    {
  name: "DemoClient",
  version: "1.0.0"
    },
    {
        capabilities: {}
      }
);

const transport = new SSEClientTransport(new URL(`http://localhost:3000/sse`));

// Connect to the server using stdio transport
await client.connect(transport);

const tools = await client.listTools();

console.log(tools)


const resp = await client.callTool({
    name: "pullTestResults",
    arguments: {
      a: "2024-12-04_18-13-21-190087751"
    }
  })

  console.log(resp)

Issue exist in both client or api way.

Api way

curl --location 'http://localhost:3000/messages?sessionId=40652e8f-2633-40b8-98f8-5258fbbcb06a' \
--header 'Content-Type: application/json' \
--data '{
        "jsonrpc": "2.0",
        "id": "a29ba38d-fed4-49f0-bbba-6c8b1f4606c9",
        "method": "tools/call",
        "params": {
            "name": "pullTestResults",
            "arguments": {
                "a": "2024-12-04_18-13-21-190087751"
            }
        }
        
    }'

Expected behavior
List out tools and execute pullTestResults tool.

Logs

throw new Error(`Error POSTing to endpoint (HTTP ${response.status}): ${text}`);
                      ^

Error: Error POSTing to endpoint (HTTP 400): InternalServerError: stream is not readable

Workaround for this issue is to send reqbody to handlePostMessage function.

..... same as index.js
      await transport.handlePostMessage(req, res, req.body);

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions