摘要:企业私有MCP Hub实现内部工具的统一管理、版本控制和权限分配。本文提供私有MCP Hub的完整搭建方案,包含工具注册、API网关、权限管理和监控告警模块。

私有MCP Hub搭建 企业内部MCP工具市场

上个月有个在银行做技术架构的朋友找我喝酒,说他们部门有十几个团队都在搞AI Agent,每个团队自己搭自己的MCP Server,重复造轮子严重。A团队写了个查行内数据库的MCP Server,B团队不知道,又写了一个一模一样的。更要命的是安全团队开始介入了,说这些MCP Server散落在各处,没有统一管理,审计根本没法做。

他问我有没有办法搭一个企业内部的MCP工具市场,让所有团队的MCP Server集中管理。我说这事我正好做过,今天就跟你聊聊怎么搭一个私有MCP Hub。

为什么需要私有MCP Hub

先说清楚为什么要搞这个东西。直接让各团队自己搭MCP Server不行吗?行,但会碰到三个问题。

重复建设。同样的数据库查询能力,三个团队各写一遍。代码重复,维护重复,出了bug修三遍。

安全失控。每个MCP Server都有数据库或API的访问凭证,散落在各团队手里,安全团队看不到全貌。谁在什么时候调了什么,没有统一日志。

版本混乱。A团队用的MCP协议是1.0版本,B团队还在用0.5版本。Agent连接不同版本的Server时各种报错。

私有MCP Hub就是解决这三个问题的。它是一个中心化的管理平台,负责Server的注册、发现、版本管理和权限控制。

Hub架构设计

我设计的Hub架构分四层。

层次 职责 关键组件
接入层 对外提供API,处理认证 FastAPI + OAuth2
注册层 管理Server的注册和发现 注册表 + 元数据存储
管控层 版本管理和权限控制 策略引擎 + 审计日志
执行层 实际运行MCP Server 容器编排 + 进程管理

接入层负责对外暴露API,所有Agent通过Hub来发现和访问MCP Server。注册层管理所有Server的元数据,包括名称、版本、能力描述等。管控层做权限控制和审计,决定谁能用哪个Server。执行层负责实际启动和管理Server进程。

跟直接用MCP Server的区别在于,Agent不直接连Server,而是通过Hub来代理。Hub在中间做了一层管控。

方案 直连MCP Server 通过MCP Hub
安全控制 各团队自己管 统一管控
版本管理 各自为政 集中管理
审计能力 完整审计日志
性能开销 低(直连) 中(多一跳代理)
运维成本 高(分散) 中(集中但需维护Hub)

完整项目 用FastAPI实现MCP Hub

下面我用FastAPI实现一个可运行的MCP Hub。包含Server注册、发现、版本管理、权限控制和审计日志。

项目结构

mcp_hub/
├── hub.py                # Hub主服务
├── auth.py               # 认证和权限模块
├── audit.py              # 审计日志模块
├── proxy.py              # 请求代理模块
├── models.py             # 数据模型
├── requirements.txt
└── start.sh              # 启动脚本

requirements.txt

# FastAPI,Web框架
fastapi==0.111.0
# Uvicorn,ASGI服务器
uvicorn==0.30.0
# Pydantic,数据模型
pydantic==2.7.0
# httpx,异步HTTP客户端
httpx==0.27.0
# PyJWT,JWT令牌
pyjwt==2.9.0
# passlib,密码哈希
passlib==1.7.4

models.py

"""
数据模型定义
定义Hub中所有核心实体的数据结构
"""
from pydantic import BaseModel
from typing import Optional
from datetime import datetime
from enum import Enum

class ServerStatus(str, Enum):
    """MCP Server运行状态枚举"""
    REGISTERED = "registered"    # 已注册但未启动
    RUNNING = "running"          # 运行中
    STOPPED = "stopped"          # 已停止
    ERROR = "error"              # 出错

class MCPServerRegistration(BaseModel):
    """MCP Server注册信息"""
    server_id: str               # Server唯一ID
    name: str                    # Server名称
    version: str                 # 版本号,语义化版本
    description: str             # 功能描述
    tools: list[str]             # 提供的工具列表
    endpoint: str                # Server实际地址
    owner_team: str             # 负责团队
    status: ServerStatus = ServerStatus.REGISTERED  # 运行状态
    registered_at: datetime = datetime.now()  # 注册时间
    config: dict = {}            # 额外配置

