# How to Configure MCP Servers in ML Intern for Extended Tool Capabilities

> Learn to configure MCP servers in ML Intern to unlock new tool capabilities. This guide shows how to integrate external back-ends using JSON configuration and Pydantic models for enhanced functionality.

- Repository: [Hugging Face/ml-intern](https://github.com/huggingface/ml-intern)
- Tags: how-to-guide
- Published: 2026-04-24

---

**ML Intern uses MCP (Multi-Channel Protocol) servers to expose additional tool back-ends via JSON configuration in [`configs/main_agent_config.json`](https://github.com/huggingface/ml-intern/blob/main/configs/main_agent_config.json), loading them through Pydantic models in [`agent/config.py`](https://github.com/huggingface/ml-intern/blob/main/agent/config.py) and routing calls via `ToolRouter` in [`agent/core/tools.py`](https://github.com/huggingface/ml-intern/blob/main/agent/core/tools.py).**

The ML Intern agent framework from Hugging Face leverages the FastMCP protocol to connect with remote and local tool providers. This architecture allows the agent to execute tools hosted on external servers or local subprocesses without hard-coding credentials into your repository. By configuring the `mcpServers` map in the main configuration file, you enable the agent to discover and invoke specialized capabilities ranging from Hugging Face repository operations to custom local utilities.

## Understanding the MCP Configuration Architecture

The MCP integration in ML Intern follows a strict validation pipeline that ensures type safety and secure credential handling.

### The Configuration Schema

In [`agent/config.py`](https://github.com/huggingface/ml-intern/blob/main/agent/config.py), the codebase defines a Pydantic `Config` model containing the field `mcpServers: dict[str, MCPServerConfig]`. Each entry in this dictionary must conform to either the `RemoteMCPServer` or `StdioMCPServer` schema imported from `fastmcp.mcp_config`. 

- **RemoteMCPServer**: Uses HTTP transport for external endpoints
- **StdioMCPServer**: Uses standard input/output for local subprocess communication

### Environment Variable Substitution

Security-critical values like API tokens must never reside in version control. The `substitute_env_vars()` function in [`agent/config.py`](https://github.com/huggingface/ml-intern/blob/main/agent/config.py) processes the JSON configuration before validation, replacing `${VAR}` placeholders with values from a `.env` file or system environment. This substitution occurs inside the `load_config()` helper, which reads [`configs/main_agent_config.json`](https://github.com/huggingface/ml-intern/blob/main/configs/main_agent_config.json) and returns a validated `Config` instance.

## Step-by-Step MCP Server Configuration

### 1. Define Servers in the JSON Config

Edit [`configs/main_agent_config.json`](https://github.com/huggingface/ml-intern/blob/main/configs/main_agent_config.json) to add entries under the `mcpServers` key. Each server requires a logical name and transport-specific parameters.

```json
{
  "model_name": "bedrock/us.anthropic.claude-opus-4-6-v1",
  "save_sessions": true,
  "auto_file_upload": true,
  "mcpServers": {
    "hf-mcp-server": {
      "transport": "http",
      "url": "https://huggingface.co/mcp?login",
      "headers": {
        "Authorization": "Bearer ${HF_MCP_TOKEN}"
      }
    },
    "local-stdio": {
      "transport": "stdio",
      "command": "python -m fastmcp.server"
    }
  }
}

```

The `hf-mcp-server` entry demonstrates remote configuration with header-based authentication, while `local-stdio` shows a local Python module invocation.

### 2. Secure Secrets with Environment Variables

Create a `.env` file at the repository root (ensure this is gitignored) to store sensitive tokens:

```bash
HF_MCP_TOKEN=hf_XXXXXXXXXXXXXXXXXXXX

```

When `load_config()` executes, it automatically interpolates `${HF_MCP_TOKEN}` with the actual value before Pydantic validation occurs.

### 3. Load and Validate the Configuration

The configuration loading happens programmatically through the [`agent/config.py`](https://github.com/huggingface/ml-intern/blob/main/agent/config.py) module:

```python
from pathlib import Path
from agent.config import load_config

config_path = Path(__file__).parent.parent / "configs" / "main_agent_config.json"
config = load_config(config_path)          # Validates & substitutes env vars

print(config.mcpServers)                  # Parsed server dictionary

```

This instantiation validates the schema and confirms that all referenced environment variables exist.

### 4. Initialize the Tool Router

In [`agent/main.py`](https://github.com/huggingface/ml-intern/blob/main/agent/main.py), the application constructs the `ToolRouter` by passing the parsed server configuration:

```python
from agent.core.tools import ToolRouter

tool_router = ToolRouter(config.mcpServers, hf_token=hf_token, local_mode=True)

```

This initialization creates internal `fastmcp.Client` instances for each configured MCP server, establishing the communication channels before the agent loop begins.

## Routing Tool Calls Through MCP

Once configured, tool execution flows through the router transparently. When the LLM requests an MCP-registered tool, `ToolRouter.execute_tool()` in [`agent/core/tools.py`](https://github.com/huggingface/ml-intern/blob/main/agent/core/tools.py) forwards the request to the appropriate client.

```python
await tool_router.execute_tool(
    tool_name="hf_repo_files",
    args={"repo_id": "my-org/my-repo", "path": "/data"}
)

```

The router detects that `hf_repo_files` resides on the remote MCP server, serializes the request, waits for the HTTP response, and injects the returned file list back into the agent context. This implementation spans lines 147-170 in [`agent/core/tools.py`](https://github.com/huggingface/ml-intern/blob/main/agent/core/tools.py), handling both transport types uniformly.

## Summary

- **Configure** MCP servers in [`configs/main_agent_config.json`](https://github.com/huggingface/ml-intern/blob/main/configs/main_agent_config.json) using `RemoteMCPServer` or `StdioMCPServer` schemas from `fastmcp`
- **Secure** credentials via `${VAR}` placeholders processed by `substitute_env_vars()` in [`agent/config.py`](https://github.com/huggingface/ml-intern/blob/main/agent/config.py) using `.env` files
- **Validate** configurations through the Pydantic `Config` model loaded by `load_config()` in [`agent/config.py`](https://github.com/huggingface/ml-intern/blob/main/agent/config.py)
- **Route** tool calls through `ToolRouter` initialized in [`agent/main.py`](https://github.com/huggingface/ml-intern/blob/main/agent/main.py), which manages `fastmcp.Client` instances in [`agent/core/tools.py`](https://github.com/huggingface/ml-intern/blob/main/agent/core/tools.py)

## Frequently Asked Questions

### What is the difference between RemoteMCPServer and StdioMCPServer in ML Intern?

**RemoteMCPServer** configures HTTP-based connections to external services, requiring a `url` and optional `headers` for authentication, while **StdioMCPServer** launches local subprocesses using a `command` string and communicates over standard input/output. The [`agent/config.py`](https://github.com/huggingface/ml-intern/blob/main/agent/config.py) module imports both schemas from `fastmcp.mcp_config` and validates them through the Pydantic `MCPServerConfig` union type.

### How does ML Intern handle sensitive API keys for MCP servers?

ML Intern processes the JSON configuration through `substitute_env_vars()` in [`agent/config.py`](https://github.com/huggingface/ml-intern/blob/main/agent/config.py), which replaces `${VAR}` syntax with values from the environment or `.env` file before Pydantic validation. This ensures tokens like `HF_MCP_TOKEN` remain outside version control while being available to the `fastmcp.Client` at runtime.

### Where is the MCP client instantiated in the ML Intern codebase?

The `fastmcp.Client` instantiation occurs inside [`agent/core/tools.py`](https://github.com/huggingface/ml-intern/blob/main/agent/core/tools.py) when `ToolRouter` initializes. The router receives the `config.mcpServers` dictionary from [`agent/main.py`](https://github.com/huggingface/ml-intern/blob/main/agent/main.py) and creates dedicated client instances for each configured server, managing their lifecycle and connection pooling throughout the agent session.

### Can I add multiple MCP servers to a single ML Intern configuration?

Yes. The `mcpServers` field in [`configs/main_agent_config.json`](https://github.com/huggingface/ml-intern/blob/main/configs/main_agent_config.json) accepts a dictionary mapping logical names to server configurations. You can define any number of remote HTTP servers and local stdio processes simultaneously; `ToolRouter` maintains separate client connections for each entry and routes tool calls to the appropriate endpoint based on the tool name registration.