Problem
The current external-MCP support (the skillberry-plugin-mcp-importer plugin) is too limited:
- SSE transport only.
plugin.py connects exclusively via mcp.client.sse.sse_client. It rejects anything that is not an http(s) SSE endpoint, so stdio and streamable-HTTP MCP servers cannot be imported at all.
- Requires the external server to stay running. Imported tools are stored as
packaging_format: "mcp" with packaging_params: {mcp_url, mcp_tool_name} and a one-shot import that just lists tools. Every later tool call reconnects to that live SSE URL, so the imported tools only work while the upstream server is up. There is no managed/owned connection — the store is fully dependent on an external process being alive and reachable.
In short: a single import-time list_tools() over SSE, no connection ownership, no support for the other MCP transports.
What we want
Manage external MCPs the way I implemented it back in #4 (#4), using the MCP SDK directly:
- Read an MCP servers JSON list (Claude-Desktop
{"mcpServers": {...}} shape and friends) and, at startup, spin up the connections to each configured MCP server.
- Use the MCP SDK to own one long-lived
ClientSession per server across all transports — stdio, sse, and streamable-HTTP — instead of SSE-only.
- The store manages the connections itself (lifecycle: start at boot, reconcile
list_tools() into store primitives, keep the session pooled, shut down cleanly). For stdio servers the store launches and supervises the child process, so we don't need a separate external server running that we then point at — we just call the tool and the pooled session handles it.
- Tool calls on external-MCP primitives go through the pooled session (fast path, no per-call cold connect).
This is essentially porting the ExternalMCPManager approach from #4 forward (it's too old to merge as-is), but the key requirement is: manage MCPs with the MCP SDK from a JSON list at startup, own the connections, and support every MCP transport — not just SSE, and not only while an external server happens to be running.
Acceptance criteria
References
Problem
The current external-MCP support (the
skillberry-plugin-mcp-importerplugin) is too limited:plugin.pyconnects exclusively viamcp.client.sse.sse_client. It rejects anything that is not anhttp(s)SSE endpoint, sostdioand streamable-HTTP MCP servers cannot be imported at all.packaging_format: "mcp"withpackaging_params: {mcp_url, mcp_tool_name}and a one-shot import that just lists tools. Every later tool call reconnects to that live SSE URL, so the imported tools only work while the upstream server is up. There is no managed/owned connection — the store is fully dependent on an external process being alive and reachable.In short: a single import-time
list_tools()over SSE, no connection ownership, no support for the other MCP transports.What we want
Manage external MCPs the way I implemented it back in #4 (#4), using the MCP SDK directly:
{"mcpServers": {...}}shape and friends) and, at startup, spin up the connections to each configured MCP server.ClientSessionper server across all transports —stdio,sse, and streamable-HTTP — instead of SSE-only.list_tools()into store primitives, keep the session pooled, shut down cleanly). Forstdioservers the store launches and supervises the child process, so we don't need a separate external server running that we then point at — we just call the tool and the pooled session handles it.This is essentially porting the
ExternalMCPManagerapproach from #4 forward (it's too old to merge as-is), but the key requirement is: manage MCPs with the MCP SDK from a JSON list at startup, own the connections, and support every MCP transport — not just SSE, and not only while an external server happens to be running.Acceptance criteria
stdio,sse, and streamable-HTTP transports all work.References
plugins/skillberry-plugin-mcp-importer/src/skillberry_plugin_mcp_importer/plugin.pymodules/external_mcp_manager.py(ExternalMCPManager)