MCP Ends the AI Tool Language War with a Single Protocol
MCP Protocol Practical Blog: A Standardized Solution for Cross-Process, Cross-Language Reusable AI Tools
Foreword
Developing AI Agents has long suffered from two fatal pain points:
- Tool code is tightly coupled with the main project. Switching to a different Agent requires copying and rewriting the adaptation layer, making it completely non-reusable;
- Tools are limited by the development language. Tools written in Node cannot be directly called by Java/Python/Rust programs, resulting in extremely high cross-language communication costs.
Both traditional solutions have shortcomings:
- Tools embedded in the main process: severe coupling, poor reusability;
- HTTP interface-wrapped tools: they merely fetch data and cannot natively integrate into the LLM context system.
Model Context Protocol (MCP) is specifically designed to solve the above problems: a standardized communication protocol that allows Agents to call independently deployed tools and static resources written in any language in a cross-process manner, achieving complete decoupling of LLM, tools, and context.
This article breaks down the server-side and client-side logic module by module, without piling up large blocks of code, explaining the principles and functions section by section.
1. MCP Basic Core Concepts
1. What is MCP
A standardized communication specification responsible for connecting LLM clients (Agents) and external capability servers, unifying the interaction format. The server provides two types of core capabilities:
- Tool: Executable tool functions that the LLM can actively call as needed;
- Resource: Static text resources that are pre-injected into the model context.
2. Two Communication Transport Layers
- Stdio (Local) Uses the operating system's standard input/output streams for IPC parent-child process communication. No port is needed, it is lightweight with no extra overhead, and is the first choice for local tools.
- HTTP (Remote) Cross-machine network calls, suitable for distributed, remotely deployed MCP services.
3. Core Advantage: Cross-Process Decoupling
Traditional tools: run in the same process as the Agent, with dependencies, lifecycles, and code all bound together. The MCP architecture splits the two ends, achieving complete isolation:
- MCP Server: An independent executable program, implementable in Node/Python/Java/Rust, only exposing Tool/Resource;
- MCP Client (Agent Host): The main LLM program, which can connect to multiple MCP services simultaneously and uniformly call all external capabilities.
4. Distinction from Other Technologies
- Compared to HTTP Interfaces HTTP only returns raw data; MCP incorporates tools and document resources into the LLM's native context, allowing the model to automatically identify and autonomously decide when to call them.
- Compared to RAG RAG excels at long document retrieval; MCP Resources are lightweight, fixed short texts (manuals, rules) directly inserted into the system prompt. The two are complementary.
2. MCP Server-Side Breakdown (Independent Tool Process)
File: my-mcp-server.mjs Function: A standalone child process that exposes a user query tool and usage documentation resources, with no coupling to the Agent main program.
1. Dependency Imports
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { z } from 'zod';
- McpServer: The core MCP server instance, used for registering tools and resources;
- StdioServerTransport: The stdio standard stream communication carrier, implementing cross-process IPC;
- zod: A parameter validation library that standardizes tool input structures, providing clear parameter descriptions to the LLM.
2. Mock Business Data Source
const database = {
users: {
'001': { id: '001', name: 'Zuhao', email: '[email protected]', role: 'admin' },
'002': { id: '002', name: 'Guangguang', email: '[email protected]', role: 'user' },
'003': { id: '003', name: 'Xiaohong', email: '[email protected]', role: 'user' },
}
}
Business logic is separated from the MCP protocol layer, allowing seamless replacement with a real database later without modifying the MCP registration code.
3. Initialize MCP Service Instance
const server = new McpServer({
name: 'my-mcp-server',
version: '1.0.0'
});
Defines the service's unique identifier and version, allowing the client to distinguish between different tool services in a multi-service scenario.
4. Register Tool: query_user
server.registerTool('query_user', {
description: `Query user information in the database. Input a user ID to return the user's detailed information (name, email, role)`,
inputSchema: {
userId: z.string().describe('User ID, for example: 001, 002, 003')
}
}, async ({userId}) => {
// Business query logic
});
Three-layer structure breakdown:
- Tool name:
query_user, the unique identifier for the client to recognize the call; - Metadata: description shows the LLM the tool's purpose, inputSchema defines the input parameter format and description;
- Callback function: receives parameters passed by the LLM, executes business logic, and uniformly returns standard MCP format text
{content: [{type: "text"}]}.
Internal business logic:
- Matches user data based on userId;
- If not found, returns a prompt text indicating available IDs;
- If found, concatenates user information text and returns it to the client.
5. Register Resource Static Resource
server.registerResource(
'Usage Guide',
'docs://guide',
{ description: 'MCP Server Usage Guide', mimeType: 'text/plain' },
async () => { return { contents: [{uri, text}] } }
)
Parameter description:
- Resource display name;
- Resource unique URI identifier, used by the client to read the resource;
- Resource description and text type;
- Callback: returns fixed static text (tool manual, business rules).
Function: The client reads all Resources once at startup, concatenates them into a SystemMessage, and injects them into the model, equivalent to issuing business rules to the AI in advance.
6. Bind stdio Cross-Process Communication Channel
const transport = new StdioServerTransport();
await server.connect(transport);
Key code: mounts the MCP service onto the standard input/output stream. The client launches this file as a child process via the node command, and the parent-child process relies on stdio to send and receive MCP protocol messages bidirectionally, completing cross-process communication.
3. MCP Client Agent Client-Side Breakdown (LLM Main Program)
File: langchain-mcp-test.mjs Function: The AI main program, acting as an MCP client, automatically starts the MCP child process, reads resources, binds cross-process tools, and automatically loops tool calls to answer user questions.
1. Dependency Imports
import 'dotenv/config';
import { MultiServerMCPClient } from '@langchain/mcp-adapters';
import { ChatOpenAI } from '@langchain/openai';
import chalk from 'chalk';
import { HumanMessage, SystemMessage, ToolMessage } from '@langchain/core/messages';
- dotenv: Reads environment variables to store the large model API key;
- MultiServerMCPClient: A unified management client for multiple MCP services, supporting simultaneous connection to multiple MCP services in different languages;
- ChatOpenAI: A large model wrapper compatible with the OpenAI interface (DeepSeek / Tongyi Qianwen are both acceptable);
- chalk: Colored console logs for easy debugging of the tool call flow;
- Message classes: LangChain standard message structures, distinguishing system prompts, user questions, and tool return results.
2. Initialize 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' },
});
temperature=0 turns off randomness to ensure stable tool calls; connects to domestic large models through a compatible interface.
3. Configure MCP Multi-Service Client
const mcpClient = new MultiServerMCPClient({
mcpServers: {
'my-mcp-server': {
command: 'node',
args: ['file absolute path/my-mcp-server.mjs']
}
}
})
Core logic:
- Configuration dictionary, key is the service name;
- command: The command to start the server program (node/python/java/rust binaries are all acceptable);
- args: Startup parameters, filled with the MCP server file path; The client internally automatically calls child_process to spawn a child process and automatically establishes stdio communication, without manual process management. Supports simultaneous configuration of multiple MCP services in different languages and paths.
4. Fetch Tools & Read All Resource Resources
4.1 Get All Cross-Process Tools
const tools = await mcpClient.getTools();
The client actively fetches tool metadata from all MCP services, automatically wrapping them into LangChain standard Tool instances that can be directly bound to the large model.
4.2 Iterate and Read All Static Resources, Concatenate System Prompt
const allResources = await mcpClient.listResources();
let resourceContent = '';
for (const [serverName, resources] of Object.entries(allResources)) {
for (const resource of resources) {
const contentList = await mcpClient.readResource(serverName, resource.uri)
resourceContent += contentList[0].text;
}
}
Process breakdown:
- listResources: Queries the resource list registered by all MCP services;
- Double-layer loop iterates through each service and each resource;
- readResource: Reads the resource text based on service name + URI;
- All text is concatenated into a complete context block and stored in the SystemMessage for the model.
5. Model Binds All Cross-Process Tools
const modelWithTools = model.bindTools(tools);
LangChain standardized binding, the model automatically perceives all cross-process tools exposed by MCP and outputs a standard tool_calls invocation structure.
6. Agent Automatic Tool Loop Function runAgentWithTools
Input Parameters and Initialize Messages
async function runAgentWithTools(query, maxIterations=30) {
const messages = [
new SystemMessage(resourceContent),
new HumanMessage(query)
];
- maxIterations: Maximum tool call rounds to prevent infinite loops;
- messages message queue: SystemMessage stores the Resource manual, HumanMessage stores the user's original question.
Loop Reasoning Logic
for (let i = 0; i < maxIterations; i++) {
const response = await modelWithTools.invoke(messages);
messages.push(response);
Each loop round: sends the complete messages to the large model, saves the model's returned result to the message queue.
Determine if Tool Call is Needed
if (!response.tool_calls || response.tool_calls.length === 0) {
console.log(`AI Final Reply: ${response.content}`);
return response.content;
}
If the model has no tool_calls, it means no further tool calls are needed, directly output the natural language answer and terminate the loop.
Execute Cross-Process Tool Call, Backfill Result
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);
messages.push(new ToolMessage({
content: toolResult,
tool_call_id: toolCall.id
}))
}
}
Execution flow:
- Iterate through each tool call instruction output by the model;
- Match the corresponding tool in the MCP-fetched tool list;
- invoke internally automatically passes parameters to the MCP child process for execution via stdio;
- Gets the text returned by the server, wraps it as a ToolMessage, carrying the tool_call_id, and stores it in the message queue;
- Enters the next loop round, the model re-reasons based on the tool result.
Loop Upper Limit Fallback
If the loop reaches 30 times without giving a final answer, directly return the last round's model output to avoid getting stuck.
7. Execute Test & Release Process Resources
// Read Resource test
await runAgentWithTools('What is the usage guide for the MCP Server?');
// Query user tool test
// await runAgentWithTools('Look up information for user 002');
// Crucial: Close all MCP child processes
await mcpClient.close();
close() function: Destroys all automatically started MCP child processes, disconnects the stdio communication channel, prevents background residual processes after script execution completes, and allows the program to exit normally.
4. Complete Execution Chain (Stdio Local Cross-Process)
- Execute the client script, MultiServerMCPClient spawns the MCP server child process via child_process;
- Parent-child processes bind standard input/output, establishing a bidirectional MCP protocol communication channel;
- The client actively fetches all Tool and Resource metadata from the server;
- Reads all Resources and concatenates them into a SystemMessage as the model's initial context;
- User question is sent to the message queue, the large model determines whether to call a tool;
- Tool call parameters are sent down to the child process MCP Server via stdio to execute business logic;
- Tool result returns to the main process via the same path, wrapped as a ToolMessage and appended to the message list;
- The model performs secondary reasoning based on the tool's returned content; if there are no tool calls, it outputs the final answer;
- Task ends, calls close, destroys all child processes, and the program exits.
5. How MCP Solves the Two Major Pain Points from the Opening
Pain Point 1: Tools are bound to the project and cannot be reused across projects
MCP Server is an independent executable program, completely isolated from the Agent business:
- Packaged and deployed independently, any Agent project only needs to add the service startup command in the Client configuration to reuse it;
- Multiple Agents and multiple business systems can share the same set of MCP tool services without copying tool code.
Pain Point 2: Only usable in Node, cannot be compatible with Java/Python/Rust tools
MCP is a pure protocol, language-agnostic:
- The transport layer only relies on stdio or HTTP, any language implementing the MCP SDK can act as a Server;
- The client is uniformly encapsulated, the upper-layer Agent is completely unaware of the underlying tool's development language, and the calling logic remains unchanged.
6. Expansion and Implementation Optimization Directions
- Remote Deployment Transformation The current example is a local stdio process; for distributed scenarios, replace the HTTP transport layer and deploy the MCP service in the cloud for remote calls;
- Resource and RAG Combination Resource is suitable for short specifications and tool manuals; use RAG retrieval for long business knowledge bases, combining the two to build a complete context;
- Multi-Service Modular Splitting MultiServerMCPClient supports simultaneously mounting multiple independent MCP services such as databases, file processing, and API requests, splitting tools by business;
- Production Environment Enhancement Add process keep-alive, call timeout, log collection, and permission verification to prevent child process crashes from blocking the Agent.