MCP client adapter that joins external MCP server tools into the Spakky Agent tool catalog
Project description
spakky-mcp
spakky-mcp is the Spakky Agent connector for external MCP servers.
It does one thing: connect MCP servers selected at run time and make their tools callable by the agent. It does not build MCP servers, and it does not expose an agent's own tools as an MCP server.
When to use it
Use this plugin when an agent service needs to attach MCP servers supplied by the developer, the service, or the end user:
- a configured company MCP server,
- a tenant-specific remote MCP endpoint,
- a user-connected GitHub/Linear/search MCP server,
- a per-run inline MCP server declaration.
The MCP server itself can be implemented with FastMCP, the official MCP SDK, or any compatible server implementation.
Install
uv add spakky-mcp
# or through the agent bundle
uv add "spakky[agent]"
Loading the plugin registers McpClient as IAgentRunnerFactory. Inbound adapters such as AG-UI and A2A can keep using the runner factory; MCP servers join the run through RunAgentInput.metadata.
v7 breaking change
spakky-mcp v7 removes the reverse "Agent tools as an MCP server" surface:
- removed
MCPServer,MCPToolServer,McpToolServerConfig,build_agent_tool_server,serve_stdio, and the server registry modules, - removed
McpConfig.tool_server, - removed Agent annotations whose only purpose was exposing local Agent tools as an MCP server.
The replacement path is intentionally one-way:
- Build MCP servers with FastMCP, the official MCP SDK, or another MCP server framework.
- Register allowed servers in
McpConfig.serversor accept per-run inline declarations from user/service settings. - Pass selected servers through
RunAgentInput.metadata["mcp"]["servers"]. - Let
spakky-mcpattach those external tools lazily throughmcp_search_toolsandmcp_call_tool.
Configure servers
Configured servers use the SPAKKY_MCP__ settings prefix.
export SPAKKY_MCP__SERVERS='[
{"name": "weather", "transport": "stdio", "command": "weather-mcp-server"}
]'
| Setting | Meaning | Default |
|---|---|---|
SPAKKY_MCP__SERVERS |
JSON array of external MCP server declarations | [] |
SPAKKY_MCP__CONNECT_TIMEOUT_SECONDS |
MCP connection timeout in seconds | 30.0 |
Server fields:
| Field | Meaning |
|---|---|
name |
Unique server name for one run. It cannot contain __. |
transport |
stdio or streamable_http |
command, args, env |
stdio server process command, arguments, and environment |
url |
streamable HTTP MCP endpoint |
auth.headers |
Static HTTP headers |
auth.bearer_token_env |
Environment variable containing a bearer token |
auth.oauth_client_credentials |
OAuth2 client-credentials token request config |
call_timeout_seconds |
Per-tool call timeout. Default 60.0 |
Runtime selection
At run time, pass configured server names or inline declarations through RunAgentInput.metadata["mcp"]["servers"].
from spakky.agent import IAgentRunnerFactory, RunAgentInput
async def run_with_user_mcp(factory: IAgentRunnerFactory, agent: object) -> None:
run_input = RunAgentInput(
state_id="run-1",
instruction="answer with external tools",
metadata={"mcp": {"servers": ["weather"]}},
)
async with factory.open_runner(agent, run_input=run_input) as runner:
async for item in runner.run(run_input):
...
Inline server declarations support user self-service connections:
RunAgentInput(
state_id="run-2",
instruction="inspect issue status",
metadata={
"mcp": {
"servers": [
{
"name": "tenant-linear",
"transport": "streamable_http",
"url": "https://tenant.example.com/mcp",
"auth": {"bearer_token": access_token},
}
]
}
},
)
Production services usually implement IMcpRuntimeServerResolver so a request carries stable connection IDs, while the server loads URLs and credentials from a DB or vault. Register that resolver as a Pod and bind it over the default resolver:
from spakky.core.application.application import SpakkyApplication
from spakky.core.application.plugin import Plugin
from spakky.plugins.mcp import IMcpRuntimeServerResolver
PLUGIN_NAME = Plugin(name="my-mcp-connections")
def initialize(app: SpakkyApplication) -> None:
app.add(UserMcpResolver)
app.container.bind_to_type(IMcpRuntimeServerResolver, UserMcpResolver)
Browser users should generally be allowed to add streamable_http endpoints, not arbitrary stdio commands.
AG-UI maps forwardedProps.mcp into the same metadata shape. A2A maps the data part mcp object into the same shape.
Lazy tool search
MCP servers can expose many tools. spakky-mcp does not push every external tool schema into the initial model request. The model sees only two MCP meta-tools:
| Tool | Purpose |
|---|---|
mcp_search_tools |
Search tools available from the MCP servers attached to this run. |
mcp_call_tool |
Call one tool returned by mcp_search_tools. |
External tool names are returned by search as <server_name>__<tool_name>. For example, weather server tool forecast becomes weather__forecast.
This keeps large MCP toolsets from polluting the model context while still letting the model discover and invoke the tools it needs.
When mcp_call_tool requires human approval, the approval request names the selected external MCP tool and includes the selected arguments in metadata.
Development checks
Run package checks from this package directory:
uv run ruff format .
uv run ruff check .
uv run --project ../.. pyrefly check --disable-project-excludes-heuristics --min-severity warn --no-progress-bar --output-format min-text
uv run pytest
License
MIT License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file spakky_mcp-7.0.0.tar.gz.
File metadata
- Download URL: spakky_mcp-7.0.0.tar.gz
- Upload date:
- Size: 14.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9d9ae3a263f6e816fc5e110e310c5cd4634a3f40d8ea0d2525b5e45ea2475c46
|
|
| MD5 |
e912116a1819bb68b81d78c434654f81
|
|
| BLAKE2b-256 |
11325fa5efe6db8b40920e16b434268d035de1fd845d82b7a158025f21b1b073
|
Provenance
The following attestation bundles were made for spakky_mcp-7.0.0.tar.gz:
Publisher:
release.yml on E5presso/spakky-framework
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
spakky_mcp-7.0.0.tar.gz -
Subject digest:
9d9ae3a263f6e816fc5e110e310c5cd4634a3f40d8ea0d2525b5e45ea2475c46 - Sigstore transparency entry: 1969786611
- Sigstore integration time:
-
Permalink:
E5presso/spakky-framework@7cc4185678359df49253b24f0e5ea0b4f0ed870b -
Branch / Tag:
refs/heads/main - Owner: https://github.com/E5presso
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@7cc4185678359df49253b24f0e5ea0b4f0ed870b -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file spakky_mcp-7.0.0-py3-none-any.whl.
File metadata
- Download URL: spakky_mcp-7.0.0-py3-none-any.whl
- Upload date:
- Size: 19.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7791175727a2c3d52315969c1db3f2d380478ad2a27f690cfe174e11e6364426
|
|
| MD5 |
7b482a362cd85a2a3a31ac3871c86cff
|
|
| BLAKE2b-256 |
eb9a327d83e19867d815470a617a928964036053b06c6c42da1d08422d4faa9b
|
Provenance
The following attestation bundles were made for spakky_mcp-7.0.0-py3-none-any.whl:
Publisher:
release.yml on E5presso/spakky-framework
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
spakky_mcp-7.0.0-py3-none-any.whl -
Subject digest:
7791175727a2c3d52315969c1db3f2d380478ad2a27f690cfe174e11e6364426 - Sigstore transparency entry: 1969786942
- Sigstore integration time:
-
Permalink:
E5presso/spakky-framework@7cc4185678359df49253b24f0e5ea0b4f0ed870b -
Branch / Tag:
refs/heads/main - Owner: https://github.com/E5presso
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@7cc4185678359df49253b24f0e5ea0b4f0ed870b -
Trigger Event:
workflow_dispatch
-
Statement type: