File size: 1,774 Bytes
7dc28be
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// FastMCP's default tools/list handler runs toJsonSchema() for every tool on every request.
// Hosts that poll tools/list frequently (or many concurrent sessions) then burn a full CPU core.
// We precompute the list once before stdio connects, then replace the handler to return that snapshot.

import { ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
import type { FastMCP } from 'fastmcp';
import { toJsonSchema } from 'xsschema';
import { logger } from './logger.js';

type AddToolArg = Parameters<FastMCP['addTool']>[0];

export function collectToolsWhileRegistering(server: FastMCP, out: AddToolArg[]): void {
  const add = server.addTool.bind(server);
  (server as unknown as { addTool: (tool: AddToolArg) => void }).addTool = (tool) => {
    out.push(tool);
    add(tool);
  };
}

export async function buildCachedToolsListPayload(tools: AddToolArg[]) {
  return {
    tools: await Promise.all(
      tools.map(async (tool) => ({
        annotations: tool.annotations,
        description: tool.description,
        inputSchema: tool.parameters
          ? await toJsonSchema(tool.parameters)
          : {
              additionalProperties: false,
              properties: {},
              type: 'object' as const,
            },
        name: tool.name,
      }))
    ),
  };
}

export function installCachedToolsListHandler(
  server: FastMCP,
  listPayload: Awaited<ReturnType<typeof buildCachedToolsListPayload>>
): void {
  const session = server.sessions[0];
  if (!session) {
    logger.warn('No MCP session; skipping tools/list cache install.');
    return;
  }

  session.server.setRequestHandler(ListToolsRequestSchema, async () => listPayload);
  logger.debug(`Installed cached tools/list (${listPayload.tools.length} tools).`);
}