MCP and plugins
Anymo speaks the Model Context Protocol in both directions: it can consume tools from local and remote MCP servers, and it can serve its own brain to other agents. This page covers consuming; serving is the Runtime Bridge.
Two ways to connect
| Path | Transport | Configured in |
|---|---|---|
| Connectors (remote servers) | Streamable HTTP with OAuth | Desktop Plugins view: catalog or add-by-URL |
| Local servers (stdio) | stdio subprocess | .anymo/mcp.toml in the workspace |
Remote connectors
The desktop Plugins view ships a connector catalog (including Hugging Face) plus an add-by-URL path for any remote MCP server over streamable HTTP.
- OAuth happens in your system browser with a loopback callback; the app shows "Waiting for authorization" and resolves when the callback lands.
- Tokens are sealed at rest like provider keys. They never appear in config files, and removing a connector removes its token.
- Errors read as a status sentence with a Reconnect button.
Local stdio servers
The kernel discovers and invokes tools from configured stdio MCP servers. Discovered tools are exposed as ordinary registry entries named mcp.<server_id>.<tool_name>, so every call still goes through policy evaluation, approval, and the executor-enabled gate.
[[servers]]
id = "local-search"
command = "$WORKSPACE/bin/example-mcp-server"
args = ["--stdio"]
enabled = true
tool_allowlist = ["search"]
timeout_ms = 10000
max_output_bytes = 65536
[servers.env]
ANYMO_EXAMPLE_TOKEN = "fake-token"
PATH = "$WORKSPACE/bin"
Server commands, arguments, and environment variables come only from trusted config. The model never chooses process commands or launch arguments. Keep real credentials in the host's secret-storage flow, not in this file.
Safety model
- Every MCP tool is
risk_level = highandapproval_required = true: it asks for approval in every permission mode. - A tool executor is enabled only when its server has
enabled = trueand its raw tool name is intool_allowlist. Empty allowlists fail closed. - Tool names are sanitized before they enter the public registry. For example,
Read File!becomesmcp.local_server.read_file. - Tool arguments are not logged by the MCP host. Environment values and common secret assignments are redacted from returned text and error context.
- Responses are size-capped by
max_output_bytes. - MCP tool annotations are treated as untrusted hints: they can never lower a tool's risk or approval level.
Using the host from Rust
Embedders can drive the MCP host directly. The first unapproved call returns ApprovalRequired; request user approval through the existing flow before retrying with approved = true:
use std::sync::Arc;
use hive_kernel::{McpManager, SafeDefaultPolicy, ToolContext, ToolRegistry, Workspace};
let manager = Arc::new(McpManager::from_toml_file("$WORKSPACE/config/mcp.toml")?);
let mcp_registry = manager.discover_registry().await?;
let mut tools = ToolRegistry::new(Arc::new(SafeDefaultPolicy));
mcp_registry.register_into(&mut tools);
let workspace = Arc::new(Workspace::new("$WORKSPACE")?);
let ctx = ToolContext::new(workspace);
// approved must be true only after the user grants the approval request.
let output = tools
.execute(
"mcp.local-search.search",
serde_json::json!({ "query": "example" }),
&ctx,
true,
)
.await?;
Plugin hooks
Plugins can also contribute skills and hooks. Command-hook execution is disabled by default: you trust each plugin explicitly before its command hooks can run. The doctor check plugin_trust reports the current state.
Current limits
- Local servers use stdio transport only.
- One client session is opened for discovery and one for each tool call.
- Disabled servers are not launched during discovery.