返回市场
smcp代理

smcp代理

作者:ksysoev2 星标更新:2025-05-04

项目介绍

技术文档摘要

SMCP 代理

Go CI Docker 构建 Go 报告卡 Codecov Go 参考

一个用于模型上下文协议(MCP)服务的安全反向代理,支持 OIDC 身份验证。

模型上下文协议(MCP)是什么?

模型上下文协议(MCP)是一种开放协议,标准化了应用程序如何向大型语言模型(LLMs)提供上下文。它就像“AI 应用程序的 USB-C 接口”——在应用程序和 AI 模型之间创建一致的接口。

MCP 遵循客户端-服务器架构,主机应用程序连接到多个服务器,这使得在不同 AI 提供商之间切换时能够保持一致的数据处理实践和安全性。

更多详情,请访问 modelcontextprotocol.io

概览

SMCP 代理在模型上下文协议(MCP)服务前提供了一层安全保护,使用 OIDC 实现企业级的身份验证和授权。MCP 是一种设计用于以标准化方式与大型语言模型(LLMs)交互的协议。

代理由两个主要组件组成:

  1. 代理服务器:验证来自客户端的 OIDC 令牌,并将经过身份验证的请求转发给 MCP 服务器。
  2. 代理客户端:实现客户端凭证流以获取令牌,并作为本地未认证的 MCP 服务运行。

该项目的主要目标是:

  • 使用 OIDC 身份验证提供对 MCP 服务的安全访问
  • 在企业环境中支持可扩展的 MCP 基础设施
  • 为 MCP 服务实现集中式身份验证和授权
  • 简化客户端与经过身份验证的 MCP 服务的集成

架构

┌───────────────┐      ┌───────────────┐      ┌───────────────┐
│  应用程序    │      │  代理客户端  │      │  代理服务器  │      ┌───────────┐
│  (无认证)  │──────│  (本地)     │──────│  (有认证)   │──────│ MCP 服务器│
└───────────────┘      └───────────────┘      └───────────────┘      └───────────┘
                         │                       ▲
                         │                       │
                         │                       │
                         ▼                       │
                    ┌────────────┐               │
                    │ OIDC       │───────────────┘
                    │ 提供者     │
                    └────────────┘

功能

服务器端(代理服务器)

  • 可配置的身份验证模式(无、OIDC)
  • 当启用 OIDC 时:
    • 验证来自客户端的 OIDC 令牌
    • 可配置的信任发行者和令牌声明验证
  • 将请求转发给 MCP 服务器
  • 支持多个 MCP 后端
  • 多种后端服务器传输类型(HTTP 和 stdio)
  • 基于路径的路由,可选地剥离路径前缀
  • 通过 stdio 管理本地 MCP 进程
  • 模型 API 用于发现可用模型
  • 支持可扩展部署
  • 健康检查端点
  • 结构化日志和指标

客户端端(代理客户端)

  • 可配置的身份验证模式(无、OIDC)
  • 当启用 OIDC 时:
    • 实现客户端凭证流以获取令牌
    • 自动刷新令牌
  • 作为本地 MCP 服务运行
  • 将请求代理到服务器端组件
  • 健康检查端点
  • 结构化日志

安装

要求

  • Go 1.24 或更高版本

从源代码构建

# 构建包含服务器和客户端功能的单一可执行文件
go build -o smcp-proxy ./cmd/smcp

Docker 镜像

SMCP 代理也作为 Docker 镜像提供,可以从 GitHub 容器注册表拉取:

# 拉取最新镜像
docker pull ghcr.io/ksysoev/smcp-proxy:main

# 拉取特定版本
docker pull ghcr.io/ksysoev/smcp-proxy:v1.0.0

使用 Docker 运行

运行服务器:

docker run -p 8080:8080 -v $(pwd)/configs:/app/configs ghcr.io/ksysoev/smcp-proxy:main server --config=/app/configs/proxy-server.yml

运行客户端:

docker run -p 8081:8081 ghcr.io/ksysoev/smcp-proxy:main client --server-url=http://your-server:8080

Docker 镜像适用于 AMD64 和 ARM64 架构。

配置

配置通过 YAML 文件提供。示例配置文件位于 configs 目录中。

服务器配置

服务器配置指定在 configs/proxy-server.yml 中:

server:
  host: "0.0.0.0"
  port: 8080
  read_timeout: "30s"
  write_timeout: "30s"
  shutdown_timeout: "10s"

# 身份验证配置(默认:无)
auth:
  # 模式可以是 "none" 或 "oidc"
  mode: "none"

