From 94ffb7922c09d413ab9d12b7c563be7b90e470dd Mon Sep 17 00:00:00 2001 From: Jerome Swannack Date: Mon, 26 Jan 2026 15:23:39 +0000 Subject: [PATCH] Log client capabilities and extensions on initialize requests Add INFO-level logging to both the stateful SHTTP handler and the stateless example-apps handler to show the full client capabilities sent during MCP initialization, including any extensions like io.modelcontextprotocol/ui. This helps verify that clients are correctly sending UI extension capabilities during the initialization handshake. --- src/modules/example-apps/index.ts | 19 +++++++++++++++++++ src/modules/mcp/handlers/shttp.ts | 13 +++++++++---- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/modules/example-apps/index.ts b/src/modules/example-apps/index.ts index 1ac4576..b4a2248 100644 --- a/src/modules/example-apps/index.ts +++ b/src/modules/example-apps/index.ts @@ -16,6 +16,7 @@ import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { ITokenValidator } from '../../interfaces/auth-validator.js'; import { AuthInfo } from '@modelcontextprotocol/sdk/server/auth/types.js'; +import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js'; // Import createServer from each example package (compiled JS) // All packages are published on the public npm registry @@ -115,6 +116,24 @@ export class ExampleAppsModule { } try { + // Log initialization requests to inspect client capabilities/extensions + if (isInitializeRequest(req.body)) { + const initParams = req.body?.params; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const capabilities = initParams?.capabilities as Record | undefined; + console.log(JSON.stringify({ + severity: 'INFO', + message: `=== MCP INITIALIZE REQUEST (${slug}) ===`, + timestamp: new Date().toISOString(), + slug, + clientInfo: initParams?.clientInfo, + protocolVersion: initParams?.protocolVersion, + capabilities, + hasExtensions: !!capabilities?.extensions, + extensions: capabilities?.extensions, + })); + } + // Create fresh server and transport for each request (stateless mode) const server = createServer(); const transport = new StreamableHTTPServerTransport({ diff --git a/src/modules/mcp/handlers/shttp.ts b/src/modules/mcp/handlers/shttp.ts index a7a58e2..27f3fba 100644 --- a/src/modules/mcp/handlers/shttp.ts +++ b/src/modules/mcp/handlers/shttp.ts @@ -105,11 +105,16 @@ export async function handleStreamableHTTP(req: Request, res: Response) { shttpTransport = await getShttpTransport(sessionId, onsessionclosed, isGetRequest); } else if (isInitializeRequest(req.body)) { // New initialization request - use JSON response mode - logger.debug('Processing initialize request', { - body: req.body, + const initParams = req.body?.params; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const capabilities = initParams?.capabilities as Record | undefined; + logger.info('=== MCP INITIALIZE REQUEST ===', { userId, - headerSessionId: sessionId, // This is the sessionId from header (should be undefined for init) - isInitializeRequest: true + clientInfo: initParams?.clientInfo, + protocolVersion: initParams?.protocolVersion, + capabilities, + hasExtensions: !!capabilities?.extensions, + extensions: capabilities?.extensions, }); const onsessioninitialized = async (sessionId: string) => {