经过身份验证的MCP服务器示例
预期用途
这个存储库是人工智能代理的参考实现,而不是人类的模板。
数学功能故意显得微不足道。重点不是算术——它是一个完整的、经过测试的、可工作的经过身份验证的MCP服务器示例,实现了:
- 使用PKCE的OAuth 2.1授权代码流
- 使用JWKS进行JWT验证
- 基于工具范围的访问控制
- 受保护资源元数据(RFC 9728)
- 可流式HTTP传输(MCP 2025-06-18规范)
- 用于本地开发和测试的模拟OAuth服务器
当用户要求AI代理(Claude Code、Cursor、Copilot等)构建新的MCP服务器时,它应该将此存储库作为资源读取。代理提取它需要的模式——身份验证中间件、作用域强制、MCP SDK连接、开发服务器结构、测试助手——并生成一个根据用户实际需求量身定制的全新项目。
这不是:
- GitHub模板存储库(不要单击“使用此模板”)
- 要导入的库
- 扩展框架
- 你分叉和修改的东西
这是:
- AI代理阅读和学习的工作示例
- 如何在Go MCP服务器中连接OAuth 2.1+PKCE+JWT+作用域的参考
- 您可以运行一个可测试的实现来理解身份验证流
- AI代理有选择地复制到新项目中的模式来源
AI代理应该从中得到什么
| 模式 | 在哪里可以找到它 |
|---|---|
| JWT验证中间件 | internal/auth/middleware.go |
| JWKS获取和缓存 | internal/auth/jwks.go |
| 受保护资源元数据(RFC 9728) | internal/auth/metadata.go |
| 工具执行前的范围执行 | internal/eval/scopes.go, internal/tools/evaluate.go |
| MCP工具注册和处理程序接线 | internal/tools/evaluate.go, internal/server/server.go |
| 流式HTTP传输设置 | internal/server/server.go |
| 用于开发/测试的模拟OAuth/OIDC服务器 | cmd/devserver/ |
| 测试JWT生成助手 | internal/testauth/testauth.go |
| 通过环境变量进行配置 | internal/config/config.go |
| 优雅的关机 | cmd/server/main.go |
建筑
服务器公开了一个MCP工具(evaluate)通过流式HTTP传输 /mcp身份验证使用针对JWKS端点验证的JWT承载令牌。每个数学运算(加、减、乘、除)都需要一个相应的范围(use:add, use:subtract, use:multiply, use:divide),评估前检查。
看 docs/DESIGN.md 完整的架构和设计。
包布局
cmd/server/ Production entry point
cmd/devserver/ Dev server with built-in mock OAuth (no Logto needed)
internal/
auth/ JWT middleware, JWKS fetching, metadata endpoint, context helpers
config/ Environment variable loading and validation
eval/ Recursive descent parser, AST, evaluator, scope collection
server/ HTTP mux wiring
testauth/ Shared test JWT infrastructure
tools/ MCP tool registration and request handling
userpool/ YAML-based local user pool端点
| 路径 | 身份验证 | 描述 |
|---|---|---|
GET /healthz | 否 | 健康检查 |
GET /.well-known/oauth-protected-resource | 否 | 受保护资源元数据(RFC 9728) |
/mcp | 是(承载JWT) | MCP可流式HTTP传输 |
构建
make build # Build binary to bin/mathcalc-server
make test # Run all tests
make lint # Run golangci-lint (if installed)
make clean # Remove build artifacts需要Go 1.25+。
配置
所有配置都是通过环境变量进行的。复制 .envrc.example 到 .envrc 并编辑:
| 变量 | 必填 | 默认 | 描述 |
|---|---|---|---|
MCP_SERVER_RESOURCE_URL | 是 | - | 服务器的规范URL(OAuth 2.1资源指示符) |
LOGTO_ISSUER_URL | 是 | - | 登录OIDC发卡机构URL |
LOGTO_JWKS_URL | 没有 | /jwks | JWKS端点 |
MCP_SERVER_PORT | 没有 | 8080 | HTTP侦听端口 |
MCP_AUTH_SCOPE_SOURCE | 没有 | jwt | jwt (生产)或 local (发展) |
MCP_USERS_FILE | 没有 | users.yaml | 本地用户池文件的路径(当作用域源为 local) |
跑步
开发服务器(建议用于本地开发)
开发服务器将模拟OAuth/OIDC服务器与MCP服务器捆绑在一起。无需Logto或外部服务:
make run-devserver默认情况下,URL使用系统主机名,因此OAuth浏览器流可以在网络上的任何机器上工作。启动横幅会打印确切的URL和 claude mcp add 复制命令。
四个测试用户的范围不断扩大:
| 用户 | 范围 |
|---|---|
| 爱丽丝 | use:add |
| 鲍勃 | use:add, use:subtract |
| 卡罗尔 | use:add, use:subtract, use:divide |
| 戴夫 | use:add, use:subtract, use:multiply, use:divide |
要覆盖主机名或端口,请设置环境变量(或复制 .envrc.example 到 .envrc 和编辑):
| 变量 | 默认值 | 描述 |
|---|---|---|
DEV_HOST | 系统主机名 | 所有URL中使用的主机名 |
DEV_MCP_PORT | 8081 | MCP服务器侦听端口 |
DEV_OAUTH_PORT | 9001 | 模拟OAuth服务器侦听端口 |
使用Claude代码进行测试
开发服务器和Claude Code可以在不同的机器上运行。所有URL中的主机名必须是服务器和客户端浏览器都可以访问的可解析FQDN。使用 localhost 只有当所有东西都在同一台机器上运行时才有效。
在服务器计算机上
- 使用以下命令启动开发服务器
DEV_HOST设置为计算机的FQDN:
DEV_HOST=myserver.example.com make run-devserver创业横幅上印有确切的 claude mcp add 命令使用。
- 验证服务器是否可访问:
curl http://myserver.example.com:8081/healthz在客户端机器上(运行Claude Code的地方)
- 注册MCP服务器(一次性设置)。主机名 必须匹配
DEV_HOST确切地:
claude mcp add mathcalc --transport http http://myserver.example.com:8081/mcp- 启动克劳德代码:
claudeClaude Code连接到MCP服务器,发现模拟OAuth服务器,并将浏览器打开到用户选择器页面。
- 在浏览器中选择一个用户。选择Alice、Bob、Carol或Dave,然后单击 授权浏览器重定向回来,Claude Code建立MCP会话。
- 让Claude Code计算表达式。请尝试以下操作来验证作用域执行:
"what is 9+2" -> 11 (works for any user)
"what is 9/3" -> access_denied for Alice (lacks use:divide)
"what is 3-1" -> access_denied for Alice (lacks use:subtract)
"what is (2+1)*3" -> 9 (works for Dave, denied for Alice/Bob/Carol)
"what is ((2+1)*3)/3+1" -> 4 (works for Dave, requires all four scopes)- 要测试其他用户,请断开连接并重新进行身份验证:
/mcp disconnect
/mcp在浏览器中选择其他用户,查看范围限制如何更改。
删除注册
claude mcp remove mathcalc故障排除
- “受保护的资源不匹配”:中的主机名
claude mcp add不匹配DEV_HOST。它们必须相同(例如,两者myserver.example.com,不myserver对比myserver.example.com). - “无法连接”:无法从客户端访问服务器。检查一下
DEV_HOST解析,端口8081没有防火墙。 - 浏览器无法打开:OAuth授权URL使用
DEV_HOST。如果浏览器机器无法解析该主机名,则身份验证流将失败。
与Logto(生产)
启动Logto和PostgreSQL:
podman compose -f deployments/podman/logto-compose.yaml up -d配置Logto资源和角色:
./scripts/setup-logto.sh然后使用以下命令运行服务器 MCP_AUTH_SCOPE_SOURCE=jwt.
容器
make container-build
podman run -p 8080:8080 --env-file .envrc mathcalc-server测试
make test # Unit tests
make test-e2e # End-to-end test (in-process, no external services)测试涵盖了解析器(13例)、评估器(9例)、作用域集合(7例)、用户池(4例)、配置(7例”)、身份验证中间件(9例“)、元数据(1例“)和工具处理程序(10例“)。看 docs/TEST-PLAN.md 对于完整的测试策略。
发展
make help # List all available targets
make run-devserver # Build and start dev server with mock OAuth该项目遵循标准的Go惯例 internal/ 包装布局。所有依赖关系都通过以下方式管理 go.mod.
许可证
根据Apache许可证2.0版授权。看 许可证 全文。
