先理解:Resources 管数据,权限管边界
Tools 负责动作,Resources 更适合暴露状态、配置、说明文档等数据。后台 MCP 如果只有 Tools,AI 会缺少上下文;如果没有权限控制,AI 又可能看到不该看的东西。
本篇增加 Resources 和角色权限。这样不同运营角色能看到不同能力,后续也可以按角色开放写操作。
权限要靠 Server 执行
不要只在客户端隐藏工具。真正的权限判断必须在 MCP Server 里做,因为所有调用最终都经过 Server。Server 不允许,客户端再聪明也不能越权。
本篇扩展 MCP Server:暴露运营规则 Resources,并给 Tools 增加权限检查。
权限模块
src/auth.ts:
ts
export type Role = "readonly" | "operator" | "admin"
export type Context = {
userId: string
role: Role
}
export function currentContext(): Context {
return {
userId: process.env.ADMIN_USER_ID || "local-dev",
role: (process.env.ADMIN_ROLE as Role) || "readonly",
}
}
export function requireRole(ctx: Context, allowed: Role[]) {
if (!allowed.includes(ctx.role)) {
throw new Error(`permission denied: role ${ctx.role}`)
}
}Resource
在 src/index.ts 中增加:
ts
server.resource(
"refund-policy",
"admin://policy/refund",
async () => ({
contents: [{
uri: "admin://policy/refund",
mimeType: "text/plain",
text: "涉及退款金额、赔偿、封禁的操作必须人工二次确认。",
}],
}),
)给 Tool 加权限
导入:
ts
import { currentContext, requireRole } from "./auth.js"在 get_order handler 中加入:
ts
const ctx = currentContext()
requireRole(ctx, ["readonly", "operator", "admin"])低风险写入 Tool
ts
server.tool(
"update_order_note",
"给订单添加运营备注,低风险写入",
{ orderId: z.string(), note: z.string() },
async ({ orderId, note }) => {
const ctx = currentContext()
requireRole(ctx, ["operator", "admin"])
return {
content: [{ type: "text", text: `note updated for ${orderId}: ${note}` }],
}
},
)验收
只读身份:
bash
ADMIN_ROLE=readonly npm run dev预期:
get_order可用。update_order_note报权限错误。
运营身份:
bash
ADMIN_ROLE=operator npm run dev预期低风险写入可用。
权限必须在 Tool 内检查,不能只靠客户端隐藏按钮。

