跪拜 Guibai
← Back to the summary

A Single Natural-Language Command Drives Map Search, File I/O, and Browser Automation via Three MCP Servers

Foreword

In the current era of rapid AI Agent iteration, simple large-model conversations can no longer meet the needs of implementing automated business processes. The core capability of a truly usable intelligent Agent is large-model semantic understanding + standardized tool invocation + multi-end capability linkage.

The emergence of the MCP (Model Context Protocol) protocol allows various tool services to be integrated into AI models in a standardized way. This article is based on the LangChain + DeepSeek large model + multiple MCP Servers architecture, simultaneously integrating the Amap cloud MCP, a local filesystem MCP, and a Chrome debugging MCP to implement a full-chain intelligent Agent for map search, local file processing, and browser automation. All code can be deployed and run directly.

1. Core Technical Architecture

1.1 MCP Dual Communication Modes

The MCP client supports two official standard communication modes, which can be mixed simultaneously:

1.2 Overall Architecture Composition

This intelligent Agent is divided into a four-layer decoupled architecture:

  1. Large Model Layer: DeepSeek-V4-Pro, responsible for natural language decomposition, tool selection, multi-turn iterative decision-making, and result summarization.

  2. Protocol Scheduling Layer: LangChain MCP-Adapters, which uniformly support stdio / SSE dual-mode MCP, automatically discover and schedule tools.

  3. Tool Capability Layer

    1. Amap MCP (SSE Cloud): POI search, nearby query, route planning, geocoding.
    2. Filesystem MCP (stdio Local): Restricted directory read/write, file creation, document export.
    3. Chrome DevTools MCP (stdio Local): Browser automation, tab management, page operations.
  4. Business Execution Layer: Automatically completes the full closed loop of semantic decomposition, tool invocation, data acquisition, visualization display, and resource release.

2. Introduction to the Three MCP Server Capabilities

2.1 Amap MCP (SSE Cloud Remote Service)

An officially hosted MCP service from the Amap Open Platform. It requires no local deployment or process startup, and can be used via URL+Key authentication. It supports 12 core map capabilities including hotel POI queries, location search, route planning, and geocoding, offering high availability and zero maintenance.

2.2 Filesystem MCP (stdio Local Service)

An official standard local file operation service that supports directory sandbox permission restrictions, allowing read/write operations only within a specified folder. It can automatically create directories, write Markdown documents, and persist task results.

2.3 Chrome DevTools MCP (stdio Local Service)

A lightweight browser automation tool based on the Chrome Remote Debugging Protocol. It requires no heavy crawling frameworks and supports operations like creating new tabs, navigating to URLs, and modifying webpage titles.

Prerequisite: Start Chrome's remote debugging port.

chrome --remote-debugging-port=9222

3. Complete Runnable Code (All Bugs Fixed)

The following is the final production-grade code, with all syntax, variable, return value, and resource release issues fixed. It works out of the box.

import 'dotenv/config';
import { MultiServerMCPClient } from '@langchain/mcp-adapters';
import { ChatOpenAI } from '@langchain/openai';
import chalk from 'chalk';
import { HumanMessage, ToolMessage } from '@langchain/core/messages';

// Initialize DeepSeek large model
const model = new ChatOpenAI({
  modelName: 'deepseek-v4-pro',
  apiKey: process.env.DEEPSEEK_API_KEY!,
  temperature: 0,
  configuration: {
    baseURL: 'https://api.deepseek.com/v1',
  },
});

// Multi-MCP client: Cloud SSE Amap + Local stdio filesystem/browser
const mcpClient = new MultiServerMCPClient({
  mcpServers: {
    // Amap Cloud MCP: SSE remote mode
    'amap-maps': {
      url: "https://mcp.amap.com/mcp?key=54643235fb4ea7bf19021875a1685b41"
    },
    // Filesystem MCP: Local sandbox read/write
    'filesystem': {
      command: 'npx',
      args: [
        '-y',
        '@modelcontextprotocol/server-filesystem',
        'C:/Users/Administrator/Desktop/ZHUYI_AI/ai/agent_in_action/remote-mcp'
      ]
    },
    // Chrome browser automation MCP
    'chrome-devtools': {
      command: 'npx',
      args: ['-y', 'chrome-devtools-mcp@latest']
    }
  }
});