mcp:
  # 所有后端的全局超时(可以针对每个后端覆盖)
  timeout: "60s"
  
  # 配置多个 MCP 后端
  backends:
    # 顺序思维 MCP 服务器
    - id: "sequentialthinking"
      name: "顺序思维"
      transport: "stdio"
      path: "/v1/sequentialthinking"
      strip_path: true
      stdio:
        command: "docker"
        args: ["run", "--rm", "-i", "mcp/sequentialthinking"]
        stdio_timeout: "60s"
    
    # 内存 MCP 服务器
    - id: "memory"
      name: "内存"
      transport: "stdio"
      path: "/v1/memory"
      strip_path: true
      stdio:
        command: "docker"
        args: ["run", "-i", "-v", "claude-memory:/app/dist", "--rm", "mcp/memory"]
        stdio_timeout: "60s"

# OIDC 设置(仅当 auth.mode 是 "oidc" 时使用)
oidc:
  issuers:
    - "https://your-identity-provider.com"  # 替换为实际的 OIDC 发行者 URL
  audience: "your-api-audience"            # 替换为您的 API 受众
  required_claims:
    # 定义必须存在于令牌中的所需声明
    # 例如:
    # roles: "admin"
  optional_claims:
    # 定义如果存在则必须匹配特定值的可选声明
    # 例如:
    # scope: "read:data"

tls:
  enabled: false
  # cert_file: "/path/to/cert.pem"
  # key_file: "/path/to/key.pem"

metrics:
  enabled: true
  path: "/metrics"

客户端配置

代理客户端已简化为使用命令行参数和环境变量,而不是配置文件。

命令行参数

客户端标志:
  --host string                  绑定客户端的主机(默认 "127.0.0.1")
  --port int                     绑定客户端的端口(默认 8081)
  --read-timeout duration        HTTP 读取超时(默认 30s)
  --write-timeout duration       HTTP 写入超时(默认 30s)
  --shutdown-timeout duration    平滑关闭超时(默认 10s)

服务器标志:
  --server-url string            代理服务器的 URL(必需)
  --server-timeout duration      请求到服务器的超时(默认 60s)

身份验证标志:
  --auth-mode string             身份验证模式(无、oidc)(默认 "none")

OIDC 标志(仅当 auth-mode 是 "oidc" 时使用):
  --oidc-issuer string           OIDC 发行者 URL
  --oidc-client-id string        OIDC 客户端 ID
  --oidc-client-secret string    OIDC 客户端密钥
  --oidc-audience string         OIDC 受众
  --oidc-scopes string           OIDC 范围(逗号分隔)(默认 "openid")
  --oidc-cache-ttl duration      OIDC 令牌缓存 TTL(默认 5m0s)
  --oidc-token-ttl-delta duration OIDC 令牌 TTL 增量(默认 30s)

TLS 标志:
  --tls                          启用 TLS(默认 false)
  --tls-cert string              TLS 证书文件路径
  --tls-key string               TLS 密钥文件路径

指标标志:
  --metrics                      启用指标端点(默认 true)
  --metrics-path string          指标端点路径(默认 "/metrics")

日志标志:
  -l, --log-level string         日志级别(调试、信息、警告、错误)(默认 "信息")
  -f, --log-format string        日志格式(文本、json)(默认 "文本")

环境变量

所有命令行选项也可以通过带有前缀 SMCP_CLIENT_ 的环境变量设置。例如:

# 必要配置
export SMCP_SERVER_URL="http://localhost:8080"

# 身份验证模式(默认是 "none")
export SMCP_AUTH_MODE="none" # 或 "oidc"

# OIDC 设置(仅当 SMCP_AUTH_MODE="oidc" 时需要)
export SMCP_OIDC_ISSUER="https://your-identity-provider.com"
export SMCP_OIDC_CLIENT_ID="your-client-id"
export SMCP_OIDC_CLIENT_SECRET="your-client-secret"

# 可选配置
export SMCP_CLIENT_HOST="127.0.0.1"
export SMCP_CLIENT_PORT=8081
export SMCP_OIDC_AUDIENCE="your-api-audience"
export SMCP_OIDC_SCOPES="openid,profile,email"

服务器配置仍然使用 YAML 文件,并可以通过带有前缀 SMCP_PROXY_ 的环境变量进行覆盖。

使用

启动服务器

关闭身份验证(默认)

# 不带身份验证运行服务器
./smcp-proxy server --config=configs/proxy-server.yml --log-level=debug

开启 OIDC 身份验证

# 带 OIDC 身份验证运行服务器
./smcp-proxy server --config=configs/proxy-server.yml --auth-mode=oidc --log-level=debug

启动客户端

关闭身份验证(默认)

# 不带身份验证运行客户端
./smcp-proxy client --server-url="http://localhost:8080" --log-level=debug

# 或使用环境变量
export SMCP_SERVER_URL="http://localhost:8080"
./smcp-proxy client --log-level=debug

开启 OIDC 身份验证

