跪拜 Guibai
← Back to the summary

One Agent, Four Servers: Wiring Maps, Browsers, and Files into a Single AI Loop

Mastering MCP Multi-Server Architecture from Scratch: Let AI Control Maps, Browsers, and the File System Simultaneously

Foreword

Imagine this: you just say in natural language, "Find hotels near Beijing South Railway Station and save the results as a screenshot locally." The AI can automatically call the Amap to find hotels, control the browser to take a screenshot, and then write to a local file — all without you manually operating any tools.

This is the transformation brought by MCP (Model Context Protocol) . This article, based on a real project, takes you from zero to understanding MCP's multi-server architecture and provides a hands-on guide to implementing an AI Agent that connects to 4 MCP Servers simultaneously.


1. What is MCP? Why is it Important?

1.1 Understanding in One Sentence

MCP is the "USB interface protocol" for AI. Just as USB allows a computer to connect peripherals like keyboards, mice, and flash drives, MCP allows AI to connect to various tools like maps, browsers, file systems, and databases.

1.2 Core Value: Reusability

With the MCP protocol, anyone can develop an MCP Server based on this protocol, which can then be directly reused.

This is the greatest charm of MCP — develop once, use everywhere. Amap's official team developed a Maps MCP Server; you don't need to wrap the map API yourself, just take it and use it directly.

1.3 Two Connection Methods

Connection Method Transport Protocol Applicable Scenarios Example
Remote HTTP HTTP/SSE Third-party services, cloud APIs Amap MCP
Local stdio Standard Input/Output Local tools, browser control Chrome DevTools, FileSystem

Knowledge Point 1: The MCP Protocol

What is MCP: Model Context Protocol, an open-source standard protocol defined by Anthropic that specifies the communication standard between AI models and external tools. It allows LLMs to discover and invoke various external tools in a unified way, without writing custom glue code for each tool.

Core Concepts:

  • Server: A process that provides tools (can be a local program or a remote service)
  • Client: A client that connects to the Server and retrieves the tool list
  • Tool: A specific capability exposed by the Server (e.g., "query latitude and longitude", "open a webpage", "write a file")

Why it's important: Before MCP, enabling AI to call external tools required writing separate adapter code for each tool. MCP unifies this process — just like USB unified the standard for connecting peripherals.


2. Project Architecture Overview

┌─────────────────────────────────────────────────────┐
│                    AI Agent (DeepSeek)               │
│           Understands natural language → Decides which tools to call        │
└──────────────────────┬──────────────────────────────┘
                       │ bindTools()
┌──────────────────────▼──────────────────────────────┐
│              MultiServerMCPClient                     │
│            (LangChain MCP Adapter)                   │
│         Manages tools from multiple MCP Servers uniformly                 │
└──┬──────────┬──────────────┬──────────────┬─────────┘
   │ HTTP     │ stdio        │ stdio        │ stdio
┌──▼────┐ ┌───▼──────┐ ┌────▼──────┐ ┌───▼─────────┐
│ Amap  │ │ Custom MCP│ │Chrome      │ │ FileSystem  │
│  MCP   │ │  Server  │ │DevTools MCP│ │    MCP      │
│ (Remote)  │ │ (Local)    │ │  (Local)    │ │   (Local)    │
└────────┘ └──────────┘ └────────────┘ └─────────────┘

Core dependencies (package.json):


3. Creating Your Own MCP Server

Start with the simplest thing — writing a local Server using the MCP SDK. Code is in my-mcp-server.mjs:

import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { z } from 'zod';

// 1. Create a Server instance
const server = new McpServer({
  name: 'my-mcp-server',
  version: '1.0.0',
});

// 2. Register a tool: addition
server.tool(
  'add',
  'Calculate the sum of two numbers',
  {
    a: z.number().describe('The first number'),   // ← zod defines the parameter schema
    b: z.number().describe('The second number'),
  },
  async ({ a, b }) => ({
    content: [{ type: 'text', text: String(a + b) }],  // ← Returns standard format
  })
);

