Skip to main content
Glama
tung2744
by tung2744

test-mcp

一个用于手动测试 Authgear 动态客户端注册(DCR)+ 资源指示符(resource-indicator)支持的最小 MCP 资源服务器(相关文档见 authgear-server 仓库中的 docs/specs/dcr.md、docs/specs/access-token-audience-binding.md)。

它本身没什么特别之处——它唯一的任务就是位于作为授权服务器的 Authgear 之后,让一个真实的 MCP 客户端走一遍完整流程:发现(discovery)→ DCR 自助注册 → PKCE 授权与同意(authorize+consent)→ 绑定到此服务器 resource 的令牌交换 → 一次经过身份验证的 MCP 工具调用。

各部分如何配合

MCP client  --1. GET /mcp (no token)-->  test-mcp
            <--2. 401 + WWW-Authenticate: Bearer resource_metadata="..."--

MCP client  --3. GET /.well-known/oauth-protected-resource-->  test-mcp
            <--4. { resource, authorization_servers: [Authgear] }--

MCP client  --5. GET /.well-known/oauth-authorization-server-->  Authgear
            <--6. { registration_endpoint, authorization_endpoint, ... }--

MCP client  --7. POST /oauth2/register-->  Authgear   (DCR)
MCP client  --8. /oauth2/authorize + consent, resource=<RESOURCE_URI>--> Authgear
MCP client  --9. POST /oauth2/token, resource=<RESOURCE_URI>-->  Authgear
            <--10. JWT access token, aud=[RESOURCE_URI]--