class VersionInfo(BaseModel):
    """版本信息"""
    version: str                 # 版本号
    changelog: str              # 变更说明
    compatible_clients: list[str] = []  # 兼容的客户端版本
    deprecated: bool = False     # 是否已废弃

class Permission(BaseModel):
    """权限定义"""
    team: str                   # 团队名
    server_id: str              # 可访问的Server
    allowed_tools: list[str] = []  # 允许使用的工具,空列表表示全部
    expires_at: Optional[datetime] = None  # 过期时间

class AuditLog(BaseModel):
    """审计日志条目"""
    timestamp: datetime         # 时间戳
    team: str                   # 调用方团队
    server_id: str              # 目标Server
    tool_name: str              # 调用的工具
    action: str                 # 操作类型
    status: str                 # 结果状态
    request_id: str             # 请求追踪ID

auth.py

"""
认证和权限控制模块
基于JWT令牌的认证,团队级别的权限管理
"""
import jwt
from datetime import datetime, timedelta
from models import Permission

class AuthManager:
    """认证和权限管理器"""
    
    # JWT密钥,生产环境要从配置文件读取
    SECRET_KEY = "your-secret-key-change-in-production"
    # JWT算法
    ALGORITHM = "HS256"
    # 令牌有效期
    TOKEN_EXPIRE_HOURS = 24
    
    def __init__(self):
        # 权限注册表,key为"team:server_id"
        self.permissions = {}
        # 已注册的团队和API密钥
        self.team_api_keys = {
            "data_team": "key-data-001",     # 数据团队
            "ml_team": "key-ml-002",          # 机器学习团队
            "ops_team": "key-ops-003",        # 运维团队
        }
    
    def verify_api_key(self, team: str, api_key: str) -> bool:
        """验证团队的API密钥"""
        # 比对预存的密钥
        expected = self.team_api_keys.get(team)
        return expected is not None and expected == api_key
    
    def create_token(self, team: str) -> str:
        """为团队创建JWT令牌"""
        # 构造payload
        payload = {
            "team": team,                           # 团队名
            "exp": datetime.utcnow() + timedelta(hours=self.TOKEN_EXPIRE_HOURS)  # 过期时间
        }
        # 生成JWT
        token = jwt.encode(payload, self.SECRET_KEY, algorithm=self.ALGORITHM)
        return token
    
    def verify_token(self, token: str) -> Optional[str]:
        """验证JWT令牌,返回团队名"""
        try:
            # 解码JWT
            payload = jwt.decode(token, self.SECRET_KEY, algorithms=[self.ALGORITHM])
            return payload.get("team")
        except jwt.ExpiredSignatureError:
            # 令牌过期
            return None
        except jwt.InvalidTokenError:
            # 令牌无效
            return None
    
    def grant_permission(self, perm: Permission):
        """授予权限"""
        # 用"团队:ServerID"作为key
        key = f"{perm.team}:{perm.server_id}"
        self.permissions[key] = perm
    
    def check_permission(self, team: str, server_id: str, tool_name: str) -> bool:
        """检查团队是否有权限使用某Server的某工具"""
        key = f"{team}:{perm_server_id}" if False else f"{team}:{server_id}"
        perm = self.permissions.get(key)
        if perm is None:
            # 没有权限记录
            return False
        # 检查是否过期
        if perm.expires_at and datetime.now() > perm.expires_at:
            return False
        # 检查工具限制
        if perm.allowed_tools and tool_name not in perm.allowed_tools:
            # 有工具白名单且当前工具不在其中
            return False
        return True

audit.py

"""
审计日志模块
记录所有MCP工具调用的详细日志
"""
from models import AuditLog
from datetime import datetime
import uuid

class AuditLogger:
    """审计日志记录器"""
    
    def __init__(self):
        # 内存存储日志,生产环境用ELK或类似方案
        self.logs = []
    
    def log_call(self, team: str, server_id: str, tool_name: str, 
                action: str, status: str, request_id: str = None):
        """记录一次工具调用"""
        # 生成请求ID(如果没有传入)
        if request_id is None:
            request_id = str(uuid.uuid4())
        
        # 构造日志条目
        entry = AuditLog(
            timestamp=datetime.now(),    # 当前时间
            team=team,                    # 调用方团队
            server_id=server_id,          # 目标Server
            tool_name=tool_name,          # 工具名
            action=action,                # 操作类型
            status=status,                # 结果状态
            request_id=request_id          # 请求ID
        )
        # 存储日志
        self.logs.append(entry)
        return request_id
    
    def query_logs(self, team: str = None, server_id: str = None, 
                   limit: int = 100) -> list:
        """查询审计日志"""
        results = self.logs
        # 按团队过滤
        if team:
            results = [l for l in results if l.team == team]
        # 按Server过滤
        if server_id:
            results = [l for l in results if l.server_id == server_id]
        # 限制返回数量
        return results[-limit:]
    
    def get_stats(self) -> dict:
        """获取调用统计"""
        total = len(self.logs)
        success = sum(1 for l in self.logs if l.status == "success")
        failed = sum(1 for l in self.logs if l.status == "failed")
        return {
            "total_calls": total,        # 总调用数
            "success_calls": success,    # 成功调用数
            "failed_calls": failed,      # 失败调用数
            "success_rate": f"{success/total*100:.1f}%" if total > 0 else "N/A"
        }

