首页
看点啥
插画图片
首页 看点啥 MCP 系列(08):企业治理——Registry、路由与可观测性

MCP 系列(08):企业治理——Registry、路由与可观测性

2026-07-18 0

为什么需要治理

三个 MCP Server 靠记忆管理。二十个需要系统。

MCP 系列(08):企业治理——Registry、路由与可观测性

企业内 MCP Server 数量增加后出现的典型问题:

Registry 解决发现,路由解决分发,可观测性解决定位。


MCP Registry

Registry 是企业内 MCP Server 的目录,记录每个 Server 的位置、版本、能力和责任人。

 复制代码# 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 解决三个问题:

  1. 发现:新 Agent 查 Registry 知道有哪些 Server 可用,不用靠口口相传
  2. 废弃声明:deprecated 状态 + migration_guide,Agent 代码迁移有明确指引
  3. 责任归属:每个 Server 有 owner,出问题知道找谁

工具路由策略

Agent 需要"搜索 Jira 工单"时,如何自动找到正确的 Server?四种策略:

策略 1:静态配置(最简单)

在 Agent 的 settings.json 里直接声明所有 Server:

 复制代码{
  "mcpServers": {
    "jira": {
      "command": "python",
      "args": ["/opt/mcp/jira/server.py"]
    },
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"]
    }
  }
}

优点:简单、可预测。缺点:新增 Server 需要手动更新每个 Agent 的配置文件。

策略 2:按领域加载

Agent 启动时根据任务类型加载对应 Server,不一次性加载所有:

 复制代码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 描述向量化,用户请求也向量化,找最近邻:

 复制代码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 精选:

 复制代码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 结构

 复制代码from langfuse import Langfuse
from langfuse.decorators import observe, langfuse_contextlangfuse = 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

 复制代码@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 能回答的问题

 复制代码哪个工具调用最慢?
  → 按 latency_ms 排序 Span哪个 Server 错误率最高?
  → 按 server_id 分组,统计 success=False 的比例Token 消耗集中在哪里?
  → LLM Span 里的 usage 字段,按 tool_name 分组某次 Agent 失败的根因是什么?
  → 在 Langfuse 搜 session_id,展开完整的 Trace 树

告警规则

把关键指标接入告警系统(Grafana / Prometheus / 内部监控):

 复制代码# 告警规则模板(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 — 个人/小团队(立即可做):

Level 2 — 团队共享(1-2 周):

Level 3 — 企业治理(持续建设):


总结

  1. Registry 是发现的基础:没有 Registry,20 个 Server 靠口口相传,重复开发和版本混乱是必然结果
  2. 路由策略按规模选:3 个 Server 静态配置就够;20+ 个用分层路由(domain 粗分 + Embedding 精选),避免 Embedding 在同领域 Server 间混淆
  3. 可观测性把黑盒变记录:Langfuse 的三层 Trace(会话级 → 工具调用级)让失败根因从"不知道"变成"打开 Dashboard 5 秒找到"

参考资料


欢迎访问 PrimeSkills —— 一个精心策划的 AI Agent 与技能市场,所有内容均经过真实企业级工作流验证。没有噱头,只有真正有效的东西。

更多实用知识和有趣产品,欢迎访问我的个人主页

喜欢(0)

上一篇

Skill 是什么?一份让 AI 从“现想”转为“照做”的操作手册

Skill 是什么?一份让 AI 从“现想”转为“照做”的操作手册

下一篇

LLM02-Context Priming:借助强模型上下文提升弱模型能力的策略

LLM02-Context Priming:借助强模型上下文提升弱模型能力的策略
猜你喜欢