# How OpenHuman Integrates MCP Servers Using Static Config and Dynamic Registry Paths

> Learn how OpenHuman integrates MCP servers via static config and dynamic registry paths for a unified, customizable server catalog. Discover its backend management approach.

- Repository: [Tiny Humans/openhuman](https://github.com/tinyhumansai/openhuman)
- Tags: how-to-guide
- Published: 2026-08-27

---

**OpenHuman treats MCP (Mini-Control-Plane) servers as first-class backends by merging a hard-coded static configuration loaded at boot time with a mutable SQLite-backed registry stored in the user workspace, creating a unified server catalog that supports both immutable defaults and runtime customization.**

OpenHuman, developed by the tinyhumansai/openhuman repository, provides a dual-path discovery mechanism that ensures essential MCP services are available immediately upon startup while allowing users to register additional endpoints dynamically. This architecture separates immutable system defaults from user-specific configurations, enabling seamless integration of both built-in cloud services and custom self-hosted servers. Understanding how OpenHuman integrates MCP servers using static config and dynamic registry paths reveals a sophisticated balance between reliability and flexibility.

## Static Configuration: Immutable Server Definitions

OpenHuman reads static MCP server definitions from the core configuration file through the parser implemented in [`src/openhuman/mcp/config.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/mcp/config.rs). During the boot sequence, the system searches for a TOML block named `[[mcp_client.servers]]`, which contains hard-coded server entries that include a unique identifier, URL endpoint, and optional bearer token authentication.

Because these entries reside in the immutable core configuration, they are available before any user-specific workspace data loads, ensuring that critical infrastructure services remain reachable regardless of user state. The `load_static_servers()` function parses these definitions into `McpServer` structs, creating a baseline registry that guarantees production defaults are always present.

```toml

# ---------------------------------------------------------------------

# Example – Static MCP server entry in `config.toml`

# ---------------------------------------------------------------------

[[mcp_client.servers]]
id = "builtin-cloud"
url = "https://cloud.tinyhumans.ai/mcp"
bearer = "env:OPENHUMAN_CLOUD_TOKEN"

```

## Dynamic Registry: Runtime Server Management

Complementing the static configuration, OpenHuman implements a dynamic registry in [`src/openhuman/mcp/registry.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/mcp/registry.rs) that persists MCP servers in a SQLite database located at `~/.openhuman/mcp_clients.db`. This registry is managed by the `McpServerRegistry` struct, which exposes CRUD operations through RPC calls including `mcp_add_server`, `mcp_remove_server`, and `mcp_list_servers`.

Agents and users can register custom endpoints—such as self-hosted Smithery servers—at runtime without modifying the global configuration file. The system automatically reloads these entries on subsequent startups, enabling user-driven discovery of servers unknown at compile time while maintaining workspace-scoped isolation for security.

```rust
// ---------------------------------------------------------------------
// Example – Adding a server via the dynamic registry (via RPC)
// ---------------------------------------------------------------------
use openhuman_core::api::mcp::{AddServerRequest, AddServerResponse};

let req = AddServerRequest {
    id: "my‑custom‑mcp".into(),
    url: "https://mcp.mycompany.com/api".into(),
    bearer: Some("s3cr3t‑token".into()),
};
let resp: AddServerResponse = core_rpc_client
    .call("mcp_add_server", &req)
    .await?;   // registers the server in the SQLite DB

println!("Server added, now reachable as {}", resp.id);

```

## How OpenHuman Merges Static and Dynamic Discovery Paths

The integration layer in [`src/openhuman/mcp/mod.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/mcp/mod.rs) orchestrates the convergence of both configuration sources during the boot process, ensuring a single source of truth for the entire system.

### Boot-Time Loading Sequence

When the OpenHuman core initializes, it executes two distinct loading functions: `load_static_servers()` reads the TOML configuration block, while `load_registry_servers()` opens the SQLite database and reads persisted rows. Both functions return `Vec<McpServer>` collections that represent their respective configuration sources.

### Registry Merging and Deduplication

The system concatenates the static and dynamic vectors, applies deduplication logic based on server ID to prevent conflicts, and stores the merged result in a global `McpServerRegistry` instance housed within the core's `CoreContext`. This unified registry serves as the authoritative catalog for all subsequent MCP operations, ensuring that static defaults and user additions coexist without collision.

### Runtime Usage and Client Operations

RPC-exposed tools such as `mcp_list_servers` and `mcp_call_tool`, along with the internal HTTP client implemented in [`src/openhuman/mcp/http_client.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/mcp/http_client.rs), query the global registry to obtain concrete `McpServer` instances. Core server-side abstractions in [`src/openhuman/mcp/server.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/mcp/server.rs) handle request validation and error mapping, while [`src/openhuman/mcp/audit.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/mcp/audit.rs) records request metadata for observability.

```typescript
// ---------------------------------------------------------------------
// Example – Front‑end (React) fetching the list via RPC
// ---------------------------------------------------------------------
import { coreRpcClient } from "@/services/coreRpcClient";

async function fetchMcpServers() {
  const servers = await coreRpcClient.call("mcp_list_servers", {});
  return servers; // [{id, url, bearer?}, …]
}

```

```rust
// ---------------------------------------------------------------------
// Example – Listing all MCP servers (static + dynamic) from Rust
// ---------------------------------------------------------------------
use openhuman_core::mcp::registry::McpServerRegistry;

let registry = McpServerRegistry::global(); // reads the merged list
for server in registry.all() {
    println!(
        "ID: {}   URL: {}   Token: {}",
        server.id,
        server.url,
        server.bearer.as_deref().unwrap_or("<none>")
    );
}

```

## Why OpenHuman Implements Dual Discovery Mechanisms

The coexistence of static and dynamic registration serves distinct operational requirements within the OpenHuman architecture.

**Static configuration** guarantees that essential MCP services remain reachable even before user workspaces exist, making it ideal for production deployments where server sets are immutable and system-critical defaults must persist across environments.

**Dynamic registry** provides the flexibility required for end-user customization, allowing orchestrators to add custom MCP endpoints without touching version-controlled configuration files. Because the registry lives in the user workspace (`~/.openhuman`), it inherits the same security and isolation guarantees as other user data, enabling safe multi-tenant scenarios.

Together, these mechanisms allow OpenHuman to seamlessly blend built-in MCP backends with user-defined ones, maintaining a clear separation between immutable defaults and mutable user state.

## Summary

- OpenHuman loads static MCP server definitions from `[[mcp_client.servers]]` blocks in [`config.toml`](https://github.com/tinyhumansai/openhuman/blob/main/config.toml) via [`src/openhuman/mcp/config.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/mcp/config.rs), ensuring essential services are available before user workspaces load.
- The dynamic registry in [`src/openhuman/mcp/registry.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/mcp/registry.rs) persists user-added servers to `~/.openhuman/mcp_clients.db` and exposes CRUD operations through RPC calls like `mcp_add_server`.
- During boot, [`src/openhuman/mcp/mod.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/mcp/mod.rs) calls `load_static_servers()` and `load_registry_servers()`, merges the results into a deduplicated global `McpServerRegistry`, and stores it in `CoreContext`.
- The unified registry serves as the single source of truth for RPC tools and the HTTP client in [`src/openhuman/mcp/http_client.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/mcp/http_client.rs), which constructs requests using server-specific URL and authentication configuration.
- This dual-path architecture separates immutable system defaults from user-driven customizations, enabling both reliable production deployments and flexible runtime extensibility.

## Frequently Asked Questions

### What is the difference between static and dynamic MCP server configuration in OpenHuman?

Static configuration resides in the immutable [`config.toml`](https://github.com/tinyhumansai/openhuman/blob/main/config.toml) file and loads at boot time before user workspaces are available, ensuring critical services are always reachable. Dynamic configuration stores servers in a SQLite database within the user workspace (`~/.openhuman`), allowing runtime addition and modification through RPC calls without altering global configuration files.

### How does OpenHuman handle duplicate MCP server entries from both configuration sources?

When the system boots, [`src/openhuman/mcp/mod.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/mcp/mod.rs) concatenates the static and dynamic server vectors and deduplicates them by server ID before storing them in the global `McpServerRegistry`. This ensures that entries with identical identifiers do not create conflicts in the unified catalog.

### Can I modify static MCP server configurations at runtime in OpenHuman?

No, static configurations defined in the `[[mcp_client.servers]]` TOML block are immutable at runtime. To add or modify servers dynamically, use the registry RPC methods such as `mcp_add_server`, which persist changes to the SQLite-backed dynamic registry rather than the static configuration file.

### Where does OpenHuman store dynamically added MCP server credentials?

Dynamically added servers are stored in the `mcp_clients.db` SQLite database located in the user's workspace directory at `~/.openhuman`. This location ensures that server configurations follow the same security and isolation guarantees as other user-specific data, separate from the global system configuration.