fix request metadata HTTP method handling (#409)
This commit is contained in:
parent
da56f6631c
commit
a865118206
2 changed files with 74 additions and 2 deletions
|
|
@ -6,7 +6,10 @@ import {
|
|||
} from './auth/test_helpers/testClient';
|
||||
import { getHandler } from '../../../examples/clients/typescript/everything-client';
|
||||
import { getScenario } from '../index';
|
||||
import { DECLARED_CHECK_IDS } from './request-metadata';
|
||||
import {
|
||||
DECLARED_CHECK_IDS,
|
||||
RequestMetadataScenario
|
||||
} from './request-metadata';
|
||||
|
||||
// A bad client that does not send _meta
|
||||
async function badClient(serverUrl: string) {
|
||||
|
|
@ -246,6 +249,48 @@ describe('request-metadata client scenario — client never connects', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('request-metadata client scenario — HTTP handling', () => {
|
||||
test.each(['GET', 'DELETE'])(
|
||||
'rejects an empty-body %s request without parsing it as JSON',
|
||||
async (method) => {
|
||||
const scenario = new RequestMetadataScenario();
|
||||
const { serverUrl } = await scenario.start(testScenarioContext());
|
||||
|
||||
try {
|
||||
const response = await fetch(serverUrl, { method });
|
||||
|
||||
expect(response.status).toBe(405);
|
||||
expect(response.headers.get('allow')).toBe('POST');
|
||||
expect(await response.text()).toBe('Method Not Allowed');
|
||||
} finally {
|
||||
await scenario.stop();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
test('returns a JSON-RPC parse error for malformed POST bodies', async () => {
|
||||
const scenario = new RequestMetadataScenario();
|
||||
const { serverUrl } = await scenario.start(testScenarioContext());
|
||||
|
||||
try {
|
||||
const response = await fetch(serverUrl, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: '{'
|
||||
});
|
||||
|
||||
expect(response.status).toBe(400);
|
||||
expect(await response.json()).toMatchObject({
|
||||
jsonrpc: '2.0',
|
||||
id: null,
|
||||
error: { code: -32700 }
|
||||
});
|
||||
} finally {
|
||||
await scenario.stop();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('request-metadata client scenario — negative tests', () => {
|
||||
test('client fails when omitting _meta', async () => {
|
||||
const runner = new InlineClientRunner(badClient);
|
||||
|
|
|
|||
|
|
@ -129,12 +129,39 @@ export class RequestMetadataScenario implements Scenario {
|
|||
req: http.IncomingMessage,
|
||||
res: http.ServerResponse
|
||||
): void {
|
||||
// This scenario only evaluates the metadata attached to POST requests.
|
||||
// Clients may probe a Streamable HTTP endpoint with an empty-body GET
|
||||
// before sending MCP requests, so reject unsupported methods before
|
||||
// attempting to parse a JSON-RPC body.
|
||||
if (req.method !== 'POST') {
|
||||
res.writeHead(405, { Allow: 'POST' });
|
||||
res.end('Method Not Allowed');
|
||||
return;
|
||||
}
|
||||
|
||||
let body = '';
|
||||
req.on('data', (chunk) => {
|
||||
body += chunk.toString();
|
||||
});
|
||||
req.on('end', () => {
|
||||
const request = JSON.parse(body);
|
||||
let request;
|
||||
try {
|
||||
request = JSON.parse(body);
|
||||
} catch (error) {
|
||||
res.writeHead(400, { 'Content-Type': 'application/json' });
|
||||
res.end(
|
||||
JSON.stringify({
|
||||
jsonrpc: '2.0',
|
||||
id: null,
|
||||
error: {
|
||||
code: -32700,
|
||||
message: `Parse error: ${String(error)}`
|
||||
}
|
||||
})
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
this.requestsObserved++;
|
||||
|
||||
// Extract version and headers
|
||||
|
|
|
|||
Loading…
Reference in a new issue