> For the complete documentation index, see [llms.txt](https://tinyhumans.gitbook.io/openhuman/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://tinyhumans.gitbook.io/openhuman/developing/architecture/mcp-registry.md).

# MCP Registry (src/openhuman/mcp\_registry/)

`src/openhuman/mcp_registry/` is the **dynamic, user-facing** half of OpenHuman's Model Context Protocol client support. It lets a user browse the supported upstream registries (Smithery and the official modelcontextprotocol registry), install a chosen server, persist that choice to SQLite, and (for servers launched as local subprocesses or HTTP-remote endpoints) supervise the connection lifecycle. Installed servers' tools are surfaced to agents via the unified tool registry (`crate::openhuman::tool_registry`).

> **Naming note**: the Rust module path is `mcp_registry`, but the RPC namespace and on-disk SQLite filename are still `mcp_clients` for backward compatibility with existing frontend code and stored user state. Grep both names when chasing call sites.

This module is paired with `src/openhuman/mcp_client/`: the **transport library** (HTTP + stdio primitives) plus the *static, config-declared* server set read from `[[mcp_client.servers]]` in `config.toml`. Agents reach that static set through generic bridge tools. The static set is intentionally separate from this dynamic registry; both kinds will eventually share the transport primitives from `mcp_client`.

```
                 ┌───────────────────────────────────────────────┐
   Registries ───► registries/ + registry.rs (10-min SQLite cache)│
                 └────────────────────┬──────────────────────────┘
                                      │ browse / install
                                      ▼
                          ┌──────────────────────┐
   Frontend (Skills UI) ─►│  ops.rs / schemas.rs │  RPC controllers
                          └──────────┬───────────┘
                                     │
                                     ▼
                          ┌──────────────────────┐
                          │      store.rs        │  mcp_clients.db (SQLite)
                          │  InstalledServer rows│
                          └──────────┬───────────┘
                                     │ at boot
                                     ▼
                          ┌──────────────────────┐
                          │       boot.rs        │  spawn_installed_servers
                          └──────────┬───────────┘
                                     │ for each local-spawn
                                     ▼
                          ┌──────────────────────┐
                          │   connections.rs     │  wraps mcp_client::
                          │  (global registry)   │  McpStdioClient
                          └──────────┬───────────┘
                                     │ surfaces tools to
                                     ▼
                          tool_registry (agents)
```

## Server transport model

An `InstalledServer` carries a `transport: Transport` discriminator (`types.rs`) with two variants:

* **`Stdio`**: a local subprocess launched by `npx`, `uvx`, or a direct binary (see `types::CommandKind`), speaking **stdio JSON-RPC**.
* **`HttpRemote { url }`**: a hosted server (the majority of what Smithery lists), dialled over streamable HTTP by `mcp_client::McpHttpClient`.

`connections.rs` dispatches on the transport. Both the manual install dialog (`mcp_clients_install`) and the setup-agent path (`mcp_setup_install_and_connect`) pick the best connection via `setup_ops::pick_connection` (published stdio → any stdio → published http\_remote → any http\_remote) and build the transport with `setup_ops::build_install_transport`, so the two paths behave identically.

## Boot-time spawn

`boot::spawn_installed_servers` is called from `bootstrap_core_runtime` so every installed server is connected as soon as the core comes up. Errors are logged per-server and **never block boot**; a broken MCP install should not gate the desktop app starting. The lifecycle log subscriber (`bus::init`) is registered alongside the other domain subscribers in `register_domain_subscribers` so those connect events are observed.

## Layout

| Path                        | Role                                                                                                                                                                                                                                               |
| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `types.rs`                  | Data structures: `InstalledServer`, `McpTool`, `ConnStatus`, Smithery DTOs, etc.                                                                                                                                                                   |
| `store.rs`                  | SQLite persistence: `mcp_clients.db`, CRUD over `InstalledServer` rows.                                                                                                                                                                            |
| `registry.rs`               | Smithery HTTP client with a 10-minute SQLite cache so re-browsing doesn't hammer the upstream registry.                                                                                                                                            |
| `registries/`               | Adapters for the upstream registries this code can browse: Smithery (`smithery.rs`) + the official modelcontextprotocol registry (`mcp_official.rs`). Each reads optional auth config-first with an env-var fallback (`mcp_client.registry_auth`). |
| `connections.rs`            | Global in-process connection registry. Wraps `crate::openhuman::mcp_client::McpStdioClient` (there is no separate stdio client implementation here).                                                                                               |
| `boot.rs`                   | Boot-time spawn (`spawn_installed_servers`) called from `bootstrap_core_runtime`.                                                                                                                                                                  |
| `setup.rs` / `setup_ops.rs` | "Setup agent" support: the small agent that walks a user through configuring a freshly installed server (env vars, secrets, first connect).                                                                                                        |
| `ops.rs`                    | RPC handler implementations (install, uninstall, list, browse, enable / disable, etc.).                                                                                                                                                            |
| `schemas.rs`                | Controller schemas + handler dispatch. Re-exported from `mod.rs` as `all_mcp_registry_controller_schemas` / `all_mcp_registry_registered_controllers`.                                                                                             |
| `bus.rs`                    | `DomainEvent` subscriber for lifecycle logging.                                                                                                                                                                                                    |

## Public surface

The exports from `mod.rs` are intentionally narrow:

```rust
pub use schemas::{
    all_controller_schemas as all_mcp_registry_controller_schemas,
    all_registered_controllers as all_mcp_registry_registered_controllers,
    schemas as mcp_registry_schemas,
};

pub use types::{ConnStatus, InstalledServer, McpTool};
```

Everything else (`boot`, `bus`, `connections`, `store`, `setup`, `setup_ops`) is `pub mod` for in-crate callers but not re-exported.

## Calls into

* `crate::openhuman::mcp_client::McpStdioClient`: the actual stdio transport.
* `crate::openhuman::tool_registry`: installed servers' tools land here so agents see them alongside native tools.
* `memory_store` / workspace SQLite, for `mcp_clients.db` persistence.
* Smithery.ai HTTP, for registry browsing.

## Called by

* `bootstrap_core_runtime` (via `boot::spawn_installed_servers`).
* Frontend Skills UI: the **MCP** tab at `/skills?tab=mcp` (`McpServersTab`) dispatches through `ops.rs` over the `openhuman.mcp_clients_*` RPC namespace: browse, install (auto-connects), connect/disconnect, status, tool\_call, `update_env` (reconfigure + reconnect), and `registry_settings_get` / `registry_settings_set` (Smithery / official-registry credentials; secret values are write-only). The agent-native flow uses `openhuman.mcp_setup_*` via the `mcp_setup` sub-agent (orchestrator delegate `setup_mcp_server`).
* The setup agent in `setup_ops.rs`, for first-connect onboarding.

## Tests

Unit tests are co-located inline under `#[cfg(test)]` blocks in `store.rs`, `connections.rs`, and `setup.rs`. There is no dedicated `*_tests.rs` sibling per file (the convention in this domain is inline).

## Related

* [`mcp_registry/mod.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/mcp_registry/mod.rs): the authoritative rustdoc this page mirrors.
* `src/openhuman/mcp_client/`: the transport library + static config-declared server set.
* [Agent Harness](/openhuman/developing/architecture/agent-harness.md): how the agent ends up calling MCP tools through `tool_registry`.
* [Architecture overview](https://github.com/tinyhumansai/openhuman/blob/main/gitbooks/developing/architecture.md): where this fits in the wider system.
