From 64ff731fc4d2084b25a52ab13e3171f6ed349d98 Mon Sep 17 00:00:00 2001 From: corvid-agent <0xOpenBytes@gmail.com> Date: Mon, 9 Feb 2026 14:19:45 -0700 Subject: [PATCH 1/2] fix: register logging/setLevel handler when logging capability is added via registerCapabilities When logging capability was added via `registerCapabilities()` instead of the constructor options, the `logging/setLevel` request handler was not being registered, causing setLevel requests to fail silently. Extract the handler registration into a private `registerLoggingHandler()` method with an idempotency guard, and call it from both the constructor and `registerCapabilities()`. Fixes #1464 Co-Authored-By: Claude Opus 4.6 --- .../fix-register-capabilities-logging.md | 5 +++ packages/server/src/server/server.ts | 36 +++++++++++++------ test/integration/test/server.test.ts | 33 +++++++++++++++++ 3 files changed, 64 insertions(+), 10 deletions(-) create mode 100644 .changeset/fix-register-capabilities-logging.md diff --git a/.changeset/fix-register-capabilities-logging.md b/.changeset/fix-register-capabilities-logging.md new file mode 100644 index 000000000..36a4e8c18 --- /dev/null +++ b/.changeset/fix-register-capabilities-logging.md @@ -0,0 +1,5 @@ +--- +'@modelcontextprotocol/server': patch +--- + +Fix `registerCapabilities` to properly register the `logging/setLevel` request handler when logging capability is added after construction diff --git a/packages/server/src/server/server.ts b/packages/server/src/server/server.ts index 613766a58..b21f52747 100644 --- a/packages/server/src/server/server.ts +++ b/packages/server/src/server/server.ts @@ -115,16 +115,7 @@ export class Server extends Protocol { this.setNotificationHandler('notifications/initialized', () => this.oninitialized?.()); if (this._capabilities.logging) { - this.setRequestHandler('logging/setLevel', async (request, ctx) => { - const transportSessionId: string | undefined = - ctx.sessionId || (ctx.http?.req?.headers.get('mcp-session-id') as string) || undefined; - const { level } = request.params; - const parseResult = parseSchema(LoggingLevelSchema, level); - if (parseResult.success) { - this._loggingLevels.set(transportSessionId, parseResult.data); - } - return {}; - }); + this.registerLoggingHandler(); } } @@ -179,6 +170,27 @@ export class Server extends Protocol { return currentLevel ? this.LOG_LEVEL_SEVERITY.get(level)! < this.LOG_LEVEL_SEVERITY.get(currentLevel)! : false; }; + private _loggingHandlerRegistered = false; + + private registerLoggingHandler(): void { + if (this._loggingHandlerRegistered) { + return; + } + + this.setRequestHandler('logging/setLevel', async (request, ctx) => { + const transportSessionId: string | undefined = + ctx.sessionId || (ctx.http?.req?.headers.get('mcp-session-id') as string) || undefined; + const { level } = request.params; + const parseResult = parseSchema(LoggingLevelSchema, level); + if (parseResult.success) { + this._loggingLevels.set(transportSessionId, parseResult.data); + } + return {}; + }); + + this._loggingHandlerRegistered = true; + } + /** * Registers new capabilities. This can only be called before connecting to a transport. * @@ -189,6 +201,10 @@ export class Server extends Protocol { throw new SdkError(SdkErrorCode.AlreadyConnected, 'Cannot register capabilities after connecting to transport'); } this._capabilities = mergeCapabilities(this._capabilities, capabilities); + + if (this._capabilities.logging) { + this.registerLoggingHandler(); + } } /** diff --git a/test/integration/test/server.test.ts b/test/integration/test/server.test.ts index 436b4427a..874286c9c 100644 --- a/test/integration/test/server.test.ts +++ b/test/integration/test/server.test.ts @@ -1303,6 +1303,39 @@ test('should only allow setRequestHandler for declared capabilities', () => { }).toThrow(/^Server does not support logging/); }); +test('should register logging/setLevel handler when logging capability is added via registerCapabilities', async () => { + const server = new Server( + { + name: 'test server', + version: '1.0' + } + ); + + // Register logging capability after construction + server.registerCapabilities({ logging: {} }); + + const client = new Client( + { + name: 'test client', + version: '1.0' + } + ); + + const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair(); + await Promise.all([client.connect(clientTransport), server.connect(serverTransport)]); + + // Client sets logging level - should work without error + await expect(client.setLoggingLevel('warning')).resolves.not.toThrow(); + + // Sending a log message should also work + await expect( + server.sendLoggingMessage({ + level: 'warning', + data: 'Test log message' + }) + ).resolves.not.toThrow(); +}); + test('should handle server cancelling a request', async () => { const server = new Server( { From d25511ffe236276085b842b080758f8a68c65abe Mon Sep 17 00:00:00 2001 From: corvid-agent <0xOpenBytes@gmail.com> Date: Mon, 9 Feb 2026 14:25:38 -0700 Subject: [PATCH 2/2] style: fix prettier formatting in integration test Co-Authored-By: Claude Opus 4.6 --- test/integration/test/server.test.ts | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/test/integration/test/server.test.ts b/test/integration/test/server.test.ts index 874286c9c..9531ec519 100644 --- a/test/integration/test/server.test.ts +++ b/test/integration/test/server.test.ts @@ -1304,22 +1304,18 @@ test('should only allow setRequestHandler for declared capabilities', () => { }); test('should register logging/setLevel handler when logging capability is added via registerCapabilities', async () => { - const server = new Server( - { - name: 'test server', - version: '1.0' - } - ); + const server = new Server({ + name: 'test server', + version: '1.0' + }); // Register logging capability after construction server.registerCapabilities({ logging: {} }); - const client = new Client( - { - name: 'test client', - version: '1.0' - } - ); + const client = new Client({ + name: 'test client', + version: '1.0' + }); const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair(); await Promise.all([client.connect(clientTransport), server.connect(serverTransport)]);