Agent Interoperability: MCP, UTCP, and A2A¶
In a nutshell
This page is about letting OVOS work together with other AI systems. OVOS can offer its abilities, like speech, translation, and reasoning, to outside AI tools. It can also call on them, using a few shared "languages" (the protocols MCP, UTCP, and A2A) so different systems can find and use each other. Think of it as agents agreeing on a common plug and socket so they can cooperate. See the Glossary for unfamiliar terms.
OVOS exposes its speech, translation, and reasoning services as agent tools via two discovery and calling protocols: MCP (Model Context Protocol) and UTCP (Universal Tool Calling Protocol). It also implements bidirectional A2A (Agent-to-Agent) bridging.
flowchart TD
subgraph OVOS Service Servers
STT[STT Server]
TTS[TTS Server]
TX[Translate Server]
PS[Persona Server]
end
Ext["External MCP/UTCP<br/>client<br/>e.g. Claude Desktop"] -->|/mcp, /utcp| STT
Ext -->|/mcp, /utcp| TTS
Ext -->|/mcp, /utcp| TX
Ext -->|"/mcp, /utcp,<br/>/tools/*"| PS
PS -->|"/.well-known/<br/>agent-card.json,<br/>SendMessage"| A2AClient["External<br/>A2A client"]
ExtA2A["External<br/>A2A server"] -->|"ovos-a2a-solver<br/>ChatEngine"| Persona[OVOS persona]
ExtMCP["External MCP/UTCP<br/>server"] -->|"ovos-mcp-toolbox /<br/>ovos-utcp-toolbox"| Loop["Agentic loop<br/>ToolBox"]
Diagram: The flow starts at an external MCP/UTCP client or server and ends at OVOS's service servers or agentic loop ToolBox, branching between the persona server's A2A client link and the OVOS-persona A2A solver path.
Not what you're looking for?
This page is about LLM/agent tool protocols (MCP/A2A). If you're building a voice satellite or a remote voice client instead, see HiveMind Agents.
Protocol Overview¶
| Protocol | Discovery | Invocation | Deps |
|---|---|---|---|
| UTCP | GET /utcp → UTCP 1.0 JSON manifest |
POST /utcp/{tool} or native HTTP endpoints |
None (always on) |
| MCP | MCP initialize + list_tools |
call_tool over Streamable HTTP / SSE |
pip install …[mcp] |
| A2A | GET /.well-known/agent-card.json (agent card; /.well-known/agent.json kept for 0.3.x clients) |
JSON-RPC 2.0 SendMessage / SendStreamingMessage (0.3.x clients: message/send / message/stream) |
pip install …[a2a] |
MCP + UTCP on the Service Servers¶
STT Server¶
pip install --pre "ovos-stt-http-server[mcp]>=0.26.0a1"
ovos-stt-server --engine ovos-stt-plugin-whisper --port 8080
| Endpoint | Method | Description |
|---|---|---|
/utcp |
GET | UTCP manifest (always on, no extra package required) |
/mcp |
Streamable HTTP | MCP server (opt-in: start with --mcp, requires the [mcp] extra) |
MCP is opt-in: pass --mcp at startup (the flag exists on all the OVOS servers now). With
the flag set but the extra missing, the server logs a warning and runs without the endpoint.
UTCP tools exposed: stt, lang_detect, status.
Claude Desktop config:
TTS Server¶
pip install "ovos-tts-server[mcp]"
ovos-tts-server --engine ovos-tts-plugin-phoonnx --port 9666 --mcp
| Endpoint | Method | Description |
|---|---|---|
/utcp |
GET | UTCP manifest (always on) |
/mcp |
Streamable HTTP | MCP server (requires [mcp] extra and --mcp flag) |
UTCP tools exposed: tts_status, tts_synthesize_v2, tts_synthesize_legacy.
MCP tool: synthesize. Parameters: text (str), voice (str, optional), lang (str, optional). Returns base64 WAV.
# Discover all TTS tools via UTCP
curl -s http://localhost:9666/utcp | jq '.tools[].name'
# Synthesize via HTTP
curl -s 'http://localhost:9666/v2/synthesize?utterance=hello%20world' -o out.wav
Translate Server¶
pip install --pre "ovos-translate-server[mcp]>=0.10.0a1"
python -m ovos_translate_server --tx-engine ovos-google-translate-plugin --port 9686 --mcp
| Endpoint | Method | Description |
|---|---|---|
/utcp |
GET | UTCP manifest (always on) |
/mcp |
Streamable HTTP | MCP server (requires [mcp] extra and the --mcp flag) |
UTCP tools: ovos_translate.translate, ovos_translate.translate_with_source,
ovos_translate.detect_language, ovos_translate.classify_language,
ovos_translate.supported_languages, and the native HTTP REST endpoints.
MCP tools: translate (params: text, target_lang, optional source_lang), detect_language (param: text).
Persona Server: Tool Plugins via MCP + UTCP¶
The persona server surfaces every installed OPM ToolBox plugin as both a UTCP tool and an MCP tool.
| Endpoint | Method | Description |
|---|---|---|
/tools/manual |
GET | UTCP 1.0 manifest of all installed tool plugins |
/tools/{name} |
POST | Direct HTTP invocation of a tool |
/mcp |
Streamable HTTP | MCP server (one tool per OPM ToolBox tool) |
/mcp (stdio) |
— | Console script ovos-persona-tools-mcp |
A2A (Agent-to-Agent Protocol)¶
A2A is the Google A2A open protocol. An A2A server publishes a discovery document (agent card) and accepts tasks via JSON-RPC 2.0.
Persona Server as A2A Server¶
pip install --pre "ovos-persona-server[a2a]>=0.17.2a1"
ovos-persona-server --persona my_persona.json
The OVOSPersonaAgentExecutor wraps the active persona. create_a2a_application()
builds the A2A app, with an agent card at /.well-known/agent-card.json (the 0.3.x
/.well-known/agent.json path stays as a compat alias) and support for blocking
(SendMessage) and streaming (SendStreamingMessage) modes when the persona
solver supports streaming.
Start it with --a2a-base-url, which both enables the /a2a endpoint and sets the public
base URL that goes into the agent card:
The flag needs a2a-sdk installed. See Persona Server.
OVOS as A2A Consumer¶
OpenVoiceOS/ovos-a2a-agent-plugin (pip: ovos-a2a-solver-plugin) is an A2AChatEngine ChatEngine plugin (OPM group opm.agents.chat, entry point ovos-a2a-solver) that delegates persona reasoning to any external A2A server.
{
"name": "my-a2a-persona",
"handlers": ["ovos-a2a-solver"],
"ovos-a2a-solver": {
"agent_url": "https://my-a2a-agent.example.com",
"auth_header": "Bearer <token>",
"timeout": 60,
"streaming": false
}
}
Config keys:
| Key | Default | Description |
|---|---|---|
agent_url |
— | Base URL of the A2A server (required) |
auth_header |
— | Authorization header value, e.g. Bearer <token> |
timeout |
60 |
Seconds per call |
streaming |
false |
Use the SSE streaming endpoint when true |
ovos-tool-adapters: Consuming MCP/UTCP from the Agentic Loop¶
OpenVoiceOS/ovos-tool-adapters bridges external MCP and UTCP servers into the OVOS agentic loop as standard ToolBox plugins.
pip install ovos-tool-adapters[mcp] # MCP support
pip install ovos-tool-adapters[utcp] # UTCP support
Add to a persona JSON:
{
"name": "researcher",
"handlers": ["ovos-react-loop"],
"ovos-react-loop": {
"brain": "ovos-chat-openai-plugin",
"toolboxes": ["ovos-mcp-toolbox"],
"ovos-mcp-toolbox": {
"transport": "stdio",
"command": "uvx",
"args": ["mcp-server-fetch"],
"timeout": 30
}
}
}
ovos-personaselects its engine viahandlers(see Personas for the legacysolversalias). The agentic loop names its inner LLM withbrainand loads adapters viatoolboxes. Neitherovos-personanorovos-tool-adaptersreads thechat_modulekey seen in some READMEs.
MCP transports (ovos-mcp-toolbox)¶
| Transport | Config |
|---|---|
| stdio (subprocess) | "transport": "stdio", "command": "uvx", "args": [...], optional "env": {...} |
| SSE | "transport": "sse", "url": "http://..." |
| Streamable HTTP | "transport": "http", "url": "http://..." |
For stdio, env is an optional dict of extra environment variables passed to
StdioServerParameters, letting you inject secrets or PATH into the subprocess
MCP server. Both ovos-mcp-toolbox and ovos-utcp-toolbox also accept a
per-instance toolbox_id (defaults ovos-mcp-toolbox / ovos-utcp-toolbox) so
multiple servers of the same type can run side by side, and a timeout (default
30 seconds per call) to tune slow tools.
UTCP (ovos-utcp-toolbox)¶
{
"toolboxes": ["ovos-utcp-toolbox"],
"ovos-utcp-toolbox": {
"utcp_config": {
"tool_providers": [
{"name": "stt", "provider_type": "http", "url": "http://localhost:8080/utcp"}
]
}
}
}
A background asyncio event loop keeps sessions alive between tool calls. Each server's JSON Schema is translated to a Pydantic model at discovery time so the LLM receives the actual input schema.
Tool discovery degrades gracefully: if the mcp/utcp extra is missing, or the
configured server cannot be reached, list_tools() logs a LOG.warning and
returns an empty list rather than crashing the agent loop. A misconfigured
toolbox therefore loads zero tools silently. Check the logs when expected tools
are absent.
ovos-tool-adapters and the Persona Server's own MCP/UTCP bridge
Both MCPToolBox and UTCPToolBox (from ovos-tool-adapters) and the Persona Server's tool
surface (/tools/manual, /mcp) are ToolBox plugins under the same opm.agents.toolbox
entry-point group, so installing ovos-tool-adapters alongside ovos-persona-server also
exposes the bridged external tools through the Persona Server's own MCP/UTCP endpoints.
Every ToolBox implementation (DuckDuckGoToolbox, WikipediaToolbox, MCPToolBox,
UTCPToolBox, ...) takes (config=None, bus=None) and passes its own toolbox_id up
to the base class, so the Persona Server constructs each one with a single
cls(config=cfg, bus=bus) call. See Agent Tool Plugins for the
full contract.
Read next: OpenAI-compatible Related: Agent Tool Plugins · GGUF / Local LLM