/**
 * MCP Agent multi-turn iteration executor
 */
async function runAgentWithTools(query: string, maxIterations = 30) {
  const tools = await mcpClient.getTools();
  const modelWithTools = model.bindTools(tools);
  const messages = [new HumanMessage(query)];

  for (let i = 0; i < maxIterations; i++) {
    console.log(chalk.bgGreen.white(`【Iteration ${i+1}】`));
    const response = await modelWithTools.invoke(messages);
    messages.push(response);

    // If no tool calls, the task ends
    if (!response.tool_calls || response.tool_calls.length === 0) {
      console.log(chalk.bgRed.white(`【AI Final Result】${response.content}`));
      return response.content;
    }

    console.log(chalk.bgBlue.white(`【Calling Tools】${response.tool_calls.map(t => t.name).join(', ')}`));

    // Iterate and execute all tools
    for (const toolCall of response.tool_calls) {
      const foundTool = tools.find(t => t.name === toolCall.name);
      if (foundTool) {
        const toolResult = await foundTool.invoke(toolCall.args);
        
        // Unified compatibility for all MCP return formats
        let contentStr: string;
        if (typeof toolResult === 'string') {
          contentStr = toolResult;
        } else if (toolResult && toolResult.text) {
          contentStr = toolResult.text;
        } else {
          contentStr = JSON.stringify(toolResult, null, 2);
        }

        messages.push(new ToolMessage({
          content: contentStr,
          tool_call_id: toolCall.id
        }));
      }
    }
  }

  return messages.at(-1)?.content || 'Task completed';
}

// Program entry point
async function main() {
  try {
    await runAgentWithTools(
      "Hotels near Beijing South Railway Station, the 3 nearest hotels, get hotel images, open the browser, display the image URL in each tab, and change each page title to the corresponding hotel name"
    );
  } catch (err) {
    console.error('【Task Exception】', err);
  } finally {
    await mcpClient.close();
    console.log(chalk.green('【All MCP connections closed】'));
  }
}

main();

4. In-Depth Code Analysis Section by Section

4.1 Dependency Import Module

This section uniformly imports the core dependencies required for the project, responsible for reading environment variables, managing multiple MCP services, calling the large model, beautifying logs, and defining the dialogue message structure. It is the foundational support for the entire project.

import 'dotenv/config';
import { MultiServerMCPClient } from '@langchain/mcp-adapters';
import { ChatOpenAI } from '@langchain/openai';
import chalk from 'chalk';
import { HumanMessage, ToolMessage } from '@langchain/core/messages';

Core Functions:

4.2 Large Model Instance Initialization

This section completes the creation and parameter configuration of the DeepSeek large model instance, fixing the model's capability style to suit automated Agent scenarios.

const model = new ChatOpenAI({
  modelName: 'deepseek-v4-pro',
  apiKey: process.env.DEEPSEEK_API_KEY!,
  temperature: 0,
  configuration: {
    baseURL: 'https://api.deepseek.com/v1',
  },
});

Core Functions:

4.3 Multi-MCP Service Client Configuration

This section is the core configuration of the project, simultaneously mounting three types of services—cloud SSE remote MCP and local stdio process MCP—to centrally manage all tool capabilities.

const mcpClient = new MultiServerMCPClient({
  mcpServers: {
    'amap-maps': {
      url: "https://mcp.amap.com/mcp?key=54643235fb4ea7bf19021875a1685b41"
    },
    'filesystem': {
      command: 'npx',
      args: [
        '-y',
        '@modelcontextprotocol/server-filesystem',
        'C:/Users/Administrator/Desktop/ZHUYI_AI/ai/agent_in_action/remote-mcp'
      ]
    },
    'chrome-devtools': {
      command: 'npx',
      args: ['-y', 'chrome-devtools-mcp@latest']
    }
  }
});

