Skip to main content

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:

  1. Build MCP servers with FastMCP, the official MCP SDK, or another MCP server framework.
  2. Register allowed servers in McpConfig.servers or accept per-run inline declarations from user/service settings.
  3. Pass selected servers through RunAgentInput.metadata["mcp"]["servers"].
  4. Let spakky-mcp attach those external tools lazily through mcp_search_tools and mcp_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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

spakky_mcp-7.1.0.tar.gz (14.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

spakky_mcp-7.1.0-py3-none-any.whl (19.0 kB view details)

Uploaded Python 3

File details

Details for the file spakky_mcp-7.1.0.tar.gz.

File metadata

  • Download URL: spakky_mcp-7.1.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

Hashes for spakky_mcp-7.1.0.tar.gz
Algorithm Hash digest
SHA256 2ee2eef1d86fd363b392eca8146aba1b0286b1ee2ddc318c042bbcf32adb45a8
MD5 8f4be54d012904bc934513543cadcdd1
BLAKE2b-256 40978e53d4c516306aa7dd65dab8522ec88faa727e786852934644de0af63fbc

See more details on using hashes here.

Provenance

The following attestation bundles were made for spakky_mcp-7.1.0.tar.gz:

Publisher: release.yml on E5presso/spakky-framework

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file spakky_mcp-7.1.0-py3-none-any.whl.

File metadata

  • Download URL: spakky_mcp-7.1.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

Hashes for spakky_mcp-7.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 55f9267672970f1c3ad4f4480531bc4786d3b6260965cbd6554edfefaba852b6
MD5 77c4022d1d498bbc1079497f89631e39
BLAKE2b-256 77b261790d8634fe2a78b799ae08c22baebea70d0d211c2ec7e8c3775d62c13b

See more details on using hashes here.

Provenance

The following attestation bundles were made for spakky_mcp-7.1.0-py3-none-any.whl:

Publisher: release.yml on E5presso/spakky-framework

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page