proxy.py

"""
请求代理模块
将Agent的工具调用请求转发到实际的MCP Server
"""
import httpx
from audit import AuditLogger

class MCPProxy:
    """MCP请求代理"""
    
    def __init__(self, audit_logger: AuditLogger):
        # 审计日志记录器
        self.audit = audit_logger
        # Server注册表,server_id到endpoint的映射
        self.server_endpoints = {}
    
    def register_endpoint(self, server_id: str, endpoint: str):
        """注册Server的实际地址"""
        self.server_endpoints[server_id] = endpoint
    
    async def forward_tool_call(self, team: str, server_id: str, 
                                tool_name: str, arguments: dict) -> dict:
        """转发工具调用请求到实际MCP Server"""
        # 获取Server地址
        endpoint = self.server_endpoints.get(server_id)
        if not endpoint:
            # Server未注册
            self.audit.log_call(team, server_id, tool_name, 
                              "tool_call", "failed", )
            return {"error": f"Server {server_id} 未注册"}
        
        try:
            # 转发请求到实际Server
            async with httpx.AsyncClient() as client:
                resp = await client.post(
                    f"{endpoint}/mcp/tools/call",
                    json={
                        "tool_name": tool_name,  # 工具名
                        "arguments": arguments,   # 工具参数
                    },
                    timeout=30.0  # 30秒超时
                )
                result = resp.json()
                # 记录审计日志
                self.audit.log_call(
                    team=team,                     # 调用方
                    server_id=server_id,           # 目标Server
                    tool_name=tool_name,           # 工具名
                    action="tool_call",            # 操作类型
                    status="success"               # 成功
                )
                return result
        except httpx.TimeoutException:
            # 请求超时
            self.audit.log_call(team, server_id, tool_name,
                              "tool_call", "failed")
            return {"error": "请求超时"}
        except Exception as e:
            # 其他异常
            self.audit.log_call(team, server_id, tool_name,
                              "tool_call", "failed")
            return {"error": str(e)}
    
    async def list_tools(self, team: str, server_id: str) -> dict:
        """获取Server的工具列表"""
        endpoint = self.server_endpoints.get(server_id)
        if not endpoint:
            return {"error": f"Server {server_id} 未注册"}
        
        async with httpx.AsyncClient() as client:
            resp = await client.get(f"{endpoint}/mcp/tools/list")
            # 记录审计日志
            self.audit.log_call(team, server_id, "", 
                              "list_tools", "success")
            return resp.json()

hub.py

"""
MCP Hub主服务
整合注册、发现、权限、代理和审计功能
"""
from fastapi import FastAPI, Header, HTTPException
from typing import Optional
from models import (MCPServerRegistration, VersionInfo, Permission, 
                    ServerStatus)
from auth import AuthManager
from audit import AuditLogger
from proxy import MCPProxy
import uvicorn

app = FastAPI(title="MCP Hub", version="1.0.0")

# 初始化各模块
auth = AuthManager()
audit = AuditLogger()
proxy = MCPProxy(audit)

# Server注册表,key为server_id
servers = {}
# 版本历史,key为server_id,value为版本列表
version_history = {}

@app.post("/hub/register")
async def register_server(reg: MCPServerRegistration, 
                          x_team: str = Header(...),
                          x_api_key: str = Header(...)):
    """注册一个MCP Server到Hub"""
    # 验证调用方身份
    if not auth.verify_api_key(x_team, x_api_key):
        raise HTTPException(status_code=401, detail="API密钥无效")
    
    # 检查是否已存在同名Server
    if reg.server_id in servers:
        # 已存在,添加为新版本
        if reg.server_id not in version_history:
            version_history[reg.server_id] = []
        # 记录版本信息
        version_history[reg.server_id].append(VersionInfo(
            version=reg.version,
            changelog="版本更新",
        ))
    
    # 存储注册信息
    servers[reg.server_id] = reg
    # 注册Server地址到代理
    proxy.register_endpoint(reg.server_id, reg.endpoint)
    
    # 记录审计日志
    audit.log_call(x_team, reg.server_id, "", "register", "success")
    
    return {"status": "registered", "server_id": reg.server_id}