Core Functions:

4.4 Core Agent Multi-Turn Iteration Function

This section is the task scheduling core of the intelligent Agent, implementing the complete closed loop of "model decision → tool invocation → result feedback → multi-turn iteration."

async function runAgentWithTools(query: string, maxIterations = 30) {
  const tools = await mcpClient.getTools();
  const modelWithTools = model.bindTools(tools);
  const messages = [new HumanMessage(query)];

  for (let i = 0; i < maxIterations; i++) {
    console.log(chalk.bgGreen.white(`【Iteration ${i+1}】`));
    const response = await modelWithTools.invoke(messages);
    messages.push(response);

    if (!response.tool_calls || response.tool_calls.length === 0) {
      console.log(chalk.bgRed.white(`【AI Final Result】${response.content}`));
      return response.content;
    }

    console.log(chalk.bgBlue.white(`【Calling Tools】${response.tool_calls.map(t => t.name).join(', ')}`));

    for (const toolCall of response.tool_calls) {
      const foundTool = tools.find(t => t.name === toolCall.name);
      if (foundTool) {
        const toolResult = await foundTool.invoke(toolCall.args);
        
        let contentStr: string;
        if (typeof toolResult === 'string') {
          contentStr = toolResult;
        } else if (toolResult && toolResult.text) {
          contentStr = toolResult.text;
        } else {
          contentStr = JSON.stringify(toolResult, null, 2);
        }

        messages.push(new ToolMessage({
          content: contentStr,
          tool_call_id: toolCall.id
        }));
      }
    }
  }

  return messages.at(-1)?.content || 'Task completed';
}

Core Functions:

4.5 Program Entry Point and Resource Release

This section is the unified startup entry point for the project, handling exception catching and graceful resource release to ensure stable program operation.

async function main() {
  try {
    await runAgentWithTools(
      "Hotels near Beijing South Railway Station, the 3 nearest hotels, get hotel images, open the browser, display the image URL in each tab, and change each page title to the corresponding hotel name"
    );
  } catch (err) {
    console.error('【Task Exception】', err);
  } finally {
    await mcpClient.close();
    console.log(chalk.green('【All MCP connections closed】'));
  }
}

main();

Core Functions:

5. Common Errors and Fixes

5.1 Amap MCP Configuration Error

Problem: Using the command / npx local process method to configure the Amap MCP.

Solution: Amap is a cloud SSE service and only supports url+key configuration; no local process is needed.

5.2 Variable Not Defined Error: client is not defined

Problem: Incorrectly writing the variable name as client.close().

Solution: Uniformly use mcpClient.close() to release the connection.

5.3 Tool Return Value undefined Error

Problem: Different MCP services return data in non-uniform structures.

Solution: Use a three-stage type check to fully accommodate strings, text objects, and plain JSON objects.

5.4 Chrome MCP Call Timeout

Problem: Chrome's remote debugging port is not enabled.

Solution: Start Chrome with the debugging port enabled via the command line before running the project.

5.5 Top-Level await Syntax Error

Problem: The Node.js non-module environment does not support global await.

Solution: Encapsulate a standard async main function as the program entry point.

6. Overall Execution Flow

  1. Start the Chrome browser with the remote debugging port enabled.
  2. The program loads the DeepSeek model and the capabilities of the three MCP services.
  3. The large model automatically decomposes the natural language task, calling the Amap MCP to get nearby hotel and image information.
  4. Calls the Chrome MCP to automatically create new tabs, display images, and modify page titles.
  5. After the task is completed, all MCP connections are automatically closed, releasing resources.

7. Summary

This article implements a purely natural-language-driven intelligent Agent for map queries and browser automation based on the LangChain + dual-mode MCP architecture. Through the standardized MCP protocol, multi-tool linkage AI automation scenarios can be quickly implemented without manually encapsulating interfaces. The architecture is lightweight and highly scalable, adaptable to various business scenarios such as local life services, data visualization, and office automation.