Skip to content

Commit a2558ec

Browse files
fix: use Object.hasOwn in isRequestMethod/isNotificationMethod to avoid prototype-chain false positives
1 parent 683fe35 commit a2558ec

File tree

2 files changed

+9
-2
lines changed

2 files changed

+9
-2
lines changed

packages/core/src/types/schemas.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2213,14 +2213,14 @@ const notificationSchemas = buildSchemaMap([...ClientNotificationSchema.options,
22132213
* Type predicate: returns true if `method` is a standard MCP request method.
22142214
*/
22152215
export function isRequestMethod(method: string): method is RequestMethod {
2216-
return method in requestSchemas;
2216+
return Object.hasOwn(requestSchemas, method);
22172217
}
22182218

22192219
/**
22202220
* Type predicate: returns true if `method` is a standard MCP notification method.
22212221
*/
22222222
export function isNotificationMethod(method: string): method is NotificationMethod {
2223-
return method in notificationSchemas;
2223+
return Object.hasOwn(notificationSchemas, method);
22242224
}
22252225

22262226
/**

packages/core/test/shared/customMethods.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,13 @@ describe('custom request handlers', () => {
7676
expect(() => server.removeCustomRequestHandler('tools/list')).toThrow(/standard MCP request method/);
7777
});
7878

79+
test('collision guard: does NOT trigger on Object.prototype keys', () => {
80+
for (const m of ['toString', 'constructor', 'hasOwnProperty', '__proto__']) {
81+
expect(() => server.setCustomRequestHandler(m, z.object({}), () => ({}))).not.toThrow();
82+
expect(() => server.setCustomNotificationHandler(m, z.object({}), () => {})).not.toThrow();
83+
}
84+
});
85+
7986
test('removeCustomRequestHandler -> subsequent request fails MethodNotFound', async () => {
8087
server.setCustomRequestHandler('acme/search', SearchParams, () => ({ hits: [], total: 0 }));
8188
await client.sendCustomRequest('acme/search', { query: 'x' }, SearchResult);

0 commit comments

Comments
 (0)