# How OpenHuman Handles the Static versus Dynamic Server Split for MCP Servers

> Discover how OpenHuman expertly manages MCP server splits using static configurations and dynamic Smithery discoveries for a unified host layer server list. Learn the technical implementation.

- Repository: [Tiny Humans/openhuman](https://github.com/tinyhumansai/openhuman)
- Tags: architecture
- Published: 2026-08-28

---

**OpenHuman splits MCP servers into a static set defined in [`config.toml`](https://github.com/tinyhumansai/openhuman/blob/main/config.toml) and a dynamic set discovered from Smithery modules at runtime, combining both in the host layer to provide a unified server list.**

The OpenHuman project implements a dual-layer architecture for managing Model Context Protocol (MCP) servers, separating user-declared static configurations from runtime-discovered dynamic modules. This static versus dynamic server split for MCP servers ensures that core integrations remain stable while allowing flexible extension through the Smithery ecosystem.

## Understanding the Two-Layer MCP Architecture

OpenHuman's MCP implementation organizes server management into two distinct layers that operate in parallel during the initialization phase.

### The Static Server Set

The static layer provides a read-only collection of MCP servers declared explicitly by the user. Located in [`src/openhuman/mcp/config_servers/registry.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/mcp/config_servers/registry.rs), the `McpServerRegistry` reads `[[mcp_client.servers]]` entries from [`config.toml`](https://github.com/tinyhumansai/openhuman/blob/main/config.toml) at startup, validates each definition, and creates a `McpTransportClient` (either HTTP or stdio) that remains cached for the entire process.

This module is leaf-gated on the `mcp` feature flag and lives under the `openhuman::mcp::config_servers` namespace. Its primary responsibilities include parsing TOML configuration through `McpClientConfig`, `McpServerConfig`, and `McpAuthConfig` structures, then building `McpServerDefinition` objects stored in the registry.

### The Dynamic Server Registry

The dynamic layer handles Smithery-installed MCP servers discovered at runtime. Implemented in [`src/openhuman/mcp/registry/ops.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/mcp/registry/ops.rs), the `McpRegistry` scans the Smithery directory, loads each module's manifest, and constructs an `McpStdioClient` for communication with dynamically-added servers.

Unlike the static set, these servers require no configuration file changes. When OpenHuman boots, `openhuman::mcp::registry::ops::load_registry()` automatically detects new modules placed in the Smithery directory and adds them to the active registry.

## Configuring Static MCP Servers

Static servers require explicit declaration in the user configuration file. The system parses these entries during the initialization sequence in [`src/openhuman/mcp/host.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/mcp/host.rs).

To configure a static server, add an entry to your [`config.toml`](https://github.com/tinyhumansai/openhuman/blob/main/config.toml):

```toml
[[mcp_client.servers]]
name = "my-mcp"
url = "https://mcp.example.com"
auth = { token = "secret-token" }

```

The `McpServerConfig` parser validates this entry and instantiates an `McpStdioClient` that spawns a subprocess for the declared server. This approach ensures that critical integrations remain available regardless of runtime module scanning results.

## Discovering Dynamic MCP Servers

Dynamic servers leverage the Smithery module system for zero-configuration additions. The registry implementation reuses the same `McpStdioClient` transport used by static servers, but discovers servers from the Smithery "modules" directory rather than TOML entries.

To register a dynamic server without modifying [`config.toml`](https://github.com/tinyhumansai/openhuman/blob/main/config.toml):

```bash

# Place a compiled Smithery module under the user's Smithery directory

cp my_dynamic_mcp.so $HOME/.openhuman/smithery/

```

When the host initializes, `load_registry()` scans this directory, loads the module manifest, and constructs the appropriate client transport. This means adding a new Smithery server instantly makes it available to MCP clients without service restarts or configuration edits.

## Host Layer Aggregation and Fallback

The `openhuman::mcp::host` module orchestrates the combination of both server sets during core initialization. The host attempts to construct the static registry first; if this fails, the error is logged and the host continues, allowing the dynamic registry to supply servers that were not statically declared.

When an MCP client queries the combined server list through the JSON-RPC interface, the `initialize` method returns both static definitions from [`config.toml`](https://github.com/tinyhumansai/openhuman/blob/main/config.toml) and dynamically discovered Smithery servers:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": { 
    "protocolVersion": "2025-11-25", 
    "clientInfo": { "name": "my-client" } 
  }
}

```

The response aggregates entries from both `McpServerRegistry` (static) and `McpRegistry` (dynamic), presenting a unified server list to the client.

## Key Implementation Files

The static versus dynamic server split for MCP servers is implemented across several critical source files:

- [`src/openhuman/mcp/config_servers/registry.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/mcp/config_servers/registry.rs) — Implements the read-only static registry and stdio transport
- [`src/openhuman/mcp/registry/ops.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/mcp/registry/ops.rs) — Scans Smithery directories and populates the dynamic registry  
- [`src/openhuman/mcp/host.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/mcp/host.rs) — Core startup code that builds both registries with fallback logic
- [`tests/mcp_registry_multi_server.rs`](https://github.com/tinyhumansai/openhuman/blob/main/tests/mcp_registry_multi_server.rs) — Integration test verifying combined static and dynamic server aggregation

## Summary

- **Static servers** are declared in [`config.toml`](https://github.com/tinyhumansai/openhuman/blob/main/config.toml) and parsed by `McpServerRegistry` at startup, providing stable, configuration-driven integrations
- **Dynamic servers** are discovered from Smithery modules at runtime via `McpRegistry`, enabling flexible extension without configuration changes
- Both layers use the `McpStdioClient` transport implementation for consistent communication
- The host layer in [`host.rs`](https://github.com/tinyhumansai/openhuman/blob/main/host.rs) attempts static initialization first, falling back to dynamic-only operation if static configuration fails
- Client requests receive a unified server list combining both static and dynamic sources

## Frequently Asked Questions

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

Static MCP servers are explicitly defined in the user's [`config.toml`](https://github.com/tinyhumansai/openhuman/blob/main/config.toml) file and loaded at startup by `McpServerRegistry`, while dynamic servers are discovered at runtime from Smithery modules placed in the user's `.openhuman/smithery/` directory. Static servers provide guaranteed availability for critical integrations, whereas dynamic servers offer flexibility for experimental or third-party extensions.

### How do I add a static MCP server to OpenHuman?

Add a `[[mcp_client.servers]]` entry to your [`config.toml`](https://github.com/tinyhumansai/openhuman/blob/main/config.toml) file with the server name, URL, and authentication details. The `McpServerConfig` parser in [`src/openhuman/mcp/config_servers/registry.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/mcp/config_servers/registry.rs) validates the entry and creates a persistent `McpTransportClient` for the duration of the process.

### Can dynamic MCP servers replace static ones if the configuration fails?

Yes. According to the implementation in [`src/openhuman/mcp/host.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/mcp/host.rs), if the static registry fails to initialize, the error is logged and the host continues startup, allowing the dynamic registry discovered through `openhuman::mcp::registry::ops::load_registry()` to supply available servers.

### What transport protocols does OpenHuman use for MCP server communication?

OpenHuman supports both HTTP and stdio transports through the `McpTransportClient` trait. Static servers may use either transport based on their URL scheme, while dynamic Smithery servers currently utilize `McpStdioClient` which spawns a subprocess for communication.