// 3. Start via stdio, waiting for client connection
const transport = new StdioServerTransport();
await server.connect(transport);

Knowledge Point 2: The Three Elements of an MCP Server

Every MCP tool contains three core parts:

1. Name: A unique identifier, like 'add'. The AI uses the name to distinguish and select tools.

2. Parameter Schema (input schema): Defines parameter types and descriptions using Zod. Zod is a schema validation library for TypeScript/JavaScript. The AI reads this schema to understand "what parameters this tool requires."

{ a: z.number().describe('The first number') }

z.number() indicates the parameter type is a number, and .describe() provides a parameter description for the AI.

3. Callback Function (handler): The function that actually executes the business logic, returning data in the { content: [{ type: 'text', text: '...' }] } format.

stdio Transport: The client runs the MCP Server by launching a child process, and the two exchange JSON messages via standard input/output (stdin/stdout). This means an MCP Server can be a command-line program written in any language.


4. AI Agent Client: Connecting to Multiple MCP Servers Simultaneously

The most exciting part is here — mcp-test.mjs. It uses a single MultiServerMCPClient to manage all MCP Servers uniformly:

const mcpClient = new MultiServerMCPClient({
    mcpServers: {
        // Type 1: Remote HTTP MCP
        'amap': {
            "url": "https://mcp.amap.com/mcp?key=YOUR_KEY"
        },
        // Type 2: Local stdio MCP (runs a JS file)
        'my-mcp-server': {
            command: 'node',
            args: ['./src/my-mcp-server.mjs']
        },
        // Type 3: Local stdio MCP (runs an npm package via npx)
        'chrome-devtools': {
            command: 'npx',
            args: ['-y', 'chrome-devtools-mcp']
        },
        // Type 4: File System MCP
        'filesystem': {
            command: 'npx',
            args: ['-y', '@modelcontextprotocol/server-filesystem', './output']
        }
    }
});

// Get all tools from all Servers with one line of code!
const tools = await mcpClient.getTools();

Configuration comparison for the four types of Servers:

MCP Server Type Configuration Method
Amap HTTP Remote Fill in the URL directly; the SDK handles the connection automatically
Custom Server stdio Local command: 'node' + script path
Chrome DevTools stdio Local npx -y pulls and runs the npm package
FileSystem stdio Local Same as above, followed by the allowed access directory

Knowledge Point 3: How MultiServerMCPClient Works

MultiServerMCPClient is the aggregation client provided by the LangChain MCP Adapter.

Workflow:

  1. Reads each MCP Server from the configuration
  2. For HTTP type → Sends an HTTP request to get the tool list
  3. For stdio type → Starts a child process and communicates via stdin/stdout
  4. Merges the tools from all Servers into a unified tool list
  5. Injects the tools into the AI model via model.bindTools(tools)

Key Advantage: The AI doesn't need to know which tool comes from which Server — it just sees a unified tool list and calls them as needed. This is like the "hardware abstraction layer" of an operating system.


5. AI Agent Loop: Letting the Model Make Autonomous Decisions

After having the tool list, how do you get the AI to call them autonomously? The core is the Agent Loop:

async function runAgentWithTools(query, maxIterations = 10) {
    const messages = [new HumanMessage(query)];

    for (let i = 0; i < maxIterations; i++) {
        // Step 1: Send the conversation history to the model
        const response = await modelWithTools.invoke(messages);
        messages.push(response);

        // Step 2: If the model returns text directly → Task complete!
        if (!response.tool_calls || response.tool_calls.length === 0) {
            return response.content;
        }

        // Step 3: The model says to call tools → Execute them one by one
        for (const tool_call of response.tool_calls) {
            const foundTool = tools.find(t => t.name === tool_call.name);
            const result = await foundTool.invoke(tool_call.args);

            // Step 4: Tell the model the tool execution result, letting it decide the next step
            messages.push(new ToolMessage({
                content: result,
                tool_call_id: tool_call.id,
            }));
        }
        // Back to Step 1, the model continues reasoning based on the results...
    }
}

