Skip to main content

How to Serve Tools over MCP

An agent project's tools can be served as an MCP server, so MCP clients (Claude Desktop, Cursor, the MCP Inspector, or any agent runtime with MCP support) call them directly, without going through one of your agents. The same tool sources you configure for agents, including custom ones, become MCP tools.

This is the local, SDK-served flavor. The Zeta Alpha Platform also hosts a managed MCP server per tenant, see MCP Server; za mcp install --remote points a client at it.

Quickstart

Serving MCP needs the mcp extra (Python 3.10+):

pip install 'zetaalpha.agents[mcp]'
za mcp init my-agents # add an MCP exposure to the project
za mcp dev my-agents # serve + open the MCP Inspector

za mcp init writes an mcp_setups.json with a default exposure, seeded from the project's default agent (or --from-agent <id>, or a starter web-tools bundle when the project has no agents). za mcp dev serves it and launches the MCP Inspector; za mcp serve serves without the Inspector.

The endpoint is:

http://127.0.0.1:8000/mcp/zetaalpha/?mcp_server_identifier=default

mcp_server_identifier selects which exposure to serve on a request; there is no fallback, unknown or missing identifiers are rejected. The MCP surface is only mounted by za mcp serve/za mcp dev; za agents serve stays agents-only.

mcp_setups.json

Each entry names an exposure and configures its tools with the same configuration blocks as agent_configuration:

[
{
"mcp_server_identifier": "default",
"configuration": {
"tools_provider_configuration": { "include_sources": ["web_tools"] },
"web_tools_source_configuration": { "enabled": true }
}
}
]

An exposure is a tool bundle: only tools_provider_configuration and *_tools_source_configuration blocks apply (when seeding from an agent, the agent's LLM, memory, and agent-loop configuration are not copied). The served surface is the tools of the enabled tool sources, plus the memory and skill tools when those providers are configured.

Manage exposures with za mcp add|list|show|remove. Multiple exposures serve different tool bundles from one project, selected per request via ?mcp_server_identifier=.

Tools that search a specific index accept the index at call time via the URL, for example ?mcp_server_identifier=default&index_id=<id>.

Tools that need an LLM

Over MCP there is no agent, so an exposure that serves LLM-using tools (for example image_tools) selects the model through the model policy: an llm_selection_configuration block in the exposure's configuration. Names resolve against the project's named LLM configurations; credentials never appear in an exposure.

{
"mcp_server_identifier": "default",
"configuration": {
"llm_selection_configuration": { "llm_configuration_name": "vision" },
"tools_provider_configuration": { "include_sources": ["image_tools"] },
"image_tools_source_configuration": { "enabled": true }
}
}

When the exposure pins no name, the caller supplies one per request with ?llm_configuration_name=<name>. A pinned name cannot be overridden by the request; an unpinned exposure accepts any of the named LLM configurations. A tool with no LLM in scope stays listable; its LLM-backed calls answer that validation is unavailable.

Inside an agent, nothing needs configuring: tools follow the agent's own model selection.

Custom tools

Author a tool source without creating an agent:

za tools add currency-converter

This scaffolds dependencies/currency_converter.py with a registered ToolsSource (source name currency_converter, configuration block currency_converter_configuration). Enable it in an exposure like any other source:

"configuration": {
"tools_provider_configuration": { "include_sources": ["currency_converter"] },
"currency_converter_configuration": { "enabled": true }
}

Agents in the same project can use the same source. See How to Configure Tools for the tool source anatomy.

For a tool that calls the model itself, scaffold with za tools add <name> --with-llm: the source injects ZAVChatCompletionClient, and the model resolves at call time through the model policy described above.

Connecting a client

za mcp install claude-desktop # writes the mcpServers entry for Claude Desktop
za mcp install cursor # same for Cursor
za mcp install print # print the JSON for any other host

--remote --tenant <tenant> produces the config for the hosted Zeta Alpha MCP server instead; the hosted endpoint authenticates with an OIDC bearer token or an X-Auth API key. The local server has no authentication and serves the single tenant zetaalpha; keep it on localhost.