feat(mcp): unified MCP server registration for tool and resource access (RFC-0058) - #372
Merged
Million-mo merged 11 commits intoAug 17, 2026
Conversation
…ion to SkillManagerCap McpServerCap gains a model-visible tool namespace (derived from display_name) so prefixed MCP tool names are predictable. list_resources() now prefers the server-provided title over the raw name. SkillManagerCap implements ResourceAccess, delegating to its skill-level MCP children, so top-level resources are discoverable through the ExtensionRegistry (RFC-0058). Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…ools directly AgentPool._rebuild_skill_capabilities() now registers each top-level McpServerCap independently in the ExtensionRegistry at POOL scope, making them discoverable via get_resource_access() for @ mention. get_agentlet() injects these providers directly into tool_capabilities and passes exclude_global=True to get_capabilities() so session/skill configs are not double-processed. MCPManager de-duplicates display_name tool prefixes and supports the exclude_global flag. /experimental/resource lists resources by URI so opencode @ mention surfaces them consistently (RFC-0058). Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…eAccess delegation Adds test_skill_manager_cap_resource_access.py (9 delegation cases for the new ResourceAccess implementation), McpServerCap resource title preference and prefixed toolset cases, top-level MCP pool registration + tool_prefix de-duplication in test_pool_skills.py, and updates the factory scope assertion to filter ResourceAccess caps correctly (RFC-0058). Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Describes the dual-object problem (tools via get_capabilities, resources via SkillManagerCap.children) and the decision to register each top-level McpServerCap independently at POOL scope with direct tool injection. Documents the RFC-0051 -> RFC-0052 -> RFC-0058 decision lineage and the open question on top-level vs skill-MCP prefix convention divergence. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…list Demo server exposing kb_data/ files as kb:// static resources plus resource templates. resources/list is re-scanned in the background (--scan-interval) so files added or removed from kb_data appear in @ mention without a server restart (RFC-0058). Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…el providers exclude_global=True skipped ALL of the agent's global MCP configs even when the agent owns a dedicated MCPManager (NativeAgentConfig with mcp_servers=[]). Such agents never have their servers surfaced via pool.mcp.providers, so the exclude dropped them entirely and MCP tools disappeared from the model (test_mcp_tool_with_progress KeyError). Only exclude when the agent shares the pool's MCPManager, whose providers are injected directly above. Fixes the Integration tests failure on wolf1069b#372. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…mantics MCPClient gains a public set_notification_callbacks() API replacing the private attribute writes in McpServerCap.\_ensure_client. The message handler reads callbacks dynamically from the client on each notification, so a handler created before callbacks are bound still observes them (\_rebind_session_message_handler after transport connect). McpServerCap.tool_prefix now defaults to None instead of falling back to config.display_name. The manager already passes an explicit prefix for POOL-scope servers, and skill-level MCP wraps its children itself; falling back to display_name silently prefixed dedicated-agent servers and broke their raw MCP tool names. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
FakeMCPClient in test_mcp_server_cap and test_review_fixes gains the public set_notification_callbacks() method and missing callback fields so McpServerCap._ensure_client can bind through the public API. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Capture connected sessions via a FastMCP middleware instead of a manual caller_register tool. A background scan loop detects kb_data changes and broadcasts notifications/resources/list_changed to every active session, so @-mention resource listings stay fresh without a server restart. FileResource entries carry annotations.lastModified; add a kb://docs/ directory listing resource and name/describe the resource templates. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Spawn the kb MCP server as a real subprocess against a temp kb-dir, add a file, and assert the McpServerCap receives a ChangeEvent(kind=resource_list_changed). Exercises the full chain: server broadcast -> MCP transport -> MCPMessageHandler -> McpServerCap. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
McpServerCap.tool_prefix is str | None now that tool_prefix no longer falls back to display_name. The attr-defined ignore on ClientSession. _message_handler became unused after the mcp SDK gained the attribute. Fixes remaining mypy failures on wolf1069b#372. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Million-mo
added a commit
to Million-mo/agentpool
that referenced
this pull request
Aug 19, 2026
…ss (RFC-0058) (wolf1069b#372) * feat(mcp): add tool_prefix to McpServerCap and ResourceAccess delegation to SkillManagerCap McpServerCap gains a model-visible tool namespace (derived from display_name) so prefixed MCP tool names are predictable. list_resources() now prefers the server-provided title over the raw name. SkillManagerCap implements ResourceAccess, delegating to its skill-level MCP children, so top-level resources are discoverable through the ExtensionRegistry (RFC-0058). Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> * feat(mcp): register top-level McpServerCap at POOL scope and inject tools directly AgentPool._rebuild_skill_capabilities() now registers each top-level McpServerCap independently in the ExtensionRegistry at POOL scope, making them discoverable via get_resource_access() for @ mention. get_agentlet() injects these providers directly into tool_capabilities and passes exclude_global=True to get_capabilities() so session/skill configs are not double-processed. MCPManager de-duplicates display_name tool prefixes and supports the exclude_global flag. /experimental/resource lists resources by URI so opencode @ mention surfaces them consistently (RFC-0058). Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> * test(mcp): cover top-level McpServerCap POOL registration and ResourceAccess delegation Adds test_skill_manager_cap_resource_access.py (9 delegation cases for the new ResourceAccess implementation), McpServerCap resource title preference and prefixed toolset cases, top-level MCP pool registration + tool_prefix de-duplication in test_pool_skills.py, and updates the factory scope assertion to filter ResourceAccess caps correctly (RFC-0058). Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> * docs(rfc): add RFC-0058 unified MCP server registration design Describes the dual-object problem (tools via get_capabilities, resources via SkillManagerCap.children) and the decision to register each top-level McpServerCap independently at POOL scope with direct tool injection. Documents the RFC-0051 -> RFC-0052 -> RFC-0058 decision lineage and the open question on top-level vs skill-MCP prefix convention divergence. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> * feat(examples): add knowledge base MCP server with dynamic resources/list Demo server exposing kb_data/ files as kb:// static resources plus resource templates. resources/list is re-scanned in the background (--scan-interval) so files added or removed from kb_data appear in @ mention without a server restart (RFC-0058). Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> * fix(mcp): preserve dedicated-agent MCP servers when injecting top-level providers exclude_global=True skipped ALL of the agent's global MCP configs even when the agent owns a dedicated MCPManager (NativeAgentConfig with mcp_servers=[]). Such agents never have their servers surfaced via pool.mcp.providers, so the exclude dropped them entirely and MCP tools disappeared from the model (test_mcp_tool_with_progress KeyError). Only exclude when the agent shares the pool's MCPManager, whose providers are injected directly above. Fixes the Integration tests failure on wolf1069b#372. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> * feat(mcp): dynamic notification callbacks and explicit tool_prefix semantics MCPClient gains a public set_notification_callbacks() API replacing the private attribute writes in McpServerCap.\_ensure_client. The message handler reads callbacks dynamically from the client on each notification, so a handler created before callbacks are bound still observes them (\_rebind_session_message_handler after transport connect). McpServerCap.tool_prefix now defaults to None instead of falling back to config.display_name. The manager already passes an explicit prefix for POOL-scope servers, and skill-level MCP wraps its children itself; falling back to display_name silently prefixed dedicated-agent servers and broke their raw MCP tool names. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> * test(mcp): sync test doubles with set_notification_callbacks API FakeMCPClient in test_mcp_server_cap and test_review_fixes gains the public set_notification_callbacks() method and missing callback fields so McpServerCap._ensure_client can bind through the public API. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> * feat(examples): broadcast resources/list_changed from kb MCP server Capture connected sessions via a FastMCP middleware instead of a manual caller_register tool. A background scan loop detects kb_data changes and broadcasts notifications/resources/list_changed to every active session, so @-mention resource listings stay fresh without a server restart. FileResource entries carry annotations.lastModified; add a kb://docs/ directory listing resource and name/describe the resource templates. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> * test(e2e): verify kb server list_changed reaches McpServerCap Spawn the kb MCP server as a real subprocess against a temp kb-dir, add a file, and assert the McpServerCap receives a ChangeEvent(kind=resource_list_changed). Exercises the full chain: server broadcast -> MCP transport -> MCPMessageHandler -> McpServerCap. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> * fix(mcp): align tool_prefix return type and drop stale type ignore McpServerCap.tool_prefix is str | None now that tool_prefix no longer falls back to display_name. The attr-defined ignore on ClientSession. _message_handler became unused after the mcp SDK gained the attribute. Fixes remaining mypy failures on wolf1069b#372. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> --------- Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This was referenced Aug 21, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements RFC-0058: Unified MCP Server Registration. Top-level MCP servers were previously represented as a child of
SkillManagerCap, making their resources invisible to@ mention(/experimental/resource) while their tools flowed through a separateget_capabilities()path — the "dual-object problem".Now each top-level
McpServerCapis registered independently at POOL scope in theExtensionRegistryand injected directly into agent tool capabilities, unifying tool + resource access behind one object per MCP server.Changes
Implementation
capabilities/mcp_server_cap.py: addstool_prefix(model-visible namespace fromdisplay_name);get_toolset()wraps tools inPrefixedToolset;list_resources()prefers servertitleover rawnamecapabilities/skill_manager_cap.py: implementsResourceAccess, delegating to skill-level MCP childrendelegation/pool.py: registers each top-levelMcpServerCapindependently at POOL scope in_rebuild_skill_capabilities()mcp_server/manager.py: de-duplicatesdisplay_nametool prefixes (kb→kb_2); addsexclude_globalflag toget_capabilities()agents/native_agent/agent.py:get_agentlet()injects top-levelMcpServerCapdirectly intotool_capabilities; session/skill configs useget_capabilities(exclude_global=True)routes/agent_routes.py:/experimental/resourcelists resources by URI so opencode@ mentionsurfaces them consistentlyTests (
74 passed)test_skill_manager_cap_resource_access.py— 9 ResourceAccess delegation casestest_pool_skills.py— top-level McpServerCap POOL registration + tool_prefix de-duptest_mcp_server_cap.py— resource title preference + prefixed toolsettest_factory.py— updated scope assertionDocs & Examples
examples/kb_mcp_server_example.py— demo KB server with dynamicresources/list(background scan ofkb_data/, no restart needed)Test Evidence
Notes