From 5523cd67de46be145cff01a4770059d891a5bca3 Mon Sep 17 00:00:00 2001 From: lonewolfyx Date: Fri, 28 Aug 2026 10:41:54 +0800 Subject: [PATCH] refactor(mcp): migrate to high-level server API --- src/commands/mcp.ts | 33 ++++++++++++-------------- src/mcp/tools.ts | 57 +++++++++++++++++---------------------------- 2 files changed, 37 insertions(+), 53 deletions(-) diff --git a/src/commands/mcp.ts b/src/commands/mcp.ts index a4f8cce..09e6f12 100644 --- a/src/commands/mcp.ts +++ b/src/commands/mcp.ts @@ -1,8 +1,7 @@ import type { ResolvedVersion } from '@/types.ts' import process from 'node:process' -import { Server } from '@modelcontextprotocol/sdk/server/index.js' +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js' import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js' -import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError } from '@modelcontextprotocol/sdk/types.js' import { defineCommand } from 'citty' import { defaultArgs } from '@/args/default.ts' import { resolveConfig } from '@/config.ts' @@ -10,8 +9,8 @@ import toolsHandler from '@/mcp/handler.ts' import { antdvMcpToolDefinitions, createAntdvToolHandler } from '@/mcp/tools.ts' import { resolveVersion } from '@/utils/version.ts' -function createAntdvMcpServer(version: ResolvedVersion): Server { - const server = new Server( +function createAntdvMcpServer(version: ResolvedVersion): McpServer { + const server = new McpServer( { name: 'antdv-mcp', version: __CLI_VERSION__, @@ -24,20 +23,18 @@ function createAntdvMcpServer(version: ResolvedVersion): Server { }, ) - server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools: antdvMcpToolDefinitions, - })) - - server.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: params } = request.params - const handler = createAntdvToolHandler({ version }, toolsHandler) - - if (!handler) { - throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}`) - } - - return await handler(name, params ?? {}) - }) + const handler = createAntdvToolHandler({ version }, toolsHandler) + for (const tool of antdvMcpToolDefinitions) { + server.registerTool( + tool.name, + { + description: tool.description, + inputSchema: tool.inputSchema, + annotations: tool.annotations, + }, + (params: Record) => handler(tool.name, params), + ) + } return server } diff --git a/src/mcp/tools.ts b/src/mcp/tools.ts index 6b43a7b..442b129 100644 --- a/src/mcp/tools.ts +++ b/src/mcp/tools.ts @@ -1,4 +1,4 @@ -import type { CallToolResult, Tool } from '@modelcontextprotocol/sdk/types.js' +import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js' import type { ResolvedVersion } from '@/types.ts' import * as z from 'zod' @@ -17,72 +17,59 @@ export const antdvMcpToolDefinitions = [ { name: 'antdv_list', description: 'List all available antd components with names, categories, and descriptions', - inputSchema: z.toJSONSchema(z.object({}).strict(), - ) as Tool['inputSchema'], + inputSchema: z.object({}).strict(), annotations: readOnlyAnnotations, }, { name: 'antdv_info', description: 'Get component API information including props, events, slots, methods, and other API information for a component.', - inputSchema: z.toJSONSchema( - z.object({ - component: z.string().trim().describe('Component name (e.g. Button, Table)'), - }).strict(), - ) as Tool['inputSchema'], + inputSchema: z.object({ + component: z.string().trim().describe('Component name (e.g. Button, Table)'), + }).strict(), annotations: readOnlyAnnotations, }, { name: 'antdv_doc', description: 'Get the full markdown documentation for a component', - inputSchema: z.toJSONSchema( - z.object({ - component: z.string().trim().describe('Component name (e.g. Button, Table)'), - }).strict(), - ) as Tool['inputSchema'], + inputSchema: z.object({ + component: z.string().trim().describe('Component name (e.g. Button, Table)'), + }).strict(), annotations: readOnlyAnnotations, }, { name: 'antdv_demo', description: 'Get demo source code for a component. Without a name, lists all demos; with a name, returns specific demo code', - inputSchema: z.toJSONSchema( - z.object({ - component: z.string().trim().describe('Component name (e.g. Button, Table)'), - name: z.string().trim().optional().describe('Demo name to get specific demo code'), - }).strict(), - ) as Tool['inputSchema'], + inputSchema: z.object({ + component: z.string().trim().describe('Component name (e.g. Button, Table)'), + name: z.string().trim().optional().describe('Demo name to get specific demo code'), + }).strict(), annotations: readOnlyAnnotations, }, { name: 'antdv_token', description: 'Query design tokens. Without a component, returns global tokens; with a component, returns component-level tokens.', - inputSchema: z.toJSONSchema( - z.object({ - component: z.string().trim().describe('Component name (e.g. Button, Table)'), - }).strict(), - ) as Tool['inputSchema'], + inputSchema: z.object({ + component: z.string().trim().describe('Component name (e.g. Button, Table)'), + }).strict(), annotations: readOnlyAnnotations, }, { name: 'antdv_semantic', description: 'Query the semantic customization structure of a component.', - inputSchema: z.toJSONSchema( - z.object({ - component: z.string() - .trim() - .describe('Component name (e.g. Button, Table)'), - }).strict(), - ) as Tool['inputSchema'], + inputSchema: z.object({ + component: z.string() + .trim() + .describe('Component name (e.g. Button, Table)'), + }).strict(), annotations: readOnlyAnnotations, }, { name: 'antdv_design_md', description: 'Obtain the design language document (design.md) of the target main version: It includes the complete color, font, rounded corners, spacing and component token values for the default light theme, as well as explanations about the design principles. It can be used to understand the overall design language of the component library, or as input data for AI design tools (such as Figma Make, Stitch, etc.).', - inputSchema: z.toJSONSchema( - z.object({}).strict(), - ) as Tool['inputSchema'], + inputSchema: z.object({}).strict(), annotations: readOnlyAnnotations, }, -] as const satisfies readonly Tool[] +] as const export type AntdvMcpToolName = typeof antdvMcpToolDefinitions[number]['name'] export type AntdvToolStrategy = (ctx: Readonly, params: Record) => Promise