diff --git a/packages/core/src/types/types.ts b/packages/core/src/types/types.ts index f3e1b92a8..bf89cf732 100644 --- a/packages/core/src/types/types.ts +++ b/packages/core/src/types/types.ts @@ -2384,11 +2384,6 @@ type Flatten = T extends Primitive type Infer = Flatten>; -/** - * Headers that are compatible with both Node.js and the browser. - */ -export type IsomorphicHeaders = Record; - /** * Information about the incoming request. */ @@ -2396,7 +2391,7 @@ export interface RequestInfo { /** * The headers of the request. */ - headers: IsomorphicHeaders; + headers: Headers; } /** diff --git a/packages/middleware/node/test/streamableHttp.test.ts b/packages/middleware/node/test/streamableHttp.test.ts index b406b80c0..5f865ef49 100644 --- a/packages/middleware/node/test/streamableHttp.test.ts +++ b/packages/middleware/node/test/streamableHttp.test.ts @@ -12,13 +12,13 @@ import type { JSONRPCResultResponse, RequestId } from '@modelcontextprotocol/core'; +import type { EventId, EventStore, StreamId } from '@modelcontextprotocol/server'; +import { McpServer } from '@modelcontextprotocol/server'; import type { ZodMatrixEntry } from '@modelcontextprotocol/test-helpers'; import { listenOnRandomPort, zodTestMatrix } from '@modelcontextprotocol/test-helpers'; +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; import { NodeStreamableHTTPServerTransport } from '../src/streamableHttp.js'; -import { McpServer } from '@modelcontextprotocol/server'; -import type { EventId, EventStore, StreamId } from '@modelcontextprotocol/server'; -import { describe, expect, beforeEach, afterEach, it } from 'vitest'; async function getFreePort() { return new Promise(res => { @@ -402,10 +402,15 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { 'A simple test tool with request info', { name: z.string().describe('Name to greet') }, async ({ name }, { requestInfo }): Promise => { + // Convert Headers object to plain object for JSON serialization + // Headers is a Web API class that doesn't serialize with JSON.stringify + const serializedRequestInfo = { + headers: Object.fromEntries(requestInfo?.headers ?? new Headers()) + }; return { content: [ { type: 'text', text: `Hello, ${name}!` }, - { type: 'text', text: `${JSON.stringify(requestInfo)}` } + { type: 'text', text: `${JSON.stringify(serializedRequestInfo)}` } ] }; } diff --git a/packages/server/src/server/server.ts b/packages/server/src/server/server.ts index 8132e342b..c0e0541e8 100644 --- a/packages/server/src/server/server.ts +++ b/packages/server/src/server/server.ts @@ -168,7 +168,7 @@ export class Server< if (this._capabilities.logging) { this.setRequestHandler(SetLevelRequestSchema, async (request, extra) => { const transportSessionId: string | undefined = - extra.sessionId || (extra.requestInfo?.headers['mcp-session-id'] as string) || undefined; + extra.sessionId || (extra.requestInfo?.headers.get('mcp-session-id') as string) || undefined; const { level } = request.params; const parseResult = LoggingLevelSchema.safeParse(level); if (parseResult.success) { diff --git a/packages/server/src/server/streamableHttp.ts b/packages/server/src/server/streamableHttp.ts index 7034ce64a..19360310e 100644 --- a/packages/server/src/server/streamableHttp.ts +++ b/packages/server/src/server/streamableHttp.ts @@ -596,7 +596,7 @@ export class WebStandardStreamableHTTPServerTransport implements Transport { // Build request info from headers const requestInfo: RequestInfo = { - headers: Object.fromEntries(req.headers.entries()) + headers: req.headers }; let rawMessage;