@app.get("/hub/discover")
async def discover_servers(capability: Optional[str] = None,
                           x_team: str = Header(...),
                           x_api_key: str = Header(...)):
    """发现可用的MCP Server"""
    # 验证身份
    if not auth.verify_api_key(x_team, x_api_key):
        raise HTTPException(status_code=401, detail="API密钥无效")
    
    # 生成令牌供后续调用使用
    token = auth.create_token(x_team)
    
    # 过滤Server列表
    results = []
    for sid, server in servers.items():
        # 按能力过滤
        if capability and capability not in server.tools:
            continue
        results.append({
            "server_id": server.server_id,
            "name": server.name,
            "version": server.version,
            "description": server.description,
            "tools": server.tools,
            "status": server.status.value,
        })
    
    return {"servers": results, "token": token}

@app.post("/hub/call/{server_id}/{tool_name}")
async def call_tool(server_id: str, tool_name: str,
                    arguments: dict,
                    authorization: str = Header(...)):
    """通过Hub代理调用MCP工具"""
    # 从header中提取token
    token = authorization.replace("Bearer ", "")
    # 验证令牌
    team = auth.verify_token(token)
    if not team:
        raise HTTPException(status_code=401, detail="令牌无效或过期")
    
    # 检查Server是否存在
    if server_id not in servers:
        raise HTTPException(status_code=404, detail="Server不存在")
    
    # 检查权限
    if not auth.check_permission(team, server_id, tool_name):
        raise HTTPException(status_code=403, detail="无权限使用此工具")
    
    # 转发调用
    result = await proxy.forward_tool_call(team, server_id, tool_name, arguments)
    return result

@app.get("/hub/tools/{server_id}")
async def list_tools(server_id: str,
                     authorization: str = Header(...)):
    """列出某Server的所有工具"""
    # 验证令牌
    token = authorization.replace("Bearer ", "")
    team = auth.verify_token(token)
    if not team:
        raise HTTPException(status_code=401, detail="令牌无效")
    
    # 转发工具列表请求
    return await proxy.list_tools(team, server_id)

@app.post("/hub/permissions")
async def grant_permission(perm: Permission,
                           x_team: str = Header(...),
                           x_api_key: str = Header(...)):
    """授予团队权限(仅管理员)"""
    # 验证身份
    if not auth.verify_api_key(x_team, x_api_key):
        raise HTTPException(status_code=401, detail="API密钥无效")
    
    # 授权
    auth.grant_permission(perm)
    # 记录日志
    audit.log_call(x_team, perm.server_id, "", "grant_permission", "success")
    return {"status": "granted"}

@app.get("/hub/audit/logs")
async def get_audit_logs(team: Optional[str] = None,
                         limit: int = 100,
                         x_team: str = Header(...),
                         x_api_key: str = Header(...)):
    """查询审计日志"""
    if not auth.verify_api_key(x_team, x_api_key):
        raise HTTPException(status_code=401, detail="API密钥无效")
    
    # 查询日志
    logs = audit.query_logs(team=team, limit=limit)
    return {
        "logs": [l.dict() for l in logs],
        "stats": audit.get_stats()
    }

@app.get("/hub/health")
async def health_check():
    """Hub健康检查端点"""
    return {
        "status": "healthy",
        "registered_servers": len(servers),
        "total_calls": len(audit.logs)
    }

if __name__ == "__main__":
    # 启动Hub服务
    uvicorn.run(app, host="0.0.0.0", port=9000)

start.sh

#!/bin/bash
# MCP Hub启动脚本

# 安装依赖
pip install -r requirements.txt

# 初始化权限(示例)
python -c "
from auth import AuthManager
from models import Permission
auth = AuthManager()
# 给数据团队授权访问filesystem Server
auth.grant_permission(Permission(
    team='data_team',
    server_id='fs-001',
    allowed_tools=[],  # 空列表表示全部工具
))
# 给ML团队授权
auth.grant_permission(Permission(
    team='ml_team',
    server_id='fs-001',
    allowed_tools=['read_file'],  # 只允许读文件
))
print('权限初始化完成')
"