Knowledge Point 4: The Execution Flow of an Agent Loop

The whole process is like an "intelligent while loop":

User: "Find hotels near Beijing South Station, write to a file"
   ↓
Round 1: AI calls amap.search("Hotels near Beijing South Station")        ← I need location data
   ↓ (Tool returns: Hotel list)
Round 2: AI calls amap.get_detail(hotel1_id)              ← I need detailed info
   ↓ (Tool returns: Name, address, rating)
Round 3: AI calls filesystem.write("hotels.txt", result)   ← Data is sufficient, write to file
   ↓ (Tool returns: Write successful)
Round 4: AI returns "Done! Hotel info has been written to hotels.txt"     ← Task complete, stop loop

Key Design Points:

  • ToolMessage: The tool execution result is wrapped as a ToolMessage and appended to the message history, so the model can see "the result of the last tool call"
  • maxIterations: A safety valve to prevent infinite loops (e.g., if a tool keeps failing)
  • Model Autonomous Decision-Making: Which tool to call at each step and what parameters to pass are entirely decided by the model

6. Practical Demonstration

Scenario 1: Map + File System Integration

await runAgentWithTools(`
    Help me find hotels near Beijing South Railway Station, find the nearest 3.
    For each hotel, write the name, address, rating, and other info
    into the hotels_near_beijing_south_station.txt file.
`);

The AI will automatically: call the Amap MCP to search → get details → call the FileSystem MCP to write to a file.

Scenario 2: Browser Control

await runAgentWithTools('Open the Baidu homepage and tell me what the page title is');

The AI automatically calls the Chrome DevTools MCP's navigate_pagetake_snapshot tools.


Knowledge Point 5: The Role of Chrome DevTools MCP

chrome-devtools-mcp is an npm package that provides 29 browser control tools:

Category Tools
Page Navigation navigate_page, new_page, close_page, select_page
Element Interaction click, fill, hover, drag, type_text, press_key
Data Retrieval take_screenshot, take_snapshot, evaluate_script
Debugging & Analysis list_console_messages, list_network_requests, performance_start_trace

It allows you to control a browser using natural language — "Open Taobao and search for iPhone", "Take a screenshot and save it", "Check console errors", the AI can help you complete all of these.

Note: Requires Chrome or Edge browser installed locally (any Chromium-based browser will do).


Knowledge Point 6: Environment Variable Management

The project uses dotenv to manage sensitive configuration (.env):

DEEPSEEK_API_KEY=sk-xxx
DEEPSEEK_API_BASE_URL=https://api.deepseek.com/v1
DEEPSEEK_MODEL=deepseek-v4-flash

In the code, it's automatically loaded via import 'dotenv/config', then read using process.env.XXX. Never hardcode API Keys in your code.


7. Summary

Review of Core Points

  1. MCP is a tool protocol for AI: It unifies the communication method between AI and external tools, making tools reusable
  2. Two transport methods: HTTP (remote services) and stdio (local processes)
  3. MultiServerMCPClient: One client manages multiple MCP Servers simultaneously; the AI doesn't need to care about the tool's source
  4. Agent Loop: The AI cycles through "think → call tool → see result → think again" until the task is complete
  5. Creating a custom MCP Server only takes three steps: Create Server → Register tool (name + zod schema + handler) → Connect transport

File Index

File Purpose
readme.md Project notes, recording application scenarios and design ideas
my-mcp-server.mjs Custom MCP Server example (add/get_current_time/reverse_string)
mcp-test.mjs AI Agent client, connecting multiple MCP Servers + Agent Loop
package.json Project dependencies
.env Environment variables (API Key)

Remember MCP in one sentence: It transforms AI from "just chatting" to "capable of doing anything" — and all you need to do is fill in the MCP Server configuration.

Welcome to discuss in the comments! If you've also written interesting MCP Servers, feel free to share 🚀