# 带 OIDC 身份验证运行客户端
./smcp-proxy client \
    --auth-mode=oidc \
    --server-url="http://localhost:8080" \
    --oidc-issuer="https://your-identity-provider.com" \
    --oidc-client-id="your-client-id" \
    --oidc-client-secret="your-client-secret" \
    --log-level=debug

# 或使用环境变量
export SMCP_SERVER_URL="http://localhost:8080"
export SMCP_AUTH_MODE="oidc"
export SMCP_OIDC_ISSUER="https://your-identity-provider.com"
export SMCP_OIDC_CLIENT_ID="your-client-id"
export SMCP_OIDC_CLIENT_SECRET="your-client-secret"
./smcp-proxy client --log-level=debug

一旦两个组件都在运行:

  1. 应用程序可以连接到客户端组件(默认在 http://localhost:8081)
  2. 客户端组件将请求转发到服务器
  3. 如果启用了身份验证,客户端将通过 OIDC 提供者进行身份验证,服务器将验证令牌
  4. 服务器根据请求路径将请求转发到适当的 MCP 后端

多个后端支持

代理服务器支持具有不同传输类型的多个 MCP 后端:

┌─────────────┐                  ┌───────────────────────────────┐
│ 请求到     │                  │        代理服务器           │
│ /v1/seq../  ├─────────────────►│                               │──► Stdio 顺序思维后端
└─────────────┘                  │                               │
                                 │                               │
┌─────────────┐                  │                               │
│ 请求到     │                  │    OIDC 身份验证 +      │
│ /v1/memory/ ├─────────────────►│     基于路径的路由        │──► Stdio 内存后端
└─────────────┘                  │                               │
                                 │                               │
┌─────────────┐                  │                               │
│ 请求到     │                  │                               │
│ /other/path ├─────────────────►│                               │──► 404 未找到
└─────────────┘                  └───────────────────────────────┘

基于路径的路由

启用 strip_path 选项后,代理将在转发请求到后端之前移除路径前缀:

  • 请求到 /v1/sequentialthinking/completions → 转发到顺序思维后端作为 /completions
  • 请求到 /v1/memory/messages → 转发到内存后端作为 /messages
  • 请求到 /some/other/path → 返回 404 未找到(没有匹配的后端)

传输类型

代理支持两种类型的后端:

  1. HTTP 后端transport: "http"):

    • 通过 HTTP 访问的远程 MCP 服务器
    • 使用 URL 和标准代理设置配置
    • 示例:url: "http://mcp-server.example.com"
  2. Stdio 后端transport: "stdio"):

    • 作为子进程运行的本地 MCP 服务器
    • 通过标准输入/输出通信
    • 对于运行本地模型服务器很有用
    • 示例:
      # 顺序思维 MCP 服务器
      stdio:
        command: "docker"
        args: ["run", "--rm", "-i", "mcp/sequentialthinking"]
      
      # 内存 MCP 服务器
      stdio:
        command: "docker"
        args: ["run", "-i", "-v", "claude-memory:/app/dist", "--rm", "mcp/memory"]
      

模型 API

代理提供了一个 /api/models 端点,返回有关所有配置后端的信息,遵循 Anthropic API 模型格式。这允许客户端发现可用模型及其功能。

开发

项目结构

.
├── cmd/                    # 应用程序入口点
│   └── smcp/               # 单一可执行目录 
│       └── main.go         # 主入口点
├── configs/                # 配置文件
│   ├── proxy-server.yml    # 服务器配置
│   └── proxy-client.yml    # 客户端配置示例(非必需)
├── internal/               # 私有应用代码
│   ├── middleware/         # HTTP 中间件
│   │   ├── logging.go      # 请求日志中间件
│   │   └── recovery.go     # 异常恢复中间件
│   └── metrics/            # 指标实现(占位符)
├── pkg/                    # 公共 API
│   ├── auth/               # 身份验证组件
│   │   ├── validator.go    # OIDC 令牌验证
│   │   └── client.go       # OIDC 客户端凭证流
│   ├── cmd/                # 命令行界面
│   │   ├── root.go         # 根命令
│   │   ├── server.go       # 服务器命令
│   │   └── client.go       # 客户端命令
│   ├── config/             # 配置处理
│   │   ├── server_config.go # 服务器配置
│   │   └── client_config.go # 客户端配置
│   └── proxy/              # 代理实现
│       ├── server.go       # 服务器端代理
│       └── client.go       # 客户端端代理
├── go.mod                  # Go 模块定义
└── README.md               # 本文件

设计原则

  1. 安全第一:所有身份验证和授权都按照最佳安全实践实施。
  2. 可扩展性:代理设计用于处理多个 MCP 服务器和客户端。
  3. 可配置性:广泛的配置选项允许针对不同环境进行定制。
  4. 弹性:系统优雅地处理失败,具有适当的错误处理和恢复。
  5. 可观测性:全面的日