关于 skgate
skgate 是可自托管的 MCP 网关和大模型代理,面向需要集中管理 MCP 接入及模型 API 的运营者。它支持 OAuth 2.1、托管 MCP 服务和可配置模型别名。
主要功能
- 01受 OAuth 2.1 保护的 MCP 网关
- 02按需启动托管 MCP 服务
- 03兼容 OpenAI 的多提供商 API
- 04自定义模型别名和虚拟密钥
- 05将 REST API 暴露为 MCP 工具
适用场景
- 01集中接入远程及托管 MCP 服务
- 02切换大模型提供商而不改客户端配置
- 03向 MCP 客户端开放选定的 OpenAPI 操作
MCP 相关
skgate 将 MCP 客户端路由至远程、REST/OpenAPI 和托管 MCP 服务,并支持 OAuth 2.1。托管服务可按需启动。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
docker run -i --rm -e PUBLIC_URL -e OIDC_ISSUER -e OIDC_CLIENT_ID -e OIDC_CLIENT_SECRET ghcr.io/helv-io/skgate:0.28.0PUBLIC_URLPublic origin of skgate, no trailing slash.OIDC_ISSUERIssuer URL of the OIDC provider used for admin sign-in.OIDC_CLIENT_IDOIDC client ID.OIDC_CLIENT_SECRET密钥OIDC client secret.本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
ghcr.io/helv-io/skgate:0.28.0Streamable HTTPghcr.io/helv-io/skgate:0.28.0-slimStreamable HTTP工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
skgate
可自托管的 MCP 网关和大模型代理。通过一个地址,在 OAuth 2.1 后提供任意 MCP 服务或 REST API;还可通过一个兼容 OpenAI 的 API 代理各种大模型提供商(OpenAI、Anthropic、Gemini、Grok、Ollama 等),并支持模型别名和虚拟密钥。Grok 订阅也能用,无需 API 密钥。
任意 MCP 服务。skgate 可以代为运行,无需每个服务都使用一个容器。
名称由来
skgate /ɛsˈkɑːɡeɪt/(ess-KAH-gate)
很多 SI API 密钥都以「sk」开头,而「gate」代表网关。名字不怎么样,但这是我们的项目。
徽标里的飞机是个内部笑话。公众不会明白,我也不打算解释。抱歉。
质量
它好用吗?
好用
快速开始
你需要一个 OIDC 提供商,并为 skgate 配置一个机密客户端。管理员只能通过 OIDC 登录。只想在一台机器上试用?docs/quickstart.md 会使用内置提供商运行 skgate,无需账户。
# docker-compose.yml
services:
skgate:
container_name: skgate
image: ghcr.io/helv-io/skgate:latest
restart: always
ports:
- 8080:8080
environment:
- PUBLIC_URL=https://skgate.example.com
- OIDC_ISSUER=https://auth.example.com
- OIDC_CLIENT_ID=skgate
- OIDC_CLIENT_SECRET=change-me
volumes:
- ./data:/data
healthcheck:
test: ["CMD", "/skgate", "healthcheck"]
interval: 30s
timeout: 5s
retries: 3
docker compose up -d- 打开
https://skgate.example.com/admin,通过 OIDC 提供商登录。 - mcp upstreams > Add upstream:添加远程 MCP 服务,或添加由 skgate 代为运行的 GitHub 仓库、npm 包或 PyPI 包(参见示例)。
- 将 MCP 客户端指向
https://skgate.example.com/mcp或站点根地址,即可访问所有已添加的上游;也可以指向https://skgate.example.com/mcp/<alias>,仅访问一个上游。按提示登录。
镜像标签:
latest:代理 + 托管的 MCP 服务。内置 Node.js(npx)、pnpm、Bun(bunx)、Deno、Python(uv、uvx)、Go、.NET 和 git。slim:仅代理
升级前,请备份 ./data,然后运行 docker compose pull && docker compose up -d。
代理你的 SI 提供商
skgate 还是一个位于你的 SI 提供商前端、兼容 OpenAI 的 API。让应用指向同一个地址;无需更改应用,即可切换其背后的提供商。用户自定义的模型别名可为应用提供稳定的模型名称,由你自行选择。
Grok 支持通过订阅登录,无需 API 密钥。其他提供商使用各自的 API 密钥(OpenAI、Anthropic、Gemini、Mistral、DeepSeek、Groq、OpenRouter、Ollama、LM Studio,以及任何兼容 OpenAI 的端点)。
- status > Grok > Sign in:打开显示的地址,输入代码并批准。skgate 会保持登录状态有效。
- keys > 输入名称 > Create key。复制
sk-...密钥;它只会显示一次。 - 使用该密钥:基础 URL 为
https://skgate.example.com/v1,API 密钥为sk-...(参见示例)。- 这些基础 URL 都会访问同一个 API:
/v1、/api、/api/v1和纯主机地址。根据客户端的要求选择即可。
- 这些基础 URL 都会访问同一个 API:
- 添加其他提供商:status > Add provider,选择一个提供商并输入其 API 密钥。以任意格式输入提供商地址;skgate 会找到可用地址。
示例
curl:获取模型列表并完成聊天
export SKGATE=https://skgate.example.com KEY=sk-...
curl -s $SKGATE/v1/models -H "Authorization: Bearer $KEY"
curl -s $SKGATE/v1/chat/completions -H "Authorization: Bearer $KEY" \
-H 'Content-Type: application/json' \
-d '{"model":"<id from /v1/models>","messages":[{"role":"user","content":"Say hi"}]}'
OpenAI 客户端
export OPENAI_BASE_URL=https://skgate.example.com/v1 OPENAI_API_KEY=sk-...
from openai import OpenAI
client = OpenAI() # reads the two variables above
r = client.chat.completions.create(model="<id from /v1/models>", messages=[{"role": "user", "content": "Say hi"}])
print(r.choices[0].message.content)
模型别名:为模型自定义名称
别名由用户自行定义:skgate 不提供任何预设别名。选择任意名称,并将其指向一个模型。本例使用 grok-latest,名称由你决定。
只需在这个位置更改目标,所有使用该名称的应用都会立即切换,无需更改客户端配置。
Grok > Aliases:New alias grok-latest,Target model grok-4.7,Add alias。
client sends {"model": "grok-latest", ...}
skgate sends {"model": "grok-4.7", ...}
别名会列在 /v1/models 的最前面。
使用 Suggest configuration 添加 MCP 服务
需要使用 `latest` 镜像,以及来自任意就绪提供商的 MCP 辅助模型。首次使用时,点击按钮旁的 **Pick MCP helper model**,即可直接在页面上打开模型选择器。mcp upstreams > Add upstream > 输入 managed process:
-
MCP source URL / package,以下任选其一:
来源 运行方式 @modelcontextprotocol/server-everythingnpm 包, npxpypi:mcp-server-timePyPI 包, uvxhttps://github.com/example-org/notes-mcpgit 仓库:克隆、安装、运行(私有仓库:Suggest 会要求提供令牌) -
Suggest configuration。skgate 会获取 README 和清单(
package.json、pyproject.toml、server.json)。MCP 辅助模型会提供命令、参数、安装步骤,以及环境变量名称(是否为密钥、是否必填)。Manual configuration 字段会自动填入,并附带置信度和任何警告。
此时还不会保存任何内容。请设置服务器所需的变量。
-
设置别名,填写所需变量(空值不会传递给服务器),然后点击 Save。服务器地址为
https://skgate.example.com/mcp/<alias>。
如果按钮呈灰色,请将鼠标悬停在按钮上。使用旁边的 Pick MCP helper model,或先在 status 中添加提供商。
MCP 客户端:单个上游或全部上游
| URL | 提供内容 |
|---|---|
https://skgate.example.com/mcp/<alias> | 单个上游 |
https://skgate.example.com/mcp | 所有标记为 In /mcp 的上游 |
https://skgate.example.com/(MCP 客户端) | 当 Accept/Content-Type 看起来像 MCP 时,与 /mcp 提供相同的聚合内容;浏览器仍会访问 /admin |
托管连接器使用 OAuth(client ID 和 secret 留空)。脚本和 CLI 需要发送密钥:
{"mcpServers": {"skgate": {"type": "http", "url": "https://skgate.example.com/mcp/<alias>",
"headers": {"Authorization": "Bearer sk-..."}}}}
按需 MCP 服务:空闲时不占用 RAM
在 RAM 受限的家庭实验室中,空闲的 MCP 服务不应产生任何开销。
托管服务(npx、pnpm dlx、bunx、deno、uvx、git)是 skgate 的子进程。
默认情况下(Lifecycle 为 on-demand),服务会在收到第一个请求时启动,并在 10 分钟没有请求后停止;下一个请求会再次启动它。
before 3 MCP servers = 3 containers, always running
after 1 skgate container; 0 server processes while idle, 1 per server in use
stopped --request--> starting --> running --10 min idle--> stopped
- 默认模式为按需;Lifecycle 设为
always-on后,服务会在启动时运行。 - 服务停止后的第一个请求会等待服务启动。
- 有正在处理的请求时,服务绝不会停止。
- 空闲时间通过导入 JSON 中的
idleTimeoutSeconds设置(默认值为 600;表单中没有此项):
{"mcpServers": {"time": {"command": "uvx", "args": ["mcp-server-time"], "skgate": {"idleTimeoutSeconds": 120}}}}
- 聚合端点
/mcp会包含标记为 In /mcp 的远程、OpenAPI 和常驻上游。按需服务会被排除,因此/mcp绝不会启动它们。要使用某个按需服务,请将客户端指向/mcp/<alias>。 - 远程和 OpenAPI 上游没有进程,因此无需进入空闲状态。
- 管理员点击 Stop 后,服务会保持停止状态,直到点击 Start 或 Restart。
托管 MCP 服务:npx(stdio)
mcp upstreams > import JSON > 粘贴 > Import。需要使用 latest 镜像。
{"mcpServers": {"everything": {"command": "npx", "args": ["-y", "@modelcontextprotocol/server-everything"]}}}
服务地址为 https://skgate.example.com/mcp/everything。同一个包可以使用任意内置运行器运行:
| 运行器 | command | args |
|---|---|---|
| npm | npx | ["-y", "<package>"] |
| pnpm | pnpm | ["dlx", "<package>"] |
| Bun | bunx | ["<package>"] |
| Deno | deno | ["run", "-A", "npm:<package>"] |
| Python | uvx | ["<package>"] |
托管 MCP 服务:git 仓库
mcp upstreams > import JSON > 粘贴 > Import。skgate 会克隆仓库、运行 install,然后执行命令。
{"mcpServers": {"notes": {"command": "node", "args": ["server.js"],
"skgate": {"gitUrl": "https://github.com/example-org/notes-mcp.git", "gitRef": "main", "install": "npm ci"}}}}
远程 MCP 服务
mcp upstreams > Add upstream > 输入 remote server,或导入:
{"mcpServers": {"docs": {"type": "http", "url": "https://mcp.example.com/mcp",
"headers": {"Authorization": "Bearer ..."}}}}
| 功能 | 作用 |
|---|---|
| Grok 登录 | 通过设备代码或从浏览器粘贴授权结果;令牌会刷新 |
| 其他提供商 | 通过 API 密钥接入 OpenAI、Anthropic、Gemini 等(文档) |
| 模型别名 | 用户自定义模型名称;只需更改一次目标模型 |
| API | /v1、/api/v1、/api 或无前缀;SSE(文档) |
| 虚拟密钥 | 经哈希处理;记录每个密钥的令牌输入和输出量(文档) |
| MCP | 通过 OAuth 2.1 接入远程、stdio 和 git 服务(文档) |
| 实时工具更新 | 上游工具发生变化(例如更新、重新安装或启用、停用工具)时,已连接的客户端会收到通知,并且无需重新连接即可获取新工具 |
| 将 REST API 用作工具 | 提供 OpenAPI 描述,选择操作(或让 Suggest names and selection 为其命名并选择核心操作),MCP 客户端便可将它们用作工具(文档) |
已测试的 MCP 客户端
作者在运行中的 skgate 上测试过的客户端。状态仅表示测试结果,不构成承诺。
| 客户端 | 状态 | 备注 |
|---|---|---|
| ChatGPT | 正常 | |
| Claude | 正常 | |
| Grok | 正常 | |
| Hermes | 正常 | |
| Open WebUI | 正常 | 使用 OAuth 2.1;注册并授权客户端。 |
| Gemini | 警告 | 可以连接,但从不调用工具。 |
| Home Assistant | 警告 | 需要手动设置 OAuth 客户端 ID 和密钥。只能使用一个 MCP 上游。 |
| Cline | 未测试 | |
| Continue | 未测试 | |
| Cursor | 正常 | |
| Goose | 未测试 | |
| LibreChat | 未测试 | |
| VS Code | 未测试 | |
| Windsurf | 未测试 | |
| Zed | 未测试 |
目录模式
skgate stdio 会在 stdin 和 stdout 上启动一个小型只读 MCP 服务。它的用途是让 MCP 目录和扫描器能够启动服务并查询其功能,从而了解 skgate。它不适用于实际使用:要运行 skgate,请使用上面的 Docker 镜像。
它无需设置,不会开放端口、读取数据库或使用网络。它包含三个工具:about、list_features 和 config_help。这些工具只介绍 skgate,不提供其他功能。更多信息请参阅 docs/mcp.md。
skgate 对比
根据各项目截至 2026-10-13 的文档整理的粗略指南。请查阅文档了解当前功能。
| skgate | LiteLLM | MetaMCP | |
|---|---|---|---|
| 兼容 OpenAI 的大模型代理 | 是 | 是,支持 100 多家提供商 | 否 |
| MCP 网关 | 是 | 是 | 是 |
| 运行 stdio MCP 服务 | 是,按需启动,空闲时停止 | 是,除非设置 LITELLM_ENABLE_MCP_STDIO=true,否则默认关闭 | 是 |
| 面向 MCP 客户端的 OAuth | OAuth 2.1,支持动态客户端注册 | 是,可在网关进行动态客户端注册 | 是,支持 MCP 规范 2025-06-18 OAuth |
| 数据库 | SQLite,单个容器 | 虚拟密钥使用 Postgres | Postgres(Docker Compose) |
对比
各提供商在其他地方的登录方式,以及 skgate 如何接入:
| 提供商 | 在其他地方使用订阅登录 | 在 skgate 中 |
|---|---|---|
| xAI Grok * | OpenCode;计划支持更多平台 [1] | 订阅 |
| Anthropic Claude | 不向第三方提供 [2] | API 密钥 |
| DeepSeek | 无 | API 密钥 |
| Google Gemini * | CLI 登录不可重复使用 [3] | API 密钥 |
| Groq * | 无 | API 密钥 |
| Mistral * | 无 | API 密钥 |
| OpenAI | 使用 ChatGPT 登录 [4] | API 密钥 |
| OpenRouter * | 无 | API 密钥 |
| LM Studio | 无 | 无需密钥(本地) |
| Ollama | 无 | 无需密钥(本地) |
* 提供免费套餐。
截至 2026-10-05;请查阅各提供商的条款。GitHub Copilot 不是 skgate 支持的提供商。
来源
- xAI,在 OpenCode 中使用 Grok
- Anthropic,法律与合规
- Google,Gemini CLI 条款
- OpenAI,使用 ChatGPT 登录
在 environment: 下设置这些变量,或放入 env_file。占位值见 .env.example。
| 变量 | 默认值 | 用途 |
|---|---|---|
PUBLIC_URL | http://localhost:8080 | 公共源,不带尾部斜杠。 |
OIDC_ISSUER | 颁发者 URL,须与提供方发现文档中的 issuer 相同。 | |
OIDC_CLIENT_ID、OIDC_CLIENT_SECRET | 机密客户端凭据。 | |
OIDC_SCOPES | openid profile email groups | 请求的作用域。 |
OIDC_REDIRECT_URL | PUBLIC_URL/admin/oidc/callback | 在提供方注册的回调地址。 |
OIDC_ALLOWED_EMAILS、OIDC_ALLOWED_GROUPS | 空 | 限定管理员范围的逗号分隔列表。 |
MCP_OAUTH_REQUIRE_CONSENT | true | 登录后在 /authorize 显示批准/拒绝页面。 |
SECRETS_KEY | 随机生成的 secrets.key 文件 | 加密存储的上游密钥。使用 32 字节的 base64(openssl rand -base64 32),或使用经 scrypt 拉伸的密码短语。 |
GITHUB_TOKEN | 空 | 可选的 GitHub 令牌,用于 Suggest 读取仓库时使用。上游自身的访问令牌优先级更高。可提高 GitHub 的速率限制。 |
UPDATE_CHECK | true | 有较新版本时,页眉中的版本号会变黄;设为 false 可关闭检查。 |
LISTEN_ADDR | :8080 | 监听地址。 |
DB_PATH | /data/skgate.db | SQLite 文件。 |
LOG_LEVEL | info | info 或 debug。 |
LOG_LINES | 1000 | 每个受管理进程保留的输出行数(当前运行和上一次运行,最多 512 KB)。 |
TZ | UTC | UI 和日志使用的时区,例如 America/New_York。 |
PUID、PGID | 1000 | 运行身份 ID;不能为 0、65534 或 61000-64999(这些 ID 供受管理的服务使用)。 |
MANAGED_DIR | /data/managed | 受管理上游的工作目录和克隆目录。 |
MANAGED_MAX_PROCS | 0 | 并发运行的受管理进程数;0 表示不限制。 |
Grok 无需任何变量。在状态页面登录。模型别名可通过该卡片上的 Aliases 控件设置。
所有内容都位于 /data(skgate.db、secrets.key):请备份这两个文件。
反向代理
将 PUBLIC_URL 设为公共 https 源。
不要在 /v1、/api、/mcp、/sse、/messages、/authorize、/token、/register 或 /.well-known 上配置 forward-auth。
作者只测试过 Traefik。提交问题,说明你尝试了什么。
Traefik
services:
skgate:
container_name: skgate
image: ghcr.io/helv-io/skgate:latest
restart: always
network_mode: web # existing Docker network shared with Traefik; no ports needed
environment:
- PUBLIC_URL=https://skgate.example.com # the public https origin
- OIDC_ISSUER=https://auth.example.com
- OIDC_CLIENT_ID=skgate
- OIDC_CLIENT_SECRET=change-me
volumes:
- ./data:/data
healthcheck:
test: ["CMD", "/skgate", "healthcheck"]
interval: 30s
timeout: 5s
retries: 3
labels:
# no forward-auth middleware on /v1, /api, /mcp, /sse, /messages, /authorize, /token, /register, /.well-known
- traefik.enable=true
- traefik.http.routers.skgate.rule=Host(`skgate.example.com`)
- traefik.http.routers.skgate.entryPoints=websecure
- traefik.http.services.skgate.loadbalancer.server.port=8080
nginx
server {
listen 443 ssl;
http2 on;
server_name skgate.example.com;
ssl_certificate /etc/ssl/skgate/fullchain.pem;
ssl_certificate_key /etc/ssl/skgate/privkey.pem;
client_max_body_size 32m; # skgate accepts up to 32 MB
location / {
proxy_pass http://skgate:8080;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host; # keep Host
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off; # SSE streaming
proxy_read_timeout 3600s; # long streams
proxy_send_timeout 3600s;
}
}
Caddy
skgate.example.com {
# Host and X-Forwarded-* are set by default; no body limit, no response timeout
reverse_proxy skgate:8080 {
flush_interval -1 # SSE streaming
}
}
HAProxy
defaults
mode http
timeout connect 5s
timeout client 1h # long streams
timeout server 1h
timeout tunnel 1h
frontend https
bind :443 ssl crt /etc/haproxy/certs/skgate.pem alpn h2,http/1.1
option forwardfor # X-Forwarded-For; Host is kept, responses are not buffered
http-request set-header X-Forwarded-Proto https
default_backend skgate
backend skgate
option httpchk GET /healthz
server skgate skgate:8080 check
Apache
# a2enmod ssl proxy proxy_http headers
<VirtualHost *:443>
ServerName skgate.example.com
SSLEngine on
SSLCertificateFile /etc/ssl/skgate/fullchain.pem
SSLCertificateKeyFile /etc/ssl/skgate/privkey.pem
# keep Host
ProxyPreserveHost On
RequestHeader set X-Forwarded-Proto "https"
# long streams
ProxyTimeout 3600
# flushpackets: no buffering (SSE)
ProxyPass / http://skgate:8080/ flushpackets=on
ProxyPassReverse / http://skgate:8080/
</VirtualHost>
OIDC 设置
| 客户端设置 | 值 |
|---|---|
| 类型 | 机密客户端,client_secret_basic 或 client_secret_post |
| 流程 | 使用 PKCE S256 的授权码流程 |
| 重定向 URI | https://skgate.example.com/admin/oidc/callback |
| 作用域 | openid profile email groups(如果不支持 groups:OIDC_SCOPES=openid profile email) |
| ID 令牌 | 非对称签名(RS、PS、ES、EdDSA);发现文档中的 issuer 须与 OIDC_ISSUER 相同 |
如果未设置 OIDC_ISSUER、OIDC_CLIENT_ID 和 OIDC_CLIENT_SECRET,skgate 仍会启动,但管理员入口会保持关闭。
提供方允许登录的每位用户都是管理员。请限制提供方的访问权限,或设置 OIDC_ALLOWED_EMAILS/OIDC_ALLOWED_GROUPS。
Authelia、Authentik、Keycloak、Zitadel 和 Pocket ID 的提示见:docs/oidc.md。
安全说明
- 虚拟密钥以 SHA-256 哈希形式存储;上游凭据使用 AES-256-GCM 加密。
/authorize需要管理员会话。- 受管理的上游服务会运行管理员提供的命令;使用
slim镜像可将其禁用。 /register、/token、/authorize和管理表单会截断到达过慢的请求正文。上传和流(/v1、/mcp)不受此限制。- 对于无法发送标头的客户端,可允许在 URL 中使用密钥(
?key=)。默认情况下,每个密钥均禁用此功能,因为 URL 会泄露到日志、历史记录和引荐来源中。
更多信息(包括已知权衡):运维。
在 SI 协助下构建
skgate 在 SI 协助下构建:编码 Agent 会编写大部分代码、测试和文档。
每项更改都由作者审核,安全相关路径(OAuth、令牌、机密)由人工审核和测试。前沿模型的审核是补充,而非替代。欢迎提交问题和拉取请求来检验它。
开发
go build ./... && go vet ./... && go test ./...
docs/development.md。贡献者和 Agent:AGENT.md。
许可证
MIT,参见 LICENSE。
Star 历史
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。
