Skip to content

Commit 64ff731

Browse files
corvid-agentclaude
andcommitted
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 <noreply@anthropic.com>
1 parent 65bbcea commit 64ff731

3 files changed

Lines changed: 64 additions & 10 deletions

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+
Fix `registerCapabilities` to properly register the `logging/setLevel` request handler when logging capability is added after construction

packages/server/src/server/server.ts

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -115,16 +115,7 @@ export class Server extends Protocol<ServerContext> {
115115
this.setNotificationHandler('notifications/initialized', () => this.oninitialized?.());
116116

117117
if (this._capabilities.logging) {
118-
this.setRequestHandler('logging/setLevel', async (request, ctx) => {
119-
const transportSessionId: string | undefined =
120-
ctx.sessionId || (ctx.http?.req?.headers.get('mcp-session-id') as string) || undefined;
121-
const { level } = request.params;
122-
const parseResult = parseSchema(LoggingLevelSchema, level);
123-
if (parseResult.success) {
124-
this._loggingLevels.set(transportSessionId, parseResult.data);
125-
}
126-
return {};
127-
});
118+
this.registerLoggingHandler();
128119
}
129120
}
130121

@@ -179,6 +170,27 @@ export class Server extends Protocol<ServerContext> {
179170
return currentLevel ? this.LOG_LEVEL_SEVERITY.get(level)! < this.LOG_LEVEL_SEVERITY.get(currentLevel)! : false;
180171
};
181172

173+
private _loggingHandlerRegistered = false;
174+
175+
private registerLoggingHandler(): void {
176+
if (this._loggingHandlerRegistered) {
177+
return;
178+
}
179+
180+
this.setRequestHandler('logging/setLevel', async (request, ctx) => {
181+
const transportSessionId: string | undefined =
182+
ctx.sessionId || (ctx.http?.req?.headers.get('mcp-session-id') as string) || undefined;
183+
const { level } = request.params;
184+
const parseResult = parseSchema(LoggingLevelSchema, level);
185+
if (parseResult.success) {
186+
this._loggingLevels.set(transportSessionId, parseResult.data);
187+
}
188+
return {};
189+
});
190+
191+
this._loggingHandlerRegistered = true;
192+
}
193+
182194
/**
183195
* Registers new capabilities. This can only be called before connecting to a transport.
184196
*
@@ -189,6 +201,10 @@ export class Server extends Protocol<ServerContext> {
189201
throw new SdkError(SdkErrorCode.AlreadyConnected, 'Cannot register capabilities after connecting to transport');
190202
}
191203
this._capabilities = mergeCapabilities(this._capabilities, capabilities);
204+
205+
if (this._capabilities.logging) {
206+
this.registerLoggingHandler();
207+
}
192208
}
193209

194210
/**

test/integration/test/server.test.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1303,6 +1303,39 @@ test('should only allow setRequestHandler for declared capabilities', () => {
13031303
}).toThrow(/^Server does not support logging/);
13041304
});
13051305

1306+
test('should register logging/setLevel handler when logging capability is added via registerCapabilities', async () => {
1307+
const server = new Server(
1308+
{
1309+
name: 'test server',
1310+
version: '1.0'
1311+
}
1312+
);
1313+
1314+
// Register logging capability after construction
1315+
server.registerCapabilities({ logging: {} });
1316+
1317+
const client = new Client(
1318+
{
1319+
name: 'test client',
1320+
version: '1.0'
1321+
}
1322+
);
1323+
1324+
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
1325+
await Promise.all([client.connect(clientTransport), server.connect(serverTransport)]);
1326+
1327+
// Client sets logging level - should work without error
1328+
await expect(client.setLoggingLevel('warning')).resolves.not.toThrow();
1329+
1330+
// Sending a log message should also work
1331+
await expect(
1332+
server.sendLoggingMessage({
1333+
level: 'warning',
1334+
data: 'Test log message'
1335+
})
1336+
).resolves.not.toThrow();
1337+
});
1338+
13061339
test('should handle server cancelling a request', async () => {
13071340
const server = new Server(
13081341
{

0 commit comments

Comments
 (0)