From b7c3b847e89ae4bf28bc9f86da7f3399a6568fa0 Mon Sep 17 00:00:00 2001 From: "Nolann B." <100787331+nolannbiron@users.noreply.github.com> Date: Sat, 27 Jun 2026 09:31:20 +0200 Subject: [PATCH] Prevent insights tracking failures from breaking MCP tool requests (#4346) --- .../[siteData]/~gitbook/mcp/handler.ts | 98 ++++++++++--------- 1 file changed, 52 insertions(+), 46 deletions(-) diff --git a/packages/gitbook/src/app/sites/dynamic/[mode]/[siteURL]/[siteData]/~gitbook/mcp/handler.ts b/packages/gitbook/src/app/sites/dynamic/[mode]/[siteURL]/[siteData]/~gitbook/mcp/handler.ts index a194d6b48..abeee5895 100644 --- a/packages/gitbook/src/app/sites/dynamic/[mode]/[siteURL]/[siteData]/~gitbook/mcp/handler.ts +++ b/packages/gitbook/src/app/sites/dynamic/[mode]/[siteURL]/[siteData]/~gitbook/mcp/handler.ts @@ -12,6 +12,18 @@ import { createMcpHandler } from 'mcp-handler'; import type { NextRequest } from 'next/server'; import { z } from 'zod'; +/** + * Fire-and-forget insights tracking for the MCP endpoint. A tracking failure (e.g. a 422 from the + * insights API) must never reject into the request lifecycle, or it surfaces as an MCP transport error. + */ +function trackMcpEvent(args: Parameters[0]) { + waitUntil( + trackServerInsightsEvents(args).catch((error) => { + console.error('Failed to track MCP insights event:', error); + }) + ); +} + export async function handleMcpRequest( rawRequest: NextRequest, params: RouteLayoutParams, @@ -31,21 +43,19 @@ export async function handleMcpRequest( requestURL.search = rawRequest.nextUrl.search; const request = new Request(requestURL, rawRequest); - waitUntil( - trackServerInsightsEvents({ - organizationId: context.organizationId, - siteId: context.site.id, - events: [ - { - type: 'mcp_request', - location: { - displayContext: SiteInsightsDisplayContext.Server, - }, + trackMcpEvent({ + organizationId: context.organizationId, + siteId: context.site.id, + events: [ + { + type: 'mcp_request', + location: { + displayContext: SiteInsightsDisplayContext.Server, }, - ], - request, - }) - ); + }, + ], + request, + }); const mcpHandler = createMcpHandler( (server) => { @@ -65,22 +75,20 @@ export async function handleMcpRequest( }) ); - waitUntil( - trackServerInsightsEvents({ - organizationId: context.organizationId, - siteId: site.id, - events: [ - { - type: 'search_type_query', - query, - location: { - displayContext: SiteInsightsDisplayContext.Mcp, - }, + trackMcpEvent({ + organizationId: context.organizationId, + siteId: site.id, + events: [ + { + type: 'search_type_query', + query, + location: { + displayContext: SiteInsightsDisplayContext.Mcp, }, - ], - request, - }) - ); + }, + ], + request, + }); return { content: results.flatMap((result) => { @@ -186,24 +194,22 @@ export async function handleMcpRequest( resolved.page ); - waitUntil( - trackServerInsightsEvents({ - organizationId: context.organizationId, - siteId: site.id, - events: [ - { - type: 'page_view', - location: { - displayContext: SiteInsightsDisplayContext.Mcp, - page: resolved.page.id, - space: match.siteSpace.space.id, - revision: match.siteSpace.space.revision, - }, + trackMcpEvent({ + organizationId: context.organizationId, + siteId: site.id, + events: [ + { + type: 'page_view', + location: { + displayContext: SiteInsightsDisplayContext.Mcp, + page: resolved.page.id, + space: match.siteSpace.space.id, + revision: match.siteSpace.space.revision, }, - ], - request, - }) - ); + }, + ], + request, + }); return { content: [{ type: 'text', text: markdown }] }; } catch (error) {