MCP client  --11. POST /mcp, Authorization: Bearer <token>-->  test-mcp
            <--12. tool result (or 401 if scope/audience don't match)--

步骤 1-2 和 11-12 发生在本服务器上。中间的一切都由 Authgear 完成,任何符合规范的 MCP 客户端都会自动发现它——你无需直接用 Authgear 的 URL 来配置客户端。

Related MCP server: MCP Server OAuth Toy

前置条件

  • 一个正在运行且已启用 DCR 的 Authgear 实例,例如在 authgear.yaml 中:

    oauth:
      dynamic_client_registration:
        enabled: true
        initial_access_token_required: false # open registration, for easy testing
  • 在该项目中注册一个与下面的 RESOURCE_URI 匹配的 Resource,并在 Resource 本身以及测试工具所需的每个 Scope 上都设置 access_policy.allow_dynamic_third_party_client_access: true——否则 DCR 客户端的 resource= 请求会得到 invalid_target/invalid_scope。可通过 Admin API GraphQL playground 创建(如果你是在 authgear-server 仓库内操作,也可以在 e2e 测试中使用 admin_api_graphql):

    mutation {
      createResource(input: {
        resourceURI: "https://localhost:8090"
        name: "test-mcp"
        accessPolicy: { allowDynamicThirdPartyClientAccess: true }
      }) {
        resource { id }
      }
    }
    
    mutation {
      createScope(input: {
        resourceURI: "https://localhost:8090"
        scope: "read:tools"
        accessPolicy: { allowDynamicThirdPartyClientAccess: true }
      }) {
        scope { id }
      }
    }
    
    mutation {
      createScope(input: {
        resourceURI: "https://localhost:8090"
        scope: "execute:tools"
        accessPolicy: { allowDynamicThirdPartyClientAccess: true }
      }) {
        scope { id }
      }
    }

    https://localhost:8090 必须与下面的 RESOURCE_URI 逐字节匹配,并且必须是本服务器自身的真实来源(origin,即协议 + 主机 + 端口),而不能是任意占位符。两个相互独立的约束条件锁定了这一点:

    • Authgear 要求每个 Resource URI 都必须是 https://(见 pkg/lib/resourcescope/formats.go)。

    • RFC 9728 受保护资源元数据中的 resource 字段应当与客户端实际连接的 URL(或 origin)匹配,严格的客户端会强制校验这一点——如果你将 RESOURCE_URI 指向无关的标识符而不是服务器的真实地址,MCP Inspector 将拒绝连接,并报出类似 Protected resource ... does not match expected ... (or origin) 的错误。

    正是这种组合,本服务器才默认提供 HTTPS(自签名)而不是纯 HTTP:https://localhost:<PORT> 同时是一个合法的 Authgear Resource URI 和本服务器的真实来源。如果你更改了 PORT,请同步更新 Resource 的 URI(以及下面的 RESOURCE_URI)以保持匹配。

设置

npm install
npm run setup   # generates a self-signed TLS cert for localhost (see below)

运行

npm start

环境变量(均为可选):

变量

默认值

说明

PORT

8090

本服务器监听的端口。

AUTHGEAR_ENDPOINT

http://localhost:4000

你的 Authgear 实例的基础 URL。如果你直接访问 make start 进程,请使用 http://localhost:3000;如果你通过常规的本地开发 nginx 代理(docker compose up -d proxy)访问,则使用 http://localhost:3100——无论哪种方式,它都必须指向 /.well-known/openid-configuration 实际可解析到的位置。

RESOURCE_URI

https://localhost:<PORT>

RFC 8707 资源标识符——必须与上面创建的 Resource 匹配,并且必须是本服务器的真实来源(见上文)。

USE_HTTP

未设置

设置为 1 以提供纯 HTTP 而不是 HTTPS。不推荐:使用 USE_HTTP=1 时,RESOURCE_URI 无法再等于本服务器的真实来源(它必须是 http://...,而 Authgear 会拒绝将其作为 Resource URI),因此严格的 MCP 客户端的资源匹配检查将会失败。仅可对你知道不会强制执行该检查的客户端使用。

使用真实的 MCP 客户端进行测试

MCP Inspector(推荐的第一步)

npx @modelcontextprotocol/inspector

打开打印出来的本地 URL,将服务器 URL 设置为 https://localhost:8090/mcp,然后连接——Inspector 的“Auth”面板会逐步走完发现、DCR 以及授权/令牌交换流程,让你能确切地看到每个响应包含什么。

由于证书是自签名的,你可能需要让 Node 信任它,以便 Inspector 自身的出站请求能够正常发起:

NODE_EXTRA_CA_CERTS=$(pwd)/certs/localhost.crt npx @modelcontextprotocol/inspector

(只应在本地测试时这样做——切勿为任何与真实服务器通信的对象禁用证书验证。)

mcp-remote(用于配合 Claude Desktop 进行测试)

npx mcp-remote https://localhost:8090/mcp

然后按照 mcp-remote 自己的文档,将 Claude Desktop 的配置指向生成的本地 stdio 桥接。

需要关注什么

  • 未请求 resource=(普通的 OIDC 客户端,或不发送 resource 的 MCP 客户端):Authgear 默认会向第三方/DCR 客户端签发**不透明(opaque)**令牌。本服务器完全无法验证不透明令牌(它不是 JWT),因此每次工具调用都会以 401 失败——这正是预期的行为(docs/specs/dcr.md、access-token-audience-binding.md):未绑定的第三方令牌只能在 Authgear 自己的 /oauth2/userinfo 端点使用,其他地方都不行。

  • 请求了 resource=<RESOURCE_URI>:Authgear 会签发 aud: [RESOURCE_URI] 的 JWT。此时无论授予了哪些 scope,whoami 都应成功;list_widgets/run_widget 只有在同意(consent)时授予了相应 scope(read:tools/execute:tools)的情况下才会成功。

  • 来自其他资源的资源绑定令牌,或其 Resource/Scope 缺少 allow_dynamic_third_party_client_access 的令牌:会在到达本服务器之前就被 Authgear 本身拒绝(invalid_target/invalid_scope)。

故障排查

  • Failed to connect ... Protected resource <X> does not match expected <Y> (or origin)(MCP Inspector 或另一个严格遵循 RFC 9728 的客户端)——RESOURCE_URI 被设置成了本服务器真实来源以外的值。请将 RESOURCE_URI(以及 Authgear 中匹配的 Resource)修正为 https://localhost:<PORT>,而不是任意占位符——参见上面的“前置条件”。

  • 在 /oauth2/authorize 或 /oauth2/token 处出现 invalid_target——Resource(和/或特定的 Scope)没有设置 access_policy.allow_dynamic_third_party_client_access: true,或者客户端发送的 resource= 值与已注册的内容不完全匹配。

  • 本服务器返回 401,并带有 error_description: "fetch failed"——本服务器无法访问 AUTHGEAR_ENDPOINT 来获取发现元数据;请检查 Authgear 是否确实在该地址运行。

  • 返回 401 并带有 JWT 验证错误——令牌本身是真实的,但要么已过期,要么由不同的签发者(issuer)签名,要么绑定到了与 RESOURCE_URI 不同的 aud。

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    A proof-of-concept MCP server implementing OAuth 2.1 authorization with CIMD client registration and PKCE, demonstrating protected resource access and step-up authentication.
    -
  • -
    license
    Not graded
    quality
    F
    maintenance
    A minimal remote (Streamable HTTP) MCP server that is an OAuth 2.1 resource server, demonstrating the MCP authorization spec with token validation and audience checks.
    -
  • A
    license
    Not graded
    quality
    C
    maintenance
    A demo MCP server protected by OAuth (DCR), enabling hands-on exploration of OAuth flow for local MCP servers.
    MIT