Skip to content

Commit 446fb93

Browse files
2sumtechclaude
andcommitted
fix(server): honor logging/setLevel when sendLoggingMessage omits sessionId
The logging/setLevel handler stores the level under the transport's session id, but sendLoggingMessage(params) looked it up under an undefined key. On session-bearing transports (Streamable HTTP, SSE) the client's level was therefore ignored and every message was sent, while the same call filtered correctly on stdio. Default the lookup to the connected transport's session id. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
1 parent 7f7a94c commit 446fb93

3 files changed

Lines changed: 36 additions & 1 deletion

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@modelcontextprotocol/server': patch
3+
---
4+
5+
Make `sendLoggingMessage(params)` honor the level a client set with `logging/setLevel` on session-bearing transports. The `logging/setLevel` handler stores the level under the transport's session id, but `sendLoggingMessage` looked it up under the `sessionId` argument, which is `undefined` when omitted, as in the documented example. On Streamable HTTP and SSE every message was sent regardless of the client's level, while the same call filtered correctly on stdio. When no `sessionId` is passed, the lookup now uses the connected transport's session id. Passing one explicitly works as before.

‎packages/server/src/server/server.ts‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,8 +435,11 @@ export class Server extends Protocol<ServerContext> {
435435
private readonly LOG_LEVEL_SEVERITY = new Map(LoggingLevelSchema.options.map((level, index) => [level, index]));
436436

437437
// Is a message with the given level ignored in the log level set for the given session id?
438+
// Without an explicit session id, use the connected transport's: `logging/setLevel` stored
439+
// the level under it, so on Streamable HTTP or SSE `sendLoggingMessage(params)` would
440+
// otherwise skip the filter the client asked for.
438441
private isMessageIgnored = (level: LoggingLevel, sessionId?: string): boolean => {
439-
const currentLevel = this._loggingLevels.get(sessionId);
442+
const currentLevel = this._loggingLevels.get(sessionId ?? this.transport?.sessionId);
440443
return currentLevel ? this.LOG_LEVEL_SEVERITY.get(level)! < this.LOG_LEVEL_SEVERITY.get(currentLevel)! : false;
441444
};
442445

‎test/integration/test/server.test.ts‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1956,6 +1956,33 @@ test('should respect log level for transport with sessionId', async () => {
19561956
expect(clientTransport.onmessage).toHaveBeenCalled();
19571957
});
19581958

1959+
test('should respect log level for transport with sessionId when sendLoggingMessage omits sessionId', async () => {
1960+
// Session-bearing transports (Streamable HTTP, SSE) store the level set by
1961+
// logging/setLevel under the transport's session id. The documented call
1962+
// `sendLoggingMessage(params)` must honor it, as it does on stdio.
1963+
const server = new Server({ name: 'test server', version: '1.0' }, { capabilities: { logging: {} } });
1964+
const client = new Client({ name: 'test client', version: '1.0' });
1965+
1966+
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
1967+
clientTransport.sessionId = 'test-session-id';
1968+
serverTransport.sessionId = 'test-session-id';
1969+
1970+
await Promise.all([client.connect(clientTransport), server.connect(serverTransport)]);
1971+
await client.setLoggingLevel('warning');
1972+
1973+
const received: string[] = [];
1974+
clientTransport.onmessage = message => {
1975+
if ('method' in message && message.method === 'notifications/message') {
1976+
received.push(message.params?.level as string);
1977+
}
1978+
};
1979+
1980+
await server.sendLoggingMessage({ level: 'debug', data: 'Debug message' });
1981+
await server.sendLoggingMessage({ level: 'warning', data: 'Warning message' });
1982+
1983+
expect(received).toEqual(['warning']);
1984+
});
1985+
19591986
describe('createMcpExpressApp', () => {
19601987
test('should create an Express app', () => {
19611988
const app = createMcpExpressApp();

0 commit comments

Comments
 (0)