fix(server): validate Content-Type by parsed media type instead of substring match (#2441)

This commit is contained in:
Felix Weinberger 2026-07-06 20:29:58 +01:00 • committed by GitHub
commit 561c6d8345
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 452 additions and 20 deletions

View file

@ -10,6 +10,7 @@ import {
isJSONRPCResultResponse,
isModernProtocolVersion,
JSONRPCMessageSchema,
mediaTypeEssence,
normalizeHeaders,
PROTOCOL_VERSION_META_KEY,
SdkError,
@ -1080,11 +1081,12 @@ export class StreamableHTTPClientTransport implements Transport {
const hasRequests = messages.some(msg => 'method' in msg && 'id' in msg && msg.id !== undefined);
// Check the response type
// Check the response type (parsed media type — see mediaTypeEssence)
const contentType = response.headers.get('content-type');
const responseMediaType = mediaTypeEssence(contentType);
if (hasRequests) {
if (contentType?.includes('text/event-stream')) {
if (responseMediaType === 'text/event-stream') {
// Handle SSE stream responses for requests
// We use the same handler as standalone streams, which now supports
// reconnection with the last event ID
@ -1097,7 +1099,7 @@ export class StreamableHTTPClientTransport implements Transport {
},
false
);
} else if (contentType?.includes('application/json')) {
} else if (responseMediaType === 'application/json') {
// For non-streaming servers, we might get direct JSON responses
const data = await response.json();
const responseMessages = Array.isArray(data)

View file

@ -1,4 +1,5 @@
import type { FetchLike } from '@modelcontextprotocol/core-internal';
import { isJsonContentType } from '@modelcontextprotocol/core-internal';
import type { Mocked, MockedFunction, MockInstance } from 'vitest';
import type { OAuthClientProvider } from '../../src/client/auth';
@ -1016,7 +1017,7 @@ describe('createMiddleware', () => {
const transformMiddleware = createMiddleware(async (next, input, init) => {
const response = await next(input, init);
if (response.headers.get('content-type')?.includes('application/json')) {
if (isJsonContentType(response.headers.get('content-type'))) {
const data = (await response.json()) as Record<string, unknown>;
const transformed = { ...data, timestamp: 123_456_789 };