如何把 agno AgentOS 暴露成带 PAT 鉴权与工具范围控制的 MCP 服务器【免费下载链接】agnoBuild, run, and manage agent platforms.项目地址: https://gitcode.com/GitHub_Trending/ag/agno当你已经用 AgentOS 跑通了一个或多个 agent想把它们通过/mcp端点开放给 MCP 客户端Cursor、FastMCP 程序化客户端、Claude Desktop 等但又不能把裸的mcpTrue直接挂到网络上时需要完成三件事让客户端用 PATPersonal Access Token前缀agno_pat_的服务账号令牌而不是根密钥访问/mcp用标签把暴露的工具面从默认的 8 个收敛到需要的集合在工具或模型执行前拒绝不在白名单内的调用方。仓库中的 secure_mcp.py 就是这条完整路径的可运行实现本文按它的真实代码与配套文档组织步骤。适用前提Python 环境已通过 demo 环境安装MCP 额外依赖包含在内并已配置模型 API 密钥。准备条件在仓库根目录执行来自 14_mcp/README.md 的 Prerequisites 一节./scripts/demo_setup.sh export OPENAI_API_KEY...secure_mcp.py还需要一个 OS 级根安全密钥用于通过 REST 铸造 PATexport OS_SECURITY_KEY$(openssl rand -base64 32)这个根密钥的作用边界要分清它能调用POST /service-accounts铸造服务账号但它本身会被 MCP 的authorize门拒掉返回 401这正是该例子里刻意演示的匿名路径。服务端配置密钥、标签范围与 authorize 回调secure_mcp.py的服务端核心配置如下省略了导入语句与客户端函数BASE_URL os.getenv(AGENTOS_URL, http://localhost:7777).rstrip(/) OS_SECURITY_KEY os.environ[OS_SECURITY_KEY] SERVICE_ACCOUNT_PREFIX secure-mcp-client- ALLOWED_HOSTS [ host.strip() for host in os.getenv(MCP_ALLOWED_HOSTS, ).split(,) if host.strip() ] db SqliteDb( idsecure-mcp-db, db_filetmp/secure_mcp.db, ) secure_agent Agent( idsecure-assistant, nameSecure Assistant, modelOpenAIResponses(idgpt-5.5), dbdb, instructionsAnswer authenticated callers concisely., ) def authorize_service_account(user_id: str | None) - bool: Allow only service accounts minted for this MCP integration. return bool(user_id and user_id.startswith(fsa:{SERVICE_ACCOUNT_PREFIX})) agent_os AgentOS( idsecure-mcp-os, descriptionPAT-authenticated and explicitly scoped AgentOS MCP server., dbdb, agents[secure_agent], settingsAgnoAPISettings(os_security_keyOS_SECURITY_KEY), mcpMCPConfig( include_tags{core, session}, exclude_tags{session}, result_modefull, authorizeauthorize_service_account, allowed_hostsALLOWED_HOSTS, ), ) app agent_os.get_app()各配置项的作用均来自 MCPConfig 定义 与 READMEAgnoAPISettings(os_security_key...)设置根密钥。客户端用它调用POST /service-accounts铸造 PATPAT 明文agno_pat_...只返回一次AgentOS 只存哈希。include_tags{core, session}后接exclude_tags{session}先纳入core与session两个标签组再减去session最终暴露 6 个 core 工具get_agentos_config、run_agent、run_team、run_workflow、continue_run、cancel_run。裸mcpTrue会暴露 8 个默认工具core 6 个加get_sessions、get_session_runs两个 session 工具这里显式把 session 只读工具挡在 MCP 面之外。authorize每次调用前的门。它收到已验证的调用方 principal服务账号解析为sa:account-name返回True放行、False以 401 拒绝发生在任何工具或模型运行之前。authorize_service_account只放行自己铸造的sa:secure-mcp-client-*前缀账号。allowed_hostsALLOWED_HOSTS注意默认值是空列表[]而非None。只要allowed_hosts被设置哪怕是空列表AgentOS 就会启用 Host 与 Origin 校验内置的 localhost 放行保留其他来源返回 400部署或隧道场景可设置MCP_ALLOWED_HOSTSagentos.example.com。若保持None则不做任何主机校验。result_modefullrun 工具的structuredContent返回 run 的完整to_dict()供程序化客户端消费默认trimmed只返回回答内容加run_id、session_id、status等字段。db用同步的 OS 级SqliteDb服务账号存在AgentOS(db...)上而不是挂在某个 agent 的库上所以这里必须给 AgentOS 配库。关于authorize回调看到sa:...而不是None该文件未启用AgentOS(authorizationTrue, ...)服务账号校验器会把 PAT principal 填进request.state.user_idauthorize因此收到sa:...只有匿名路径例如直接拿根密钥访问才会以None到达该门——文档说明启动时库会提示 “authorizeis set whileAgentOS(authorizationFalse)”对本例不适用属预期行为。运行服务器与验证客户端在两个终端分别运行服务器在 1 号终端验证客户端在 2 号终端均使用 demo 环境的 Python.venvs/demo/bin/python cookbook/05_agent_os/14_mcp/secure_mcp.py.venvs/demo/bin/python cookbook/05_agent_os/14_mcp/secure_mcp.py --client客户端流程run_authenticated_client()内置了四条硬断言任何一条不满足就抛RuntimeError终止这就是本场景的验证方式用OS_SECURITY_KEY作为 Bearer 直接 POST/mcp断言状态码为401根密钥不能代替 PAT 过 MCP 门携带Host: untrusted.example.com再发一次断言400Host 白名单拒绝了不可信主机用根密钥POST /service-accountsjson{name: account_name}铸造账号断言返回令牌以agno_pat_开头用该 PAT 作为 Bearer 连上http://localhost:7777/mcplist_tools()的集合必须恰好等于6 个 core 工具出现get_sessions/get_session_runs即报错再调用run_agentagent_idsecure-assistant断言structuredContent中status COMPLETED且messages非空result_modefull生效的证据。客户端成功后打印的结果形如文档测试记录中的示例输出run_id等值随每次运行变化Authenticated principal: sa:secure-mcp-client-b0ebb699ad Token display prefix: agno_pat_... Root key at /mcp: 401 Untrusted Host at /mcp: 400 Scoped MCP tools: [cancel_run, continue_run, get_agentos_config, run_agent, run_team, run_workflow] Full run result: 586b12d0-5bc3-47d6-b373-ede496e9d129 - COMPLETED看到这个输出即说明PAT 鉴权生效、主机校验生效、工具面被收敛到 core 六个、full 结果格式返回完整消息列表。可选分支从 stdio-only 客户端接入如果你的客户端如 Claude Desktop只支持 stdio 方式README 给出的做法是把 PAT 存在 JSON 文件之外环境变量用mcp-remote桥接远端 streamable-HTTP 服务。下面 JSON 中的${AUTH_HEADER}是该文档原有写法由同段env中的AUTH_HEADER提供agno_pat_replace_me替换为你铸造的真实 PAT{ mcpServers: { agentos: { command: npx, args: [ -y, mcp-remote, https://agentos.example.com/mcp, --header, Authorization:${AUTH_HEADER} ], env: { AUTH_HEADER: Bearer agno_pat_replace_me } } } }支持原生远程 MCP 的客户端可直接发送Authorization: Bearer agno_pat_...头。此分支用于验证接入方式不改变服务端的鉴权与范围配置。限制与注意PAT 明文只出现一次创建响应默认有效期 90 天成功验证默认缓存 30 秒撤销在处理该请求的 worker 上立即生效其他 worker 在缓存过期后收敛见 07_security/README.md 的 Service Accounts 一节。服务账号的默认 scope 为agents:run、teams:run、workflows:run、sessions:read、config:read铸造更特权 scope 需要allow_privileged_scopestrue。continue_run/cancel_run随组件暴露而附带当 core 标签被纳入时这对工具天然在 6 个工具之中只对已发布组件的 run 生效。若 MCP 面上要发布Toolkit而其中数据是按用户隔离的README 要求先配置AgentOS(authorizationTrue, ...)否则 RunContext 中的调用方身份为None所有客户端共享同一身份。声明了requires_confirmation、requires_user_input或external_execution的工具会在 MCP 面被拒发构建期失败而不是静默放行因为 MCP 请求会绕过这些审批路径。铸造、scope 与撤销的完整 REST 操作参见 service_accounts.py同目录其余文件如 agents_as_tools.py、stateless.py分别覆盖把 agent 直接作为具名工具发布与无状态传输属于不同的暴露策略可按需另行阅读。【免费下载链接】agnoBuild, run, and manage agent platforms.项目地址: https://gitcode.com/GitHub_Trending/ag/agno创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考