Skip to main content

yjgr-agent-dns

基于 DNS 的 AI Agent 发现与调用 MCP 服务器(DNS-AID 协议),修好了远程 MCP 的鉴权。

这是 dns-aid/dns-aid-core(Apache-2.0)的二次开发版本。 上游的 MCP 插件在调用需要鉴权的远程 Agent 时,Bearer 只有一种精确写法能通, OAuth 对 MCP 场景基本不可用,而且所有 401 都被吞成一句 Invocation failed (status: error)。 我们向上游反馈过,没有回应,所以自己修、自己发。

在 Claude Code / Codex 里使用

发布到 PyPI 后,两边都只需要一段配置,不用预装任何东西(依赖 uv)。

Claude Code(写入项目根目录 .mcp.json,或 ~/.claude.json 的 mcpServers):

{
  "mcpServers": {
    "yjgr-agent-dns": {
      "command": "uvx",
      "args": ["--from", "yjgr-agent-dns", "yjgr-agent-dns-mcp"]
    }
  }
}

或者一条命令:

claude mcp add yjgr-agent-dns -- uvx --from yjgr-agent-dns yjgr-agent-dns-mcp

Codex(~/.codex/config.toml):

[mcp_servers.yjgr-agent-dns]
command = "uvx"
args = ["--from", "yjgr-agent-dns", "yjgr-agent-dns-mcp"]

只做发现和调用时不需要任何环境变量。要发布自己的 Agent 到 DNS 时, 按上游文档配置 DNS_AID_BACKEND 等后端凭据(见 docs/UPSTREAM-README.md)。

鉴权怎么用

远程 Agent 有三种常见鉴权方式,现在三种都能用:

远程服务要求 怎么调
Bearer token / API key call_agent_tool(..., credentials={"token": "..."})。auth_type 可省略,会按凭据的键名推断;access_token、bearer_token、api_key 都认。
OAuth2 客户端凭据(机器对机器) credentials={"client_id": "...", "client_secret": "..."},token 地址来自发现元数据或 auth_config.token_url。
MCP 规范 OAuth(浏览器登录) 先调一次 agent_login(endpoint),浏览器里完成授权;之后对该服务的所有调用自动带 token、自动刷新,不用再传任何凭据。
还要一个平台/租户标识 用 headers={"X-Platform": "..."}。有些服务在检查 token 之前先看这个头,不带就直接 403。鉴权头始终盖过这里设的同名头。

判断远程服务用哪种:直接调一次,401 的报错里会带服务端的 WWW-Authenticate 挑战和下一步提示,例如:

HTTP 401 Unauthorized from https://agent.example.com/mcp;
WWW-Authenticate: Bearer resource_metadata="https://agent.example.com/.well-known/oauth-protected-resource";
The server uses MCP OAuth: run the agent_login tool for this endpoint (browser login), then retry.

MCP 规范 OAuth 就是 Claude Code / Codex 连远程 MCP 用的那套: RFC 9728 资源元数据 → RFC 8414 授权服务器元数据 → RFC 7591 动态注册 → 授权码 + PKCE → 回调到本机 → 换 token。 实现直接用官方 mcp SDK 的 OAuthClientProvider,本项目只补了 token 落盘、本机回调服务和浏览器拉起。

新增的 MCP 工具:

  • agent_login(endpoint, scopes?, client_id?, client_secret?, timeout_seconds?) 浏览器登录
  • agent_logout(endpoint) 忘掉登录
  • agent_auth_status(endpoint) 查看登录状态(不返回 token 值)

list_agent_tools 也补上了 auth_type / auth_config / credentials 参数,上游版本连这个入口都没有。

A2A 多轮对话

message/send 返回的是一个 Task,不只是一段文字。智能体可能先回 state="input-required" 要你确认,这时返回里会带 task_id、context_id、state 和 data_parts。 续话要把 task_id 和 context_id 原样传回去,否则每次都是新任务,确认流程永远走不完:

r1 = send_a2a_message(endpoint=EP, message="给我推荐一些商品", credentials={"token": TOKEN})
# r1: state="input-required", data_parts=[{"action_type":"confirmation_required", ...}]
r2 = send_a2a_message(endpoint=EP, message="", credentials={"token": TOKEN},
                      task_id=r1["task_id"], context_id=r1["context_id"],
                      data={"action_type": "confirmed"})

确认的 data 具体是什么形状由对方智能体定义,看它 data_parts 里的 task_intent。

命令行同样可用:

yjgr-agent-dns agent login  https://agent.example.com/mcp
yjgr-agent-dns agent status https://agent.example.com/mcp
yjgr-agent-dns list-tools   https://agent.example.com/mcp            # 自动用已登录的 token
yjgr-agent-dns call         https://agent.example.com/mcp echo -a '{"text":"hi"}' --token XXX

token 存在 ~/.yjgr-agent-dns/oauth/<origin>.json,权限 0600,按服务的 origin 隔离。

相关环境变量