# 启动Hub
python hub.py

效果验证

# 1. 安装依赖并启动Hub
chmod +x start.sh
./start.sh

# 2. 注册一个MCP Server(用curl模拟)
curl -X POST http://localhost:9000/hub/register \
  -H "Content-Type: application/json" \
  -H "x-team: data_team" \
  -H "x-api-key: key-data-001" \
  -d '{
    "server_id": "fs-001",
    "name": "filesystem-server",
    "version": "1.0.0",
    "description": "文件系统操作",
    "tools": ["read_file", "write_file", "list_dir"],
    "endpoint": "http://localhost:8003",
    "owner_team": "ops_team"
  }'

# 3. 发现可用Server
curl http://localhost:9000/hub/discover \
  -H "x-team: data_team" \
  -H "x-api-key: key-data-001"

# 4. 通过Hub调用工具
curl -X POST http://localhost:9000/hub/call/fs-001/read_file \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <token_from_discover>" \
  -d '{"path": "/tmp/test.txt"}'

# 5. 查看审计日志
curl http://localhost:9000/hub/audit/logs \
  -H "x-team: data_team" \
  -H "x-api-key: key-data-001"

预期输出是Server注册成功,发现接口返回Server列表和JWT令牌,工具调用通过Hub代理执行,审计日志记录完整。

独家踩坑经验 企业内网HTTPS证书问题

这个坑折磨了我整整三天。企业内网环境下搭MCP Hub,HTTPS证书是个大麻烦。

事情是这样的。Hub部署在企业的内网服务器上,域名是mcp-hub.internal.company.com。内网CA签发的证书在大部分内部系统上都没问题,但MCP的客户端SDK对证书校验特别严格,默认不信任内网CA签发的证书。

具体表现是Agent连接Hub时报错SSL: CERTIFICATE_VERIFY_FAILED。你以为加个环境变量NODE_EXTRA_CA_CERTS就行了吗?不行,因为MCP SDK内部用的是Python的httpx,httpx默认用系统证书库,跟Node的环境变量不是一回事。

我试了三种方案。

方案 做法 效果 推荐度
方案A 在每台Agent机器上导入内网CA证书 有效但运维成本高 不推荐
方案B Hub用Let’s Encrypt证书 内网域名无法签发 不可行
方案C Hub使用自签证书,Agent端关闭校验 有效但有安全风险 不推荐
方案D 搭建内部CA,统一分发根证书 一劳永逸 推荐

最终我采用了方案D,搭建内部CA。核心步骤如下。

"""
内部CA证书管理工具
解决企业内网MCP Hub的HTTPS证书问题
"""
import subprocess
import os
from datetime import datetime, timedelta

class InternalCAManager:
    """内部CA证书管理器"""
    
    def __init__(self, ca_dir="/etc/mcp-hub/ca"):
        # CA证书存放目录
        self.ca_dir = ca_dir
        # 根证书路径
        self.root_cert = os.path.join(ca_dir, "root-ca.crt")
        # 根私钥路径
        self.root_key = os.path.join(ca_dir, "root-ca.key")
    
    def generate_root_ca(self):
        """生成根CA证书"""
        # 使用openssl生成根证书
        # 这个证书需要分发给所有Agent机器
        subprocess.run([
            "openssl", "req", "-x509", "-newkey", "rsa:4096",
            "-keyout", self.root_key,          # 输出私钥
            "-out", self.root_cert,            # 输出证书
            "-days", "3650",                    # 有效期10年
            "-nodes",                           # 不加密私钥
            "-subj", "/CN=MCP Hub Internal CA",  # 证书主题
        ], check=True)
        print(f"根CA证书已生成: {self.root_cert}")
        print("请将此证书分发到所有Agent机器的信任库中")
    
    def sign_server_cert(self, domain: str):
        """为Hub域名签发服务器证书"""
        # 生成私钥
        server_key = os.path.join(self.ca_dir, f"{domain}.key")
        # 生成CSR
        server_csr = os.path.join(self.ca_dir, f"{domain}.csr")
        # 签发证书
        server_cert = os.path.join(self.ca_dir, f"{domain}.crt")
        
        # 第一步:生成服务器私钥
        subprocess.run([
            "openssl", "genrsa", "-out", server_key, "2048"
        ], check=True)
        
        # 第二步:生成CSR(证书签名请求)
        subprocess.run([
            "openssl", "req", "-new",
            "-key", server_key,
            "-out", server_csr,
            "-subj", f"/CN={domain}",  # 证书主题设为域名
        ], check=True)
        
        # 第三步:用根CA签发证书
        subprocess.run([
            "openssl", "x509", "-req",
            "-in", server_csr,                # 输入CSR
            "-CA", self.root_cert,            # 根CA证书
            "-CAkey", self.root_key,          # 根CA私钥
            "-CAcreateserial",                # 生成序列号文件
            "-out", server_cert,              # 输出证书
            "-days", "365",                   # 有效期1年
            "-extfile", "-",                  # 从stdin读取扩展配置
        ], input=f"subjectAltName=DNS:{domain}\n".encode(), check=True)
        
        print(f"服务器证书已签发: {server_cert}")
        print(f"私钥: {server_key}")
        return server_cert, server_key
    
    def get_agent_config(self):
        """生成Agent端的证书配置指引"""
        return """
Agent端配置步骤:

1. 将根CA证书复制到Agent机器:
   cp root-ca.crt /usr/local/share/ca-certificates/mcp-hub-ca.crt
   
2. 更新系统证书库:
   # Ubuntu/Debian
   update-ca-certificates
   
   # CentOS/RHEL
   update-ca-trust
   
3. 设置Python环境变量(如果用httpx):
   export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
   export REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
   
4. 验证证书是否生效:
   python -c "import httpx; r=httpx.get('https://mcp-hub.internal.company.com/hub/health'); print(r.json())"
"""


