---
description: >-
  The dynamic, user-facing side of MCP-client support — discover servers on
  Smithery and the official MCP registry, persist installs to SQLite, supervise
  local-spawn subprocess lifecycle, surface their tools to agents via the
  unified tool registry.
icon: plug
---

# 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`.

```text
                 ┌───────────────────────────────────────────────┐
   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 — 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](agent-harness.md) — how the agent ends up calling MCP tools through `tool_registry`.
- [Architecture overview](../architecture.md) — where this fits in the wider system.