变量 作用
YJGR_AGENT_DNS_HOME token 存放根目录(默认 ~/.yjgr-agent-dns)
YJGR_AGENT_DNS_OAUTH_LOGIN_TIMEOUT 等浏览器登录的秒数(默认 180)
YJGR_AGENT_DNS_OAUTH_CALLBACK_PORT 固定回调端口(默认随机;授权服务器要求固定回调地址时用)
YJGR_AGENT_DNS_OAUTH_NO_BROWSER 设为 1 则不自动拉浏览器,只在 stderr 打印授权 URL
DNS_AID_FETCH_ALLOWLIST 逗号分隔的主机白名单,白名单内的主机不再受 HTTPS-only 和公网 IP 限制
DNS_AID_ALLOW_PRIVATE_NETWORKS 设为 1 允许 http:// 和内网 / 回环地址(内网部署、内网 IdP 必开)

内网部署注意

上游的 SSRF 防护把所有 http:// 和私网地址一律拒绝,连白名单都绕不过, 所以 OAuth2 客户端凭据模式的 token 地址不能指向内网 IdP。 现在:白名单的主机不限 scheme;或者整体开 DNS_AID_ALLOW_PRIVATE_NETWORKS=1。 file:// 和 URL 内嵌账号密码依旧拒绝。

相对上游改了什么

全部改动都在 git log 里逐条可查,这里列结论:

  1. 凭据被静默丢弃:auth_type 为空时上游直接不鉴权。现在按凭据推断类型,或自动用已存的登录。
  2. list_agent_tools 没有鉴权参数:补上。
  3. 401 / 403 被吞:从 anyio 的 ExceptionGroup 里解出 HTTP 状态和 WWW-Authenticate,报错说明是没带凭据还是凭据被拒。
  4. 没有 MCP 规范 OAuth:上游只有 client_credentials。新增 sdk/auth/mcp_oauth.py 与三个工具。
  5. 内网 IdP 被 SSRF 防护拦死:白名单优先于 scheme 检查,新增 DNS_AID_ALLOW_PRIVATE_NETWORKS。
  6. A2A 的 401/403 也被吞:只报 HTTP 401: {body},没有 WWW-Authenticate、不说该做什么。三个协议处理器现在共用一个报错构造器,会区分「没带凭据」「带了被拒」「缺身份头」。
  7. 发不了自定义请求头:请求头写死,需要 X-Platform 这类标识的服务根本调不了。
  8. A2A 只能单轮:每次调用都新建 task,data part 被丢弃,确认类流程无法完成。
  9. 发现阶段不报鉴权要求:agent card 里明明声明了 bearer,auth_type 却一直是 null;而且 card 里的 http / httpAuth 不是处理器名字,直接用会报 Unknown auth_type。
  10. 依赖声明打架:上游 main 允许 mcp<3,装上 mcp 2.x 后客户端直接报 transport unavailable。现钉死 <2.0.0,且 mcp、typer、rich 进核心依赖,uvx --from yjgr-agent-dns yjgr-agent-dns-mcp 不需要任何 extra(--from 是 uvx 的规则:命令名和包名不同就要写)。

包名、模块名、命令名全部改为 yjgr-agent-dns / yjgr_agent_dns。 线上协议标识(X-DNS-AID-* 头、dns-aid-jwks.json、DNS_AID_* 环境变量)刻意没改, 保证和上游工具发布的 DNS 记录互通。

开发

uv venv --python 3.12 && uv pip install -e '.[all,dev]'
scripts/test_per_file.sh                 # 单元测试(每个文件独立进程,上游测试之间有状态泄漏)
.venv/bin/python -m pytest tests/integration/test_mcp_oauth_e2e.py   # OAuth 全流程端到端
.venv/bin/ruff check src/ && .venv/bin/mypy src/yjgr_agent_dns
uv build                                 # dist/ 下出 wheel

tests/testbed/oauth_mcp_target.py 是一个符合 MCP 规范的本地授权服务器 + 受保护 MCP 服务, 可以单独起来手工验证:python tests/testbed/oauth_mcp_target.py 8766,然后 yjgr-agent-dns agent login http://127.0.0.1:8766/mcp。

同步上游:git fetch upstream && git merge upstream/main(remote 名为 upstream)。

许可

Apache-2.0,与上游一致。保留上游 LICENSE 与 NOTICE,修改部分版权归 YJGR。

Metadata

Release files for yjgr-agent-dns 1.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for yjgr-agent-dns 1.1.0
File Size Uploaded Provenance
yjgr_agent_dns-1.1.0.tar.gz 1.2 MB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for yjgr-agent-dns 1.1.0
File Interpreter ABI Platform
yjgr_agent_dns-1.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 1.6 MB

Release files / yjgr_agent_dns-1.1.0.tar.gz

Download URL yjgr_agent_dns-1.1.0.tar.gz
Size 1.2 MB
Tags Source
SHA-256 checksum
How to use checksums
1216a34760b38bd0ac630fc723153bfa90e7c2209427557137c56ec31515574c
BLAKE2b-256 checksum
How to use checksums
518e64b77baf2fbf7bb159668a1245a91bcf25b9d01869aa414f60b62548abea
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / yjgr_agent_dns-1.1.0-py3-none-any.whl

Download URL yjgr_agent_dns-1.1.0-py3-none-any.whl
Size 418.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
40c107cc84ec741876276e9f2555828a70efd99bdf875834461c48363f994913
BLAKE2b-256 checksum
How to use checksums
fecf8b3772b16ccdf3b9d12f0c0139ccd369c5f59433b397fe9fe9f820d166d7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for yjgr-agent-dns 1.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

1.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page