# 使用示例
if __name__ == "__main__":
    ca = InternalCAManager()
    # 生成根CA(只需一次)
    ca.generate_root_ca()
    # 为Hub域名签发证书
    ca.sign_server_cert("mcp-hub.internal.company.com")
    # 打印Agent配置指引
    print(ca.get_agent_config())

搞定内部CA之后,Agent连接Hub的HTTPS报错彻底消失。核心教训就是,企业内网环境下部署MCP基础设施,HTTPS证书一定要提前规划好,不要等到最后才发现证书不信任的问题。

版本管理的最佳实践

Hub还有一个重要功能是版本管理。我总结了三条原则。

原则一,保留所有历史版本。不要因为出了新版本就把旧版本删了。有些Agent可能依赖旧版本的接口格式,删了就连接不上了。

原则二,废弃但不删除。旧版本标记为deprecated,新注册的Server不允许用旧版本,但已经连接的Agent可以继续用。

原则三,版本兼容性矩阵。在Hub里维护一张表,记录哪个版本的Server兼容哪个版本的Agent客户端。

# 版本兼容性矩阵示例
COMPATIBILITY_MATRIX = {
    "server_v1.0": ["client_v1.0", "client_v1.1"],  # v1.0 Server兼容这些客户端
    "server_v1.1": ["client_v1.1", "client_v2.0"],  # v1.1 Server兼容这些客户端
    "server_v2.0": ["client_v2.0"],                  # v2.0只兼容v2.0客户端
}

def check_compatibility(server_version: str, client_version: str) -> bool:
    """检查Server和Client版本是否兼容"""
    compatible_clients = COMPATIBILITY_MATRIX.get(server_version, [])
    return client_version in compatible_clients

常见问题与避坑

Q:Hub本身会不会成为单点故障?

会。所以Hub要部署高可用方案,至少两台机器做负载均衡。Hub本身是无状态的(数据存在外部数据库),横向扩展比较容易。

Q:Hub会不会成为性能瓶颈?

会有一定影响,因为每次工具调用都多了一跳。对于高频调用的场景,可以考虑给Hub加缓存,对相同的工具调用结果做短期缓存。

Q:权限模型太复杂怎么办?

如果团队不多(5个以内),可以简化为基于团队的白名单模型,不需要细粒度到工具级别。等团队多了再加细粒度控制。

Q:Hub需要支持MCP协议的原生格式吗?

建议支持。Hub最好能同时作为MCP Server对外暴露,这样Agent不需要改代码就能从直连模式切换到Hub模式。

小结

私有MCP Hub解决的是企业内部MCP工具集中管理的问题。核心功能包括Server注册与发现、版本管理、权限控制和审计日志。搭Hub时最难的不是代码,而是企业内网的HTTPS证书问题。提前规划好证书体系,能省你很多深夜加班的时间。

最后一篇我们聊MCP工具的商业化,从开发到变现,看看怎么把一个MCP Server变成一门生意。


相关推荐

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