Tool Registry + MCP Server:把你的系统变成 Claude 和 Cursor 的超级工具箱

> 把 EAMX 开放为 MCP Server,意味着外部 AI(如 Claude Desktop、Cursor、VS Code Copilot)可以直接调用 EAMX 的 AI Tools。但问题来了:外部 AI 不知道调用的用户是谁——怎么保证权限不泄露?EAMX 的方案是:Tool Registry 集中注册 + getAuthorized() 按权限过滤 + MCP Server 对外暴露。本文详解 Tool Registry 的设计和 MCP Server 的权限门控。

1. Tool 的五个要素

``typescript<br>interface McpTool {<br> name: string; // "equipment:list"<br> description: string; // "搜索设备列表..."<br> annotations: {<br> casl?: { action: Actions; subject: Subjects }; // 权限要求<br> timeout?: number; // 超时控制(默认 15s)<br> };<br> inputSchema: object; // Zod schema → JSON Schema<br> handler: (input, ctx) => Promise<ToolCallResult>;<br>}<br>``

每个 Tool 自声明它需要的权限(casl 注解),Tool Registry 依据此注解做权限过滤。

2. Tool Registry 核心实现

```typescript<br>class ToolRegistry {<br> private tools = new Map<string, McpTool>();

registerAll(tools: McpTool[]): void {<br> for (const t of tools) {<br> if (this.tools.has(t.name))<br> throw new Error(Tool "${t.name}" already registered);<br> this.tools.set(t.name, t);<br> }<br> }

get(name: string): McpTool | undefined {<br> return this.tools.get(name);<br> }

// 关键:按 CASL 权限过滤<br> getAuthorized(ability: AppAbility): McpTool[] {<br> return [...this.tools.values()].filter(t => {<br> const casl = t.annotations?.casl;<br> if (!casl) return true; // 无权限注解 = 对所有人开放<br> return ability.can(casl.action, casl.subject);<br> });<br> }

getAll(): McpTool[] {<br> return [...this.tools.values()];<br> }<br>}<br>```

86 行,职责单一:存储 Tool + 按权限过滤。

3. Tool 注册入口

```typescript<br>// tools/register.ts — 启动时一次性注册<br>export function registerAllTools(): void {<br> toolRegistry.registerAll([<br> // Equipment<br> listEquipmentsTool, // "equipment:list" → read Equipment<br> getEquipmentTool, // "equipment:get" → read Equipment

// Fault<br> createFaultReportTool, // "fault:create-report" → create FaultReport<br> listFaultReportsTool, // "fault:list" → read FaultReport

// System<br> entitySearchTool, // "system:entity-search" → 无权限要求(通用)<br> ]);

console.log([Tools] Registered ${toolRegistry.getAll().length} AI tools);<br>}<br>```

新增 Tool 只需:

1
创建 tools/<module>/<name>.tool.ts
2
register.ts 加一行 import + 注册

不碰其他任何文件。

4. Tool Example:设备列表

``typescript<br>// tools/equipment/list.tool.ts<br>export const listEquipmentsTool: McpTool = {<br> name: "equipment:list",<br> description: 搜索设备列表。支持按名称、资产编码、型号、位置、运行状态等条件筛选...,<br> annotations: {<br> casl: { action: "read", subject: "Equipment" },<br> timeout: 10000,<br> },<br> inputSchema: z.object({<br> keyword: z.string().optional(),<br> operationalStatus: z.enum(["running","idle","fault","repairing","scrapped"]).optional(),<br> department: z.string().optional(),<br> page: z.number().default(1),<br> pageSize: z.number().default(20),<br> }),<br> handler: async (input, ctx) => {<br> const conditions = buildConditions(input, ctx.ability);<br> const rows = await db.select().from(equipmentsTable).where(conditions);<br> return { success: true, data: { rows, total: rows.length }, cardType: "equipment_list" };<br> },<br>};<br>``

5. MCP Server:对外暴露

```typescript<br>// mcp/server.ts — MCP 协议适配层<br>export function generateMcpToolList(ctx: AuthorizedContext) {<br> const tools = toolRegistry.getAuthorized(ctx.ability); // 按权限过滤<br> return {<br> tools: tools.map(t => ({<br> name: t.name,<br> description: t.description,<br> inputSchema: { type: "object", properties: {} },<br> })),<br> };<br>}

export async function executeMcpToolCall(<br> name: string, args: Record<string, unknown>, ctx: AuthorizedContext,<br>) {<br> const tool = toolRegistry.get(name);<br> if (!tool) return { content: [{ type: "text", text: "Tool not found" }], isError: true };

const result = await tool.handler(args, ctx);<br> if (result.success) {<br> return { content: [{ type: "text", text: JSON.stringify(result.data) }], isError: false };<br> }<br> return { content: [{ type: "text", text: result.error?.message }], isError: true };<br>}<br>```

6. 三层消费路径对比

| 消费方 | 入口 | 权限检查位置 |<br>|---|---|---|<br>| 内部 AI(EAMX ChatBot) | Tool Factory → mcpToolToAiSdkTool() | Tool Factory 的 execute 内 |<br>| 外部 AI(Claude / Cursor) | MCP Server → generateMcpToolList() | getAuthorized() 过滤列表 |<br>| HTTP API | Express Router → 中间件 | API 中间件 |

同一个 Tool 可以被三种消费者调用,权限检查策略统一。

7. 架构总结:本系列全景

10 篇文章覆盖了 EAMX 2.0 AI 系统的完整技术栈:

| 编号 | 主题 | 核心模块 |<br>|---|---|---|<br>| 01 | 技术架构全景 | 全栈俯瞰 |<br>| 02 | 意图识别三层策略 | intent.agent.ts |<br>| 03 | AI Pipeline 编排器 | orchestrator.ts + tool-factory.ts |<br>| 04 | 铭牌OCR两阶段管线 | nameplate-extractor + field-classifier |<br>| 05 | pgvector RAG 故障知识库 | rag.ts + external-knowledge.agent.ts |<br>| 06 | DynamicForm 置信度着色 | equipment.agent.ts L226-438 |<br>| 07 | 插件化架构 | plugin-registry.ts + lifecycle-bus.ts |<br>| 08 | CASL 同构权限 | ability.ts (132行) |<br>| 09 | 审批工作流引擎 | lifecycle-bus.ts 拦截模式 |<br>| 10 | Tool Registry + MCP | tool-registry.ts + mcp/server.ts |

8. 核心文件索引

| 文件 | 行数 | 职责 |<br>|---|---|---|<br>| ai/tool-registry.ts | 86 | Tool 注册 + getAuthorized 权限过滤 |<br>| mcp/server.ts | 66 | MCP 协议适配层 |<br>| tools/register.ts | 30 | 启动时注册入口 |<br>| tools//.tool.ts | — | 各 Tool 实现 |<br>| ai/tool-factory.ts | 93 | McpTool → Vercel AI SDK Tool |

作者:白杨,十余年设备资产管理从业经验,EAMX 产品负责人。