为什么需要治理
三个 MCP Server 靠记忆管理。二十个需要系统。
企业内 MCP Server 数量增加后出现的典型问题:
- 新同事不知道已有哪些 Server,重复开发了 Jira 工具
- Agent 调用了已废弃的
search_jira工具(v1.x)而不是新的search_issues(v2.x) - 某次工具调用失败,没有日志,不知道是 Server 挂了还是参数有问题
- Token 消耗异常,不知道是哪个 Server 的哪个工具
Registry 解决发现,路由解决分发,可观测性解决定位。
MCP Registry
Registry 是企业内 MCP Server 的目录,记录每个 Server 的位置、版本、能力和责任人。
yaml
# mcp-registry.yaml
servers:
- id: jira-tools
name: Jira 工具集
description: "Jira 工单的搜索、创建、更新操作"
version: "2.1.0"
domain: engineering # 按领域分类
owner: "@team-platform"
status: active # active / deprecated / experimental
transport: stdio
command: python
args: ["/opt/mcp/jira/server.py"]
capabilities:
tools: [search_issues, create_issue, update_issue]
resources: [jira://projects, jira://sprint/current]
metrics:
monthly_calls: 4521
avg_latency_ms: 180
error_rate: 0.2%
- id: github-tools
name: GitHub 工具集
version: "1.5.0"
domain: engineering
owner: "@team-platform"
status: active
transport: stdio
command: npx
args: ["-y", "@modelcontextprotocol/server-github"]
capabilities:
tools: [create_pull_request, search_repositories, get_file_contents]
- id: postgres-readonly
name: PostgreSQL 只读查询
version: "1.0.0"
domain: data
owner: "@team-data"
status: active
transport: stdio
command: npx
args: ["-y", "@modelcontextprotocol/server-postgres", "${DATABASE_URL}"]
capabilities:
tools: [query]
resources: ["postgres://analytics/schema"]
- id: jira-tools-legacy
name: Jira 工具集(旧版)
version: "1.2.0"
domain: engineering
status: deprecated
deprecation:
reason: "已被 jira-tools v2.x 取代,search_jira 更名为 search_issues"
migration_guide: "将 search_jira 替换为 search_issues,参数结构不变"
removal_date: "2026-10-01"
capabilities:
tools: [search_jira, create_jira_ticket]
Registry 解决三个问题:
- 发现:新 Agent 查 Registry 知道有哪些 Server 可用,不用靠口口相传
- 废弃声明:deprecated 状态 + migration_guide,Agent 代码迁移有明确指引
- 责任归属:每个 Server 有 owner,出问题知道找谁
工具路由策略
Agent 需要"搜索 Jira 工单"时,如何自动找到正确的 Server?四种策略:
策略 1:静态配置(最简单)
在 Agent 的 settings.json 里直接声明所有 Server:
json
{
"mcpServers": {
"jira": {
"command": "python",
"args": ["/opt/mcp/jira/server.py"]
},
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"]
}
}
}
优点:简单、可预测。缺点:新增 Server 需要手动更新每个 Agent 的配置文件。
策略 2:按领域加载
Agent 启动时根据任务类型加载对应 Server,不一次性加载所有:
python
DOMAIN_SERVERS = {
"engineering": ["jira-tools", "github-tools", "gitlab-tools"],
"data": ["postgres-readonly", "bigquery-tools"],
"communication": ["slack-tools", "email-tools"],
}
def load_servers_for_task(task_type: str) -> list[dict]:
"""根据任务领域加载相关 Server,避免加载不必要的服务"""
domain = classify_task_domain(task_type)
server_ids = DOMAIN_SERVERS.get(domain, [])
registry = load_registry()
return [
s for s in registry["servers"]
if s["id"] in server_ids and s["status"] == "active"
]
优点:减少不必要的 Server 启动开销,每个 Agent 只加载需要的工具。
策略 3:Embedding 路由(语义匹配)
和 Skill 系列第 06 篇的做法一样------把 Server 描述向量化,用户请求也向量化,找最近邻:
python
def route_to_server(user_input: str, registry: list[dict]) -> list[str]:
"""返回与用户请求语义最匹配的 Server ID 列表"""
query_embedding = embedder.embed(user_input)
scored = []
for server in registry:
desc_embedding = get_cached_embedding(server["id"], server["description"])
score = cosine_similarity(query_embedding, desc_embedding)
scored.append((server["id"], score))
# 取相似度最高的前 3 个
scored.sort(key=lambda x: x[1], reverse=True)
return [s[0] for s in scored[:3] if s[1] > 0.6]
适合 Server 数量多(> 20 个)且经常新增 Server 的场景。同样的问题------同领域 Server 描述相似,容易混淆------需要在描述里加负面示例(见 Skill 系列第 06 篇的讨论)。
策略 4:分层路由(推荐)
先按 domain 粗过滤,再在 domain 内用 Embedding 精选:
python
def hierarchical_route(user_input: str, registry: list[dict]) -> list[str]:
# 第一层:LLM 快速分类 domain
domain = llm_classify_domain(user_input) # "engineering" / "data" / ...
# 第二层:在 domain 内 Embedding 匹配
domain_servers = [s for s in registry if s.get("domain") == domain]
return embedding_route(user_input, domain_servers)
可观测性:接入 Langfuse
没有 Trace,MCP 工具调用是黑盒------失败了不知道原因,慢了不知道哪里慢,Token 贵了不知道贵在哪个工具。
三层 Trace 结构
python
from langfuse import Langfuse
from langfuse.decorators import observe, langfuse_context
langfuse = Langfuse()
@observe(name="mcp_tool_call")
async def traced_tool_call(
server_id: str,
tool_name: str,
arguments: dict,
call_fn # 实际调用 MCP Server 的函数
) -> dict:
# 记录调用上下文
langfuse_context.update_current_observation(
input={"tool": tool_name, "arguments": arguments},
metadata={
"server_id": server_id,
"server_version": get_server_version(server_id),
}
)
t0 = time.perf_counter()
try:
result = await call_fn(tool_name, arguments)
latency_ms = (time.perf_counter() - t0) * 1000
langfuse_context.update_current_observation(
output=result,
metadata={"latency_ms": round(latency_ms, 2), "success": True}
)
return result
except Exception as exc:
latency_ms = (time.perf_counter() - t0) * 1000
langfuse_context.update_current_observation(
output={"error": str(exc)},
metadata={"latency_ms": round(latency_ms, 2), "success": False},
level="ERROR"
)
raise
在 Agent 会话里创建顶层 Trace
python
@observe(name="agent_session")
async def run_agent_session(user_input: str, session_id: str):
langfuse_context.update_current_trace(
session_id=session_id,
user_id="user:alice",
metadata={"task_type": "jira_query"}
)
# Agent 运行时,每次工具调用都自动关联到这个 Trace
result = await agent.run(user_input)
langfuse_context.update_current_observation(output={"result": result})
return result
Trace 能回答的问题
ini
哪个工具调用最慢?
→ 按 latency_ms 排序 Span
哪个 Server 错误率最高?
→ 按 server_id 分组,统计 success=False 的比例
Token 消耗集中在哪里?
→ LLM Span 里的 usage 字段,按 tool_name 分组
某次 Agent 失败的根因是什么?
→ 在 Langfuse 搜 session_id,展开完整的 Trace 树
告警规则
把关键指标接入告警系统(Grafana / Prometheus / 内部监控):
yaml
# 告警规则模板(Prometheus alerting rules 格式)
groups:
- name: mcp_server_alerts
rules:
# Server 可用率告警
- alert: MCPServerHighErrorRate
expr: mcp_tool_call_error_rate_5m > 0.05
for: 5m
labels:
severity: warning
annotations:
summary: "MCP Server {{ $labels.server_id }} error rate {{ $value | humanizePercentage }}"
# 工具调用延迟告警
- alert: MCPToolHighLatency
expr: mcp_tool_call_p90_latency_ms > 5000
for: 3m
labels:
severity: warning
annotations:
summary: "Tool {{ $labels.tool_name }} P90 latency {{ $value }}ms"
# Server 版本仍在使用废弃工具
- alert: DeprecatedToolInUse
expr: mcp_deprecated_tool_calls_total > 0
for: 0m
labels:
severity: info
annotations:
summary: "Deprecated tool {{ $labels.tool_name }} called {{ $value }} times today"
三级治理路线图
Level 1 --- 个人/小团队(立即可做):
- 建 mcp-registry.yaml,列出所有 Server 的 id / version / owner / status
- 每个 Server 的 README 写清楚工具清单和使用示例
Level 2 --- 团队共享(1-2 周):
- Registry 存入 Git,变更走 PR review
- 加 Langfuse Trace,至少记录每次工具调用的 tool_name / latency / success
- 设置错误率告警
Level 3 --- 企业治理(持续建设):
- 分层路由(domain 分类 + Embedding 精选)
- 月度 Server 健康报告(调用量 / 错误率 / 主要用户)
- Server 废弃流程规范(声明 → 告警 → 90 天宽限 → 删除)
总结
- Registry 是发现的基础:没有 Registry,20 个 Server 靠口口相传,重复开发和版本混乱是必然结果
- 路由策略按规模选:3 个 Server 静态配置就够;20+ 个用分层路由(domain 粗分 + Embedding 精选),避免 Embedding 在同领域 Server 间混淆
- 可观测性把黑盒变记录:Langfuse 的三层 Trace(会话级 → 工具调用级)让失败根因从"不知道"变成"打开 Dashboard 5 秒找到"
参考资料
- Langfuse MCP 集成文档
- 本系列完整规划:MCP 知识系列大纲
欢迎访问 PrimeSkills ------ 一个精心策划的 AI Agent 与技能市场,所有内容均经过真实企业级工作流验证。没有噱头,只有真正有效的东西。
更多实用知识和有趣产品,欢迎访问我的个人主页