构建具有数十或数百个工具的MCP服务器通常会对LLM性能和开发者体验造成负面影响:
Toolception通过将工具分组到工具集中,并让您仅在需要时暴露所需内容来解决这些问题。
enable_toolset、disable_toolset、list_toolsets、describe_toolset、list_tools)按需启用工具集。context传递给加载器。tools.listChanged通知,以便客户端可以响应更新的工具列表。set.tool以避免冲突并明确意图。ToolRegistry验证名称并防止冲突。ModuleLoaders是确定性的/幂等的,用于重复运行和缓存。list_toolsets → 启用一个集合 → 调用命名空间工具(例如core.ping)。list_tools并按常规方式调用。npm i toolception
import { createMcpServer } from "toolception";
const catalog = {
quotes: { name: "Quotes", description: "市场报价", modules: ["quotes"] },
};
const quoteTool = {
name: "price",
description: "返回假的价格",
inputSchema: {
type: "object",
properties: { symbol: { type: "string" } },
required: ["symbol"],
},
handler: async ({ symbol }: { symbol: string }) => ({
content: [{ type: "text", text: `${symbol}: 123.45` }],
}),
} as const;
const moduleLoaders = {
quotes: async () => [quoteTool],
};
const configSchema = {
$schema: "https://json-schema.org/draft/2020-12/schema",
type: "object",
properties: {
REQUIRED_PARAM: { type: "string", title: "必需参数" },
OPTIONAL_PARAM: { type: "string", title: "可选参数" },
},
required: ["REQUIRED_PARAM"],
} as const;
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
// 您拥有SDK服务器;将工厂传入Toolception(在DYNAMIC模式下需要)
const createServer = () =>
new McpServer({
name: "my-mcp-server",
version: "0.0.0",
capabilities: { tools: { listChanged: true } },
});
const { start, close } = await createMcpServer({
catalog,
moduleLoaders,
startup: { mode: "DYNAMIC" },
http: { port: 3000 },
createServer,
// configSchema, // 注释掉以在/.well-known/mcp-config中暴露
});
await start();
process.on("SIGINT", async () => {
await close();
process.exit(0);
});
process.on("SIGTERM", async () => {
await close();
process.exit(
0);
});
在引导时启用一些或全部工具集。注意:提供一个服务器或工厂:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
const staticCatalog = {
search: { name: "Search", description: "搜索工具", modules: ["search"] },
quotes: { name: "Quotes", description: "市场报价", modules: ["quotes"] },
};
createMcpServer({
catalog: staticCatalog,
startup: { mode: "STATIC", toolsets: ["search", "quotes"] },
http: { port: 3001 },
server: new McpServer({
name: "static-1",
version: "0.0.0",
capabilities: { tools: { listChanged: false } },
}),
});
createMcpServer({
catalog: staticCatalog,
startup: { mode: "STATIC", toolsets: "ALL" },
http: { port: 3002 },
server: new McpServer({
name: "static-2",
version: "0.0.0",
capabilities: { tools: { listChanged: false } },
}),
});
使用createPermissionBasedMcpServer当您需要强制执行客户端特定的工具集权限时。这对于多租户应用程序、安全敏感的环境或不同客户端应有不同的访问级别时非常理想。
npm i toolception
import { createPermissionBasedMcpServer } from "toolception";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
const catalog = {
admin: {
name: "管理工具",
description: "管理操作",
modules: ["admin"],
},
user: {
name: "用户工具",
description: "标准用户操作",
modules: ["user"],
},
};
const adminTool = {
name: "delete_user",
description: "删除用户账户",
inputSchema: {
type: "object",
properties: {
userId: { type: "string", description: "要删除的用户ID" },
},
required: ["userId"],
},
handler: async ({ userId }: { userId: string }) => ({
content: [{ type: "text", text: `用户${userId}已被删除` }],
}),
} as const;
const userTool = {
name: "get_profile",
description: "获取用户资料信息",
inputSchema: {
type: "object",
properties: {
userId: { type: "string", description: "用户ID" },
},
required: ["userId"],
},
handler: async ({ userId }: { userId: string }) => ({
content: [{ type: "text", text: `用户${userId}的资料:{...}` }],
}),
} as const;
const moduleLoaders = {
admin: async () => [adminTool],
user: async () => [userTool],
};
您有两种管理权限的方法:
基于头部的权限:
基于配置的权限:
选项A:基于头部的权限
const createServer = () =>
new McpServer({
name: "permission-header-server",
version: "1.0.0",
capabilities: { tools: { listChanged: false } },
});
const { start, close } = await createPermissionBasedMcpServer({
catalog,
moduleLoaders,
permissions: {
source: "headers",
headerName: "mcp-toolset-permissions", // 可选,默认值
},
http: { port: 3000 },
createServer,
});
await start();
选项B:基于配置的权限(静态映射)
const createServer = () =>
new McpServer({
name: "permission-config-server",
version: "1.0.0",
capabilities: { tools: { listChanged: false } },
});
const { start, close } = await createPermissionBasedMcpServer({
catalog,
moduleLoaders,
permissions: {
source: "config",
staticMap: {
"admin-client-id": ["admin", "user"],
"user-client-id": ["user"],
},
defaultPermissions: [], // 未知客户端没有任何工具集
},
http: { port: 3000 },
createServer,
});
await start();
选项C:基于配置的权限(解析函数)
const createServer = () =>
new McpServer({
name: "permission-resolver-server",
version: "1.0.0",
capabilities: { tools: { listChanged: false } },
});
const { start, close } = await createPermissionBasedMcpServer({
catalog,
moduleLoaders,
permissions: {
source: "config",
resolver: (clientId: string) => {
// 您的自定义权限逻辑
if (clientId.startsWith("admin-")) {
return ["admin", "user"];
}
if (clientId.startsWith("user-")) {
return ["user"];
}
return [];
},
defaultPermissions: [],
},
http: { port: 3000 },
createServer,
});
await start();
process.on("SIGINT", async () => {
await close();
process.exit(0);
});
process.on("SIGTERM", async () => {
await close();
process.exit(0);
});
当您有一个验证请求的认证网关或代理时使用基于头部的权限。这种方法对于动态权限非常灵活,但需要外部头部验证。
import { createPermissionBasedMcpServer } from "toolception";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
const createServer = () =>
new McpServer({
name: "permission-header-server",
version: "1.0.0",
capabilities: { tools: { listChanged: false } },
});
const { start, close } = await createPermissionBasedMcpServer({
catalog: {
admin: {
name: "Admin",
description: "管理员工具",
modules: ["admin"],
},
user: {
name: "User",
description: "用户工具",
modules: ["user"],
},
},
moduleLoaders: {
admin: async () => [
/* 管理员工具 */
],
user: async () => [
/* 用户工具 */
],
},
permissions: {
source: "headers",
headerName: "mcp-toolset-permissions", // 可选,默认值
},
http: { port: 3000 },
createServer,
});
await start();
何时使用:
当您有一组固定的已知客户端及其已知权限时使用静态映射。这提供了服务器端控制和更高的安全性。
import { createPermissionBasedMcpServer } from "toolception";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
const createServer = () =>
new McpServer({
name: "permission-config-server",
version: "1.0.0",
capabilities: { tools: { listChanged: false } },
});
const { start, close } = await createPermissionBasedMcpServer({
catalog: {
admin: {
name: "Admin",
description: "管理员工具",
modules: ["admin"],
},
user: {
name: "User",
description: "用户工具",
modules: ["user"],
},
},
moduleLoaders: {
admin: async () => [
/* 管理员工具 */
],
user: async () => [
/* 用户工具 */
],
},
permissions: {
source: "config",
staticMap: {
"admin-client-id": ["admin", "user"],
"user-client-id": ["user"],
},
defaultPermissions: [], // 不在映射中的客户端没有任何工具集
},
http: { port: 3000 },
createServer,
});
await start();
何时使用:
当您需要自定义逻辑来确定权限时使用解析函数,例如从数据库查找或应用复杂规则。
import { createPermissionBasedMcpServer } from "toolception";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
const createServer = () =>
new McpServer({
name: "permission-resolver-server",
version: "1.0.0",
capabilities: { tools: { listChanged: false } },
});
const { start, close } = await createPermissionBasedMcpServer({
catalog: {
admin: {
name: "Admin",
description: "管理员工具",
modules: ["admin"],
},
user: {
name: "User",
description: "用户工具",
modules: ["user"],
},
},
moduleLoaders: {
admin: async () => [
/* 管理员工具 */
],
user: async () => [
/* 用户工具 */
],
},
permissions: {
source: "config",
resolver: (clientId: string) => {
// 自定义逻辑 - 可能检查数据库、配置文件等
if (clientId.startsWith("admin-")) {
return ["admin", "user"];
}
if (clientId.startsWith("user-")) {
return ["user"];
}
return [];
},
staticMap: {
// 可选的后备
"special-client": ["admin"],
},
defaultPermissions: [],
},
http: { port: 3000 },
createServer,
});
await start();
何时使用:
注意: