一个用于模型上下文协议(MCP)服务的安全反向代理,支持 OIDC 身份验证。
模型上下文协议(MCP)是一种开放协议,标准化了应用程序如何向大型语言模型(LLMs)提供上下文。它就像“AI 应用程序的 USB-C 接口”——在应用程序和 AI 模型之间创建一致的接口。
MCP 遵循客户端-服务器架构,主机应用程序连接到多个服务器,这使得在不同 AI 提供商之间切换时能够保持一致的数据处理实践和安全性。
更多详情,请访问 modelcontextprotocol.io。
SMCP 代理在模型上下文协议(MCP)服务前提供了一层安全保护,使用 OIDC 实现企业级的身份验证和授权。MCP 是一种设计用于以标准化方式与大型语言模型(LLMs)交互的协议。
代理由两个主要组件组成:
该项目的主要目标是:
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ 应用程序 │ │ 代理客户端 │ │ 代理服务器 │ ┌───────────┐
│ (无认证) │──────│ (本地) │──────│ (有认证) │──────│ MCP 服务器│
└───────────────┘ └───────────────┘ └───────────────┘ └───────────┘
│ ▲
│ │
│ │
▼ │
┌────────────┐ │
│ OIDC │───────────────┘
│ 提供者 │
└────────────┘
# 构建包含服务器和客户端功能的单一可执行文件
go build -o smcp-proxy ./cmd/smcp
SMCP 代理也作为 Docker 镜像提供,可以从 GitHub 容器注册表拉取:
# 拉取最新镜像
docker pull ghcr.io/ksysoev/smcp-proxy:main
# 拉取特定版本
docker pull ghcr.io/ksysoev/smcp-proxy:v1.0.0
运行服务器:
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 身份验证运行服务器
./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 身份验证运行客户端
./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
一旦两个组件都在运行:
代理服务器支持具有不同传输类型的多个 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 未找到(没有匹配的后端)代理支持两种类型的后端:
HTTP 后端(transport: "http"):
url: "http://mcp-server.example.com"Stdio 后端(transport: "stdio"):
# 顺序思维 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/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 # 本文件