您现在的位置是:网站首页> AI人工智能

AI模型调用MCP服务及实用MCP服务

摘要

AI模型调用MCP服务及实用MCP服务

***Agent让调用模型变得简单***

***Python编写MCP一般使用FastMCP,支持发布为studio sse streamable_http***

FastMCP文档

***LangChain 调用各类 MCP 例子***

***一个操作鼠标 STDIO 通讯方式的 MCP 例子***

方便调用AI模型的Agent编程框架

AI入门编程推荐隔壁的程序员老王,点击进入

***STDIO本地MCP服务采用UVX NPX方式调用的MCP若没有安装则会自动从仓库安装,UVX、NPX是临时安装***

***Streamable HTTP、WebSocket远程的MCP服务***

*LangChain Agent框架支持Python与.NET*

1.jpg


客户端将MCP工具列表和用户问题-》大语言模型-》需要调用MCP的信息返回给调用模型的客户端,客户端调用指定MCP->客户端获得MCP结果-》大语言模型-》返回给最终客户


最简单的MCP服务及调用,使用FastMCP编写MCP服务,C#成功调用

FastMCP编写MCP,支持websocket通讯方式

大模型调用websocket MCP例子

***LangChain 调用各类 MCP 例子***

***一个操作鼠标 STDIO 通讯方式的 MCP 例子***

LangChain 调用不同通讯方式MCP例子

.NET Core编写MCP服务,AI赋能

让 AI 读取 FastMCP的Resource

***STDIO方式的MCP如何调用不用第三方库C#如何调用***

LangChain.NET如何调用Ollama制作知识库和调用MCP服务

UV与UVX区别

AI学习MCP

AI辅助生成MCP例子

MCP协议:AI界的USB-C统一接口,从知识点到实践,从使用别人的MCP到自己编写部署MCP,cherry-studio使用链接MCP

UV与Conda工具使用收集

UVX NPX介绍

Awesome MCP Servers

mcp.so

Cherry Studio 新版本 1.2.9 一键式添加MCP服务器

CherryStudio的MCP配置

详细介绍NPX或UVX配置MCP服务

MCP客户端神器全收录

C# .NET4.5用 IHttpHandler如何编写SSE服务

MCP协议官网

MCP相关视频

MCP服务相关技术收集MCP

MCP协议详细讲解

AI 模型调用 MCP 服务的过程

AI 模型调用 MCP 服务的代码示例

C# 编写 Agent 调用 ollama 及 MCP 的方法

Trae+Chrome MCP Server 让AI接管你的浏览器

MCP典型服务

Chrome MCP Server(逆天神器来了!MCP Chrome:超越Playwright,让AI接管你的浏览器)

Chrome MCP官方

mcp2mqtt动动嘴就可以控制智能家居

excel-mcp-server使用 AI 代理创建、读取和修改 Excel 工作簿

Windows MCP.Net基于 .NET 的 Windows 桌面自动化 MCP (Model Context Protocol) 服务器

Windows-MCP用于 Windows 计算机的轻量级 MCP 服务器

大模型实战 | Dify+Chrome MCP打造网页自动化AI助手

AI辅助生成MCP例子

收集一些MCP


根据 MCP 协议规范(截至 2025-06-18 版本),initialize和tools/list是所有 MCP 服务必须强制实现的核心方法,属于协议的 “基础交互层” 定义。这一设计的核心目的是保证 MCP 服务的互操作性—— 任何遵循 MCP 标准的服务都必须能被 AI 模型(或客户端)正常识别、连接和使用,而这两个方法正是实现这一目标的基础。

一、initialize:必须实现的 “握手协议”

initialize方法是 MCP 服务与客户端建立连接的第一个交互步骤,其核心作用是:

确认双方支持的 MCP 协议版本(如2025-06-18),避免版本不兼容导致的通信失败;

服务器声明自身的基础能力(如是否支持工具调用、资源访问、提示模板等);

交换客户端与服务器的元数据(名称、版本等),用于日志和调试。

协议明确规定:如果 MCP 服务未实现initialize方法,客户端必须拒绝建立连接。这类似于 TCP 协议中的 “三次握手”—— 没有初始化确认,后续所有交互都失去了基础。

示例:若服务器未响应initialize,客户端会返回错误:

json

{

  "jsonrpc": "2.0",

  "id": "1",

  "error": {

    "code": -32601,

    "message": "Method 'initialize' not found"

  }

}

二、tools/list:必须实现的 “服务目录”

tools/list方法是 AI 模型获取服务能力的唯一标准化入口,其核心作用是:

向客户端返回服务器支持的所有工具(如weather/forecast、filesystem/read);

提供每个工具的元数据(名称、描述、参数结构等),使 AI 模型能动态解析如何调用;

支持分页查询(通过cursor参数),适配工具数量较多的场景。

协议规定:即使服务不提供任何工具(极端情况),也必须实现tools/list并返回空列表。这是因为 AI 模型需要通过该方法确认 “服务是否有可用功能”,而非通过其他非标准化方式猜测。

示例:无工具的服务返回的tools/list响应:

json

{

  "jsonrpc": "2.0",

  "id": "2",

  "result": {

    "tools": [],

    "nextCursor": null

  }

}

例子包:

// 服务器返回工具列表{
  "jsonrpc": "2.0",
  "id": "2",
  "result": {
    "tools": [
      {
        "name": "weather/forecast",
        "description": "获取指定城市的天气预报",
        "inputSchema": {
          "type": "object",
          "properties": {
            "city": {"type": "string", "description": "城市名称"},
            "days": {"type": "number", "description": "预报天数", "default": 1}
          },
          "required": ["city"]
        }
      }
    ],
    "nextCursor": "可选分页游标"
  }}
  
  端到端例子(带代码)
示例 1:用 Node.js(标准 fetch)连接一个 MCP Server,发现工具并调用
约定:通过环境变量 MCP_SERVER_URL 配置服务地址,例如 http://localhost:4000 (实际路径由你的服务实现决定);我们将通过 JSON-RPC 请求 method: "tools/list" 和 "tools/call" 完成发现与执行。 2 3
代码示例(JavaScript):
1. 1.
   基础 RPC 封装
说明:将 JSON-RPC 请求发送到 MCP Server 的 RPC 端点(比如 ${SERVER_URL}/rpc 或根路径,具体由服务器决定)。
代码:
  const SERVER_URL = process.env.MCP_SERVER_URL || ' http://localhost:4000 ';
  async function rpc(method, params) {
  const res = await fetch( ${SERVER_URL} , {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
  jsonrpc: '2.0',
  id: Math.floor(Math.random() * 1e9),
  method,
  params
  })
  });
  const data = await res.json();
  if (data.error) throw new Error(JSON.stringify(data.error));
  return data.result;
  }
2. 1发现工具列表(tools/list),选择某个工具
代码:
  (async () => {
  const tools = await rpc('tools/list', {});
  console.log('Tools:', tools);
  
  // 假设有一个名为 "calculate" 的工具,带有 operation/x/y 参数
  const calcTool = tools.find(t => t.name === 'calculate');
  if (!calcTool) throw new Error('No calculate tool');
  
  // 查看该工具的参数模式(例如 JSON Schema)
  console.log('calculate schema:', calcTool.input_schema || calcTool.parameters);
  })();
3. 1 调用工具(tools/call)
代码:
  (async () => {
  const result = await rpc('tools/call', {
  name: 'calculate',
  arguments: { operation: 'add', x: 2, y: 3 }
  });
  console.log('Call result:', result);
  })();
示例 2:用 curl 直接做 JSON-RPC 请求(适合快速调试)

 发现工具(tools/list):
  curl -X POST http://localhost:4000 -H "Content-Type: application/json" -d '{ "jsonrpc":"2.0", "id":1, "method":"tools/list", "params":{} }'
调用工具(tools/call):
  curl -X POST http://localhost:4000 -H "Content-Type: application/json" -d '{ "jsonrpc":"2.0", "id":2, "method":"tools/call", "params":{ "name":"calculate", "arguments":{ "operation":"add", "x":2, "y":3 } } }'
示例 3:发现并使用 prompts(提示词模板)

先列出可用模板(prompts/list),再获取具体模板(prompts/get)并传入动态参数(例如 name)来生成消息序列。 1
代码:
  (async () => {
  const promptList = await rpc('prompts/list', {});
  console.log('Prompts:', promptList);
  
  const greeting = promptList.find(p => p.name === 'greeting');
  const messages = await rpc('prompts/get', {
  name: greeting.name,
  arguments: { name: 'Alice' }
  });
  console.log('Rendered messages:', messages);
  })();


AI学习MCP

npx启动一个AI的MCP服务,默认的端口是多少,给个例子

如何源码方式安装npx的 AI MCP

stdio 方式部署的MCP 如何调用

sse 方式部署的MCP 如何调用

StreamableHTTP 方式部署的MCP 如何调用

Agent如何组包MCP发送给大模型

MCP操作数据库通用化



####【豆包】

Q:npx启动一个AI的MCP服务,默认的端口是多少,给个例子

A:...

在常见的 Node.js/AI 相关服务中,默认端口通常为开发常用的3000、5000、8000等(例如 Express 框架默认 3000,FastAPI 常用 8000)。如果是某个特定的 AI MCP 服务包,其默认端口需以该包的文档为准。

举例(假设服务包名为ai-mcp-service):

如果该服务默认端口为3000,启动命令可能如下:

bash

运行

npx ai-mcp-service

启动后,服务会默认监听3000端口,可通过 http://localhost:3000 访问。

提示:

若启动后端口被占用,通常可通过参数指定端口,例如:

bash

运行

npx ai-mcp-service --port 5000  # 手动指定端口为5000

具体默认端口和使用方式,建议查看该 MCP 服务对应的 npm 包文档(可通过 npx ai-mcp-service --help 查看帮助信息)。





####【豆包】

Q:如何源码方式安装npx的 AI MCP

A:...

若需要从源码方式安装并通过npx调用 AI MCP(模型组件包),通常需要手动克隆源码仓库、进行本地构建,再通过npx引用本地路径。以下是通用步骤:

1. 克隆源码仓库

首先获取 AI MCP 的源代码(假设托管在 Git 仓库):

bash

# 克隆仓库(替换为实际仓库地址)

git clone https://github.com/example/ai-mcp.git

cd ai-mcp  # 进入源码目录

2. 安装依赖并构建

源码通常需要安装依赖并执行构建(如编译 TypeScript、打包等):

bash

# 安装项目依赖

npm install


# 执行构建(根据项目脚本调整,常见命令如下)

npm run build  # 或 npm run compile

如果项目有特殊构建步骤(如需要 Python 环境、额外编译工具等),需参考源码中的README文档。

3. 链接本地包(可选)

若希望在全局环境中通过包名调用,可使用npm link创建本地链接:

bash

# 在源码目录执行,将本地包链接到全局

npm link


# 此时可直接通过包名调用(无需npx)

ai-mcp --version  # 验证是否链接成功

4. 通过 npx 调用本地源码

如果不希望全局链接,可直接通过npx引用本地路径:

bash

# 在源码目录外,通过相对路径调用

npx ./path/to/ai-mcp [命令参数]


# 例如,从源码目录的父级调用

npx ./ai-mcp --input=test.txt

5. 验证安装

执行简单命令验证功能是否正常:

bash

# 查看版本(根据组件实际命令调整)

npx ./ai-mcp --version


# 运行示例功能

npx ./ai-mcp --demo

注意事项

依赖缺失:若构建或运行时报错,检查是否缺少系统级依赖(如python、make等),根据错误提示安装。

权限问题:npm link可能需要管理员权限(Linux/macOS 加sudo,Windows 用管理员终端)。

更新源码:后续源码有更新时,需重新拉取代码并执行npm install和npm run build。


####【豆包】

Q:stdio 方式部署的MCP 如何调用

A:

import subprocess

import json

import sys


def call_mcp(request_data):

    # 启动MCP进程(假设MCP是可执行程序)

    mcp_process = subprocess.Popen(

        ["./mcp_service"],  # MCP程序路径

        stdin=subprocess.PIPE,

        stdout=subprocess.PIPE,

        stderr=subprocess.PIPE,

        text=True  # 以文本模式通信(避免二进制处理)

    )

    

    try:

        # 序列化请求数据并发送到MCP的stdin

        request_str = json.dumps(request_data) + "\n"  # 加换行符作为结束标志

        mcp_process.stdin.write(request_str)

        mcp_process.stdin.flush()  # 强制刷新缓冲区,确保MCP能立即收到

        

        # 从MCP的stdout读取响应(假设响应以换行结束)

        response_str = mcp_process.stdout.readline()

        if not response_str:

            # 读取错误信息(如果MCP崩溃)

            error = mcp_process.stderr.read()

            raise RuntimeError(f"MCP error: {error}")

        

        # 反序列化响应

        return json.loads(response_str)

    

    finally:

        # 关闭进程(如果MCP是单次请求模式,否则保持运行)

        mcp_process.stdin.close()

        mcp_process.wait()


# 调用示例

if __name__ == "__main__":

    request = {"action": "predict", "data": [1, 2, 3]}

    response = call_mcp(request)

    print("MCP响应:", response)



####【豆包】

Q:sse 方式部署的MCP 如何调用

A:

SSE(Server-Sent Events,服务器发送事件)是一种基于 HTTP 的单向通信协议,允许服务器主动向客户端持续推送数据。以 SSE 方式部署的 MCP(模型 / 服务控制程序)本质是一个 HTTP 服务器,通过text/event-stream格式向客户端推送实时响应,适用于需要持续输出的场景(如流式生成、实时日志等)

调用原理

SSE 调用的核心是 “客户端发起一次 HTTP 请求,服务器保持连接并持续推送数据”:

1.客户端向 MCP 的 SSE 接口发起 HTTP GET 请求(需指定Accept: text/event-stream头);

2.MCP 接受请求后,保持 TCP 连接不关闭,通过text/event-stream格式持续向客户端推送数据;

3.客户端持续监听响应流,解析 SSE 格式的数据并处理;

4.通信结束时,MCP 关闭连接,或客户端主动断开。

SSE 数据格式遵循特定规范,每条消息由字段组成(用\n分隔),常见字段:

data::消息内容(核心字段,可多行,以\n\n结束一条完整消息);

event::事件类型(可选,客户端可按类型处理);

id::消息 ID(可选,用于重连时恢复进度);

retry::重连间隔(可选,单位毫秒)。


1. 浏览器端调用(JavaScript)

// 初始化SSE连接(参数为MCP的SSE接口URL,可带查询参数)

const sse = new EventSource('http://localhost:8000/mcp/sse?action=stream&input=test');


// 监听默认事件(无event字段的消息)

sse.onmessage = (event) => {

  const data = JSON.parse(event.data); // 解析JSON数据

  console.log('收到消息:', data);

  // 处理数据(如更新UI)

};


// 监听特定事件(如"progress"类型)

sse.addEventListener('progress', (event) => {

  const progress = JSON.parse(event.data);

  console.log('处理进度:', progress.step);

});


// 监听完成事件

sse.addEventListener('complete', (event) => {

  const result = JSON.parse(event.data);

  console.log('最终结果:', result.final_result);

  sse.close(); // 完成后关闭连接

});


// 监听错误

sse.onerror = (error) => {

  console.error('SSE连接错误:', error);

  // 可在这里处理重连逻辑

};


2. 后端服务调用(Python)

import requests

import json


def call_sse_mcp(url, params):

    # 发起SSE请求,设置必要的头信息

    headers = {

        'Accept': 'text/event-stream',

        'Cache-Control': 'no-cache'

    }

    

    try:

        # 发送GET请求,stream=True表示流式读取

        with requests.get(url, params=params, headers=headers, stream=True) as response:

            response.raise_for_status()  # 检查HTTP错误状态码

            

            # 逐行解析响应流(SSE消息以"\n\n"分隔)

            buffer = []

            for line in response.iter_lines(decode_unicode=True):

                if not line:  # 空行表示一条消息结束

                    if buffer:

                        process_sse_message('\n'.join(buffer))

                        buffer = []

                    continue

                buffer.append(line)

                

    except requests.exceptions.RequestException as e:

        print(f"请求错误: {e}")


def process_sse_message(raw_message):

    """解析单条SSE消息"""

    event_type = 'message'  # 默认事件类型

    data = None

    

    # 拆分消息的字段(如event: progress、data: {...})

    for part in raw_message.split('\n'):

        if part.startswith('event:'):

            event_type = part.split(':', 1)[1].strip()

        elif part.startswith('data:'):

            data_str = part.split(':', 1)[1].strip()

            data = json.loads(data_str)  # 解析JSON数据

    

    # 按事件类型处理

    if event_type == 'progress':

        print(f"进度更新: {data['step']}/{data['total']}")

    elif event_type == 'complete':

        print(f"最终结果: {data['result']}")

    else:

        print(f"收到消息: {data}")


# 调用示例

if __name__ == "__main__":

    mcp_sse_url = "http://localhost:8000/mcp/sse"

    request_params = {

        "action": "stream_predict",

        "input": "需要处理的内容"

    }

    call_sse_mcp(mcp_sse_url, request_params)


3. Java 调用示例(使用 OkHttp)

import okhttp3.*;

import com.google.gson.Gson;

import java.io.IOException;


public class SseMcpClient {

    private static final Gson gson = new Gson();

    private static final String MCP_SSE_URL = "http://localhost:8000/mcp/sse";


    public static void main(String[] args) {

        OkHttpClient client = new OkHttpClient();


        // 构建请求(带参数)

        HttpUrl url = HttpUrl.parse(MCP_SSE_URL)

                .newBuilder()

                .addQueryParameter("action", "stream_predict")

                .addQueryParameter("input", "需要处理的内容")

                .build();


        Request request = new Request.Builder()

                .url(url)

                .header("Accept", "text/event-stream")

                .header("Cache-Control", "no-cache")

                .build();


        // 发送请求并处理流式响应

        client.newCall(request).enqueue(new Callback() {

            @Override

            public void onResponse(Call call, Response response) throws IOException {

                if (!response.isSuccessful()) {

                    throw new IOException("请求失败: " + response);

                }


                // 逐行读取响应体

                ResponseBody body = response.body();

                if (body == null) return;


                try (BufferedSource source = body.source()) {

                    StringBuilder buffer = new StringBuilder();

                    while (!source.exhausted()) {

                        String line = source.readUtf8Line();

                        if (line == null) break;


                        if (line.isEmpty()) {  // 空行表示一条消息结束

                            if (buffer.length() > 0) {

                                processSseMessage(buffer.toString());

                                buffer.setLength(0);

                            }

                        } else {

                            buffer.append(line).append("\n");

                        }

                    }

                } finally {

                    response.close();

                }

            }


            @Override

            public void onFailure(Call call, IOException e) {

                System.err.println("连接失败: " + e.getMessage());

            }

        });

    }


    private static void processSseMessage(String rawMessage) {

        String eventType = "message";

        String dataJson = null;


        // 解析SSE消息字段

        for (String part : rawMessage.split("\n")) {

            if (part.startsWith("event:")) {

                eventType = part.substring(6).trim();

            } else if (part.startsWith("data:")) {

                dataJson = part.substring(5).trim();

            }

        }


        // 处理数据(根据事件类型解析)

        if (dataJson != null) {

            if ("progress".equals(eventType)) {

                ProgressData progress = gson.fromJson(dataJson, ProgressData.class);

                System.out.println("进度: " + progress.step + "/" + progress.total);

            } else if ("complete".equals(eventType)) {

                CompleteData result = gson.fromJson(dataJson, CompleteData.class);

                System.out.println("最终结果: " + result.result);

            } else {

                System.out.println("收到消息: " + dataJson);

            }

        }

    }


    // 定义数据模型类(与MCP响应格式对应)

    static class ProgressData {

        int step;

        int total;

    }


    static class CompleteData {

        String result;

    }

}


4.C#调用SSE

using System;

using System.Net.Http;

using System.Threading.Tasks;


namespace SSEClientDemo

{

    class Program

    {

        static async Task Main(string[] args)

        {

            await ConnectToSSEServer();

        }


        static async Task ConnectToSSEServer()

        {

            var client = new HttpClient();

            // 设置 SSE 专用的请求头

            client.DefaultRequestHeaders.Accept.Add(

                new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("text/event-stream")

            );


            try

            {

                // 建立连接

                using (var response = await client.GetAsync(

                    "http://localhost:8000/sse", // 你的 SSE 服务端地址

                    HttpCompletionOption.ResponseHeadersRead)) // 立即读取响应头,而不是等待整个响应体

                {

                    response.EnsureSuccessStatusCode();


                    using (var stream = await response.Content.ReadAsStreamAsync())

                    using (var reader = new System.IO.StreamReader(stream))

                    {

                        Console.WriteLine("已连接到 SSE 服务器,等待消息...");


                        // 持续监听消息

                        while (!reader.EndOfStream)

                        {

                            var line = await reader.ReadLineAsync();

                            if (string.IsNullOrWhiteSpace(line))

                                continue;


                            // 解析 SSE 格式的数据(格式:data: 消息内容\n\n)

                            if (line.StartsWith("data:"))

                            {

                                var data = line.Substring(5).Trim();

                                Console.WriteLine($"收到消息:{data}");

                            }

                        }

                    }

                }

            }

            catch (Exception ex)

            {

                Console.WriteLine($"连接异常: {ex.Message}");

            }

        }

    }

}


结合 MCP 的 SSE 调用示例

using System;

using System.Net.Http;

using System.Text;

using System.Threading.Tasks;

using System.Text.Json;


namespace McpSSEClient

{

    class Program

    {

        static async Task Main(string[] args)

        {

            await CallMcpViaSSE();

        }


        static async Task CallMcpViaSSE()

        {

            var client = new HttpClient();

            client.DefaultRequestHeaders.Accept.Add(

                new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("text/event-stream")

            );


            try

            {

                using (var response = await client.GetAsync("http://localhost:8000/sse", HttpCompletionOption.ResponseHeadersRead))

                {

                    response.EnsureSuccessStatusCode();


                    using (var stream = await response.Content.ReadAsStreamAsync())

                    using (var reader = new System.IO.StreamReader(stream))

                    {

                        Console.WriteLine("已连接到 MCP SSE 服务...");


                        while (!reader.EndOfStream)

                        {

                            var line = await reader.ReadLineAsync();

                            if (string.IsNullOrWhiteSpace(line) || !line.StartsWith("data:"))

                                continue;


                            var data = line.Substring(5).Trim();

                            Console.WriteLine($"收到 MCP 响应: {data}");


                            // 解析 JSON 数据

                            var result = JsonSerializer.Deserialize<McpResponse>(data);

                            Console.WriteLine($"工具调用结果: {result.Result}");

                        }

                    }

                }

            }

            catch (Exception ex)

            {

                Console.WriteLine($"Error: {ex.Message}");

            }

        }

    }


    // MCP 响应数据模型

    public class McpResponse

    {

        public string Result { get; set; }

        public string Status { get; set; }

    }

}


完整的 C# MCP + SSE 客户端(带自动重连)

using System;

using System.Net.Http;

using System.Threading.Tasks;

using System.Text.Json;


namespace McpSSEClient

{

    class Program

    {

        private static readonly HttpClient client = new HttpClient();

        private static string sseUrl = "http://localhost:8000/sse";


        static async Task Main(string[] args)

        {

            // 循环重连

            while (true)

            {

                try

                {

                    await ConnectAndListen();

                }

                catch (Exception ex)

                {

                    Console.WriteLine($"连接断开: {ex.Message},5 秒后重连...");

                    await Task.Delay(5000);

                }

            }

        }


        static async Task ConnectAndListen()

        {

            client.DefaultRequestHeaders.Accept.Add(

                new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("text/event-stream")

            );


            using (var response = await client.GetAsync(sseUrl, HttpCompletionOption.ResponseHeadersRead))

            {

                response.EnsureSuccessStatusCode();


                using (var stream = await response.Content.ReadAsStreamAsync())

                using (var reader = new System.IO.StreamReader(stream))

                {

                    Console.WriteLine($"已连接到 {sseUrl}");


                    while (!reader.EndOfStream)

                    {

                        var line = await reader.ReadLineAsync();

                        if (string.IsNullOrWhiteSpace(line))

                            continue;


                        if (line.StartsWith("data:"))

                        {

                            var data = line.Substring(5).Trim();

                            Console.WriteLine($"\n收到消息: {DateTime.Now:HH:mm:ss} -> {data}");


                            // 解析 MCP 响应

                            try

                            {

                                var result = JsonSerializer.Deserialize<McpResponse>(data);

                                Console.WriteLine($"工具调用结果: {result.Result}");

                                Console.WriteLine($"状态: {result.Status}");

                            }

                            catch

                            {

                                Console.WriteLine("无法解析响应数据");

                            }

                        }

                        else if (line.StartsWith("event:"))

                        {

                            var eventType = line.Substring(6).Trim();

                            Console.WriteLine($"事件类型: {eventType}");

                        }

                    }

                }

            }

        }

    }


    public class McpResponse

    {

        public string Result { get; set; }

        public string Status { get; set; }

        public string Tool { get; set; } // 调用的工具名称

    }

}




####【豆包】

Q:StreamableHTTP 方式部署的MCP 如何调用

A:

StreamableHTTP 是一种基于 HTTP 协议的流式通信方式,常用于需要服务器持续返回部分结果的场景(如大模型流式生成、实时数据处理等)。与 SSE 不同,StreamableHTTP 更灵活,通常使用 POST 方法 发送请求(支持复杂输入),并通过 分块传输编码(Chunked Transfer Encoding) 流式返回响应,允许客户端边接收边处理数据。


与 SSE 的区别:

StreamableHTTP 通常用 POST 方法,支持复杂请求体;SSE 用 GET 方法,参数通过 URL 传递。

StreamableHTTP 无固定消息格式,更灵活;SSE 严格遵循 text/event-stream 规范。

两者均基于 HTTP 分块传输,但适用场景不同(StreamableHTTP 更适合需要发送大量输入的流式场景)


调用原理

StreamableHTTP 的核心是 “一次 HTTP 请求,持续分块响应”:

1.客户端通过 HTTP POST 向 MCP 接口发送请求(包含完整输入数据,如 JSON 格式);

2.MCP 接收到请求后,立即返回 HTTP 200 响应,并通过 Transfer-Encoding: chunked 头部告知客户端将采用分块传输;

3.MCP 处理数据时,将中间结果按 “数据块” 持续写入响应流,每个块包含长度标识(十六进制)和数据内容;

4.客户端持续读取响应流中的分块数据,实时解析并处理(如拼接部分结果);

5.所有数据传输完成后,MCP 发送一个长度为 0 的块(0\r\n\r\n)标识结束,客户端关闭连接。


客户端

代码示例(不同场景)

1. 浏览器端调用(JavaScript,使用 Fetch API)

浏览器可通过 fetch 配合 ReadableStream 处理流式响应:

javascript

运行

async function callStreamableMCP(inputData) {

  try {

    const response = await fetch('http://localhost:8000/mcp/stream', {

      method: 'POST',

      headers: {

        'Content-Type': 'application/json',

      },

      body: JSON.stringify({  // 请求体携带完整输入

        action: 'stream_generate',

        input: inputData,

        max_tokens: 1000

      })

    });


    if (!response.ok) {

      throw new Error(`HTTP 错误: ${response.status}`);

    }


    // 获取响应流的读取器

    const reader = response.body.getReader();

    const decoder = new TextDecoder();  // 解码二进制流为文本

    let fullResult = '';  // 累积完整结果


    while (true) {

      // 读取一个数据块(done 表示结束,value 是 Uint8Array 类型的块内容)

      const { done, value } = await reader.read();

      if (done) break;


      // 解码当前块并处理

      const chunk = decoder.decode(value, { stream: true });  // stream: true 表示后续还有数据

      console.log('收到部分结果:', chunk);

      

      // 假设每个块是 JSON 片段(如 {"token": "hello"})

      try {

        const data = JSON.parse(chunk);

        fullResult += data.token;  // 拼接结果

        // 更新 UI 等操作(如实时显示)

      } catch (e) {

        console.warn('当前块解析失败,可能是不完整数据:', e);

      }

    }


    console.log('最终完整结果:', fullResult);

    return fullResult;


  } catch (error) {

    console.error('调用失败:', error);

  }

}


// 调用示例

callStreamableMCP("请生成一篇关于人工智能的短文");

2. 后端服务调用(Python,使用 requests 库)

Python 可通过 requests 库的 stream=True 处理流式响应:

python

运行

import requests

import json


def call_streamable_mcp(input_data):

    url = "http://localhost:8000/mcp/stream"

    headers = {

        "Content-Type": "application/json"

    }

    payload = {  # 请求体参数

        "action": "stream_generate",

        "input": input_data,

        "max_tokens": 1000

    }


    try:

        # 发送 POST 请求,stream=True 启用流式读取

        with requests.post(

            url,

            headers=headers,

            json=payload,

            stream=True,

            timeout=300  # 长超时(适应流式传输)

        ) as response:

            response.raise_for_status()  # 检查 HTTP 错误状态


            full_result = ""

            # 逐行/逐块读取响应(根据 MCP 输出格式选择)

            for chunk in response.iter_lines(decode_unicode=True):

                if chunk:  # 忽略空行

                    print(f"收到块: {chunk}")

                    # 解析块数据(假设为 JSON 格式)

                    try:

                        data = json.loads(chunk)

                        full_result += data.get("token", "")

                    except json.JSONDecodeError:

                        print(f"块解析失败: {chunk}")


            print(f"最终结果: {full_result}")

            return full_result


    except requests.exceptions.RequestException as e:

        print(f"请求异常: {e}")

        return None


# 调用示例

if __name__ == "__main__":

    call_streamable_mcp("请生成一篇关于人工智能的短文")

3. Java 调用示例(使用 OkHttp)

Java 可通过 OkHttp 处理分块传输的流式响应:

java

运行

import okhttp3.*;

import com.google.gson.Gson;

import java.io.IOException;

import java.nio.charset.StandardCharsets;


public class StreamableMcpClient {

    private static final OkHttpClient client = new OkHttpClient.Builder()

            .readTimeout(300, java.util.concurrent.TimeUnit.SECONDS)  // 长超时

            .build();

    private static final Gson gson = new Gson();

    private static final String MCP_URL = "http://localhost:8000/mcp/stream";


    public static void main(String[] args) {

        // 构造请求体

        RequestBody requestBody = RequestBody.create(

                MediaType.parse("application/json; charset=utf-8"),

                gson.toJson(new McpRequest(

                        "stream_generate",

                        "请生成一篇关于人工智能的短文",

                        1000

                ))

        );


        // 构建请求

        Request request = new Request.Builder()

                .url(MCP_URL)

                .post(requestBody)

                .build();


        // 发送请求并处理流式响应

        client.newCall(request).enqueue(new Callback() {

            @Override

            public void onResponse(Call call, Response response) throws IOException {

                if (!response.isSuccessful()) {

                    throw new IOException("请求失败: " + response);

                }


                ResponseBody body = response.body();

                if (body == null) {

                    throw new IOException("响应体为空");

                }


                // 读取分块数据(OkHttp 会自动处理 Chunked 编码)

                try (BufferedSource source = body.source()) {

                    StringBuilder fullResult = new StringBuilder();

                    while (!source.exhausted()) {

                        // 读取一行(假设每个块是一行 JSON)

                        String chunk = source.readUtf8Line();

                        if (chunk == null) break;


                        System.out.println("收到块: " + chunk);

                        // 解析块数据

                        McpResponse chunkData = gson.fromJson(chunk, McpResponse.class);

                        fullResult.append(chunkData.token);

                    }


                    System.out.println("最终结果: " + fullResult.toString());

                } finally {

                    response.close();

                }

            }


            @Override

            public void onFailure(Call call, IOException e) {

                System.err.println("调用失败: " + e.getMessage());

            }

        });

    }


    // 定义请求和响应的数据模型

    static class McpRequest {

        String action;

        String input;

        int max_tokens;


        public McpRequest(String action, String input, int max_tokens) {

            this.action = action;

            this.input = input;

            this.max_tokens = max_tokens;

        }

    }


    static class McpResponse {

        String token;  // 流式返回的部分结果

        boolean done;  // 是否结束的标志

    }

}


C#调用Streamable Http


using System;

using System.Net.Http;

using System.Threading.Tasks;


namespace StreamableClient

{

    class Program

    {

        static async Task Main(string[] args)

        {

            var client = new HttpClient();

            var requestContent = new StringContent("Hello Streamable HTTP");


            using var response = await client.PostAsync(

                "http://localhost:5000/stream/echo",

                requestContent,

                HttpCompletionOption.ResponseHeadersRead);


            using var stream = await response.Content.ReadAsStreamAsync();

            using var reader = new StreamReader(stream);


            while (!reader.EndOfStream)

            {

                var line = await reader.ReadLineAsync();

                Console.WriteLine(line);

            }

        }

    }

}


C#结合 MCP 的完整示例

using System;

using System.Net.Http;

using System.Threading.Tasks;

using System.Text.Json;


namespace McpStreamableClient

{

    class Program

    {

        static async Task Main(string[] args)

        {

            await CallMcpStreamableService();

        }


        static async Task CallMcpStreamableService()

        {

            var client = new HttpClient();


            // MCP 请求格式

            var requestData = new

            {

                jsonrpc = "2.0",

                id = "1",

                method = "call_tool",

                @params = new

                {

                    tool_name = "stream_echo",

                    arguments = new { message = "Hello MCP Streamable!", chunk_size = 2 }

                }

            };


            var requestContent = new StringContent(

                JsonSerializer.Serialize(requestData),

                Encoding.UTF8,

                "application/json"

            );


            try

            {

                using (var response = await client.PostAsync(

                    "http://localhost:8000/mcp",

                    requestContent,

                    HttpCompletionOption.ResponseHeadersRead))

                {

                    response.EnsureSuccessStatusCode();


                    using (var stream = await response.Content.ReadAsStreamAsync())

                    using (var reader = new StreamReader(stream))

                    {

                        Console.WriteLine("已连接到 MCP Streamable 服务...");


                        while (!reader.EndOfStream)

                        {

                            var line = await reader.ReadLineAsync();

                            if (!string.IsNullOrWhiteSpace(line))

                            {

                                Console.WriteLine($"收到: {line}");


                                // 解析 MCP 响应

                                try

                                {

                                    var result = JsonSerializer.Deserialize<McpStreamableResponse>(line);

                                    Console.WriteLine($"结果: {result.Result.Data}");

                                    Console.WriteLine($"状态: {result.Result.Status}");

                                }

                                catch (Exception ex)

                                {

                                    Console.WriteLine($"解析错误: {ex.Message}");

                                }

                            }

                        }

                    }

                }

            }

            catch (Exception ex)

            {

                Console.WriteLine($"请求失败: {ex.Message}");

            }

        }

    }


    // MCP Streamable 响应模型

    public class McpStreamableResponse

    {

        public string Jsonrpc { get; set; }

        public string Id { get; set; }

        public McpResult Result { get; set; }

    }


    public class McpResult

    {

        public string Data { get; set; }

        public string Status { get; set; }

        public string Tool { get; set; }

    }

}


服务端:

ASP.NET Core实现Streamable Http

using Microsoft.AspNetCore.Mvc;

using System.Text;

using System.Threading.Tasks;


namespace StreamableHttpServer.Controllers

{

    [ApiController]

    [Route("[controller]")]

    public class StreamController : ControllerBase

    {

        [HttpPost("echo")]

        public async Task EchoStream()

        {

            // 设置响应头

            Response.Headers.Add("Content-Type", "text/plain");

            Response.Headers.Add("Transfer-Encoding", "chunked");

//.NET4.5

// response.BufferOutput = false; // 禁用输出缓冲


            // 读取请求体

            using var reader = new StreamReader(Request.Body);

            var requestBody = await reader.ReadToEndAsync();


            // 模拟流式响应(分块发送)

            var chunks = requestBody.Split(' ');

            foreach (var chunk in chunks)

            {

                var data = Encoding.UTF8.GetBytes(chunk + Environment.NewLine);

                await Response.Body.WriteAsync(data);

               //.NET4.5

               //await  response.OutputStream.WriteAsync(data, 0, data.Length);

                await Response.Body.FlushAsync(); // 立即发送数据

                await Task.Delay(500); // 模拟延迟

            }

        }

    }

}


ASP.NET Core 结合 MCP 的 Streamable HTTP 服务

namespace StreamableHttpServer.Models

{

    public class McpRequest

    {

        public string Tool { get; set; }

        public object Params { get; set; }

    }

}

using Microsoft.AspNetCore.Mvc;

using StreamableHttpServer.Models;

using System.Text;

using System.Text.Json;

using System.Threading.Tasks;


namespace StreamableHttpServer.Controllers

{

    [ApiController]

    [Route("mcp")]

    public class McpController : ControllerBase

    {

        [HttpPost]

        public async Task McpStream()

        {

            // 设置响应头

            Response.Headers.Add("Content-Type", "application/json");

            Response.Headers.Add("Transfer-Encoding", "chunked");


            // 解析 MCP 请求

            var request = await JsonSerializer.DeserializeAsync<McpRequest>(Request.Body);


            // 根据工具名称处理请求

            switch (request.Tool)

            {

                case "stream_echo":

                    await HandleStreamEcho(request.Params);

                    break;

                // 其他工具...

            }

        }


        private async Task HandleStreamEcho(object paramObj)

        {

            // 解析参数

            var paramJson = JsonSerializer.Serialize(paramObj);

            var parameters = JsonSerializer.Deserialize<StreamEchoParams>(paramJson);


            // 流式响应

            var message = parameters.Message;

            var chunkSize = parameters.ChunkSize;


            for (int i = 0; i < message.Length; i += chunkSize)

            {

                var chunk = message.Substring(i, Math.Min(chunkSize, message.Length - i));

                var responseChunk = JsonSerializer.Serialize(new { Data = chunk, Status = "streaming" });

                

                var bytes = Encoding.UTF8.GetBytes(responseChunk + Environment.NewLine);

                await Response.Body.WriteAsync(bytes);

                await Response.Body.FlushAsync();

                

                await Task.Delay(300); // 模拟处理延迟

            }


            // 发送结束标志

            var endChunk = JsonSerializer.Serialize(new { Data = "", Status = "completed" });

            var endBytes = Encoding.UTF8.GetBytes(endChunk + Environment.NewLine);

            await Response.Body.WriteAsync(endBytes);

            await Response.Body.FlushAsync();

        }

    }


    public class StreamEchoParams

    {

        public string Message { get; set; }

        public int ChunkSize { get; set; }

    }

}



UVX NPX介绍

点击查看原文

UVX主要针对python编写的MCP, npx主要针对nodejs编写的MCP

直接使用UVX执行MCP命令(如uvx mcp-server-time)时,UVX会检查本地缓存或临时下载所需工具包。若MCP组件已存在于Python环境中,则直接调用;否则会触发下载安装过程

npx也会自动安装mcp

安装源

更换镜像源(国内用户常用)

npm config set registry https://registry.npmmirror.com/



mcp server大多使用python和typescript编写,对应的启动命令分别为uvx和npx,下面将分别具体介绍一下这两种指令。熟悉指令的基础知识,有利于我们安装和调试mcp server

示例1:

{

  "mcpServers": {

    "fetch": {

      "command": "uvx",

      "args": [

        "mcp-server-fetch"

      ]

    }

  }

}


示例2:

{

  "mcpServers": {

    "amap-maps": {

      "command": "npx",

      "args": [

        "-y",

        "@amap/amap-maps-mcp-server"

      ],

      "env": {

        "AMAP_MAPS_API_KEY": "api_key"

      }

    }

  }

}

uvx:UV运行Python包提供的命令。它是uv tool run的简写

UV是由Astral开发的新一代Python包和项目管理工具。使用Rust编写,速度比pip快10-100倍!它是一体化工具:整合包管理(替代pip)、虚拟环境管理(替代venv)、依赖锁定(替代pip-tools)、Python版本管理(替代pyenv)、脚本运行(替代pipx)等功能。


快速安装

UV的安装非常简单,有多种方式可供选择:

方法1:独立安装脚本



macOS/Linux:


curl -LsSf https://astral.sh/uv/install.sh | sh



Windows:


powershell -c "irm https://astral.sh/uv/install.ps1 | iex"



方法2:使用pip安装



pip install uv


方法

3:Homebrew安装(macOS) 



brew install uv


 安装完成后,你可以通过在命令行输入uv --version来验证是否安装成功。


1.3、uv基本用法

1.3.1、创建项目

使用UV创建一个新项目


uv init uv_demo


1.3.2、创建虚拟环境

我是在conda创建的虚拟环境中安装了uv,你可以继续使用uv创建应用的虚拟环境。


cd uv_demo

uv venv


1.3.3、安装依赖包

uv安装依赖包非常简单且迅速:


uv add numpy pandas


1.3.4、运行Python脚本

 使用UV运行Python脚本:


uv run main.py


1.3.5、依赖锁定

生成锁文件,确保项目依赖版本的一致性:


uv lock


 这会创建一个uv.lock文件,详细记录所有依赖的精确版本和来源。


1.4、高级功能


1.4.1、Python版本管理

UV可以管理多个Python版本:



# 安装特定Python版本


uv python install 3.10 3.11 3.12



# 创建特定Python版本的虚拟环境


uv venv --python 3.11




1.4.2、工具管理


像pipx一样,UV可以运行和安装Python工具



# 在临时环境中运行工具


uvx pycowsay 'Hello UV!'



# 安装工具


uv tool install ruff




1.4.3、单文件脚本支持


UV支持带有内联依赖元数据的单文件脚本:



# /// [uv]


# dependencies = ["requests"]


# ///



import requests


print(requests.get("https://astral.sh").status_code)


 

然后直接运行:



uv run example.py


 

UV会自动处理依赖并在隔离环境中运行脚本




1.4.4、pip兼容接口


UV提供了pip兼容的接口,可直接替代pip命令:



# 编译依赖


uv pip compile requirements.in --output-file requirements.txt



# 安装锁定依赖


uv pip sync requirements.txt


UV命令速查

1.png


2、npx


npx是npm包管理器自5.2.0版本起内置的工具,全称为“Node Package Execute”,核心功能是临时执行Node.js模块命令。它简化了命令行工具的调用流程,无需预先全局或本地安装依赖包即可直接运行特定命令,尤其适合一次性或实验性操作。



npm的核心操作是包的安装与管理(install、uninstall等),而npx专注于“按需执行”。npm负责持久化依赖管理,npx负责临时或一次性操作的轻量化执行。



主要优势包括:



临时安装可执行依赖包:无需全局安装,避免环境污染


自动执行依赖包命令:安装完成后自动运行


自动加载 node_modules 中的依赖:无需手动指定 $PATH


可执行特定版本的命令:便于测试不同版本

支持执行 

GitHub 代码仓库:扩展了使用场景


2.1、npx基本用法


2.1.1、执行本地依赖包命令


若项目中已安装某个包(如knex),可直接运行其命令:



npx knex migrate:latest



无需全局安装knex,也无需手动配置package.json的scripts


2.1.2、临时安装并运行包


运行未安装的包(执行后自动删除):



npx create-react-app my-app  # 临时安装 create-react-app 并执行




2.1.3、指定版本运行


运行特定版本的包:



npx eslint@7.0.0 --version  # 使用 7.0.0 版本的 ESLint




2.1.4、执行远程代码

 

直接运行GitHub仓库中的代码:



npx https://gist.github.com/user/test  # 执行远程脚本




2.1.5、交互式命令模式


 进入包的交互式环境(如node REPL):



npx node@14  # 临时使用 Node.js 14 版本


 


2.2、npx使用示例


传统方式:先全局安装脚手架工具,再使用



# 安装


npm install fast-create-app -g


# 使用


fast-create-app create-app test



传统方式的缺点:



全局污染:全局安装的包会影响整个系统环境


版本冲突:不同项目可能需要同一工具的不同版本


权限问题:全局安装通常需要管理员权限


更新困难:全局包不会随项目依赖自动更新


存储占用:长期积累大量不再使用的全局包



npx 方式:一步到位,无需全局安装



npx fast-create-app create-app test



npx 的优势:

按需临时安装,用完即删

自动使用最新版本的包

可同时使用不同版本的工具

不需要额外的管理员权限


npx执行优先级机制


当执行命令时,npx遵循三级查找逻辑



1、本地项目依赖:优先在当前项目的node_modules/.bin目录中查找目标命令,适配项目级工具调用(如项目内配置的ESLint、Jest等)。



2、全局安装包:若本地未找到,检查用户全局安装的npm包(通过npm install -g安装的模块)。



3、临时下载执行:若前两步均未找到,npx会自动从npm仓库下载目标包到临时目录,执行完成后立即清理,避免磁盘空间浪费。



MCP协议详细讲解

Model Context Protocol(MCP)是由 Anthropic 推出的一种开源协议,旨在建立 AI 模型与开发环境之间的统一上下文交互标准。以下是对其的详细讲解:

1.png

背景与起源

在 AI 领域,大语言模型的应用常常面临数据孤岛和工具集成复杂的问题,不同的数据源和工具都有自己独特的 API 和集成方式,导致开发者需要为每个工具单独编写集成代码,开发和维护成本高,工具复用性低。为解决这些问题,Anthropic 于 2024 年 11 月 25 日开源发布了 MCP。

核心概念

  • MCP Hosts :如 Claude Desktop、Cursor、 Cline、trae、Cherry Studio、IDE、AI 应用等,是运行 MCP 的主应用程序,负责发起连接并管理多个客户端实例,与用户进行交互并接收用户的问题或指令,再通过 MCP Clients 向 MCP Servers 发送请求以获取所需的数据或执行相应的操作。
  • MCP Clients :由 Host 创建,与特定的 MCP Server 建立一对一的连接,负责协议通信和能力协商,充当 MCP Host 和 MCP Server 之间的“连接器”或“总机”,将 Host 的请求转发给 Server,并将 Server 的响应返回给 Host。
  • MCP Servers :轻量级程序,通过标准化的模型上下文协议暴露特定功能,如文件读取、API 调用、数据库查询等,为 MCP Host 提供实际的数据和功能支持,每个 Server 提供一个特定的工具或能力。

工作原理

  • 通信机制 :MCP 采用客户端 - 服务器架构,基于 JSON-RPC 2.0 消息格式,支持请求、响应和通知三种消息类型,确保通信的标准化和一致性。它主要支持两种通信方式,一种是标准输入输出(Stdio),适用于在同一台机器上运行的客户端和服务器之间的通信,客户端启动服务器程序作为子进程,消息通讯通过 stdin/stdout 进行;另一种是服务器发送事件(SSE),利用 HTTP 协议实现跨网络的实时数据传输,适用于需要访问远程资源的场景。
  • 工作流程 :首先,Host 初始化 Client,Client 尝试与 Server 建立连接,并询问 Server 有哪些能力,Server 回应并返回所有支持的功能,从而建立 1:1 的连接。当用户与 LLM 交互提出问题或指令时,LLM 会告诉 Client 需要调用哪些 Tools,Client 收到 Host 的请求后,将请求信息发送给对应的 Server,Server 接收到信息后开始处理,处理完成后返回结果给 Client,Client 再将信息返回给 Host,Host 根据这些信息生成最终的回复返回给用户。

主要功能与特性

  • 统一接口 :提供标准化的 API 接口,简化 AI 与各类上下文信息的交互,使得开发者无需为不同的数据源或工具编写复杂的适配代码,降低了开发难度和成本。
  • 无缝集成 :能够轻松集成到现有开发工作流程中,无需对现有的系统和工具进行大规模的改造,即可实现 AI 模型与各种数据源和工具的快速连接和集成,提高了开发效率。
  • 多源数据支持 :支持从多种来源获取上下文信息,包括代码仓库、文档、文件系统、数据库、远程 API 等,丰富了 AI 模型可以利用的数据资源,为模型的训练和推理提供了更全面、准确的上下文信息。
  • 智能上下文管理 :优化上下文信息的传递,根据 AI 模型的需求和任务场景,自动筛选、组织和更新上下文信息,提高 AI 模型理解和生成的质量,使模型能够更准确地理解和处理复杂的任务。
  • 扩展性设计 :具有灵活的架构,允许添加新的数据源和功能,开发者可以根据实际需求自由扩展 MCP 的功能,不断增加新的 MCP Servers 来提供新的工具和能力,以满足不断变化的业务需求。

应用场景

  • 智能开发环境 :将 AI 模型与开发工具集成,如代码编辑器、IDE 等,使 AI 能够实时理解代码上下文,为开发者提供智能代码补全、代码生成、代码解释等功能,提高开发效率和代码质量。
  • 智能办公助手 :连接办公软件和在线服务,如日历、邮件、文档管理系统等,帮助用户自动完成日常办公任务,如安排会议、发送邮件、生成报告等,提升办公自动化水平。
  • 智能数据分析 :将 AI 模型与数据分析工具和数据源集成,如数据库、数据仓库、BI 工具等,使 AI 能够协助分析师进行数据查询、数据分析、数据可视化等工作,为决策提供更有力的支持。
  • 智能客服系统 :集成企业内部的客户信息管理系统、订单管理系统等,使 AI 客服能够快速准确地获取客户相关的信息,为客户提供更精准、高效的咨询服务,提高客户满意度


JSON-RPC 2.0 的请求和响应示例

请求示例

{

  "jsonrpc": "2.0",

  "method": "add",

  "params": [2, 3],

  "id": 1

}

响应示例

{

  "jsonrpc": "2.0",

  "result": 5,

  "id": 1

}

错误响应示例

{

  "jsonrpc": "2.0",

  "error": {

    "code": -32601,

    "message": "Method not found"

  },

  "id": 1

}


批量请求示例

[

  {

    "jsonrpc": "2.0",

    "method": "add",

    "params": [2, 3],

    "id": 1

  },

  {

    "jsonrpc": "2.0",

    "method": "subtract",

    "params": [5, 2],

    "id": 2

  }

]

批量响应示例

[

  {

    "jsonrpc": "2.0",

    "result": 5,

    "id": 1

  },

  {

    "jsonrpc": "2.0",

    "result": 3,

    "id": 2

  }

]

这些示例展示了 JSON-RPC 2.0 请求和响应的基本格式,包括请求、响应以及错误处理等场景。



AI 模型调用 MCP 服务的过程

准备工作

  • 搭建 MCP 服务器 :开发者需先搭建 MCP 服务器,可使用 Anthropic 提供的开源框架如 FastMCP 等。定义好服务器的基本配置,如名称、版本等,并通过装饰器注册工具函数,每个工具函数对应一个具体的功能,如查询天气、发送邮件等。
  • 集成 MCP 客户端 :在 AI 模型所在的系统或应用中集成 MCP 客户端,如在 Python 项目中安装相应的客户端库等。

调用过程

  1. 用户发起请求 :用户通过与 AI 模型交互的方式,如在聊天界面输入问题或指令,表达其想要实现的需求。
  2. AI 模型解析意图 :MCP 客户端将用户请求发送给 AI 模型,AI 模型对用户输入的自然语言进行理解和解析,确定用户的需求,并选择与之匹配的 MCP 函数及相应的参数。
  3. 发送调用请求 :MCP 客户端根据 AI 模型返回的函数调用信息,向 MCP 服务器发送请求。请求中包含请求 ID、函数名称及参数等,格式通常为 JSON。
  4. 执行服务并返回结果 :MCP 服务器接收到请求后,执行对应的工具函数,在本地或通过调用其他外部服务完成具体的任务处理,然后将执行结果按照规定的格式返回给 MCP 客户端。
  5. 结果整合与反馈 :MCP 客户端将 MCP 服务器返回的结果整合到对话上下文中,再次发送给 AI 模型。AI 模型根据整合后的上下文生成自然语言的回复,由 MCP 客户端将最终结果呈现给用户。

通信机制

  • STDIO 方式 :适用于本地服务。MCP 客户端启动 MCP 服务器程序作为子进程,通过 stdin 和 stdout 进行消息传递,消息格式遵循 JSON-RPC 2.0。
  • SSE 方式 :用于远程服务。MCP 客户端通过 Server-Sent Events 与 MCP 服务器进行通信,服务器定义特定接口用于推送和接收数据,消息格式同样基于 JSON-RPC 2.0。

动态上下文管理

MCP 协议具有动态上下文管理机制,通过上下文窗口存储用户偏好、会话记录和环境数据等。在每次交互过程中,上下文会不断扩展和更新,同时对非关键信息进行压缩,以保证对话的连贯性和减少资源消耗。

安全与认证机制

  • API 密钥验证 :MCP 服务通常会要求进行 API 密钥验证,只有拥有正确 API 密钥的客户端才能访问服务。
  • HTTPS 加密 :采用 HTTPS 协议对数据传输进行加密,确保数据在网络传输过程中的安全性。
  • 请求限制 :设置请求频率限制和配额限制等,防止服务被滥用,保护服务的稳定性和可靠性



AI 模型调用 MCP 服务的代码示例

基于 Python 的简单 MCP 服务端:

Python

pip install mcp

/*

from mcp.server.fastmcp import FastMCP

import tools


mcp=FastMCP("host info mcp")

mcp.add_tool(tools.get_host_info)


def main()->none:

   print("hello from ai-mcp!")

   mcp.run("stdio")#还有sse

   mcp.run(transport="sse", port=9000)

   


if __name__=="__main__":

   main()


tools.py内容

def get_hosts_info()->str:

...



*/


from mcp import MCP, tool


mcp = MCP()


@mcp.register_tool

class WeatherTool:

    @tool(name="get_weather", description="获取指定城市的天气信息")

    def get_weather(self, city: str):

        # 这里可以添加获取天气信息的逻辑,比如调用天气 API 等

        return f"The weather in {city} is sunny."


    @tool(name="get_weather_forecast", description="获取指定城市未来几天的天气预报")

    def get_weather_forecast(self, city: str, days: int):

        # 添加获取天气预报的逻辑

        return f"The weather forecast for {city} in the next {days} days."


if __name__ == "__main__":

    mcp.start()

基于 Java 的 MCP 服务端:

java

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.core.io.ClassPathResource;

import org.springframework.core.io.Resource;

import org.springframework.util.StringUtils;

import org.springframework.web.reactive.function.server.RouterFunctions;

import org.springframework.web.reactive.function.server.ServerResponse;

import reactor.core.publisher.Mono;


import java.util.Collections;

import java.util.Map;


@Configuration

public class MCPConfig {


    @Bean

    public RouterFunctions.Route mcpRoute() {

        return RouterFunctions.route()

                .POST("/mcp/weather", this::getWeather)

                .build();

    }


    private Mono<ServerResponse> getWeather(ServerRequest request) {

        Map<String, String> queryParams = request.queryParams();

        String city = queryParams.get("city");

        if (StringUtils.hasText(city)) {

            String weatherInfo = "The weather in " + city + " is sunny.";

            return ServerResponse.ok().bodyValue(Collections.singletonMap("weather", weatherInfo));

        } else {

            return ServerResponse.badRequest().bodyValue(Collections.singletonMap("error", "City parameter is required"));

        }

    }

}

AI 模型调用 MCP 服务的代码示例

基于 Python 的 OpenAI 模型调用 MCP 服务:

Python

import openai

import requests

from mcp import MCPClient


# 初始化 MCP 客户端

mcp_client = MCPClient()

mcp_client.connect("http://localhost:8080/mcp")  # 替换为 MCP 服务的实际地址


# 调用 MCP 服务中的工具

def call_mcp_tool(tool_name, **kwargs):

    return mcp_client.call_tool(tool_name, **kwargs)


# 使用 OpenAI 模型

openai.api_key = "your_openai_api_key"  # 替换为你的 OpenAI API 密钥


def get_ai_response(user_query):

    # 构建消息列表

    messages = [

        {"role": "system", "content": "You are a helpful assistant."},

        {"role": "user", "content": user_query}

    ]


    # 调用 OpenAI API

    response = openai.ChatCompletion.create(

        model="gpt-4-turbo-preview",

        messages=messages,

        tools=mcp_client.list_tools(),  # 提供可用的 MCP 工具

        tool_choice="auto"

    )


    # 处理模型返回的结果

    ai_response = ""

    for choice in response.choices:

        message = choice.message

        if message.content:

            ai_response += message.content + "\n"

        if message.tool_calls:

            for tool_call in message.tool_calls:

                tool_name = tool_call.function.name

                tool_args = tool_call.function.arguments

                # 调用 MCP 工具

                tool_result = call_mcp_tool(tool_name, **tool_args)

                ai_response += f"Calling tool {tool_name} with args {tool_args}\n"

                ai_response += tool_result + "\n"

                # 将工具结果添加到消息中,继续与模型对话

                messages.append({"role": "assistant", "content": "", "tool_calls": [tool_call]})

                messages.append({"role": "tool", "tool_call_id": tool_call.id, "content": tool_result})

                # 获取下一个模型响应

                next_response = openai.ChatCompletion.create(

                    model="gpt-4-turbo-preview",

                    messages=messages,

                    tools=mcp_client.list_tools(),

                    tool_choice="auto"

                )

                if next_response.choices[0].message.content:

                    ai_response += next_response.choices[0].message.content + "\n"

    return ai_response


# 示例 usage

user_input = "What's the weather like in Beijing?"

print(get_ai_response(user_input))

基于 Java 的 Spring AI 模型调用 MCP 服务:

java

import org.springframework.ai.chat.client.ChatClient;

import org.springframework.ai.chat.client.ChatClientBuilder;

import org.springframework.ai.mcp.client.McpClient;

import org.springframework.ai.mcp.client.McpClientBuilder;

import org.springframework.ai.mcp.client.McpFunctionCallback;

import org.springframework.ai.tool.ToolCallbackProvider;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;


import java.util.List;


@Configuration

public class AIConfig {


    @Bean

    public McpClient mcpClient() {

        // 配置 MCP 服务器参数

        var stdioParams = ServerParameters.builder("java")

                .args("-Dspring.ai.mcp.server.stdio=true",

                        "-Dspring.main.web-application-type=none",

                        "-Dlogging.pattern.console=",

                        "-jar",

                        "target/mcp-server-0.0.1-SNAPSHOT.jar")

                .build();

        // 创建 MCP 客户端

        return McpClient.sync(new StdioClientTransport(stdioParams));

    }


    @Bean

    public ToolCallbackProvider mcpTools(McpClient mcpClient) {

        // 获取 MCP 服务器中的工具列表并转换为 Function Callback

        return mcpClient.listTools(null)

                .tools()

                .stream()

                .map(tool -> new McpFunctionCallback(mcpClient, tool))

                .toList();

    }


    @Bean

    public ChatClient chatClient(ChatClientBuilder chatClientBuilder, ToolCallbackProvider mcpTools) {

        // 初始化聊天客户端并设置默认工具

        return chatClientBuilder.defaultFunctions(mcpTools).build();

    }

}


// 使用示例

public class AIService {

    private final ChatClient chatClient;


    public AIService(ChatClient chatClient) {

        this.chatClient = chatClient;

    }


    public String generateResponse(String userQuery) {

        return chatClient

                .prompt(userQuery)

                .call()

                .content();

    }

}


使用 ASP.NET Core 来创建一个 Web API 服务,并模拟天气查询功能。

C# MCP 服务端代码示例

csharp

using Microsoft.AspNetCore.Builder;

using Microsoft.AspNetCore.Hosting;

using Microsoft.AspNetCore.Mvc;

using Microsoft.Extensions.DependencyInjection;

using Microsoft.Extensions.Hosting;


namespace MCPService

{

    public class Startup

    {

        public void ConfigureServices(IServiceCollection services)

        {

            services.AddControllers();

        }


        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

        {

            if (env.IsDevelopment())

            {

                app.UseDeveloperExceptionPage();

            }


            app.UseRouting();


            app.UseEndpoints(endpoints =>

            {

                endpoints.MapControllers();

            });

        }

    }

    /*

这段代码定义了一个名为WeatherController的控制器类。这个类继承自ControllerBase

,并使用了[ApiController]和[Route("mcp")]特性,表明这是用于处理HTTP请求的API控制器,并指定了其基础路由为/mcp。

在控制器类中,定义了一个名为GetWeather的方法,该方法使用了[HttpGet("weather")]特性。这表明这是一个处理HTTP GET请求的方法,其对应的路由是mcp/weather。这个方法接受一个名为city的参数,通过[FromQuery]特性从查询字符串中获取。

当客户端向/mcp/weather发起一个带有查询参数(如city=Paris)的GET请求时,GetWeather方法会处理这个请求,并返回一个IActionResult类型的对象,即一个包含响应内容和状态码的对象。在实际应用中,这个方法可能会根据提供的城市名称来获取和返回相应的天气信息。

*/

    [ApiController]

    [Route("mcp")]

    public class WeatherController : ControllerBase

    {

        [HttpGet("weather")]

        public IActionResult GetWeather([FromQuery] string city)

        {

            if (string.IsNullOrEmpty(city))

            {

                return BadRequest("City parameter is required");

            }


            // 模拟天气查询逻辑

            var weatherInfo = $"The weather in {city} is sunny.";


            return Ok(new { weather = weatherInfo });

        }


        [HttpGet("weather-forecast")]

        public IActionResult GetWeatherForecast([FromQuery] string city, [FromQuery] int days)

        {

            if (string.IsNullOrEmpty(city))

            {

                return BadRequest("City parameter is required");

            }


            // 模拟天气预报逻辑

            var weatherForecast = $"The weather forecast for {city} in the next {days} days.";


            return Ok(new { forecast = weatherForecast });

        }

   

[HttpPost("weather")]

    public IActionResult PostWeather([FromBody] WeatherRequest weatherRequest)

    {

        // 处理POST请求的逻辑

        return Ok($"Received weather data for {weatherRequest.City}: {weatherRequest.Temperature}°C");

    }


// 新增的可以GET和POST调用的方法

    [HttpGet("data")]

    [HttpPost("data")]

    public IActionResult GetAndPostData([FromQuery] string name, [FromBody] string postData = null)

    {

        if (HttpContext.Request.Method == HttpMethods.Get)

        {

            return Ok($"Received GET request with name: {name}");

        }

        else if (HttpContext.Request.Method == HttpMethods.Post)

 {

                   return Ok($"Received POST request with name: {name} and post data: {postData}");

        }


        return BadRequest("Invalid request method");

    }



}


public class WeatherRequest

{

    public string City { get; set; }

    public double Temperature { get; set; }

}



    public class Program

    {

        public static void Main(string[] args)

        {

            var host = CreateHostBuilder(args).Build();

            host.Run();

        }


        public static IHostBuilder CreateHostBuilder(string[] args) =>

            Host.CreateDefaultBuilder(args)

                .ConfigureWebHostDefaults(webBuilder =>

                {

                    webBuilder.UseStartup<Startup>();

                });

    }

}

说明

项目结构:

Startup 类配置了服务和中间件。

WeatherController 是一个 ASP.NET Core 控制器,提供了两个端点 /mcp/weather 和 /mcp/weather-forecast。

功能:

/mcp/weather 接受一个 city 参数,返回该城市的天气信息。

/mcp/weather-forecast 接受 city 和 days 参数,返回该城市未来几天的天气预报。

运行服务:

创建一个 ASP.NET Core 项目并复制上述代码。

使用 dotnet run 命令启动服务,服务默认运行在 https://localhost:5001 和 http://localhost:5000。

测试服务:

使用工具如 Postman 或 curl 测试 API:

获取天气信息:GET http://localhost:5000/mcp/weather?city=Beijing

获取天气预报:GET http://localhost:5000/mcp/weather-forecast?city=Beijing&days=3


C# 用OpenAI模型调用

public class WeatherRequestFunction : IRequestFunction

{

    public string Name => "weather";


    public async Task<IDictionary<string, object>> InvokeAsync(IDictionary<string, object> parameters)

    {

        using var httpClient = new HttpClient();

        var city = parameters["city"].ToString();

        var response = await httpClient.GetAsync($"http://localhost:5000/mcp/weather?city={city}");

        response.EnsureSuccessStatusCode();

        var content = await response.Content.ReadAsStringAsync();

        return new Dictionary<string, object> { { "result", content } };

    }


    public string Serialize(IRequestFunction function)

    {

        return $"Calling tool {function.Name} with parameters {function}";

    }


    public Task SerializeAsync(IRequestFunction function)

    {

        // 实现序列化逻辑

        return Task.CompletedTask;

    }

}

代码说明

OpenAI 客户端:创建 OpenAI 客户端实例,并配置 API 密钥和日志记录器。

MCP 工具:定义一个 WeatherRequestFunction 类实现 IRequestFunction 接口,用于调用 MCP 服务中的天气查询工具。

ChatClient:创建 ChatClient 实例,传入 OpenAI 客户端和日志记录器。

聊天历史:初始化聊天历史记录。

交互式聊天:在循环中读取用户输入,将其添加到聊天历史中,并调用 OpenAI API 获取响应。打印助手的响应并将其添加到聊天历史中。

其他信息

确保你的 MCP 服务正在运行,并且可以通过 http://localhost:5000/mcp/weather 访问。

替换成您的实际 OpenAI API 密钥。

如果您没有 MCP 服务,可以参考前面的示例代码实现一个简单的 MCP 服务。



C# 编写 Agent 调用 ollama 及 MCP 的方法

调用 ollama

安装 Ollama SDK :可以使用如下命令安装 Ollama 的 C# SDK,“dotnet add package Ollama --version 1.9.0”。

简单对话 :设置模型名称和 ollama 的 API 地址,利用 OllamaApiClient 进行对话生成,示例代码如下:

**```csharp

string modelName = "qwen2:7b";

using var ollama = new OllamaApiClient(baseUri: new Uri("http://127.0.0.1:11434/api"));

Console.WriteLine("开始对话!!!");

string userInput = "";

do

{

Console.WriteLine("User:");

userInput = Console.ReadLine()!;

var enumerable = ollama.Completions.GenerateCompletionAsync(modelName, userInput);

Console.WriteLine("Agent:");

await foreach (var response in enumerable)

{

Console.Write($"{response.Response}");

}

Console.WriteLine();

} while (!string.Equals(userInput, "exit", StringComparison.OrdinalIgnoreCase));

Console.WriteLine("对话结束!!!");



**[^2^]


  * **多轮对话** :使用 Chat 对象进行分角色的多轮对话,通过 List 消息存储之前的对话记录,以便模型捕获上下文,代码示例:

**```csharp

string modelName = "glm4:9b";

using var ollama = new OllamaApiClient(baseUri: new Uri("http://127.0.0.1:11434/api"));

Console.WriteLine("开始对话!!!");

string userInput = "";

List messages = [];

do

{

    messages = messages.TakeLast(5).ToList();

    Console.WriteLine("User:");

    userInput = Console.ReadLine()!;

    messages.Add(new Message(MessageRole.User, userInput));

    var enumerable = ollama.Chat.GenerateChatCompletionAsync(modelName, messages, stream: true);

    Console.WriteLine("Agent:");

    StringBuilder builder = new();

    await foreach (var response in enumerable)

    {

        string content = response.Message.Content;

        builder.AppendLine(content);

        Console.Write(content);

    }

    messages.Add(new Message(MessageRole.Assistant, builder.ToString()));

    Console.WriteLine();

} while (!string.Equals(userInput, "exit", StringComparison.OrdinalIgnoreCase));

Console.WriteLine("对话结束!!!");



```**[^2^]


  * **Function call** :若要使用 function call 功能,需设置 autoCallTools 为 true,并给 Ollama 注册相应的工具类,代码如下:

**```csharp

string modelName = "llama3.1:8b";

using var ollama = new OllamaApiClient(baseUri: new Uri("http://127.0.0.1:11434/api"));

var chat = ollama.Chat(

    model: modelName,

    systemMessage: "You are a helpful assistant.",

    autoCallTools: true);

var mathService = new MathService();

chat.AddToolService(mathService.AsTools(), mathService.AsCalls());

while (true)

{

    try

    {

        Console.WriteLine("User>");

        var newMessage = Console.ReadLine();

        var msg = await chat.SendAsync(newMessage);

        Console.WriteLine("Agent> " + msg.Content);

    }

    finally

    {

        Console.WriteLine(chat.PrintMessages());

    }

}

```**[^2^]


### 调用 MCP

目前未查到有成熟的 C# 调用 MCP 的官方 SDK 或常用库,但可以尝试以下思路:

  * **通过 HTTP 请求调用** :如果 MCP 提供了 HTTP API 接口,可以使用 C# 中的 HttpClient 类来发送 HTTP 请求进行调用。基本步骤如下:

    1. 创建 HttpClient 对象,并设置相关请求头等信息。

    2. 构造请求内容,根据 MCP API 的要求,将请求参数进行序列化。

    3. 发送 POST 或 GET 等请求到 MCP 的 API 地址。

    4. 处理返回的响应,对响应内容进行反序列化等操作,获取所需数据。


例如,假设 MCP 的 API 地址为<http://localhost:8000/mcp/api>,需要发送一个获取数据的请求,代码可能如下:

**```csharp

using (var client = new HttpClient())

{

    client.BaseAddress = new Uri("http://localhost:8000/");

    var response = await client.GetAsync("mcp/api?param1=value1");

    if (response.IsSuccessStatusCode)

    {

        var result = await response.Content.ReadAsStringAsync();

        // 处理结果

    }

    else

    {

        // 处理错误

    }

}

```**

  * **参考 Python 实现进行移植** :上述提到的 Python 调用 MCP 的代码示例中,展示了如何创建 MCP Server、获取工具列表以及创建 Agent 等过程。可以参考其逻辑和交互方式,在 C# 中进行相应的实现。例如,对于 MCP Server 的连接,可以考虑在 C# 中使用类似的网络通信方式;对于工具的调用,可以解析 MCP 返回的工具信息,并根据用户输入的问题,选择合适的工具进行调用等[^4^]。


MathService代码:

using System;

using System.Collections.Generic;

using System.Linq;


// 定义工具接口

public interface IToolsService

{

    public string Name { get; }

    public List<ToolDefinition> DefineTools();

}


// 定义工具函数

public class MathService : IToolsService

{

    public string Name => "math";

    

    // 定义工具

    public List<ToolDefinition> DefineTools()

    {

        return new List<ToolDefinition>

        {

            new ToolDefinition("add", "Add two numbers", "a: number, b: number", Add),

            new ToolDefinition("subtract", "Subtract two numbers", "a: number, b: number", Subtract),

            new ToolDefinition("multiply", "Multiply two numbers", "a: number, b: number", Multiply),

            new ToolDefinition("divide", "Divide two numbers", "a: number, b: number", Divide)

        };

    }


    // 加法

    public double Add(double a, double b)

    {

        return a + b;

    }


    // 减法

    public double Subtract(double a, double b)

    {

        return a - b;

    }


    // 乘法

    public double Multiply(double a, double b)

    {

        return a * b;

    }


    // 除法

    public double Divide(double a, double b)

    {

        if (b == 0)

        {

            throw new DivideByZeroException("Division by zero is not allowed.");

        }

        return a / b;

    }

}


ToolDefinition类通常不是.NET标准库或框架的一部分,也不是Ollama或其他主流库的内置类。因此,您需要自己定义它,或者参考您所使用的特定库或框架的实现

using System;


public class ToolDefinition

{

    // 工具名称

    public string Name { get; set; }

    // 工具描述

    public string Description { get; set; }

    // 工具参数列表

    public string Parameters { get; set; }

    // 工具处理函数的委托类型

    public Func<object[], object> Function { get; set; }


    public ToolDefinition(string name, string description, string parameters, Func<object[], object> function)

    {

        Name = name;

        Description = description;

        Parameters = parameters;

        Function = function;

    }

}



Chrome MCP Server

点击进入源码页

知乎教程查看

Chrome MCP Server 是一个基于chrome插件的 模型上下文协议 (MCP) 服务器,它将您的 Chrome 浏览器功能暴露给 Claude 等 AI 助手,实现复杂的浏览器自动化、内容分析和语义搜索等。与传统的浏览器自动化工具(如playwright)不同,Chrome MCP server直接使用您日常使用的chrome浏览器,基于现有的用户习惯和配置、登录态,让各种大模型或者各种chatbot都可以接管你的浏览器,真正成为你的如常助手


环境要求

Node.js >= 18.19.0 和 (npm 或 pnpm)

Chrome/Chromium 浏览器

安装pnpm :npm install -g pnpm

安装步骤

1.从github上下载最新的chrome扩展

下载地址:https://github.com/hangwin/mcp-chrome/releases


一、全局安装mcp-chrome-bridge

npm

npm install -g mcp-chrome-bridge


或pnpm

# 方法1:全局启用脚本(推荐)

pnpm config set enable-pre-post-scripts true

pnpm install -g mcp-chrome-bridge


# 方法2:如果 postinstall 没有运行,手动注册

pnpm install -g mcp-chrome-bridge

mcp-chrome-bridge register

注意:pnpm v7+ 默认禁用 postinstall 脚本以提高安全性。enable-pre-post-scripts 设置控制是否运行 pre/post 安装脚本。如果自动注册失败,请使用上述手动注册命令。


二、验证安装

npm list -g mcp-chrome-bridge


三、注册 Native Messaging host

mcp-chrome-bridge register

看到 "Successfully registered user-level Native Messaging host!" 表示注册成功


四、启动 mcp-chrome-bridge 服务

执行以下命令启动服务:

node C:\Users\<你的用户名>\AppData\Roaming\npm\node_modules\mcp-chrome-bridge\dist\index.js

服务启动后,命令行可能没有详细输出,但可以通过任务管理器确认 node.exe 进程是否运行


3.加载 Chrome 扩展

1.jpg

打开 Chrome 并访问 chrome://extensions/

启用"开发者模式"

点击"加载已解压的扩展程序",选择 your/dowloaded/extension/folder

点击插件图标打开插件,点击连接即可看到mcp的配置


在支持MCP协议的客户端中使用

使用streamable http的方式连接(👍🏻推荐)

将以下配置添加到客户端的 MCP 配置中以cherryStudio为例:


推荐用streamable http的连接方式


{

  "mcpServers": {

    "chrome-mcp-server": {

      "type": "streamableHttp",

      "url": "http://127.0.0.1:12306/mcp"

    }

  }

}

使用stdio的方式连接(备选)

假设你的客户端仅支持stdio的连接方式,那么请使用下面的方法:


1.先查看你刚刚安装的npm包的安装位置

# npm 查看方式

npm list -g mcp-chrome-bridge

# pnpm 查看方式

pnpm list -g mcp-chrome-bridge

假设上面的命令输出的路径是:/Users/xxx/Library/pnpm/global/5 那么你的最终路径就是:/Users/xxx/Library/pnpm/global/5/node_modules/mcp-chrome-bridge/dist/mcp/mcp-server-stdio.js


2.把下面的配置替换成你刚刚得到的最终路径

{

  "mcpServers": {

    "chrome-mcp-stdio": {

      "command": "npx",

      "args": [

        "node",

        "/Users/xxx/Library/pnpm/global/5/node_modules/mcp-chrome-bridge/dist/mcp/mcp-server-stdio.js"

      ]

    }

  }

}




mcp2mqtt动动嘴就可以控制智能家居

点击进入开源地址

本项目通过将 MCP 协议转换为 MQTT 协议,我们能够利用强大的大型语言模型(LLMs),就能轻松操控您的智能家居、机器人或其他硬件设备。



excel-mcp-server使用 AI 代理创建、读取和修改 Excel 工作簿

点击查看源码

模型上下文协议 (MCP) 服务器,无需安装 Microsoft Excel 即可作 Excel 文件。使用 AI 代理创建、读取和修改 Excel 工作簿。

Excel 作 :创建、读取、更新工作簿和工作表

数据作 :公式、格式、图表、数据透视表和 Excel 表格

数据验证 :内置范围、公式和数据完整性验证

格式: 字体样式、颜色、边框、对齐方式和条件格式

表格作 :使用自定义样式创建和管理 Excel 表格

图表创建 :生成各种图表类型(折线图、条形图、饼图、散点图等)

数据透视表 :创建用于数据分析的动态数据透视表

工作表管理 :轻松复制、重命名、删除工作表

三重传输支持 :stdio、SSE(已弃用)和可流式传输的 HTTP

远程和本地 :既可以在本地工作,也可以作为远程服务工作



Trae+Chrome MCP Server 让AI接管你的浏览器

点击查看原文

一、安装与配置

环境准备

Node.js ≥ 18.19.0 + npm

Chrome/Chromium 浏览器

快速部署和使用

1、安装Chrome扩展插件

        从 GitHub Releases 下载最新扩展包,在 chrome://extensions 中启用开发者模式并加载解压的文件夹。


2、安装桥接工具

npm install -g mcp-chrome-bridge

AI写代码

    若自动注册失败,需手动执行 mcp-chrome-bridge register。


3、打开Chrome浏览器,点击扩展程序进入配置页

1.png


4、点击连接

1.png


5、打开Trae客户端,进入MCP管理页

1.png


6、添加MCP服务

{

  "mcpServers": {

    "chrome-mcp-server": {

      "type": "streamableHttp",

      "url": "http://127.0.0.1:12306/mcp"

    }

  }

}

AI写代码

7、MCP服务需要添加到智能体才可以在Trae内使用,进入智能体管理页面

1.png


8、配置智能体,勾选刚刚配置的MCP服务

1.png


9、在Trae的对话界面选择智能体就可以对话,让浏览器帮你干活啦

1.png


二、应用场景

内容创作

        AI 自动总结网页内容 → 调用 Excalidraw 绘制思维导图。


竞品监控

        定时截图竞品网站首页,对比分析布局更新。


工作流优化

        自动填写表单、批量关闭冗余标签页、整理书签。


开发调试

        网络请求拦截与 API 结构分析。


Windows MCP.Net基于 .NET 的 Windows 桌面自动化 MCP (Model Context Protocol) 服务器

点击进入源码页

一个基于 .NET 的 Windows 桌面自动化 MCP (Model Context Protocol) 服务器,为 AI 助手提供与 Windows 桌面环境交互的能力。

重要提示: 本项目需要 .NET 10 才能运行,请先确保你的本地安装了 .NET 10。如果尚未安装,请访问 .NET 10 下载页面 进行下载和安装。


1. MCP 客户端配置

在您的 MCP 客户端配置中添加以下配置:


使用全局安装的工具(推荐)

{

    "mcpServers": {

     "Windows-MCP.Net": {

      "type": "stdio",

      "command": "dnx",

      "args": ["Windows-MCP.Net@", "--yes"],

      "env": {}

    }

    }

}

使用项目源码直接运行(开发模式)

方式一:工作区配置

在项目根目录创建 .vscode/mcp.json 文件:


{

  "mcpServers": {

    "Windows-MCP.Net-Dev": {

      "type": "stdio",

      "command": "dotnet",

      "args": ["run", "--project", "src/Windows-MCP.Net.csproj"],

      "cwd": "${workspaceFolder}",

      "env": {}

    }

  }

}

方式二:用户配置

通过VS Code命令面板运行 MCP: Open User Configuration,添加:


{

  "mcpServers": {

    "Windows-MCP.Net-Local": {

      "type": "stdio",

      "command": "dotnet",

      "args": ["run", "--project", "src/Windows-MCP.Net.csproj"],

      "env": {}

    }

  }

}

注意: 使用项目源码方式便于开发调试,修改代码后无需重新安装即可生效。VS Code 1.102+ 版本支持MCP服务器的自动发现和管理。


2. 安装和运行

方式一:全局安装(推荐)

dotnet tool install --global WindowsMCP.Net

方式二:从源码运行

# 克隆仓库

git clone https://github.com/AIDotNet/Windows-MCP.Net.git

cd Windows-MCP.Net

# 构建项目

dotnet build

# 运行项目

dotnet run --project src/Windows-MCP.Net.csproj

3. 开始使用

配置完成后,重启您的MCP客户端,即可开始使用Windows桌面自动化功能!



Windows-MCP用于 Windows 计算机的轻量级 MCP 服务器

点击查看源码

"mcpServers": {

    "windows-mcp": {

      "command": "uv",

      "args": [

        "--directory",

        "<path to the windows-mcp directory>",

        "run",

        "main.py"

      ]

    }

  }



详细介绍NPX或UVX配置MCP服务

要使用 npx 或 uvx 配置和运行 MCP(Model Context Protocol)服务,需结合具体的 MCP 服务实现工具(通常是 Node.js 或 Python 生态的包)。以下是详细步骤和说明:

一、背景知识

npx:Node.js 生态的包执行工具,可直接运行 npm 仓库中的包(无需全局安装),适用于 Node.js 编写的 MCP 服务。

uvx:Rust 编写的快速 Python 包执行工具(类似 npx,属于 uv 包管理器的一部分),适用于 Python 编写的 MCP 服务。

MCP 服务:需遵循 MCP 协议(如可流式 HTTP 传输),提供标准化的客户端 - 服务器通信能力(如模型上下文管理、消息流式传输等)。

二、使用 npx 配置 Node.js 版 MCP 服务

若 MCP 服务基于 Node.js 实现(如 @mcp/server 等包),步骤如下:

1. 安装 Node.js 和 npm

确保环境中已安装 Node.js(含 npm),推荐版本 16+。

验证:node -v 和 npm -v 可正常输出版本号。

2. 直接运行 MCP 服务包

使用 npx 临时执行 MCP 服务包,无需提前安装。基本命令格式:


bash

npx [mcp-package-name] [配置参数]

3. 常见配置参数(以假设的 @mcp/server 为例)

MCP 服务通常支持通过命令行参数或环境变量配置核心功能,例如:


bash

# 启动 MCP 服务,指定端口、端点路径和允许的 Origin

npx @mcp/server \

  --port 8080 \                 # 服务端口(默认可能为 65432)

  --endpoint /mcp \             # MCP 端点路径(符合协议要求的单一端点)

  --allowed-origins "http://localhost:3000" \  # 允许的客户端 Origin(防 DNS 重绑定)

  --log-level info \            # 日志级别

  --session-timeout 3600        # 会话超时时间(秒)

4. 环境变量配置

部分参数可通过环境变量设置(优先级可能高于命令行):


bash

# 示例:通过环境变量配置

export MCP_PORT=8080

export MCP_ALLOWED_ORIGINS="http://localhost:3000,https://example.com"

npx @mcp/server  # 自动读取环境变量

5. 验证服务是否启动

服务启动后,可通过 curl 测试端点是否可用:


bash

curl http://localhost:8080/mcp -I  # 检查是否返回 200 或 405(允许 POST/GET)

三、使用 uvx 配置 Python 版 MCP 服务

若 MCP 服务基于 Python 实现(如 mcp-server 等包),步骤如下:

1. 安装 uv 包管理器

uvx 是 uv 的子命令,需先安装 uv:

bash

# 安装 uv(适用于 Linux/macOS,Windows 需调整)

curl -LsSf https://astral.sh/uv/install.sh | sh


验证:uv --version 和 uvx --version 可正常输出。

2. 直接运行 MCP 服务包

使用 uvx 执行 Python 版 MCP 服务,命令格式:


bash

uvx [mcp-package-name] [配置参数]

3. 常见配置参数(以假设的 mcp-server 为例)

Python 版 MCP 服务的配置参数与 Node.js 版类似,例如:


bash

# 启动 MCP 服务,配置核心参数

uvx mcp-server \

  --host 127.0.0.1 \            # 绑定本地地址(符合安全要求,避免暴露公网)

  --port 8080 \

  --endpoint /mcp \

  --cors-allowed-origins "http://localhost:3000" \  # CORS 配置(对应 Origin 验证)

  --enable-sse true             # 启用 SSE 流式传输(符合可流式 HTTP 要求)

4. 配置文件方式

复杂配置可通过 JSON 或 YAML 文件指定,例如:


bash

# 使用配置文件启动

uvx mcp-server --config ./mcp-config.json


mcp-config.json 示例:


json

{

  "port": 8080,

  "endpoint": "/mcp",

  "allowed_origins": ["http://localhost:3000"],

  "session": {

    "timeout": 3600,

    "auto_create": true

  }

}

5. 验证服务

同 Node.js 版,通过 curl 测试:


bash

curl http://localhost:8080/mcp -X POST \

  -H "Content-Type: application/json" \

  -d '{"jsonrpc": "2.0", "method": "initialize", "id": 1}'


四、核心配置项说明(符合 MCP 协议要求)

无论使用 npx 还是 uvx,MCP 服务的配置需满足协议规范:


端点路径:必须提供单一 HTTP 端点(如 /mcp),支持 POST(客户端发消息)和 GET(SSE 流)。

安全验证:

必须验证客户端的 Origin 头(通过 allowed-origins 配置)。

本地运行时绑定 127.0.0.1(而非 0.0.0.0),避免未授权访问。

会话管理:支持通过 Mcp-Session-Id 头管理会话,需配置会话超时时间。

流式传输:启用 SSE(text/event-stream)支持服务器向客户端流式发送消息。

五、总结

npx 适用于 Node.js 生态的 MCP 服务,直接运行 npm 包并通过命令行 / 环境变量配置。

uvx 适用于 Python 生态的 MCP 服务,依赖 uv 工具,支持配置文件和参数化启动。

核心是确保配置符合 MCP 协议(如端点、安全验证、流式传输),具体参数需参考所用 MCP 服务包的文档。


npx 的核心作用是 无需全局安装包,直接执行对应 MCP 工具的可执行文件。

例子 1:通用 TCP 控制型 MCP 服务(基于 mcp-server)

场景

搭建简单的 MCP 服务,实现「客户端 → MCP 服务 → 目标服务器」的 TCP 连接转发,并支持连接数限制、日志输出等基础控制。

完整 npx 命令

npx mcp-server@latest \

  --protocol tcp \

  --listen-port 8080 \

  --listen-host 0.0.0.0 \

  --target-host 192.168.1.100 \

  --target-port 9090 \

  --log-level info \

  --max-connections 50 \

  --timeout 30000


mcp-server@latest 包名 + 版本 如 @1.2.0(固定版) 指定要执行的 MCP 服务包,@latest 表示使用最新版本,生产环境建议固定版本(如 @1.2.0)。


例子 2:本地自定义 MCP 服务(基于项目依赖 mcp-cli)

场景

本地 Node.js 项目中已将 mcp-cli 作为开发依赖(npm install mcp-cli --save-dev),通过 npx 直接执行本地依赖的 MCP 工具,加载自定义配置文件启动服务(适合企业内部定制化 MCP 服务,如设备管理、数据采集)。

完整 npx 命令

bash

npx mcp-cli start \

  --config ./config/mcp-service.yaml \

  --env production \

  --port 8888 \

  --watch \

  --debug \

  --log-rotate 7


mcp-cli start包名 + 命令无默认值mcp-cli 是本地项目依赖的 MCP 管理工具,start 是其内置命令(表示 “启动 MCP 服务”)。



CherryStudio的MCP配置

点击查看官方配置MCP文档

手动配置一个STADIO MCP

一个STATIO MCP配置例子,它的源码地址

1.jpg


它的uvx的json

{

  "mcpServers": {

    "fetch": {

      "command": "uvx",

      "args": ["mcp-server-fetch"]

    }

  }

}


多参数配置,一行一个参数

1.jpg


自动安装MCP

直接给指令:

帮我安装一个 filesystem mcp server



1.png

Cherry Studio

标准输入/输出stdio

命令:UV

参数:

--directory

d:\host_info

run

main.py



AI辅助生成MCP例子

####【豆包】

你知道AI模型调用MCP吗??

。。。

写一个MCP的完整例子并给出模型调用这个MCP例子

。。。


Python实现
mcp_weather_server.py

import json

import socket

import threading

from typing import Dict, Any


class MCPWeatherServer:

    """MCP天气服务服务器实现"""

    

    def __init__(self, host: str = 'localhost', port: int = 8000):

        self.host = host

        self.port = port

        self.server_socket = None

        self.running = False

        

        # 模拟天气数据库

        self.weather_database = {

            "北京": {"temperature": 25, "condition": "晴朗", "wind": "微风"},

            "上海": {"temperature": 28, "condition": "多云", "wind": "东风3级"},

            "广州": {"temperature": 30, "condition": "小雨", "wind": "南风2级"},

            "深圳": {"temperature": 29, "condition": "阴天", "wind": "东南风1级"},

            "成都": {"temperature": 23, "condition": "晴转多云", "wind": "西北风2级"}

        }

    

    def start(self):

        """启动MCP服务器"""

        self.running = True

        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        self.server_socket.bind((self.host, self.port))

        self.server_socket.listen(5)

        print(f"MCP天气服务已启动,监听 {self.host}:{self.port}")

        

        try:

            while self.running:

                client_socket, client_address = self.server_socket.accept()

                print(f"接收到来自 {client_address} 的连接")

                client_handler = threading.Thread(

                    target=self.handle_client,

                    args=(client_socket,)

                )

                client_handler.start()

        except KeyboardInterrupt:

            print("服务器正在关闭...")

        finally:

            self.stop()

    

    def stop(self):

        """停止MCP服务器"""

        self.running = False

        if self.server_socket:

            self.server_socket.close()

        print("MCP天气服务已关闭")

    

    def handle_client(self, client_socket: socket.socket):

        """处理客户端请求"""

        try:

            # 接收请求数据

            data = client_socket.recv(1024).decode('utf-8')

            if not data:

                return

                

            print(f"收到请求: {data}")

            

            # 解析MCP请求

            request = json.loads(data)

            

            # 处理请求

            response = self.process_request(request)

            

            # 发送响应

            client_socket.sendall(json.dumps(response).encode('utf-8'))

            print(f"发送响应: {response}")

            

        except Exception as e:

            error_response = {

                "jsonrpc": "2.0",

                "error": {

                    "code": -1,

                    "message": f"处理请求时出错: {str(e)}"

                },

                "id": request.get("id") if 'request' in locals() else None

            }

            client_socket.sendall(json.dumps(error_response).encode('utf-8'))

        finally:

            client_socket.close()

    

    def process_request(self, request: Dict[str, Any]) -> Dict[str, Any]:

        """处理MCP请求"""

        # 验证请求格式

        if "jsonrpc" not in request or request["jsonrpc"] != "2.0":

            return {

                "jsonrpc": "2.0",

                "error": {"code": -32600, "message": "无效的请求"},

                "id": request.get("id")

            }

            

        if "method" not in request:

            return {

                "jsonrpc": "2.0",

                "error": {"code": -32601, "message": "方法不存在"},

                "id": request.get("id")

            }

        

        # 处理天气查询方法

        if request["method"] == "get_weather":

            params = request.get("params", {})

            city = params.get("city")

            

            if not city:

                return {

                    "jsonrpc": "2.0",

                    "error": {"code": -32602, "message": "缺少城市参数"},

                    "id": request.get("id")

                }

            

            # 查询天气数据

            weather_data = self.weather_database.get(city)

            if weather_data:

                return {

                    "jsonrpc": "2.0",

                    "result": {

                        "city": city,

                        "weather": weather_data,

                        "source": "MCP Weather Service"

                    },

                    "id": request.get("id")

                }

            else:

                return {

                    "jsonrpc": "2.0",

                    "error": {"code": 404, "message": f"未找到城市 {city} 的天气数据"},

                    "id": request.get("id")

                }

        

        # 处理服务描述方法

        elif request["method"] == "describe":

            return {

                "jsonrpc": "2.0",

                "result": {

                    "name": "WeatherService",

                    "description": "提供城市天气查询服务",

                    "methods": {

                        "get_weather": {

                            "description": "获取指定城市的天气信息",

                            "parameters": {

                                "city": {

                                    "type": "string",

                                    "description": "城市名称"

                                }

                            },

                            "returns": {

                                "type": "object",

                                "description": "包含温度、天气状况和风力的天气信息"

                            }

                        }

                    }

                },

                "id": request.get("id")

            }

        

        # 未知方法

        else:

            return {

                "jsonrpc": "2.0",

                "error": {"code": -32601, "message": f"方法 {request['method']} 不存在"},

                "id": request.get("id")

            }


if __name__ == "__main__":

    # 创建并启动MCP服务器

    server = MCPWeatherServer(host='localhost', port=8000)

    server.start()


mcp_client.py

import json

import socket

from typing import Dict, Any, Optional


class MCPClient:

    """MCP客户端,用于与MCP服务器通信"""

    

    def __init__(self, host: str = 'localhost', port: int = 8000):

        self.host = host

        self.port = port

        self.request_id = 0

    

    def _get_next_id(self) -> int:

        """获取下一个请求ID"""

        self.request_id += 1

        return self.request_id

    

    def send_request(self, method: str, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:

        """发送MCP请求到服务器"""

        # 创建请求

        request = {

            "jsonrpc": "2.0",

            "method": method,

            "id": self._get_next_id()

        }

        

        if params is not None:

            request["params"] = params

        

        # 建立连接并发送请求

        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:

            s.connect((self.host, self.port))

            s.sendall(json.dumps(request).encode('utf-8'))

            

            # 接收响应

            response_data = s.recv(1024).decode('utf-8')

            if not response_data:

                return {"error": "未收到响应"}

                

            return json.loads(response_data)

    

    def describe_service(self) -> Dict[str, Any]:

        """获取服务描述信息"""

        return self.send_request("describe")

    

    def get_weather(self, city: str) -> Dict[str, Any]:

        """查询指定城市的天气"""

        return self.send_request("get_weather", {"city": city})


# 模型调用MCP服务的示例

def model_use_mcp_service():

    """模拟AI模型使用MCP服务的过程"""

    print("=== AI模型开始运行 ===")

    

    # 1. 创建MCP客户端

    print("创建MCP客户端,准备连接天气服务...")

    client = MCPClient(host='localhost', port=8000)

    

    # 2. 先查询服务描述,了解可用功能

    print("\n查询MCP服务描述...")

    description = client.describe_service()

    print(f"服务描述: {json.dumps(description, ensure_ascii=False, indent=2)}")

    

    # 3. 根据服务描述,调用天气查询功能

    target_city = "北京"

    print(f"\n调用MCP服务查询 {target_city} 的天气...")

    weather_result = client.get_weather(target_city)

    

    # 4. 处理返回结果

    print(f"天气查询结果: {json.dumps(weather_result, ensure_ascii=False, indent=2)}")

    

    # 5. 根据结果生成回答

    if "result" in weather_result:

        weather_data = weather_result["result"]["weather"]

        response = (f"{target_city}当前的天气状况为:{weather_data['condition']},"

                   f"气温{weather_data['temperature']}°C,{weather_data['wind']}。")

    else:

        response = f"抱歉,无法获取{target_city}的天气信息:{weather_result.get('error', {}).get('message', '未知错误')}"

    

    print(f"\n=== AI模型生成回答 ===")

    print(response)


if __name__ == "__main__":

    # 模拟模型调用MCP服务

    model_use_mcp_service()


C#实现

Models.cs  

using System;

using System.Collections.Generic;

using System.Text.Json.Serialization;


namespace McpCommon

{

    /// <summary>

    /// MCP请求模型

    /// </summary>

    public class McpRequest

    {

        [JsonPropertyName("jsonrpc")]

        public string JsonRpc { get; set; } = "2.0";

        

        [JsonPropertyName("method")]

        public string Method { get; set; }

        

        [JsonPropertyName("params")]

        public Dictionary<string, object> Parameters { get; set; }

        

        [JsonPropertyName("id")]

        public int Id { get; set; }

    }

    

    /// <summary>

    /// MCP响应模型

    /// </summary>

    public class McpResponse

    {

        [JsonPropertyName("jsonrpc")]

        public string JsonRpc { get; set; } = "2.0";

        

        [JsonPropertyName("result")]

        public object Result { get; set; }

        

        [JsonPropertyName("error")]

        public McpError Error { get; set; }

        

        [JsonPropertyName("id")]

        public int Id { get; set; }

    }

    

    /// <summary>

    /// MCP错误模型

    /// </summary>

    public class McpError

    {

        [JsonPropertyName("code")]

        public int Code { get; set; }

        

        [JsonPropertyName("message")]

        public string Message { get; set; }

    }

    

    /// <summary>

    /// 天气数据模型

    /// </summary>

    public class WeatherData

    {

        public string City { get; set; }

        public string Condition { get; set; }

        public int Temperature { get; set; }

        public string Wind { get; set; }

        public DateTime UpdateTime { get; set; }

    }

    

    /// <summary>

    /// 服务描述模型

    /// </summary>

    public class ServiceDescription

    {

        public string Name { get; set; }

        public string Description { get; set; }

        public string Version { get; set; }

        public List<ServiceMethod> Methods { get; set; } = new List<ServiceMethod>();

    }

    

    /// <summary>

    /// 服务方法描述

    /// </summary>

    public class ServiceMethod

    {

        public string Name { get; set; }

        public string Description { get; set; }

        public List<MethodParameter> Parameters { get; set; } = new List<MethodParameter>();

    }

    

    /// <summary>

    /// 方法参数描述

    /// </summary>

    public class MethodParameter

    {

        public string Name { get; set; }

        public string Type { get; set; }

        public string Description { get; set; }

        public bool Required { get; set; }

    }

}

    

MCPServer.cs

using System;

using System.Collections.Generic;

using System.Net;

using System.Net.Sockets;

using System.Text;

using System.Text.Json;

using System.Threading;

using McpCommon;


namespace McpServer

{

    class Program

    {

        private static TcpListener _server;

        private static bool _isRunning;

        private static readonly Dictionary<string, WeatherData> _mockWeatherData = new Dictionary<string, WeatherData>

        {

            { "北京", new WeatherData { City = "北京", Condition = "晴朗", Temperature = 25, Wind = "微风", UpdateTime = DateTime.Now } },

            { "上海", new WeatherData { City = "上海", Condition = "多云", Temperature = 28, Wind = "东风3级", UpdateTime = DateTime.Now } },

            { "广州", new WeatherData { City = "广州", Condition = "小雨", Temperature = 30, Wind = "南风2级", UpdateTime = DateTime.Now } },

            { "深圳", new WeatherData { City = "深圳", Condition = "阴天", Temperature = 29, Wind = "东北风1级", UpdateTime = DateTime.Now } }

        };


        static void Main(string[] args)

        {

            StartServer();

            

            Console.WriteLine("MCP天气服务已启动,按任意键停止...");

            Console.ReadKey();

            

            StopServer();

        }


        private static void StartServer()

        {

            int port = 8000;

            _server = new TcpListener(IPAddress.Any, port);

            _server.Start();

            _isRunning = true;

            

            Console.WriteLine($"MCP服务器已启动,监听端口 {port}...");

            

            // 启动一个线程处理客户端连接

            new Thread(ListenForClients) { IsBackground = true }.Start();

        }


        private static void StopServer()

        {

            _isRunning = false;

            _server.Stop();

            Console.WriteLine("MCP服务器已停止");

        }


        private static void ListenForClients()

        {

            while (_isRunning)

            {

                try

                {

                    // 等待客户端连接

                    TcpClient client = _server.AcceptTcpClient();

                    Console.WriteLine("新客户端连接");

                    

                    // 为每个客户端创建一个线程处理

                    new Thread(HandleClient) { IsBackground = true }.Start(client);

                }

                catch (SocketException ex)

                {

                    if (_isRunning)

                    {

                        Console.WriteLine($"Socket错误: {ex.Message}");

                    }

                }

                catch (Exception ex)

                {

                    Console.WriteLine($"错误: {ex.Message}");

                }

            }

        }


        private static void HandleClient(object obj)

        {

            using (TcpClient client = (TcpClient)obj)

            using (NetworkStream stream = client.GetStream())

            {

                byte[] buffer = new byte[1024];

                int bytesRead;

                

                try

                {

                    // 读取客户端发送的数据

                    while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)

                    {

                        string requestString = Encoding.UTF8.GetString(buffer, 0, bytesRead);

                        Console.WriteLine($"收到请求: {requestString}");

                        

                        // 解析请求

                        McpRequest request = JsonSerializer.Deserialize<McpRequest>(requestString);

                        McpResponse response = ProcessRequest(request);

                        

                        // 发送响应

                        string responseString = JsonSerializer.Serialize(response);

                        byte[] responseBytes = Encoding.UTF8.GetBytes(responseString);

                        stream.Write(responseBytes, 0, responseBytes.Length);

                        

                        Console.WriteLine($"发送响应: {responseString}");

                    }

                }

                catch (Exception ex)

                {

                    Console.WriteLine($"处理客户端时出错: {ex.Message}");

                }

                

                Console.WriteLine("客户端连接已关闭");

            }

        }


        private static McpResponse ProcessRequest(McpRequest request)

        {

            var response = new McpResponse { Id = request.Id };

            

            try

            {

                switch (request.Method)

                {

                    case "describe":

                        response.Result = GetServiceDescription();

                        break;

                        

                    case "get_weather":

                        if (request.Parameters != null && request.Parameters.ContainsKey("city"))

                        {

                            string city = request.Parameters["city"].ToString();

                            response.Result = new { weather = GetWeatherData(city) };

                        }

                        else

                        {

                            response.Error = new McpError { Code = -1, Message = "缺少参数: city" };

                        }

                        break;

                        

                    default:

                        response.Error = new McpError { Code = -2, Message = $"未知方法: {request.Method}" };

                        break;

                }

            }

            catch (Exception ex)

            {

                response.Error = new McpError { Code = -999, Message = ex.Message };

            }

            

            return response;

        }


        private static ServiceDescription GetServiceDescription()

        {

            return new ServiceDescription

            {

                Name = "WeatherService",

                Description = "提供城市天气查询服务",

                Version = "1.0.0",

                Methods = new List<ServiceMethod>

                {

                    new ServiceMethod

                    {

                        Name = "describe",

                        Description = "获取服务描述信息",

                        Parameters = new List<MethodParameter>()

                    },

                    new ServiceMethod

                    {

                        Name = "get_weather",

                        Description = "查询指定城市的天气信息",

                        Parameters = new List<MethodParameter>

                        {

                            new MethodParameter

                            {

                                Name = "city",

                                Type = "string",

                                Description = "城市名称",

                                Required = true

                            }

                        }

                    }

                }

            };

        }


        private static WeatherData GetWeatherData(string city)

        {

            if (_mockWeatherData.TryGetValue(city, out var weatherData))

            {

                // 更新时间为当前时间

                weatherData.UpdateTime = DateTime.Now;

                return weatherData;

            }

            

            // 如果没有该城市的数据,返回一个默认值

            return new WeatherData

            {

                City = city,

                Condition = "未知",

                Temperature = 0,

                Wind = "未知",

                UpdateTime = DateTime.Now

            };

        }

    }

}

    

MCPClient.cs

MCP服务相关技术收集MCP

MCP协议详细讲解

AI 模型调用 MCP 服务的过程

AI 模型调用 MCP 服务的代码示例

C# 编写 Agent 调用 ollama 及 MCP 的方法

Trae+Chrome MCP Server 让AI接管你的浏览器

MCP典型服务

Chrome MCP Server

mcp2mqtt动动嘴就可以控制智能家居

excel-mcp-server使用 AI 代理创建、读取和修改 Excel 工作簿

Windows MCP.Net基于 .NET 的 Windows 桌面自动化 MCP (Model Context Protocol) 服务器

Windows-MCP用于 Windows 计算机的轻量级 MCP 服务器

AI辅助生成MCP例子



MCP协议详细讲解

Model Context Protocol(MCP)是由 Anthropic 推出的一种开源协议,旨在建立 AI 模型与开发环境之间的统一上下文交互标准。以下是对其的详细讲解:

1.png

背景与起源

在 AI 领域,大语言模型的应用常常面临数据孤岛和工具集成复杂的问题,不同的数据源和工具都有自己独特的 API 和集成方式,导致开发者需要为每个工具单独编写集成代码,开发和维护成本高,工具复用性低。为解决这些问题,Anthropic 于 2024 年 11 月 25 日开源发布了 MCP。

核心概念

  • MCP Hosts :如 Claude Desktop、Cursor、 Cline、trae、Cherry Studio、IDE、AI 应用等,是运行 MCP 的主应用程序,负责发起连接并管理多个客户端实例,与用户进行交互并接收用户的问题或指令,再通过 MCP Clients 向 MCP Servers 发送请求以获取所需的数据或执行相应的操作。
  • MCP Clients :由 Host 创建,与特定的 MCP Server 建立一对一的连接,负责协议通信和能力协商,充当 MCP Host 和 MCP Server 之间的“连接器”或“总机”,将 Host 的请求转发给 Server,并将 Server 的响应返回给 Host。
  • MCP Servers :轻量级程序,通过标准化的模型上下文协议暴露特定功能,如文件读取、API 调用、数据库查询等,为 MCP Host 提供实际的数据和功能支持,每个 Server 提供一个特定的工具或能力。

工作原理

  • 通信机制 :MCP 采用客户端 - 服务器架构,基于 JSON-RPC 2.0 消息格式,支持请求、响应和通知三种消息类型,确保通信的标准化和一致性。它主要支持两种通信方式,一种是标准输入输出(Stdio),适用于在同一台机器上运行的客户端和服务器之间的通信,客户端启动服务器程序作为子进程,消息通讯通过 stdin/stdout 进行;另一种是服务器发送事件(SSE),利用 HTTP 协议实现跨网络的实时数据传输,适用于需要访问远程资源的场景。
  • 工作流程 :首先,Host 初始化 Client,Client 尝试与 Server 建立连接,并询问 Server 有哪些能力,Server 回应并返回所有支持的功能,从而建立 1:1 的连接。当用户与 LLM 交互提出问题或指令时,LLM 会告诉 Client 需要调用哪些 Tools,Client 收到 Host 的请求后,将请求信息发送给对应的 Server,Server 接收到信息后开始处理,处理完成后返回结果给 Client,Client 再将信息返回给 Host,Host 根据这些信息生成最终的回复返回给用户。

主要功能与特性

  • 统一接口 :提供标准化的 API 接口,简化 AI 与各类上下文信息的交互,使得开发者无需为不同的数据源或工具编写复杂的适配代码,降低了开发难度和成本。
  • 无缝集成 :能够轻松集成到现有开发工作流程中,无需对现有的系统和工具进行大规模的改造,即可实现 AI 模型与各种数据源和工具的快速连接和集成,提高了开发效率。
  • 多源数据支持 :支持从多种来源获取上下文信息,包括代码仓库、文档、文件系统、数据库、远程 API 等,丰富了 AI 模型可以利用的数据资源,为模型的训练和推理提供了更全面、准确的上下文信息。
  • 智能上下文管理 :优化上下文信息的传递,根据 AI 模型的需求和任务场景,自动筛选、组织和更新上下文信息,提高 AI 模型理解和生成的质量,使模型能够更准确地理解和处理复杂的任务。
  • 扩展性设计 :具有灵活的架构,允许添加新的数据源和功能,开发者可以根据实际需求自由扩展 MCP 的功能,不断增加新的 MCP Servers 来提供新的工具和能力,以满足不断变化的业务需求。

应用场景

  • 智能开发环境 :将 AI 模型与开发工具集成,如代码编辑器、IDE 等,使 AI 能够实时理解代码上下文,为开发者提供智能代码补全、代码生成、代码解释等功能,提高开发效率和代码质量。
  • 智能办公助手 :连接办公软件和在线服务,如日历、邮件、文档管理系统等,帮助用户自动完成日常办公任务,如安排会议、发送邮件、生成报告等,提升办公自动化水平。
  • 智能数据分析 :将 AI 模型与数据分析工具和数据源集成,如数据库、数据仓库、BI 工具等,使 AI 能够协助分析师进行数据查询、数据分析、数据可视化等工作,为决策提供更有力的支持。
  • 智能客服系统 :集成企业内部的客户信息管理系统、订单管理系统等,使 AI 客服能够快速准确地获取客户相关的信息,为客户提供更精准、高效的咨询服务,提高客户满意度


JSON-RPC 2.0 的请求和响应示例

请求示例

{

  "jsonrpc": "2.0",

  "method": "add",

  "params": [2, 3],

  "id": 1

}

响应示例

{

  "jsonrpc": "2.0",

  "result": 5,

  "id": 1

}

错误响应示例

{

  "jsonrpc": "2.0",

  "error": {

    "code": -32601,

    "message": "Method not found"

  },

  "id": 1

}


批量请求示例

[

  {

    "jsonrpc": "2.0",

    "method": "add",

    "params": [2, 3],

    "id": 1

  },

  {

    "jsonrpc": "2.0",

    "method": "subtract",

    "params": [5, 2],

    "id": 2

  }

]

批量响应示例

[

  {

    "jsonrpc": "2.0",

    "result": 5,

    "id": 1

  },

  {

    "jsonrpc": "2.0",

    "result": 3,

    "id": 2

  }

]

这些示例展示了 JSON-RPC 2.0 请求和响应的基本格式,包括请求、响应以及错误处理等场景。



AI 模型调用 MCP 服务的过程


准备工作

  • 搭建 MCP 服务器 :开发者需先搭建 MCP 服务器,可使用 Anthropic 提供的开源框架如 FastMCP 等。定义好服务器的基本配置,如名称、版本等,并通过装饰器注册工具函数,每个工具函数对应一个具体的功能,如查询天气、发送邮件等。
  • 集成 MCP 客户端 :在 AI 模型所在的系统或应用中集成 MCP 客户端,如在 Python 项目中安装相应的客户端库等。

调用过程

  1. 用户发起请求 :用户通过与 AI 模型交互的方式,如在聊天界面输入问题或指令,表达其想要实现的需求。
  2. AI 模型解析意图 :MCP 客户端将用户请求发送给 AI 模型,AI 模型对用户输入的自然语言进行理解和解析,确定用户的需求,并选择与之匹配的 MCP 函数及相应的参数。
  3. 发送调用请求 :MCP 客户端根据 AI 模型返回的函数调用信息,向 MCP 服务器发送请求。请求中包含请求 ID、函数名称及参数等,格式通常为 JSON。
  4. 执行服务并返回结果 :MCP 服务器接收到请求后,执行对应的工具函数,在本地或通过调用其他外部服务完成具体的任务处理,然后将执行结果按照规定的格式返回给 MCP 客户端。
  5. 结果整合与反馈 :MCP 客户端将 MCP 服务器返回的结果整合到对话上下文中,再次发送给 AI 模型。AI 模型根据整合后的上下文生成自然语言的回复,由 MCP 客户端将最终结果呈现给用户。

通信机制

  • STDIO 方式 :适用于本地服务。MCP 客户端启动 MCP 服务器程序作为子进程,通过 stdin 和 stdout 进行消息传递,消息格式遵循 JSON-RPC 2.0。
  • SSE 方式 :用于远程服务。MCP 客户端通过 Server-Sent Events 与 MCP 服务器进行通信,服务器定义特定接口用于推送和接收数据,消息格式同样基于 JSON-RPC 2.0。

动态上下文管理

MCP 协议具有动态上下文管理机制,通过上下文窗口存储用户偏好、会话记录和环境数据等。在每次交互过程中,上下文会不断扩展和更新,同时对非关键信息进行压缩,以保证对话的连贯性和减少资源消耗。

安全与认证机制

  • API 密钥验证 :MCP 服务通常会要求进行 API 密钥验证,只有拥有正确 API 密钥的客户端才能访问服务。
  • HTTPS 加密 :采用 HTTPS 协议对数据传输进行加密,确保数据在网络传输过程中的安全性。
  • 请求限制 :设置请求频率限制和配额限制等,防止服务被滥用,保护服务的稳定性和可靠性



AI 模型调用 MCP 服务的代码示例


基于 Python 的简单 MCP 服务端:

Python

pip install mcp

/*


from mcp.server.fastmcp import FastMCP

import tools


mcp=FastMCP("host info mcp")

mcp.add_tool(tools.get_host_info)


def main()->none:

   print("hello from ai-mcp!")

   mcp.run("stdio")#还有sse

   mcp.run(transport="sse", port=9000)

   


if __name__=="__main__":

   main()


tools.py内容

def get_hosts_info()->str:

...



*/


from mcp import MCP, tool


mcp = MCP()


@mcp.register_tool

class WeatherTool:

    @tool(name="get_weather", description="获取指定城市的天气信息")

    def get_weather(self, city: str):

        # 这里可以添加获取天气信息的逻辑,比如调用天气 API 等

        return f"The weather in {city} is sunny."


    @tool(name="get_weather_forecast", description="获取指定城市未来几天的天气预报")

    def get_weather_forecast(self, city: str, days: int):

        # 添加获取天气预报的逻辑

        return f"The weather forecast for {city} in the next {days} days."


if __name__ == "__main__":

    mcp.start()

基于 Java 的 MCP 服务端:

java

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.core.io.ClassPathResource;

import org.springframework.core.io.Resource;

import org.springframework.util.StringUtils;

import org.springframework.web.reactive.function.server.RouterFunctions;

import org.springframework.web.reactive.function.server.ServerResponse;

import reactor.core.publisher.Mono;


import java.util.Collections;

import java.util.Map;


@Configuration

public class MCPConfig {


    @Bean

    public RouterFunctions.Route mcpRoute() {

        return RouterFunctions.route()

                .POST("/mcp/weather", this::getWeather)

                .build();

    }


    private Mono<ServerResponse> getWeather(ServerRequest request) {

        Map<String, String> queryParams = request.queryParams();

        String city = queryParams.get("city");

        if (StringUtils.hasText(city)) {

            String weatherInfo = "The weather in " + city + " is sunny.";

            return ServerResponse.ok().bodyValue(Collections.singletonMap("weather", weatherInfo));

        } else {

            return ServerResponse.badRequest().bodyValue(Collections.singletonMap("error", "City parameter is required"));

        }

    }

}

AI 模型调用 MCP 服务的代码示例

基于 Python 的 OpenAI 模型调用 MCP 服务:

Python

import openai

import requests

from mcp import MCPClient


# 初始化 MCP 客户端

mcp_client = MCPClient()

mcp_client.connect("http://localhost:8080/mcp")  # 替换为 MCP 服务的实际地址


# 调用 MCP 服务中的工具

def call_mcp_tool(tool_name, **kwargs):

    return mcp_client.call_tool(tool_name, **kwargs)


# 使用 OpenAI 模型

openai.api_key = "your_openai_api_key"  # 替换为你的 OpenAI API 密钥


def get_ai_response(user_query):

    # 构建消息列表

    messages = [

        {"role": "system", "content": "You are a helpful assistant."},

        {"role": "user", "content": user_query}

    ]


    # 调用 OpenAI API

    response = openai.ChatCompletion.create(

        model="gpt-4-turbo-preview",

        messages=messages,

        tools=mcp_client.list_tools(),  # 提供可用的 MCP 工具

        tool_choice="auto"

    )


    # 处理模型返回的结果

    ai_response = ""

    for choice in response.choices:

        message = choice.message

        if message.content:

            ai_response += message.content + "\n"

        if message.tool_calls:

            for tool_call in message.tool_calls:

                tool_name = tool_call.function.name

                tool_args = tool_call.function.arguments

                # 调用 MCP 工具

                tool_result = call_mcp_tool(tool_name, **tool_args)

                ai_response += f"Calling tool {tool_name} with args {tool_args}\n"

                ai_response += tool_result + "\n"

                # 将工具结果添加到消息中,继续与模型对话

                messages.append({"role": "assistant", "content": "", "tool_calls": [tool_call]})

                messages.append({"role": "tool", "tool_call_id": tool_call.id, "content": tool_result})

                # 获取下一个模型响应

                next_response = openai.ChatCompletion.create(

                    model="gpt-4-turbo-preview",

                    messages=messages,

                    tools=mcp_client.list_tools(),

                    tool_choice="auto"

                )

                if next_response.choices[0].message.content:

                    ai_response += next_response.choices[0].message.content + "\n"

    return ai_response


# 示例 usage

user_input = "What's the weather like in Beijing?"

print(get_ai_response(user_input))

基于 Java 的 Spring AI 模型调用 MCP 服务:

java

import org.springframework.ai.chat.client.ChatClient;

import org.springframework.ai.chat.client.ChatClientBuilder;

import org.springframework.ai.mcp.client.McpClient;

import org.springframework.ai.mcp.client.McpClientBuilder;

import org.springframework.ai.mcp.client.McpFunctionCallback;

import org.springframework.ai.tool.ToolCallbackProvider;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;


import java.util.List;


@Configuration

public class AIConfig {


    @Bean

    public McpClient mcpClient() {

        // 配置 MCP 服务器参数

        var stdioParams = ServerParameters.builder("java")

                .args("-Dspring.ai.mcp.server.stdio=true",

                        "-Dspring.main.web-application-type=none",

                        "-Dlogging.pattern.console=",

                        "-jar",

                        "target/mcp-server-0.0.1-SNAPSHOT.jar")

                .build();

        // 创建 MCP 客户端

        return McpClient.sync(new StdioClientTransport(stdioParams));

    }


    @Bean

    public ToolCallbackProvider mcpTools(McpClient mcpClient) {

        // 获取 MCP 服务器中的工具列表并转换为 Function Callback

        return mcpClient.listTools(null)

                .tools()

                .stream()

                .map(tool -> new McpFunctionCallback(mcpClient, tool))

                .toList();

    }


    @Bean

    public ChatClient chatClient(ChatClientBuilder chatClientBuilder, ToolCallbackProvider mcpTools) {

        // 初始化聊天客户端并设置默认工具

        return chatClientBuilder.defaultFunctions(mcpTools).build();

    }

}


// 使用示例

public class AIService {

    private final ChatClient chatClient;


    public AIService(ChatClient chatClient) {

        this.chatClient = chatClient;

    }


    public String generateResponse(String userQuery) {

        return chatClient

                .prompt(userQuery)

                .call()

                .content();

    }

}


使用 ASP.NET Core 来创建一个 Web API 服务,并模拟天气查询功能。

C# MCP 服务端代码示例

csharp

using Microsoft.AspNetCore.Builder;

using Microsoft.AspNetCore.Hosting;

using Microsoft.AspNetCore.Mvc;

using Microsoft.Extensions.DependencyInjection;

using Microsoft.Extensions.Hosting;


namespace MCPService

{

    public class Startup

    {

        public void ConfigureServices(IServiceCollection services)

        {

            services.AddControllers();

        }


        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

        {

            if (env.IsDevelopment())

            {

                app.UseDeveloperExceptionPage();

            }


            app.UseRouting();


            app.UseEndpoints(endpoints =>

            {

                endpoints.MapControllers();

            });

        }

    }

    /*

这段代码定义了一个名为WeatherController的控制器类。这个类继承自ControllerBase

,并使用了[ApiController]和[Route("mcp")]特性,表明这是用于处理HTTP请求的API控制器,并指定了其基础路由为/mcp。

在控制器类中,定义了一个名为GetWeather的方法,该方法使用了[HttpGet("weather")]特性。这表明这是一个处理HTTP GET请求的方法,其对应的路由是mcp/weather。这个方法接受一个名为city的参数,通过[FromQuery]特性从查询字符串中获取。

当客户端向/mcp/weather发起一个带有查询参数(如city=Paris)的GET请求时,GetWeather方法会处理这个请求,并返回一个IActionResult类型的对象,即一个包含响应内容和状态码的对象。在实际应用中,这个方法可能会根据提供的城市名称来获取和返回相应的天气信息。

*/

    [ApiController]

    [Route("mcp")]

    public class WeatherController : ControllerBase

    {

        [HttpGet("weather")]

        public IActionResult GetWeather([FromQuery] string city)

        {

            if (string.IsNullOrEmpty(city))

            {

                return BadRequest("City parameter is required");

            }


            // 模拟天气查询逻辑

            var weatherInfo = $"The weather in {city} is sunny.";


            return Ok(new { weather = weatherInfo });

        }


        [HttpGet("weather-forecast")]

        public IActionResult GetWeatherForecast([FromQuery] string city, [FromQuery] int days)

        {

            if (string.IsNullOrEmpty(city))

            {

                return BadRequest("City parameter is required");

            }


            // 模拟天气预报逻辑

            var weatherForecast = $"The weather forecast for {city} in the next {days} days.";


            return Ok(new { forecast = weatherForecast });

        }

   

[HttpPost("weather")]

    public IActionResult PostWeather([FromBody] WeatherRequest weatherRequest)

    {

        // 处理POST请求的逻辑

        return Ok($"Received weather data for {weatherRequest.City}: {weatherRequest.Temperature}°C");

    }



// 新增的可以GET和POST调用的方法

    [HttpGet("data")]

    [HttpPost("data")]

    public IActionResult GetAndPostData([FromQuery] string name, [FromBody] string postData = null)

    {

        if (HttpContext.Request.Method == HttpMethods.Get)

        {

            return Ok($"Received GET request with name: {name}");

        }

        else if (HttpContext.Request.Method == HttpMethods.Post)

 {

                   return Ok($"Received POST request with name: {name} and post data: {postData}");

        }


        return BadRequest("Invalid request method");

    }



}


public class WeatherRequest

{

    public string City { get; set; }

    public double Temperature { get; set; }

}



    public class Program

    {

        public static void Main(string[] args)

        {

            var host = CreateHostBuilder(args).Build();

            host.Run();

        }


        public static IHostBuilder CreateHostBuilder(string[] args) =>

            Host.CreateDefaultBuilder(args)

                .ConfigureWebHostDefaults(webBuilder =>

                {

                    webBuilder.UseStartup<Startup>();

                });

    }

}

说明

项目结构:

Startup 类配置了服务和中间件。

WeatherController 是一个 ASP.NET Core 控制器,提供了两个端点 /mcp/weather 和 /mcp/weather-forecast。

功能:

/mcp/weather 接受一个 city 参数,返回该城市的天气信息。

/mcp/weather-forecast 接受 city 和 days 参数,返回该城市未来几天的天气预报。

运行服务:

创建一个 ASP.NET Core 项目并复制上述代码。

使用 dotnet run 命令启动服务,服务默认运行在 https://localhost:5001 和 http://localhost:5000。

测试服务:

使用工具如 Postman 或 curl 测试 API:

获取天气信息:GET http://localhost:5000/mcp/weather?city=Beijing

获取天气预报:GET http://localhost:5000/mcp/weather-forecast?city=Beijing&days=3


C# 用OpenAI模型调用

public class WeatherRequestFunction : IRequestFunction

{

    public string Name => "weather";


    public async Task<IDictionary<string, object>> InvokeAsync(IDictionary<string, object> parameters)

    {

        using var httpClient = new HttpClient();

        var city = parameters["city"].ToString();

        var response = await httpClient.GetAsync($"http://localhost:5000/mcp/weather?city={city}");

        response.EnsureSuccessStatusCode();

        var content = await response.Content.ReadAsStringAsync();

        return new Dictionary<string, object> { { "result", content } };

    }


    public string Serialize(IRequestFunction function)

    {

        return $"Calling tool {function.Name} with parameters {function}";

    }


    public Task SerializeAsync(IRequestFunction function)

    {

        // 实现序列化逻辑

        return Task.CompletedTask;

    }

}

代码说明

OpenAI 客户端:创建 OpenAI 客户端实例,并配置 API 密钥和日志记录器。

MCP 工具:定义一个 WeatherRequestFunction 类实现 IRequestFunction 接口,用于调用 MCP 服务中的天气查询工具。

ChatClient:创建 ChatClient 实例,传入 OpenAI 客户端和日志记录器。

聊天历史:初始化聊天历史记录。

交互式聊天:在循环中读取用户输入,将其添加到聊天历史中,并调用 OpenAI API 获取响应。打印助手的响应并将其添加到聊天历史中。

其他信息

确保你的 MCP 服务正在运行,并且可以通过 http://localhost:5000/mcp/weather 访问。

替换成您的实际 OpenAI API 密钥。

如果您没有 MCP 服务,可以参考前面的示例代码实现一个简单的 MCP 服务。



C# 编写 Agent 调用 ollama 及 MCP 的方法


调用 ollama

安装 Ollama SDK :可以使用如下命令安装 Ollama 的 C# SDK,“dotnet add package Ollama --version 1.9.0”。

简单对话 :设置模型名称和 ollama 的 API 地址,利用 OllamaApiClient 进行对话生成,示例代码如下:

**```csharp

string modelName = "qwen2:7b";

using var ollama = new OllamaApiClient(baseUri: new Uri("http://127.0.0.1:11434/api"));

Console.WriteLine("开始对话!!!");

string userInput = "";

do

{

Console.WriteLine("User:");

userInput = Console.ReadLine()!;

var enumerable = ollama.Completions.GenerateCompletionAsync(modelName, userInput);

Console.WriteLine("Agent:");

await foreach (var response in enumerable)

{

Console.Write($"{response.Response}");

}

Console.WriteLine();

} while (!string.Equals(userInput, "exit", StringComparison.OrdinalIgnoreCase));

Console.WriteLine("对话结束!!!");



**[^2^]


  * **多轮对话** :使用 Chat 对象进行分角色的多轮对话,通过 List 消息存储之前的对话记录,以便模型捕获上下文,代码示例:

**```csharp

string modelName = "glm4:9b";

using var ollama = new OllamaApiClient(baseUri: new Uri("http://127.0.0.1:11434/api"));

Console.WriteLine("开始对话!!!");

string userInput = "";

List messages = [];

do

{

    messages = messages.TakeLast(5).ToList();

    Console.WriteLine("User:");

    userInput = Console.ReadLine()!;

    messages.Add(new Message(MessageRole.User, userInput));

    var enumerable = ollama.Chat.GenerateChatCompletionAsync(modelName, messages, stream: true);

    Console.WriteLine("Agent:");

    StringBuilder builder = new();

    await foreach (var response in enumerable)

    {

        string content = response.Message.Content;

        builder.AppendLine(content);

        Console.Write(content);

    }

    messages.Add(new Message(MessageRole.Assistant, builder.ToString()));

    Console.WriteLine();

} while (!string.Equals(userInput, "exit", StringComparison.OrdinalIgnoreCase));

Console.WriteLine("对话结束!!!");



```**[^2^]


  * **Function call** :若要使用 function call 功能,需设置 autoCallTools 为 true,并给 Ollama 注册相应的工具类,代码如下:

**```csharp

string modelName = "llama3.1:8b";

using var ollama = new OllamaApiClient(baseUri: new Uri("http://127.0.0.1:11434/api"));

var chat = ollama.Chat(

    model: modelName,

    systemMessage: "You are a helpful assistant.",

    autoCallTools: true);

var mathService = new MathService();

chat.AddToolService(mathService.AsTools(), mathService.AsCalls());

while (true)

{

    try

    {

        Console.WriteLine("User>");

        var newMessage = Console.ReadLine();

        var msg = await chat.SendAsync(newMessage);

        Console.WriteLine("Agent> " + msg.Content);

    }

    finally

    {

        Console.WriteLine(chat.PrintMessages());

    }

}

```**[^2^]


### 调用 MCP

目前未查到有成熟的 C# 调用 MCP 的官方 SDK 或常用库,但可以尝试以下思路:

  * **通过 HTTP 请求调用** :如果 MCP 提供了 HTTP API 接口,可以使用 C# 中的 HttpClient 类来发送 HTTP 请求进行调用。基本步骤如下:

    1. 创建 HttpClient 对象,并设置相关请求头等信息。

    2. 构造请求内容,根据 MCP API 的要求,将请求参数进行序列化。

    3. 发送 POST 或 GET 等请求到 MCP 的 API 地址。

    4. 处理返回的响应,对响应内容进行反序列化等操作,获取所需数据。


例如,假设 MCP 的 API 地址为<http://localhost:8000/mcp/api>,需要发送一个获取数据的请求,代码可能如下:

**```csharp

using (var client = new HttpClient())

{

    client.BaseAddress = new Uri("http://localhost:8000/");

    var response = await client.GetAsync("mcp/api?param1=value1");

    if (response.IsSuccessStatusCode)

    {

        var result = await response.Content.ReadAsStringAsync();

        // 处理结果

    }

    else

    {

        // 处理错误

    }

}

```**

  * **参考 Python 实现进行移植** :上述提到的 Python 调用 MCP 的代码示例中,展示了如何创建 MCP Server、获取工具列表以及创建 Agent 等过程。可以参考其逻辑和交互方式,在 C# 中进行相应的实现。例如,对于 MCP Server 的连接,可以考虑在 C# 中使用类似的网络通信方式;对于工具的调用,可以解析 MCP 返回的工具信息,并根据用户输入的问题,选择合适的工具进行调用等[^4^]。


MathService代码:

using System;

using System.Collections.Generic;

using System.Linq;


// 定义工具接口

public interface IToolsService

{

    public string Name { get; }

    public List<ToolDefinition> DefineTools();

}


// 定义工具函数

public class MathService : IToolsService

{

    public string Name => "math";

    

    // 定义工具

    public List<ToolDefinition> DefineTools()

    {

        return new List<ToolDefinition>

        {

            new ToolDefinition("add", "Add two numbers", "a: number, b: number", Add),

            new ToolDefinition("subtract", "Subtract two numbers", "a: number, b: number", Subtract),

            new ToolDefinition("multiply", "Multiply two numbers", "a: number, b: number", Multiply),

            new ToolDefinition("divide", "Divide two numbers", "a: number, b: number", Divide)

        };

    }


    // 加法

    public double Add(double a, double b)

    {

        return a + b;

    }


    // 减法

    public double Subtract(double a, double b)

    {

        return a - b;

    }


    // 乘法

    public double Multiply(double a, double b)

    {

        return a * b;

    }


    // 除法

    public double Divide(double a, double b)

    {

        if (b == 0)

        {

            throw new DivideByZeroException("Division by zero is not allowed.");

        }

        return a / b;

    }

}



ToolDefinition类通常不是.NET标准库或框架的一部分,也不是Ollama或其他主流库的内置类。因此,您需要自己定义它,或者参考您所使用的特定库或框架的实现

using System;


public class ToolDefinition

{

    // 工具名称

    public string Name { get; set; }

    // 工具描述

    public string Description { get; set; }

    // 工具参数列表

    public string Parameters { get; set; }

    // 工具处理函数的委托类型

    public Func<object[], object> Function { get; set; }


    public ToolDefinition(string name, string description, string parameters, Func<object[], object> function)

    {

        Name = name;

        Description = description;

        Parameters = parameters;

        Function = function;

    }

}



Chrome MCP Server

点击进入源码页

Chrome MCP Server 是一个基于chrome插件的 模型上下文协议 (MCP) 服务器,它将您的 Chrome 浏览器功能暴露给 Claude 等 AI 助手,实现复杂的浏览器自动化、内容分析和语义搜索等。与传统的浏览器自动化工具(如playwright)不同,Chrome MCP server直接使用您日常使用的chrome浏览器,基于现有的用户习惯和配置、登录态,让各种大模型或者各种chatbot都可以接管你的浏览器,真正成为你的如常助手


环境要求

Node.js >= 18.19.0 和 (npm 或 pnpm)

Chrome/Chromium 浏览器

安装pnpm :npm install -g pnpm

安装步骤

1.从github上下载最新的chrome扩展

下载地址:https://github.com/hangwin/mcp-chrome/releases


2.全局安装mcp-chrome-bridge

npm


npm install -g mcp-chrome-bridge

pnpm


# 方法1:全局启用脚本(推荐)

pnpm config set enable-pre-post-scripts true

pnpm install -g mcp-chrome-bridge


# 方法2:如果 postinstall 没有运行,手动注册

pnpm install -g mcp-chrome-bridge

mcp-chrome-bridge register

注意:pnpm v7+ 默认禁用 postinstall 脚本以提高安全性。enable-pre-post-scripts 设置控制是否运行 pre/post 安装脚本。如果自动注册失败,请使用上述手动注册命令。


3.加载 Chrome 扩展


打开 Chrome 并访问 chrome://extensions/

启用"开发者模式"

点击"加载已解压的扩展程序",选择 your/dowloaded/extension/folder

点击插件图标打开插件,点击连接即可看到mcp的配置


在支持MCP协议的客户端中使用

使用streamable http的方式连接(👍🏻推荐)

将以下配置添加到客户端的 MCP 配置中以cherryStudio为例:


推荐用streamable http的连接方式


{

  "mcpServers": {

    "chrome-mcp-server": {

      "type": "streamableHttp",

      "url": "http://127.0.0.1:12306/mcp"

    }

  }

}

使用stdio的方式连接(备选)

假设你的客户端仅支持stdio的连接方式,那么请使用下面的方法:


1.先查看你刚刚安装的npm包的安装位置

# npm 查看方式

npm list -g mcp-chrome-bridge

# pnpm 查看方式

pnpm list -g mcp-chrome-bridge

假设上面的命令输出的路径是:/Users/xxx/Library/pnpm/global/5 那么你的最终路径就是:/Users/xxx/Library/pnpm/global/5/node_modules/mcp-chrome-bridge/dist/mcp/mcp-server-stdio.js


2.把下面的配置替换成你刚刚得到的最终路径

{

  "mcpServers": {

    "chrome-mcp-stdio": {

      "command": "npx",

      "args": [

        "node",

        "/Users/xxx/Library/pnpm/global/5/node_modules/mcp-chrome-bridge/dist/mcp/mcp-server-stdio.js"

      ]

    }

  }

}


mcp2mqtt动动嘴就可以控制智能家居

点击进入开源地址

本项目通过将 MCP 协议转换为 MQTT 协议,我们能够利用强大的大型语言模型(LLMs),就能轻松操控您的智能家居、机器人或其他硬件设备。



excel-mcp-server使用 AI 代理创建、读取和修改 Excel 工作簿

点击查看源码

模型上下文协议 (MCP) 服务器,无需安装 Microsoft Excel 即可作 Excel 文件。使用 AI 代理创建、读取和修改 Excel 工作簿。

Excel 作 :创建、读取、更新工作簿和工作表

数据作 :公式、格式、图表、数据透视表和 Excel 表格

数据验证 :内置范围、公式和数据完整性验证

格式: 字体样式、颜色、边框、对齐方式和条件格式

表格作 :使用自定义样式创建和管理 Excel 表格

图表创建 :生成各种图表类型(折线图、条形图、饼图、散点图等)

数据透视表 :创建用于数据分析的动态数据透视表

工作表管理 :轻松复制、重命名、删除工作表

三重传输支持 :stdio、SSE(已弃用)和可流式传输的 HTTP

远程和本地 :既可以在本地工作,也可以作为远程服务工作



Trae+Chrome MCP Server 让AI接管你的浏览器

点击查看原文


一、安装与配置

环境准备

Node.js ≥ 18.19.0 + npm

Chrome/Chromium 浏览器

快速部署和使用

1、安装Chrome扩展插件

        从 GitHub Releases 下载最新扩展包,在 chrome://extensions 中启用开发者模式并加载解压的文件夹。


2、安装桥接工具

npm install -g mcp-chrome-bridge

AI写代码

    若自动注册失败,需手动执行 mcp-chrome-bridge register。


3、打开Chrome浏览器,点击扩展程序进入配置页

1.png


4、点击连接

1.png


5、打开Trae客户端,进入MCP管理页

1.png


6、添加MCP服务

{

  "mcpServers": {

    "chrome-mcp-server": {

      "type": "streamableHttp",

      "url": "http://127.0.0.1:12306/mcp"

    }

  }

}

AI写代码

7、MCP服务需要添加到智能体才可以在Trae内使用,进入智能体管理页面

1.png


8、配置智能体,勾选刚刚配置的MCP服务

1.png


9、在Trae的对话界面选择智能体就可以对话,让浏览器帮你干活啦

1.png


二、应用场景

内容创作

        AI 自动总结网页内容 → 调用 Excalidraw 绘制思维导图。


竞品监控

        定时截图竞品网站首页,对比分析布局更新。


工作流优化

        自动填写表单、批量关闭冗余标签页、整理书签。


开发调试

        网络请求拦截与 API 结构分析。


Windows MCP.Net基于 .NET 的 Windows 桌面自动化 MCP (Model Context Protocol) 服务器

点击进入源码页


一个基于 .NET 的 Windows 桌面自动化 MCP (Model Context Protocol) 服务器,为 AI 助手提供与 Windows 桌面环境交互的能力。

重要提示: 本项目需要 .NET 10 才能运行,请先确保你的本地安装了 .NET 10。如果尚未安装,请访问 .NET 10 下载页面 进行下载和安装。


1. MCP 客户端配置

在您的 MCP 客户端配置中添加以下配置:


使用全局安装的工具(推荐)

{

    "mcpServers": {

     "Windows-MCP.Net": {

      "type": "stdio",

      "command": "dnx",

      "args": ["Windows-MCP.Net@", "--yes"],

      "env": {}

    }

    }

}

使用项目源码直接运行(开发模式)

方式一:工作区配置

在项目根目录创建 .vscode/mcp.json 文件:


{

  "mcpServers": {

    "Windows-MCP.Net-Dev": {

      "type": "stdio",

      "command": "dotnet",

      "args": ["run", "--project", "src/Windows-MCP.Net.csproj"],

      "cwd": "${workspaceFolder}",

      "env": {}

    }

  }

}

方式二:用户配置

通过VS Code命令面板运行 MCP: Open User Configuration,添加:


{

  "mcpServers": {

    "Windows-MCP.Net-Local": {

      "type": "stdio",

      "command": "dotnet",

      "args": ["run", "--project", "src/Windows-MCP.Net.csproj"],

      "env": {}

    }

  }

}

注意: 使用项目源码方式便于开发调试,修改代码后无需重新安装即可生效。VS Code 1.102+ 版本支持MCP服务器的自动发现和管理。


2. 安装和运行

方式一:全局安装(推荐)

dotnet tool install --global WindowsMCP.Net

方式二:从源码运行

# 克隆仓库

git clone https://github.com/AIDotNet/Windows-MCP.Net.git

cd Windows-MCP.Net

# 构建项目

dotnet build

# 运行项目

dotnet run --project src/Windows-MCP.Net.csproj

3. 开始使用

配置完成后,重启您的MCP客户端,即可开始使用Windows桌面自动化功能!



Windows-MCP用于 Windows 计算机的轻量级 MCP 服务器

点击查看源码


"mcpServers": {

    "windows-mcp": {

      "command": "uv",

      "args": [

        "--directory",

        "<path to the windows-mcp directory>",

        "run",

        "main.py"

      ]

    }

  }



详细介绍NPX或UVX配置MCP服务


要使用 npx 或 uvx 配置和运行 MCP(Model Context Protocol)服务,需结合具体的 MCP 服务实现工具(通常是 Node.js 或 Python 生态的包)。以下是详细步骤和说明:

一、背景知识

npx:Node.js 生态的包执行工具,可直接运行 npm 仓库中的包(无需全局安装),适用于 Node.js 编写的 MCP 服务。

uvx:Rust 编写的快速 Python 包执行工具(类似 npx,属于 uv 包管理器的一部分),适用于 Python 编写的 MCP 服务。

MCP 服务:需遵循 MCP 协议(如可流式 HTTP 传输),提供标准化的客户端 - 服务器通信能力(如模型上下文管理、消息流式传输等)。

二、使用 npx 配置 Node.js 版 MCP 服务

若 MCP 服务基于 Node.js 实现(如 @mcp/server 等包),步骤如下:

1. 安装 Node.js 和 npm

确保环境中已安装 Node.js(含 npm),推荐版本 16+。

验证:node -v 和 npm -v 可正常输出版本号。

2. 直接运行 MCP 服务包

使用 npx 临时执行 MCP 服务包,无需提前安装。基本命令格式:


bash

npx [mcp-package-name] [配置参数]

3. 常见配置参数(以假设的 @mcp/server 为例)

MCP 服务通常支持通过命令行参数或环境变量配置核心功能,例如:


bash

# 启动 MCP 服务,指定端口、端点路径和允许的 Origin

npx @mcp/server \

  --port 8080 \                 # 服务端口(默认可能为 65432)

  --endpoint /mcp \             # MCP 端点路径(符合协议要求的单一端点)

  --allowed-origins "http://localhost:3000" \  # 允许的客户端 Origin(防 DNS 重绑定)

  --log-level info \            # 日志级别

  --session-timeout 3600        # 会话超时时间(秒)

4. 环境变量配置

部分参数可通过环境变量设置(优先级可能高于命令行):


bash

# 示例:通过环境变量配置

export MCP_PORT=8080

export MCP_ALLOWED_ORIGINS="http://localhost:3000,https://example.com"

npx @mcp/server  # 自动读取环境变量

5. 验证服务是否启动

服务启动后,可通过 curl 测试端点是否可用:


bash

curl http://localhost:8080/mcp -I  # 检查是否返回 200 或 405(允许 POST/GET)

三、使用 uvx 配置 Python 版 MCP 服务

若 MCP 服务基于 Python 实现(如 mcp-server 等包),步骤如下:

1. 安装 uv 包管理器

uvx 是 uv 的子命令,需先安装 uv:

bash

# 安装 uv(适用于 Linux/macOS,Windows 需调整)

curl -LsSf https://astral.sh/uv/install.sh | sh


验证:uv --version 和 uvx --version 可正常输出。

2. 直接运行 MCP 服务包

使用 uvx 执行 Python 版 MCP 服务,命令格式:


bash

uvx [mcp-package-name] [配置参数]

3. 常见配置参数(以假设的 mcp-server 为例)

Python 版 MCP 服务的配置参数与 Node.js 版类似,例如:


bash

# 启动 MCP 服务,配置核心参数

uvx mcp-server \

  --host 127.0.0.1 \            # 绑定本地地址(符合安全要求,避免暴露公网)

  --port 8080 \

  --endpoint /mcp \

  --cors-allowed-origins "http://localhost:3000" \  # CORS 配置(对应 Origin 验证)

  --enable-sse true             # 启用 SSE 流式传输(符合可流式 HTTP 要求)

4. 配置文件方式

复杂配置可通过 JSON 或 YAML 文件指定,例如:


bash

# 使用配置文件启动

uvx mcp-server --config ./mcp-config.json


mcp-config.json 示例:


json

{

  "port": 8080,

  "endpoint": "/mcp",

  "allowed_origins": ["http://localhost:3000"],

  "session": {

    "timeout": 3600,

    "auto_create": true

  }

}

5. 验证服务

同 Node.js 版,通过 curl 测试:


bash

curl http://localhost:8080/mcp -X POST \

  -H "Content-Type: application/json" \

  -d '{"jsonrpc": "2.0", "method": "initialize", "id": 1}'


四、核心配置项说明(符合 MCP 协议要求)

无论使用 npx 还是 uvx,MCP 服务的配置需满足协议规范:


端点路径:必须提供单一 HTTP 端点(如 /mcp),支持 POST(客户端发消息)和 GET(SSE 流)。

安全验证:

必须验证客户端的 Origin 头(通过 allowed-origins 配置)。

本地运行时绑定 127.0.0.1(而非 0.0.0.0),避免未授权访问。

会话管理:支持通过 Mcp-Session-Id 头管理会话,需配置会话超时时间。

流式传输:启用 SSE(text/event-stream)支持服务器向客户端流式发送消息。

五、总结

npx 适用于 Node.js 生态的 MCP 服务,直接运行 npm 包并通过命令行 / 环境变量配置。

uvx 适用于 Python 生态的 MCP 服务,依赖 uv 工具,支持配置文件和参数化启动。

核心是确保配置符合 MCP 协议(如端点、安全验证、流式传输),具体参数需参考所用 MCP 服务包的文档。


npx 的核心作用是 无需全局安装包,直接执行对应 MCP 工具的可执行文件。

例子 1:通用 TCP 控制型 MCP 服务(基于 mcp-server)

场景

搭建简单的 MCP 服务,实现「客户端 → MCP 服务 → 目标服务器」的 TCP 连接转发,并支持连接数限制、日志输出等基础控制。

完整 npx 命令

npx mcp-server@latest \

  --protocol tcp \

  --listen-port 8080 \

  --listen-host 0.0.0.0 \

  --target-host 192.168.1.100 \

  --target-port 9090 \

  --log-level info \

  --max-connections 50 \

  --timeout 30000


mcp-server@latest 包名 + 版本 如 @1.2.0(固定版) 指定要执行的 MCP 服务包,@latest 表示使用最新版本,生产环境建议固定版本(如 @1.2.0)。


例子 2:本地自定义 MCP 服务(基于项目依赖 mcp-cli)

场景

本地 Node.js 项目中已将 mcp-cli 作为开发依赖(npm install mcp-cli --save-dev),通过 npx 直接执行本地依赖的 MCP 工具,加载自定义配置文件启动服务(适合企业内部定制化 MCP 服务,如设备管理、数据采集)。

完整 npx 命令

bash

npx mcp-cli start \

  --config ./config/mcp-service.yaml \

  --env production \

  --port 8888 \

  --watch \

  --debug \

  --log-rotate 7


mcp-cli start包名 + 命令无默认值mcp-cli 是本地项目依赖的 MCP 管理工具,start 是其内置命令(表示 “启动 MCP 服务”)。



CherryStudio的MCP配置

点击查看官方配置MCP文档

手动配置一个STADIO MCP

一个STATIO MCP配置例子,它的源码地址

1.jpg


它的uvx的json

{

  "mcpServers": {

    "fetch": {

      "command": "uvx",

      "args": ["mcp-server-fetch"]

    }

  }

}


多参数配置,一行一个参数

1.jpg


自动安装MCP

直接给指令:

帮我安装一个 filesystem mcp server



AI辅助生成MCP例子

####【豆包】


你知道AI模型调用MCP吗??

。。。

写一个MCP的完整例子并给出模型调用这个MCP例子

。。。


Python实现
mcp_weather_server.py

import json

import socket

import threading

from typing import Dict, Any


class MCPWeatherServer:

    """MCP天气服务服务器实现"""

    

    def __init__(self, host: str = 'localhost', port: int = 8000):

        self.host = host

        self.port = port

        self.server_socket = None

        self.running = False

        

        # 模拟天气数据库

        self.weather_database = {

            "北京": {"temperature": 25, "condition": "晴朗", "wind": "微风"},

            "上海": {"temperature": 28, "condition": "多云", "wind": "东风3级"},

            "广州": {"temperature": 30, "condition": "小雨", "wind": "南风2级"},

            "深圳": {"temperature": 29, "condition": "阴天", "wind": "东南风1级"},

            "成都": {"temperature": 23, "condition": "晴转多云", "wind": "西北风2级"}

        }

    

    def start(self):

        """启动MCP服务器"""

        self.running = True

        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        self.server_socket.bind((self.host, self.port))

        self.server_socket.listen(5)

        print(f"MCP天气服务已启动,监听 {self.host}:{self.port}")

        

        try:

            while self.running:

                client_socket, client_address = self.server_socket.accept()

                print(f"接收到来自 {client_address} 的连接")

                client_handler = threading.Thread(

                    target=self.handle_client,

                    args=(client_socket,)

                )

                client_handler.start()

        except KeyboardInterrupt:

            print("服务器正在关闭...")

        finally:

            self.stop()

    

    def stop(self):

        """停止MCP服务器"""

        self.running = False

        if self.server_socket:

            self.server_socket.close()

        print("MCP天气服务已关闭")

    

    def handle_client(self, client_socket: socket.socket):

        """处理客户端请求"""

        try:

            # 接收请求数据

            data = client_socket.recv(1024).decode('utf-8')

            if not data:

                return

                

            print(f"收到请求: {data}")

            

            # 解析MCP请求

            request = json.loads(data)

            

            # 处理请求

            response = self.process_request(request)

            

            # 发送响应

            client_socket.sendall(json.dumps(response).encode('utf-8'))

            print(f"发送响应: {response}")

            

        except Exception as e:

            error_response = {

                "jsonrpc": "2.0",

                "error": {

                    "code": -1,

                    "message": f"处理请求时出错: {str(e)}"

                },

                "id": request.get("id") if 'request' in locals() else None

            }

            client_socket.sendall(json.dumps(error_response).encode('utf-8'))

        finally:

            client_socket.close()

    

    def process_request(self, request: Dict[str, Any]) -> Dict[str, Any]:

        """处理MCP请求"""

        # 验证请求格式

        if "jsonrpc" not in request or request["jsonrpc"] != "2.0":

            return {

                "jsonrpc": "2.0",

                "error": {"code": -32600, "message": "无效的请求"},

                "id": request.get("id")

            }

            

        if "method" not in request:

            return {

                "jsonrpc": "2.0",

                "error": {"code": -32601, "message": "方法不存在"},

                "id": request.get("id")

            }

        

        # 处理天气查询方法

        if request["method"] == "get_weather":

            params = request.get("params", {})

            city = params.get("city")

            

            if not city:

                return {

                    "jsonrpc": "2.0",

                    "error": {"code": -32602, "message": "缺少城市参数"},

                    "id": request.get("id")

                }

            

            # 查询天气数据

            weather_data = self.weather_database.get(city)

            if weather_data:

                return {

                    "jsonrpc": "2.0",

                    "result": {

                        "city": city,

                        "weather": weather_data,

                        "source": "MCP Weather Service"

                    },

                    "id": request.get("id")

                }

            else:

                return {

                    "jsonrpc": "2.0",

                    "error": {"code": 404, "message": f"未找到城市 {city} 的天气数据"},

                    "id": request.get("id")

                }

        

        # 处理服务描述方法

        elif request["method"] == "describe":

            return {

                "jsonrpc": "2.0",

                "result": {

                    "name": "WeatherService",

                    "description": "提供城市天气查询服务",

                    "methods": {

                        "get_weather": {

                            "description": "获取指定城市的天气信息",

                            "parameters": {

                                "city": {

                                    "type": "string",

                                    "description": "城市名称"

                                }

                            },

                            "returns": {

                                "type": "object",

                                "description": "包含温度、天气状况和风力的天气信息"

                            }

                        }

                    }

                },

                "id": request.get("id")

            }

        

        # 未知方法

        else:

            return {

                "jsonrpc": "2.0",

                "error": {"code": -32601, "message": f"方法 {request['method']} 不存在"},

                "id": request.get("id")

            }


if __name__ == "__main__":

    # 创建并启动MCP服务器

    server = MCPWeatherServer(host='localhost', port=8000)

    server.start()


mcp_client.py

import json

import socket

from typing import Dict, Any, Optional


class MCPClient:

    """MCP客户端,用于与MCP服务器通信"""

    

    def __init__(self, host: str = 'localhost', port: int = 8000):

        self.host = host

        self.port = port

        self.request_id = 0

    

    def _get_next_id(self) -> int:

        """获取下一个请求ID"""

        self.request_id += 1

        return self.request_id

    

    def send_request(self, method: str, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:

        """发送MCP请求到服务器"""

        # 创建请求

        request = {

            "jsonrpc": "2.0",

            "method": method,

            "id": self._get_next_id()

        }

        

        if params is not None:

            request["params"] = params

        

        # 建立连接并发送请求

        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:

            s.connect((self.host, self.port))

            s.sendall(json.dumps(request).encode('utf-8'))

            

            # 接收响应

            response_data = s.recv(1024).decode('utf-8')

            if not response_data:

                return {"error": "未收到响应"}

                

            return json.loads(response_data)

    

    def describe_service(self) -> Dict[str, Any]:

        """获取服务描述信息"""

        return self.send_request("describe")

    

    def get_weather(self, city: str) -> Dict[str, Any]:

        """查询指定城市的天气"""

        return self.send_request("get_weather", {"city": city})


# 模型调用MCP服务的示例

def model_use_mcp_service():

    """模拟AI模型使用MCP服务的过程"""

    print("=== AI模型开始运行 ===")

    

    # 1. 创建MCP客户端

    print("创建MCP客户端,准备连接天气服务...")

    client = MCPClient(host='localhost', port=8000)

    

    # 2. 先查询服务描述,了解可用功能

    print("\n查询MCP服务描述...")

    description = client.describe_service()

    print(f"服务描述: {json.dumps(description, ensure_ascii=False, indent=2)}")

    

    # 3. 根据服务描述,调用天气查询功能

    target_city = "北京"

    print(f"\n调用MCP服务查询 {target_city} 的天气...")

    weather_result = client.get_weather(target_city)

    

    # 4. 处理返回结果

    print(f"天气查询结果: {json.dumps(weather_result, ensure_ascii=False, indent=2)}")

    

    # 5. 根据结果生成回答

    if "result" in weather_result:

        weather_data = weather_result["result"]["weather"]

        response = (f"{target_city}当前的天气状况为:{weather_data['condition']},"

                   f"气温{weather_data['temperature']}°C,{weather_data['wind']}。")

    else:

        response = f"抱歉,无法获取{target_city}的天气信息:{weather_result.get('error', {}).get('message', '未知错误')}"

    

    print(f"\n=== AI模型生成回答 ===")

    print(response)


if __name__ == "__main__":

    # 模拟模型调用MCP服务

    model_use_mcp_service()


C#实现

Models.cs  

using System;

using System.Collections.Generic;

using System.Text.Json.Serialization;


namespace McpCommon

{

    /// <summary>

    /// MCP请求模型

    /// </summary>

    public class McpRequest

    {

        [JsonPropertyName("jsonrpc")]

        public string JsonRpc { get; set; } = "2.0";

        

        [JsonPropertyName("method")]

        public string Method { get; set; }

        

        [JsonPropertyName("params")]

        public Dictionary<string, object> Parameters { get; set; }

        

        [JsonPropertyName("id")]

        public int Id { get; set; }

    }

    

    /// <summary>

    /// MCP响应模型

    /// </summary>

    public class McpResponse

    {

        [JsonPropertyName("jsonrpc")]

        public string JsonRpc { get; set; } = "2.0";

        

        [JsonPropertyName("result")]

        public object Result { get; set; }

        

        [JsonPropertyName("error")]

        public McpError Error { get; set; }

        

        [JsonPropertyName("id")]

        public int Id { get; set; }

    }

    

    /// <summary>

    /// MCP错误模型

    /// </summary>

    public class McpError

    {

        [JsonPropertyName("code")]

        public int Code { get; set; }

        

        [JsonPropertyName("message")]

        public string Message { get; set; }

    }

    

    /// <summary>

    /// 天气数据模型

    /// </summary>

    public class WeatherData

    {

        public string City { get; set; }

        public string Condition { get; set; }

        public int Temperature { get; set; }

        public string Wind { get; set; }

        public DateTime UpdateTime { get; set; }

    }

    

    /// <summary>

    /// 服务描述模型

    /// </summary>

    public class ServiceDescription

    {

        public string Name { get; set; }

        public string Description { get; set; }

        public string Version { get; set; }

        public List<ServiceMethod> Methods { get; set; } = new List<ServiceMethod>();

    }

    

    /// <summary>

    /// 服务方法描述

    /// </summary>

    public class ServiceMethod

    {

        public string Name { get; set; }

        public string Description { get; set; }

        public List<MethodParameter> Parameters { get; set; } = new List<MethodParameter>();

    }

    

    /// <summary>

    /// 方法参数描述

    /// </summary>

    public class MethodParameter

    {

        public string Name { get; set; }

        public string Type { get; set; }

        public string Description { get; set; }

        public bool Required { get; set; }

    }

}

    

MCPServer.cs

using System;

using System.Collections.Generic;

using System.Net;

using System.Net.Sockets;

using System.Text;

using System.Text.Json;

using System.Threading;

using McpCommon;


namespace McpServer

{

    class Program

    {

        private static TcpListener _server;

        private static bool _isRunning;

        private static readonly Dictionary<string, WeatherData> _mockWeatherData = new Dictionary<string, WeatherData>

        {

            { "北京", new WeatherData { City = "北京", Condition = "晴朗", Temperature = 25, Wind = "微风", UpdateTime = DateTime.Now } },

            { "上海", new WeatherData { City = "上海", Condition = "多云", Temperature = 28, Wind = "东风3级", UpdateTime = DateTime.Now } },

            { "广州", new WeatherData { City = "广州", Condition = "小雨", Temperature = 30, Wind = "南风2级", UpdateTime = DateTime.Now } },

            { "深圳", new WeatherData { City = "深圳", Condition = "阴天", Temperature = 29, Wind = "东北风1级", UpdateTime = DateTime.Now } }

        };


        static void Main(string[] args)

        {

            StartServer();

            

            Console.WriteLine("MCP天气服务已启动,按任意键停止...");

            Console.ReadKey();

            

            StopServer();

        }


        private static void StartServer()

        {

            int port = 8000;

            _server = new TcpListener(IPAddress.Any, port);

            _server.Start();

            _isRunning = true;

            

            Console.WriteLine($"MCP服务器已启动,监听端口 {port}...");

            

            // 启动一个线程处理客户端连接

            new Thread(ListenForClients) { IsBackground = true }.Start();

        }


        private static void StopServer()

        {

            _isRunning = false;

            _server.Stop();

            Console.WriteLine("MCP服务器已停止");

        }


        private static void ListenForClients()

        {

            while (_isRunning)

            {

                try

                {

                    // 等待客户端连接

                    TcpClient client = _server.AcceptTcpClient();

                    Console.WriteLine("新客户端连接");

                    

                    // 为每个客户端创建一个线程处理

                    new Thread(HandleClient) { IsBackground = true }.Start(client);

                }

                catch (SocketException ex)

                {

                    if (_isRunning)

                    {

                        Console.WriteLine($"Socket错误: {ex.Message}");

                    }

                }

                catch (Exception ex)

                {

                    Console.WriteLine($"错误: {ex.Message}");

                }

            }

        }


        private static void HandleClient(object obj)

        {

            using (TcpClient client = (TcpClient)obj)

            using (NetworkStream stream = client.GetStream())

            {

                byte[] buffer = new byte[1024];

                int bytesRead;

                

                try

                {

                    // 读取客户端发送的数据

                    while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)

                    {

                        string requestString = Encoding.UTF8.GetString(buffer, 0, bytesRead);

                        Console.WriteLine($"收到请求: {requestString}");

                        

                        // 解析请求

                        McpRequest request = JsonSerializer.Deserialize<McpRequest>(requestString);

                        McpResponse response = ProcessRequest(request);

                        

                        // 发送响应

                        string responseString = JsonSerializer.Serialize(response);

                        byte[] responseBytes = Encoding.UTF8.GetBytes(responseString);

                        stream.Write(responseBytes, 0, responseBytes.Length);

                        

                        Console.WriteLine($"发送响应: {responseString}");

                    }

                }

                catch (Exception ex)

                {

                    Console.WriteLine($"处理客户端时出错: {ex.Message}");

                }

                

                Console.WriteLine("客户端连接已关闭");

            }

        }


        private static McpResponse ProcessRequest(McpRequest request)

        {

            var response = new McpResponse { Id = request.Id };

            

            try

            {

                switch (request.Method)

                {

                    case "describe":

                        response.Result = GetServiceDescription();

                        break;

                        

                    case "get_weather":

                        if (request.Parameters != null && request.Parameters.ContainsKey("city"))

                        {

                            string city = request.Parameters["city"].ToString();

                            response.Result = new { weather = GetWeatherData(city) };

                        }

                        else

                        {

                            response.Error = new McpError { Code = -1, Message = "缺少参数: city" };

                        }

                        break;

                        

                    default:

                        response.Error = new McpError { Code = -2, Message = $"未知方法: {request.Method}" };

                        break;

                }

            }

            catch (Exception ex)

            {

                response.Error = new McpError { Code = -999, Message = ex.Message };

            }

            

            return response;

        }


        private static ServiceDescription GetServiceDescription()

        {

            return new ServiceDescription

            {

                Name = "WeatherService",

                Description = "提供城市天气查询服务",

                Version = "1.0.0",

                Methods = new List<ServiceMethod>

                {

                    new ServiceMethod

                    {

                        Name = "describe",

                        Description = "获取服务描述信息",

                        Parameters = new List<MethodParameter>()

                    },

                    new ServiceMethod

                    {

                        Name = "get_weather",

                        Description = "查询指定城市的天气信息",

                        Parameters = new List<MethodParameter>

                        {

                            new MethodParameter

                            {

                                Name = "city",

                                Type = "string",

                                Description = "城市名称",

                                Required = true

                            }

                        }

                    }

                }

            };

        }


        private static WeatherData GetWeatherData(string city)

        {

            if (_mockWeatherData.TryGetValue(city, out var weatherData))

            {

                // 更新时间为当前时间

                weatherData.UpdateTime = DateTime.Now;

                return weatherData;

            }

            

            // 如果没有该城市的数据,返回一个默认值

            return new WeatherData

            {

                City = city,

                Condition = "未知",

                Temperature = 0,

                Wind = "未知",

                UpdateTime = DateTime.Now

            };

        }

    }

}

    

MCPClient.cs

using System;

using System.Collections.Generic;

using System.Net.Sockets;

using System.Text;

using System.Text.Json;

using McpCommon;


namespace McpClient

{

    class McpClient

    {

        private readonly string _host;

        private readonly int _port;

        private int _requestId;


        public McpClient(string host = "localhost", int port = 8000)

        {

            _host = host;

            _port = port;

            _requestId = 0;

        }


        private int GetNextRequestId()

        {

            return ++_requestId;

        }


        public McpResponse SendRequest(string method, Dictionary<string, object> parameters = null)

        {

            var request = new McpRequest

            {

                Method = method,

                Parameters = parameters,

                Id = GetNextRequestId()

            };


            try

            {

                using (var client = new TcpClient(_host, _port))

                using (var stream = client.GetStream())

                {

                    // 发送请求

                    string requestString = JsonSerializer.Serialize(request);

                    byte[] requestBytes = Encoding.UTF8.GetBytes(requestString);

                    stream.Write(requestBytes, 0, requestBytes.Length);

                    

                    // 接收响应

                    byte[] buffer = new byte[1024];

                    int bytesRead = stream.Read(buffer, 0, buffer.Length);

                    string responseString = Encoding.UTF8.GetString(buffer, 0, bytesRead);

                    

                    return JsonSerializer.Deserialize<McpResponse>(responseString);

                }

            }

            catch (Exception ex)

            {

                return new McpResponse

                {

                    Id = request.Id,

                    Error = new McpError { Code = -999, Message = $"通信错误: {ex.Message}" }

                };

            }

        }


        public ServiceDescription DescribeService()

        {

            var response = SendRequest("describe");

            if (response.Error != null)

            {

                throw new Exception($"获取服务描述失败: {response.Error.Message}");

            }

            

            return JsonSerializer.Deserialize<ServiceDescription>(JsonSerializer.Serialize(response.Result));

        }


        public WeatherData GetWeather(string city)

        {

            var parameters = new Dictionary<string, object>

            {

                { "city", city }

            };

            

            var response = SendRequest("get_weather", parameters);

            if (response.Error != null)

            {

                throw new Exception($"获取天气失败: {response.Error.Message}");

            }

            

            // 解析嵌套的结果

            var resultDict = JsonSerializer.Deserialize<Dictionary<string, object>>(JsonSerializer.Serialize(response.Result));

            return JsonSerializer.Deserialize<WeatherData>(JsonSerializer.Serialize(resultDict["weather"]));

        }

    }


    class Program

    {

        static void Main(string[] args)

        {

            try

            {

                ModelUseMcpService();

            }

            catch (Exception ex)

            {

                Console.WriteLine($"发生错误: {ex.Message}");

            }

            

            Console.WriteLine("按任意键退出...");

            Console.ReadKey();

        }


        static void ModelUseMcpService()

        {

            Console.WriteLine("=== AI模型开始运行 ===");

            

            // 1. 创建MCP客户端

            Console.WriteLine("创建MCP客户端,准备连接天气服务...");

            var client = new McpClient("localhost", 8000);

            

            // 2. 查询服务描述,了解可用功能

            Console.WriteLine("\n查询MCP服务描述...");

            var description = client.DescribeService();

            Console.WriteLine("服务描述:");

            Console.WriteLine($"名称: {description.Name} v{description.Version}");

            Console.WriteLine($"描述: {description.Description}");

            Console.WriteLine("可用方法:");

            foreach (var method in description.Methods)

            {

                Console.WriteLine($"- {method.Name}: {method.Description}");

                foreach (var param in method.Parameters)

                {

                    Console.WriteLine($"  * {param.Name} ({param.Type}): {param.Description} {(param.Required ? "(必填)" : "")}");

                }

            }

            

            // 3. 调用天气查询功能

            string targetCity = "北京";

            Console.WriteLine($"\n调用MCP服务查询 {targetCity} 的天气...");

            var weatherData = client.GetWeather(targetCity);

            

            // 4. 处理返回结果

            Console.WriteLine("天气查询结果:");

            Console.WriteLine($"城市: {weatherData.City}");

            Console.WriteLine($"天气状况: {weatherData.Condition}");

            Console.WriteLine($"气温: {weatherData.Temperature}°C");

            Console.WriteLine($"风向风力: {weatherData.Wind}");

            Console.WriteLine($"更新时间: {weatherData.UpdateTime:yyyy-MM-dd HH:mm:ss}");

            

            // 5. 根据结果生成回答

            string response = $"{targetCity}当前的天气状况为:{weatherData.Condition},气温{weatherData.Temperature}°C,{weatherData.Wind}。";

            

            Console.WriteLine("\n=== AI模型生成回答 ===");

            Console.WriteLine(response);

        }

    }

}

    


Python编写MCP一般使用FastMCP,支持发布为studio sse streamable_http

FastMCP介绍

FastMCP官方文档

该excel-mcp-server例子的源码地址:https://github.com/haris-musa/excel-mcp-server

源码:

excel-mcp-server-main.zip


import typer

from .server import run_sse, run_stdio, run_streamable_http

app = typer.Typer(help="Excel MCP Server")


@app.command()

def sse():

    """Start Excel MCP Server in SSE mode"""

    try:

        run_sse()

    except KeyboardInterrupt:

        print("\nShutting down server...")

    except Exception as e:

        print(f"\nError: {e}")

        import traceback

        traceback.print_exc()

    finally:

        print("Service stopped.")


if __name__ == "__main__":

    app() 


这段 Python 代码是一个使用 Typer 库创建的命令行应用程序,用于启动 Excel MCP Server 的 SSE 模式服务。下面是详细讲解:

导入依赖

import typer

from .server import run_sse, run_stdio, run_streamable_http


导入了typer库,这是一个用于构建命令行界面的工具

从当前包的server模块导入了三个函数,分别对应不同的服务运行模式

创建 Typer 应用实例

app = typer.Typer(help="Excel MCP Server")


创建了一个 Typer 应用实例,help参数设置了应用的描述信息 "Excel MCP Server"

这个app对象将用于定义各种命令

定义 SSE 模式命令

@app.command()

def sse():

    """Start Excel MCP Server in SSE mode"""

    # 函数实现...



使用@app.command()装饰器定义了一个名为sse的命令

函数文档字符串描述了该命令的功能:"以 SSE 模式启动 Excel MCP 服务器"

SSE 指的是 Server-Sent Events,是一种服务器向客户端推送实时数据的技术

命令实现逻辑

try:

    run_sse()  # 尝试运行SSE模式服务

except KeyboardInterrupt:

    print("\nShutting down server...")  # 处理用户中断(如Ctrl+C)

except Exception as e:

    print(f"\nError: {e}")  # 捕获并显示其他错误

    import traceback

    traceback.print_exc()  # 打印详细的错误堆栈信息

finally:

    print("Service stopped.")  # 无论是否发生异常,最终都显示服务已停止



MCP实现部分

mcp = FastMCP(

    "excel-mcp",

    host=os.environ.get("FASTMCP_HOST", "0.0.0.0"),

    port=int(os.environ.get("FASTMCP_PORT", "8017")),

    instructions="Excel MCP Server for manipulating Excel files"

)

@mcp.tool()

def format_range(

    filepath: str,

    sheet_name: str,

    start_cell: str,

    end_cell: Optional[str] = None,

    bold: bool = False,

    italic: bool = False,

    underline: bool = False,

    font_size: Optional[int] = None,

    font_color: Optional[str] = None,

    bg_color: Optional[str] = None,

    border_style: Optional[str] = None,

    border_color: Optional[str] = None,

    number_format: Optional[str] = None,

    alignment: Optional[str] = None,

    wrap_text: bool = False,

    merge_cells: bool = False,

    protection: Optional[Dict[str, Any]] = None,

    conditional_format: Optional[Dict[str, Any]] = None

) -> str:

    """Apply formatting to a range of cells."""

    try:

        full_path = get_excel_path(filepath)

        from excel_mcp.formatting import format_range as format_range_func

        

        # Convert None values to appropriate defaults for the underlying function

        format_range_func(

            filepath=full_path,

            sheet_name=sheet_name,

            start_cell=start_cell,

            end_cell=end_cell,  # This can be None

            bold=bold,

            italic=italic,

            underline=underline,

            font_size=font_size,  # This can be None

            font_color=font_color,  # This can be None

            bg_color=bg_color,  # This can be None

            border_style=border_style,  # This can be None

            border_color=border_color,  # This can be None

            number_format=number_format,  # This can be None

            alignment=alignment,  # This can be None

            wrap_text=wrap_text,

            merge_cells=merge_cells,

            protection=protection,  # This can be None

            conditional_format=conditional_format  # This can be None

        )

        return "Range formatted successfully"

    except (ValidationError, FormattingError) as e:

        return f"Error: {str(e)}"

    except Exception as e:

        logger.error(f"Error formatting range: {e}")

        raise


1. 装饰器与函数定义

python

运行

@mcp.tool()

def format_range(...):

    """Apply formatting to a range of cells."""

    # 函数实现

@mcp.tool():这是一个自定义装饰器,推测其作用是将该函数注册为 MCP(可能是某种管理控制协议)工具集中的一个可用工具

函数名format_range清晰表明其功能:对单元格范围应用格式化

文档字符串说明了函数的核心功能:"对单元格范围应用格式化"

2. 参数解析

函数定义了多个参数,涵盖了 Excel 单元格格式化的各种常见需求:

基础定位参数(必填):

filepath: str:Excel 文件路径

sheet_name: str:工作表名称

start_cell: str:起始单元格(如 "A1")

范围扩展参数(可选):

end_cell: Optional[str] = None:结束单元格,None 表示仅格式化单个单元格

字体格式参数:

bold: bool = False:是否加粗

italic: bool = False:是否斜体

underline: bool = False:是否下划线

font_size: Optional[int] = None:字体大小

font_color: Optional[str] = None:字体颜色

单元格样式参数:

bg_color: Optional[str] = None:背景颜色

border_style: Optional[str] = None:边框样式

border_color: Optional[str] = None:边框颜色

number_format: Optional[str] = None:数字格式(如日期、货币等)

alignment: Optional[str] = None:对齐方式

wrap_text: bool = False:是否自动换行

merge_cells: bool = False:是否合并单元格

高级功能参数:

protection: Optional[Dict[str, Any]] = None:单元格保护设置

conditional_format: Optional[Dict[str, Any]] = None:条件格式设置

所有可选参数都使用了Optional类型注解并设置了默认值None,表示这些参数是可选的。

3. 函数逻辑解析

python

运行

try:

    # 获取完整的Excel文件路径

    full_path = get_excel_path(filepath)

    # 导入实际执行格式化的函数

    from excel_mcp.formatting import format_range as format_range_func

    

    # 调用实际的格式化函数,传递所有参数

    format_range_func(...)

    return "Range formatted successfully"

except (ValidationError, FormattingError) as e:

    return f"Error: {str(e)}"

except Exception as e:

    logger.error(f"Error formatting range: {e}")

    raise

函数执行流程:

首先通过get_excel_path(filepath)获取 Excel 文件的完整路径

导入实际执行格式化操作的核心函数format_range_func

调用核心函数并传递所有参数

成功时返回 "Range formatted successfully"

4. 异常处理机制

捕获ValidationError和FormattingError(特定领域异常):

这两种异常可能是格式化过程中常见的验证错误和格式错误

捕获后返回友好的错误信息

捕获通用Exception:

记录错误日志(logger.error)

重新抛出异常(raise),让上层调用者处理未预料到的错误

5. 设计特点

职责分离:该函数主要作为接口层,实际格式化逻辑在format_range_func中实现

参数透明传递:将接收的所有参数原封不动地传递给核心函数

清晰的错误处理:区分已知异常和未知异常,分别处理

灵活性:通过大量可选参数支持各种格式化需求,用户可根据需要指定

6. 使用场景推测

这个函数很可能用于 Excel 文件的自动化处理工具中,允许用户通过代码或命令行:

批量设置单元格格式

标准化 Excel 文件的样式

实现复杂的条件格式设置

集成到工作流中自动格式化报表

通过这种设计,用户可以灵活地指定需要的格式化选项,而不必关心底层 Excel 文件操作的细节。



Chrome MCP官方

{

"mcpServers":{

"chrome-devtools":{

"command":"npx",

"args":{

"chrome-devtools-mcp@latest"

}


}

}

}

源码地址: https://github.com/ChromeDevTools/chrome-devtools-mcp

AI编程学习:Chrome DevTools MCP 到底有多强?

解决登录问题(必须搞!)

因为chrome devtools 每次启动都要重新登录 。 再次感谢群里@二米 大佬的方法,不然每次登录得烦死!


我们可以执行下面的提示词,Agent 就会自动安装程序 :


# Chrome MCP 简单配置


## 🎯 目标


让Chrome MCP保持登录状态,不用每次重新登录。


## 🔧 三步搞定


### 1. 启动专用Chrome


```bash

# macOS

/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --user-data-dir="$HOME/.chrome-mcp" --remote-debugging-port=9222


# Windows

"C:\Program Files\Google\Chrome\Application\chrome.exe" --user-data-dir="%USERPROFILE%\.chrome-mcp" --remote-debugging-port=9222


```


### 2. 手动登录网站

在这个Chrome里登录小红书、微信等,设置会自动保存。


### 3. 正常使用MCP

在Claude Code里照常使用Chrome MCP功能,登录状态会保持。


## ✅ 完成

就这么简单!以后每次启动这个Chrome,登录状态都在。


**核心原理**:`--user-data-dir` 让Chrome把数据保存在专门目录,不会丢失。



大模型实战 | Dify+Chrome MCP打造网页自动化AI助手

点击查看原文

必备软件安装

1. 安装Node.js

# Windows(使用Chocolatey)

choco install nodejs


# macOS(使用Homebrew)

brew install node


# Ubuntu/Debian

curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -

sudo apt-get install -y nodejs


# CentOS/RHEL

curl -fsSL https://rpm.nodesource.com/setup_18.x | sudo bash -

sudo yum install -y nodejs


2. 验证安装

node --version  # 应显示v18.0.0或更高版本 npm --version   # 应显示npm版本信息


本地部署Chrome MCP

1. 创建项目目录


# 创建项目目录

mkdir chrome-mcp-local

cd chrome-mcp-local


# 初始化npm项目

npm init -y


2. 下载Chrome扩展程序


首先下载Chrome MCP扩展程序:


# 创建扩展程序目录

mkdir chrome-extension

cd chrome-extension


# 下载最新版本的Chrome扩展程序

# 访问 https://github.com/hangwin/mcp-chrome/releases

# 下载最新的扩展程序压缩包并解压到此目录


3. 安装Chrome MCP桥接工具


需全局安装桥接包,推荐使用npm或pnpm:


npm install -g mcp-chrome-bridge

# 或

pnpm install -g mcp-chrome-bridge

安装完成后注册Native Messaging host:


# 注册Native Messaging host

mcp-chrome-bridge register


4. 安装和配置Chrome浏览器


验证Chrome浏览器安装


which google-chrome || which chromium-browser

如果上述命令返回空或提示"not found",说明Chrome浏览器未安装,请按以下方式安装:


macOS系统:


# 使用Homebrew安装

brew install --cask google-chrome


Ubuntu/Debian系统:


# 下载并安装Chrome

wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | sudo apt-key add -

echo"deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" | sudotee /etc/apt/sources.list.d/google-chrome.list

sudo apt update

sudo apt install google-chrome-stable


CentOS/RHEL系统:


# 添加Chrome仓库并安装

sudo yum install -y wget

wget https://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm

sudo yum localinstall google-chrome-stable_current_x86_64.rpm

加载Chrome扩展程序


打开Chrome浏览器,访问 chrome://extensions/

启用"开发者模式"

点击"加载已解压的扩展程序"

选择之前下载并解压的扩展程序文件夹

点击扩展程序图标,然后点击"连接"按钮启动MCP服务


验证Chrome MCP服务

1. 检查服务是否启动


当Chrome扩展程序连接成功后,MCP服务会在本地启动HTTP服务器(默认端口12306):


curl http://127.0.0.1:12306/mcp

# 如果服务正常,应该返回MCP协议相关信息

# 如果显示"Could not connect to server",说明Chrome扩展程序未连接

2. 通过API测试MCP工具列表


curl -X POST http://127.0.0.1:12306/mcp \

  -H "Content-Type: application/json" \

  -d '{"method": "tools/list"}'


常见问题排除

如果curl命令返回"Could not connect to server"错误:


1.检查Chrome扩展程序状态:

打开Chrome浏览器,访问 chrome://extensions/

确认Chrome MCP扩展程序已启用

点击扩展程序图标,查看连接状态


2. 重新连接扩展程序:

点击扩展程序图标

如果显示"未连接",点击"连接"按钮

等待几秒钟,直到显示"已连接"状态


3. 检查Native Messaging注册:

# 重新注册Native Messaging host

mcp-chrome-bridge register

# 注册后需要重启Chrome浏览器


4. 验证端口状态:

# 检查端口12306是否被占用

lsof -i :12306

# 如果没有输出,说明端口未被使用,需要启动扩展程序


Dify集成Chrome MCP

注意:如果你的Dify是通过Docker部署的,MCP地址不能填写127.0.0.1或localhost。应填写宿主机的实际IP地址,或使用Docker网络中的可访问地址(如host.docker.internal),否则Dify容器无法访问本地MCP服务。

1. 登录Dify控制台

访问你的Dify实例(本地)

进入「设置」→「工具」


2. 添加Chrome MCP工具

点击「添加工具」

选择「MCP工具」类型

填写配置信息:

{

"name":"Chrome MCP",

"description":"Chrome浏览器自动化工具,支持网页截图、表单填写、数据抓取等功能",

"connection":{

"type":"http",

"url":"http://host.docker.internal:12306/mcp"

},

"timeout":30000

}

1.jpg

3. 测试连接

点击「测试连接」按钮

确认显示"连接成功"状态

保存配置并启用工具

1.jpg

实战案例:自动化网页操作

案例1:网页截图助手

创建应用:

新建「Agent」应用

系统提示词:

你是一个网页截图专家,能够帮用户截取任何网页的截图。 当用户提供网址时,你需要: 1. 访问指定网页 2. 等待页面完全加载 3. 截取全屏截图 4. 返回截图结果

测试对话

1.jpg


案例2:表单自动填写

应用场景:自动填写注册表单

系统提示词:

你是一个网页截图专家,能够帮用户截取任何网页的截图。

当用户提供网址时,你需要:

1. 访问指定网页

2. 等待页面完全加载

3. 截取全屏截图

4. 返回截图结果

实际操作

1.jpg


案例3:数据抓取助手

功能描述:抓取电商网站商品信息

系统提示词:

你是数据抓取专家,能够从网页中提取结构化数据。

当用户需要抓取数据时:

1. 访问目标网页

2. 定位数据元素

3. 提取文本内容

4. 整理成结构化格式返回

抓取示例:

用户:帮我抓取京东某商品的价格和评价信息

AI:正在为您抓取商品信息...

商品名称:iPhone 15 Pro Max

当前价格:¥9999

原价:¥10999

折扣:9折

评价数量:2.5万+

好评率:98%


数据抓取完成!


高级配置与优化

Chrome扩展程序设置

1. 扩展程序选项页面配置

右键点击Chrome MCP扩展程序图标

选择"选项"或"扩展程序选项"

可配置以下设置:

HTTP服务器端口(默认12306)

请求超时时间

调试模式开关

允许的域名列表


2. Chrome浏览器优化

# 启动Chrome时的推荐参数

open -a "Google Chrome" --args \

  --remote-debugging-port=9222 \

  --disable-web-security \

  --user-data-dir=/tmp/chrome-debug


性能优化建议

1. 浏览器资源管理

定期清理浏览器缓存和Cookie

关闭不必要的标签页

禁用不需要的Chrome扩展程序


2. 系统资源监控

# 监控Chrome进程资源使用

top -p $(pgrep -f "Google Chrome")


# 查看端口占用情况

lsof -i :12306



收集一些MCP

微信聊天记录 MCP

n8n 工作流 MCP能把你在 n8n 上搭建的自动化工作流,一键变身成 AI 助手可以直接调用的工具服务器。

屏幕截图 MCP

飞书 MCP

Windows MCP操作windows电脑



微信聊天记录 MCP

开源地址:https://github.com/sjzar/chatlog



n8n 工作流 MCP能把你在 n8n 上搭建的自动化工作流,一键变身成 AI 助手可以直接调用的工具服务器。

开源地址:https://github.com/Super-Chain/N8N2MCP



屏幕截图 MCP

这个小众 MCP 能为 AI 助手提供屏幕截图功能。

能够在 macOS、Linux 和 Windows 上以编程方式截取屏幕并检索最近的截图。使用非常简单,如在 Claude Code 里面,输入:

claude mcp add snap-happy npx @mariozechner/snap-happy

开源地址:https://github.com/badlogic/lemmy/tree/main/apps/snap-happy



飞书 MCP

Feishu-MCP 能让 AI 直接读写和操作飞书文档。有了它,AI 不仅可以查看文档内容,还能帮你创建新文档、修改文本、管理文件夹,甚至搜索特定信息。

开源地址:https://github.com/cso1z/Feishu-MCP


Windows MCP操作windows电脑

开源地址:https://github.com/CursorTouch/Windows-MCP

https://github.com/CursorTouch/Windows-MCP  把这玩意给我装上

Windows-MCP is a lightweight, open-source project that enables seamless integration between AI agents and the Windows operating system. Acting as an MCP server bridges the gap between LLMs and the Windows operating system, allowing agents to perform tasks such as file navigation, application control, UI interaction, QA testing, and more.


Run at Login

Run the server directly when needed:

uvx windows-mcp serve

uvx windows-mcp serve --transport sse --host localhost --port 8000

uvx windows-mcp serve --transport streamable-http --host localhost --port 8000


Install it as a background task that starts now and at every login:

windows-mcp install

# Or choose the HTTP transport and bind address explicitly

windows-mcp install --transport sse --host 127.0.0.1 --port 8000


Install in Claude Desktop

Install in Perplexity Desktop

Install in Gemini CLI

Install in Qwen Code

Install in Codex CLI

Install in Autohand Code

Install in Claude Code





最简单的MCP服务及调用,使用FastMCP编写MCP服务,C#成功调用

MCP服务

# 方法1:用pip安装

pip install fastmcp 

# 方法2:用uv安装(更快,推荐)

uv pip install fastmcp


from fastmcp import FastMCP


mcp = FastMCP("演示 🚀",port=8020)

@mcp.tool()

def add(a: int, b: int) -> int:

    """两个数字相加"""

    return a + b+100


@mcp.tool()

def jia(a: int, b: int) -> int:

    """两个数字相减"""

    return a - b


if __name__ == "__main__":

    # mcp.run()

    #mcp.run(transport="streamable-http")

    mcp.run(transport="http")



Python客户端调用

import asyncio

from fastmcp import Client


# 配置 MCP 服务器地址

config = {

    "mcpServers": {

        "printer": {

            "url": "http://127.0.0.1:8020/mcp",

            "transport": "streamable-http"

        }

    }

}


# 初始化客户端

client = Client(config)


async def main():

    async with client:

        # 调用服务端工具

        info = await  client.list_tools()

        greet_data = await client.call_tool("add", {"a": 1,"b":3})

        print(f"tools: {info}")

        print(f"add: {greet_data}")


if __name__ == "__main__":

    asyncio.run(main())


C#成功调用该MCP的代码

正常连接MCP服务后获得mcp-session-id,每次调用方法需在header里加入mcp-session-id

async private void button32_Click(object sender, EventArgs e)

        {    

            bool bOK;   

            //初始连接MCP服务包

            Hashtable m_IHHH = new Hashtable();

            Hashtable m_pHH=new Hashtable();

            m_IHHH["jsonrpc"] = "2.0";

            m_IHHH["id"] = "0";

            m_IHHH["method"] = "initialize";

            m_IHHH["params"] = m_pHH;

            m_pHH["protocolVersion"] = "2025-11-24";

            m_pHH["capabilities"] = new Hashtable();


            //例举MCP服务的工具包

            Hashtable clientInfoHH = new Hashtable();

            m_pHH["clientInfo"] = clientInfoHH;

            clientInfoHH["name"] = "mcp";

            clientInfoHH["version"] = "0.1.0";

            Hashtable m_THHH = new Hashtable();

            m_THHH["jsonrpc"] = "2.0";

            m_THHH["id"] = "1";

            m_THHH["method"] = "tools/list";

            m_THHH["params"] = new Hashtable();


           




            string sText = JsonHelper.OBJToJsonStr(m_THHH);

            sText = JsonHelper.OBJToJsonStr(m_IHHH);


            McpClient m_McpClient = new McpClient();

            MCPReturn m_MCPReturn= await m_McpClient.SendMcpRequest("http://127.0.0.1:8020/mcp" ,sText);

            MessageBox.Show(m_MCPReturn.jsonString);


            sText = JsonHelper.OBJToJsonStr(m_THHH);

            m_MCPReturn = await m_McpClient.SendMcpRequest("http://127.0.0.1:8020/mcp", sText, m_MCPReturn.mcpSessionId);

            MessageBox.Show(m_MCPReturn.jsonString);

          

            //调用MCP工具的包

            Hashtable m_FHHH = new Hashtable();

            Hashtable m_ppHH = new Hashtable();

            Hashtable m_argumentsHH=new Hashtable();

            m_FHHH["jsonrpc"] = "2.0";

            m_FHHH["id"] = "2";

            m_FHHH["method"] = "tools/call";

            m_FHHH["params"] = m_ppHH;

            m_ppHH["name"] = "add";

            m_ppHH["arguments"] = m_argumentsHH;

            m_argumentsHH["a"] = 5;

            m_argumentsHH["b"] = 7;

            sText = JsonHelper.OBJToJsonStr(m_FHHH);

            m_MCPReturn = await m_McpClient.SendMcpRequest("http://127.0.0.1:8020/mcp", sText, m_MCPReturn.mcpSessionId);

            MessageBox.Show(m_MCPReturn.jsonString);

        }



    }


    class MCPReturn

    {

        public bool bOK;

        public string mcpSessionId = "";

        public string jsonString;

    }

    class McpClient

{

    private static readonly System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();


    public async Task<MCPReturn> SendMcpRequest(string url, string requestBody, string mcpSessionId = "")

    {

        MCPReturn m_MCPReturn = new MCPReturn();

        m_MCPReturn.bOK = false;

        try

        {

            var request = new HttpRequestMessage(HttpMethod.Post, url);

            

            // 设置请求头

            request.Headers.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));

            request.Headers.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("text/event-stream"));

            if(mcpSessionId!="")

            {

                request.Headers.Add("mcp-session-id", mcpSessionId);

            }

            // 设置请求体

            request.Content = new StringContent(

                requestBody,

                Encoding.UTF8,

                "application/json"

            );


            // 发送请求

            var response = await client.SendAsync(request);

            

            // 确保响应成功

            response.EnsureSuccessStatusCode();


            if (mcpSessionId == "")

            {

                mcpSessionId = response.Headers.GetValues("mcp-session-id").FirstOrDefault();

            }

            m_MCPReturn.bOK = true;

            m_MCPReturn.mcpSessionId = mcpSessionId;

            

            // 读取响应内容

            m_MCPReturn.jsonString= await response.Content.ReadAsStringAsync();



            return m_MCPReturn;

        }

        catch (HttpRequestException ex)

        {

            Console.WriteLine("请求失败:"+ex.Message);

            m_MCPReturn.bOK = false;

            m_MCPReturn.jsonString = ex.Message;

            return m_MCPReturn;

        }

    }





MCP - 使用 fastmcp 编写 Client 调用 MCP Serverr - Streamable HTTP 

查原文

执行初始化

Streamable HTTP 的初始化需要发送两个命令 initialize  d  notifications/initialized :

initialize :是客户端向服务器发起的第一个请求,目的是“握手”和“协商”。

notifications/initialized :是客户端在收到服务器对 initialize 的响应后,向服务器发送的一个确认通知,告知服务器“我已准备好,我们可以开始正式通信了”。

initialize

执行如下命令

curl -i POST 'http://127.0.0.1:3002/weather' \

-H 'Accept: application/json, text/event-stream' \

-H 'Content-Type: application/json' \

-d '{

    "method":"initialize",

    "params":{

        "protocolVersion":"2025-06-18",

        "capabilities":{},

        "clientInfo":{

            "name":"mcp",

            "version":"0.1.0"

        }

    },

    "jsonrpc":"2.0",

    "id":0

}'

注意:

其中  url 中的  weather   就是在代码中修改的 MCP 端点路径,也就是 path="/weather"。也可以在下图找到这个端点路径

curl 命令需要增加 -i 参数

记录响应头中的  mcp-session-id 值,后面所有请求需要这个 id 做校验


notifications/initialized

curl POST 'http://127.0.0.1:3002/weather' \

-H 'Accept: application/json, text/event-stream' \

-H 'Content-Type: application/json' \

-H 'Mcp-Session-Id: 78c703e2fc2744d78e7630c4b2ed6ebe' \

-d '{

    "method":"notifications/initialized",

    "jsonrpc":"2.0"

}'


链接 MCP 服务器监听端点

执行如下命令

curl GET 'http://127.0.0.1:3002/weather' \

-H 'Accept: application/json, text/event-stream' \

-H 'Accept: text/event-stream' \

-H 'Content-Type: application/json' \

-H 'Mcp-Session-Id: 78c703e2fc2744d78e7630c4b2ed6ebe'


列出 mcp sever 提供的所有 tools 列表

curl POST 'http://127.0.0.1:3002/weather' \

-H 'Accept: application/json, text/event-stream' \

-H 'Content-Type: application/json' \

-H 'Mcp-Session-Id: 78c703e2fc2744d78e7630c4b2ed6ebe' \

-d '{

    "method":"tools/list",

    "jsonrpc":"2.0",

    "id":1

}'










同样,MCP Server,可以运行在:


本地进程间管道(stdin/stdout)通信:Stdio

通过 HTTP 长链接通信:SSE 、 Streamable HTTP

本文讲解如果使用 fastmcp 如何跟 MCP Server(Streamable HTTP) 创建链接并调用 tools。这里都是手动调用 tools 没有使用任何大模型。


1、创建 client.py 并粘贴如下代码:

# -*- coding: utf-8 -*-

# @Time : 2025/7/28 17:09

# @Author : yangwenjie

# @Email : 邮箱

# @File : server-sse.py

# @Project : fastmcp

# weather_sse.py

from fastmcp import FastMCP

import random


# 创建MCP服务器实例,指定端口

mcp = FastMCP("Weather Service", port=3002)


# 模拟的天气数据

weather_data = {

    "New York": {"temp": range(10, 25), "conditions": ["sunny", "cloudy", "rainy"]},

    "London": {"temp": range(5, 20), "conditions": ["cloudy", "rainy", "foggy"]},

    "Tokyo": {"temp": range(15, 30), "conditions": ["sunny", "cloudy", "humid"]},

    "Sydney": {"temp": range(20, 35), "conditions": ["sunny", "clear", "hot"]},

}


@mcp.tool()

def add_numbers(a: int, b: int) -> int:

    """两个数字相加"""

    return a + b


@mcp.tool()

def get_weather(city: str) -> dict:

    """获取指定城市的当前天气"""

    if city not in weather_data:

        return {"error": f"无法找到城市 {city} 的天气数据"}


    data = weather_data[city]

    temp = random.choice(list(data["temp"]))

    condition = random.choice(data["conditions"])


    return {

        "city": city,

        "temperature": temp,

        "condition": condition,

        "unit": "celsius"

    }


@mcp.resource("weather://cities")

def get_available_cities() -> list:

    """获取所有可用的城市列表"""

    return list(weather_data.keys())


@mcp.resource("weather://forecast/{city}")

def get_forecast(city: str) -> dict:

    """获取指定城市的天气预报资源"""

    if city not in weather_data:

        return {"error": f"无法找到城市 {city} 的天气预报"}


    forecast = []

    for i in range(5):  # 5天预报

        data = weather_data[city]

        temp = random.choice(list(data["temp"]))

        condition = random.choice(data["conditions"])

        forecast.append({

            "day": i + 1,

            "temperature": temp,

            "condition": condition

        })


    return {

        "city": city,

        "forecast": forecast,

        "unit": "celsius"

    }


@mcp.prompt()

def weather(city: str = "北京") -> list:

    """提供天气查询的对话模板"""

    return [

        {

            "role": "user",

            "content": f"请帮我查询{city}的天气情况,并提供详细的天气信息。"

        }

    ]


if __name__ == "__main__":

    # 使用 Streamable HTTP 传输方式启动服务器

    mcp.run(transport="http", path="/weather")


二、创建 client.py 并粘贴如下代码:

import asyncio

from fastmcp import Client

 

# 使用 config 配置方式

config = {

    "mcpServers": {

        "server": {

            "url": "http://127.0.0.1:3002/weather",

            "transport": "streamable-http"

        }

    }

}

 

# 初始化客户端

client = Client(config)

 

async def main():

    async with client:

        print("===== 调用 tools 列表查询 =====")

        tools = await client.list_tools()

        print(tools)

 

        print("===== 调用 resources 列表查询 =====")

        resources = await client.list_resources()

        print(resources)

 

        print("===== 调用 resource_templates 列表查询 =====")

        templates = await client.list_resource_templates()

        print(templates)       

 

        print("===== 调用 prompts 列表查询 =====")

        prompts = await client.list_prompts()

        print(prompts)

 

        print("===== 调用工具 add_numbers =====")

        output = await client.call_tool("add_numbers", {"a": 1, "b": 3})

        extracted_text = output.content[0].text

        print(extracted_text)

 

        print("===== 读取指定URI对应的资源内容 =====")

        output = await client.read_resource("weather://cities")

        print(output)

 

        print("===== 读取指定URI对应的资源模版内容 =====")

        output = await client.read_resource("weather://forecast/London")

        print(output)

 

        print("===== 获取填充数据后的提示词模板 =====")

        output = await client.get_prompt("weather", {'city': '北京'})

        print(output)

 

if __name__ == "__main__":

    asyncio.run(main())






UV与UVX区别

uv run <命令>  在 当前项目的隔离环境 中运行命令,依赖当前目录的 pyproject.toml(项目配置文件),使用项目专属的虚拟环境(默认在 ./.venv),本地开发、稳定部署(需固定依赖版本,避免变动)

uvx <命令> 以 临时、独立的环境 运行命令(无需提前创建项目),自动创建一个临时虚拟环境(用完即弃,不污染本地),或复用缓存的环境,快速测试、临时启动(无需配置项目,一键运行)

若你需要搭建一个 长期稳定运行 的 MCP Server,优先选择 uv run,通过 pyproject.toml 固定依赖版本,避免意外更新。

若你只是想 临时测试 服务器,或快速启动一个联机环境,用 uvx 更高效,无需繁琐配置。

pyproject.toml 文件内容:

# 1. 初始化项目(仅首次需执行)

uv init


# 2. 添加 MCP Server 依赖(固定版本,写入 pyproject.toml)

uv add minecraft-server==1.2.3  # 替换为实际需要的版本


# 3. 启动服务器(使用项目隔离环境,依赖版本严格匹配)

uv run minecraft-server



Agent如何组包MCP发送给大模型

Q:

你是一名优秀AI研发工程师,现在编写一个Agent调用MCP 和Ollama大模型,通过tools/list获得MCP服务所有的工具函数,如何组合返回的数据发送给Ollama大模型,返回的数据如下:event: message

data: {"jsonrpc":"2.0","id":"1","result":{"tools":[{"name":"add","description":"两个数字相加","inputSchema":{"properties":{"a":{"type":"integer"},"b":{"type":"integer"}},"required":["a","b"],"type":"object"},"outputSchema":{"properties":{"result":{"type":"integer"}},"required":["result"],"type":"object","x-fastmcp-wrap-result":true},"_meta":{"_fastmcp":{"tags":[]}}},{"name":"jia","description":"两个数字相减","inputSchema":{"properties":{"a":{"type":"integer"},"b":{"type":"integer"}},"required":["a","b"],"type":"object"},"outputSchema":{"properties":{"result":{"type":"integer"}},"required":["result"],"type":"object","x-fastmcp-wrap-result":true},"_meta":{"_fastmcp":{"tags":[]}}}]}}

A:...

下面给出一种“通用、可落地”的 Python 实现思路

1.MCP 暴露出来的工具列表(SSE 格式)

2.解析、去噪、提取出「可被 LLM 理解」的函数元数据

3.组装成 Ollama 支持的「functions-calling」格式(官方 API 与 OpenAI 兼容)

4.通过 /api/chat 一次性发给本地 Ollama 模型,让模型决定下一步该调哪几个工具、传什么参数。

代码可直接跑通(需 pip install requests sseclient-py)。

#!/usr/bin/env python3

# -*- coding: utf-8 -*-

"""

Agent: 监听 MCP → 提取工具 → 发给 Ollama → 让 LLM 决定下一步

"""


import json

import requests

import sseclient  # pip install sseclient-py


# 1. 配置

MCP_SSE_URL   = "http://localhost:8000/sse"          # MCP 的 SSE 端点

OLLAMA_URL    = "http://localhost:11434/api/chat"    # Ollama 聊天接口

OLLAMA_MODEL  = "llama3.1:8b"                        # 本地已 pull 的模型

USER_PROMPT   = "帮我算 18+5,再算 30-12,把结果用中文回答我"


# 2. 从 SSE 里拿到 tools/list 的返回

def fetch_mcp_tools_list(sse_url: str):

    """

    监听第一条 event: message,解析出 tools/list 的 jsonrpc 结果

    """

    resp = requests.get(sse_url, stream=True, headers={"Accept": "text/event-stream"})

    client = sseclient.SSEClient(resp)

    for event in client.events():

        if event.event == "message":

            payload = json.loads(event.data)

            # 只拿 id=="1" 的那条

            if payload.get("id") == "1" and "result" in payload:

                return payload["result"]["tools"]

    raise RuntimeError("tools/list 未返回或格式异常")


# 3. 把 MCP 工具转成 Ollama functions 格式

def mcp2ollama_functions(tools: list) -> list:

    """

    输入 MCP 的 tools 数组,输出 Ollama / OpenAI 格式的 functions 定义

    """

    functions = []

    for t in tools:

        func = {

            "type": "function",

            "function": {

                "name": t["name"],

                "description": t["description"],

                "parameters": t["inputSchema"]

            }

        }

        functions.append(func)

    return functions


# 4. 让 Ollama 决定下一步

def chat_with_ollama(model: str, user_msg: str, functions: list):

    """

    调用 Ollama 的 /api/chat,兼容 OpenAI functions-calling

    """

    payload = {

        "model": model,

        "messages": [{"role": "user", "content": user_msg}],

        "functions": functions,

        "stream": False

    }

    r = requests.post(OLLAMA_URL, json=payload)

    r.raise_for_status()

    return r.json()


# 5. 主流程

if __name__ == "__main__":

    # 5.1 拉取 MCP 工具

    mcp_tools = fetch_mcp_tools_list(MCP_SSE_URL)

    print("=== MCP 工具列表 ===")

    print(json.dumps(mcp_tools, ensure_ascii=False, indent=2))


    # 5.2 转成 Ollama 格式

    functions = mcp2ollama_functions(mcp_tools)

    print("\n=== Ollama functions ===")

    print(json.dumps(functions, ensure_ascii=False, indent=2))


    # 5.3 发给 Ollama,让模型自己决定调不调、调谁、怎么调

    llm_resp = chat_with_ollama(OLLAMA_MODEL, USER_PROMPT, functions)

    print("\n=== Ollama 返回 ===")

    print(json.dumps(llm_resp, ensure_ascii=False, indent=2))


    # 5.4 如果模型决定调用函数,这里可以继续解析 llm_resp["message"]["function_call"]

    #     然后真正去调 MCP 的 tools/call,再把结果塞回 Ollama 做二次总结


运行效果(节选)

=== MCP 工具列表 ===

[

  {

    "name": "add",

    "description": "两个数字相加",

    ...

  },

  {

    "name": "jia",

    "description": "两个数字相减",

    ...

  }

]

=== Ollama functions ===

[

  {

    "type": "function",

    "function": {

      "name": "add",

      "description": "两个数字相加",

      "parameters": {

        "type": "object",

        "properties": {

          "a": {"type": "integer"},

          "b": {"type": "integer"}

        },

        "required": ["a", "b"]

      }

    }

  },

  ...

]

=== Ollama 返回 ===

{

  "message": {

    "role": "assistant",

    "content": "",

    "function_call": {

      "name": "add",

      "arguments": {"a": 18, "b": 5}

    }

  },

  ...

}


Q:补全后面继续调用MCP工具返回给llm处理的代码直到最后返回给客户

A:...

下面给出一份可直接跑通的完整示例,把前面缺的后半段补齐:

解析 LLM 返回的 function_call

真正去调 MCP 的 tools/call

把结果再次塞进 Ollama,让模型“总结”后返回给最终用户

支持一次请求里顺序调用多个工具(LLM 想调几个就调几个)

依赖同上文:pip install requests sseclient-py

#!/usr/bin/env python3

# -*- coding: utf-8 -*-

"""

Agent:  MCP → Ollama → MCP → Ollama → 用户

完整闭环,支持多工具顺序调用

"""


import json

import requests

import sseclient


# ---------- 配置 ----------

MCP_SSE_URL   = "http://localhost:8000/sse"          # MCP SSE 端点

OLLAMA_URL    = "http://localhost:11434/api/chat"    # Ollama 聊天接口

OLLAMA_MODEL  = "llama3.1:8b"                        # 已 pull 的模型

USER_PROMPT   = "帮我算 18+5,再算 30-12,把结果用中文回答我"


# ---------- 工具 ----------

def fetch_mcp_tools_list(sse_url: str):

    """拉取 MCP tools/list"""

    resp = requests.get(sse_url, stream=True, headers={"Accept": "text/event-stream"})

    client = sseclient.SSEClient(resp)

    for event in client.events():

        if event.event == "message":

            payload = json.loads(event.data)

            if payload.get("id") == "1" and "result" in payload:

                return payload["result"]["tools"]

    raise RuntimeError("tools/list 未返回")


def mcp2ollama_functions(tools: list) -> list:

    """MCP → Ollama functions 格式"""

    return [

        {

            "type": "function",

            "function": {

                "name": t["name"],

                "description": t["description"],

                "parameters": t["inputSchema"],

            },

        }

        for t in tools

    ]


def chat_with_ollama(model: str, messages: list, functions: list):

    """单次 Ollama 对话,支持 functions"""

    payload = {"model": model, "messages": messages, "functions": functions, "stream": False}

    r = requests.post(OLLAMA_URL, json=payload)

    r.raise_for_status()

    return r.json()


def call_mcp_tool(name: str, arguments: dict) -> dict:

    """调用 MCP tools/call,返回 result 里的内容"""

    # MCP 的 jsonrpc 格式

    payload = {

        "jsonrpc": "2.0",

        "id": "2",

        "method": "tools/call",

        "params": {"name": name, "arguments": arguments},

    }

    # 通过 SSE 发送并取第一条返回

    resp = requests.post(MCP_SSE_URL.replace("/sse", "/message"), json=payload)

    resp.raise_for_status()

    # MCP 返回也是 SSE 事件,这里简化:直接读 JSON

    line = resp.text.strip()

    if line.startswith("data:"):

        line = line[5:].strip()

    data = json.loads(line)

    if "result" in data:

        return data["result"]

    raise RuntimeError(f"MCP 调用失败: {data}")


# ---------- 主流程 ----------

def main():

    # 1. 拿工具

    mcp_tools = fetch_mcp_tools_list(MCP_SSE_URL)

    functions = mcp2ollama_functions(mcp_tools)


    # 2. 首轮对话

    messages = [{"role": "user", "content": USER_PROMPT}]

    llm_resp = chat_with_ollama(OLLAMA_MODEL, messages, functions)

    messages.append(llm_resp["message"])


    # 3. 只要模型想调工具,就继续循环

    while llm_resp["message"].get("function_call"):

        call = llm_resp["message"]["function_call"]

        name = call["name"]

        args = call["arguments"]

        print(f"[Agent] 调用 MCP 工具: {name}({args})")

        tool_result = call_mcp_tool(name, args)

        print(f"[Agent] 工具返回: {tool_result}")


        # 把工具返回包装成 role=tool 的消息

        messages.append(

            {

                "role": "tool",

                "name": name,

                "content": json.dumps(tool_result, ensure_ascii=False),

            }

        )


        # 再次发给 Ollama,让模型继续

        llm_resp = chat_with_ollama(OLLAMA_MODEL, messages, functions)

        messages.append(llm_resp["message"])


    # 4. 最终答案

    answer = llm_resp["message"]["content"]

    print("\n=== 最终回答 ===")

    print(answer)

    return answer


if __name__ == "__main__":

    main()



运行示例(本地已启动 MCP 与 Ollama):

[Agent] 调用 MCP 工具: add({'a': 18, 'b': 5})

[Agent] 工具返回: {'result': 23}

[Agent] 调用 MCP 工具: jia({'a': 30, 'b': 12})

[Agent] 工具返回: {'result': 18}


=== 最终回答 ===

18 加 5 等于 23,30 减 12 等于 18。



####【豆包】

Q:如何编写一个操作数据库的mcp服务,实现通过大模型增删改查数据

A:..

Q:不对不通用,都指定了固定表结构和对固定表的操作

A:..


让 AI 读取FastMCP Resource

最简单示例:让 AI 读取 Resource

python

运行

from fastmcp import FastMCP

mcp = FastMCP("测试资源")


# 定义一个资源

@mcp.resource("docs://company_intro")

def get_company_intro():

    return """

公司名称:AI科技有限公司

成立时间:2023年

主营:AI模型服务、MCP开发

员工数:50人

"""


if __name__ == "__main__":

    mcp.run()


你对 AI 说:

介绍一下你们公司


STDIO方式的MCP如何调用不用第三方库C#如何调用

纯 C# 调用 STDIO 模式 FastMCP(无第三方库,原生实现)

我给你最精简、可直接运行、100% 纯 C# 原生代码,完全不依赖任何 MCP 库、NuGet 包,直接通过 Process 启动 STDIO 模式 MCP 服务 → 读写标准输入输出 → 发送 MCP 协议 JSON 调用工具 / 资源。

核心原理(一句话)

STDIO 模式 MCP = 启动子进程 → 通过 stdin 发送 JSON 请求 → 通过 stdout 读取 JSON 响应

MCP 协议是基于 JSON-RPC 2.0 的纯文本协议,C# 用 Process + StreamWriter/StreamReader 就能直接调用。

一、先准备你的 MCP 服务(Python)

先写一个极简 mcp_server.py(后面 C# 调用它)

python

运行

from fastmcp import FastMCP

mcp = FastMCP("test")


@mcp.tool

def add(a: int, b: int) -> int:

    """加法"""

    return a + b


@mcp.resource("info://test")

def get_info():

    return "这是MCP资源数据"


if __name__ == "__main__":

    mcp.run()  # 默认 STDIO 模式

二、C# 原生调用 STDIO MCP(完整代码)

功能:

启动 Python MCP 子进程

初始化 MCP 连接

调用 tool(add 函数)

读取 resource(资源)

无第三方库,纯 .NET 原生

csharp

运行

using System;

using System.Diagnostics;

using System.Text.Json;

using System.Threading.Tasks;


// 纯 C# 原生调用 STDIO 模式 FastMCP

class McpStdioClient

{

    private static Process _mcpProcess;

    private static StreamWriter _stdin;

    private static StreamReader _stdout;


    static async Task Main(string[] args)

    {

        try

        {

            // 1. 启动 STDIO 模式 MCP 服务(修改为你的 python 路径 + mcp_server.py 路径)

            StartMcpProcess(

                pythonPath: "python",

                serverScriptPath: @"D:\test\mcp_server.py"

            );


            // 2. 初始化 MCP(必须发送,MCP 协议要求)

            await InitializeMcpAsync();


            // ====================== 调用工具(Tool)======================

            var toolResult = await CallToolAsync("add", new { a = 10, b = 20 });

            Console.WriteLine($"工具调用结果:{toolResult}");


            // ====================== 读取资源(Resource)======================

            var resourceContent = await ReadResourceAsync("info://test");

            Console.WriteLine($"资源内容:{resourceContent}");

        }

        catch (Exception ex)

        {

            Console.WriteLine($"错误:{ex.Message}");

        }

        finally

        {

            _mcpProcess?.Close();

        }

    }


    // 启动 MCP 子进程

    static void StartMcpProcess(string pythonPath, string serverScriptPath)

    {

        var startInfo = new ProcessStartInfo

        {

            FileName = pythonPath,

            Arguments = serverScriptPath,

            RedirectStandardInput = true,

            RedirectStandardOutput = true,

            RedirectStandardError = true,

            UseShellExecute = false,

            CreateNoWindow = true

        };


        _mcpProcess = new Process { StartInfo = startInfo };

        _mcpProcess.Start();


        _stdin = _mcpProcess.StandardInput;

        _stdout = _mcpProcess.StandardOutput;


        Console.WriteLine("MCP 进程已启动(STDIO 模式)");

    }


    // 发送 MCP 协议消息

    static async Task<JsonElement> SendMcpMessageAsync(string method, object @params)

    {

        var msg = new

        {

            jsonrpc = "2.0",

            id = 1,

            method = method,

            @params = @params

        };


        // 写入 stdin(必须加换行!)

        var json = JsonSerializer.Serialize(msg);

        await _stdin.WriteLineAsync(json);

        await _stdin.FlushAsync();


        // 读取 stdout 响应

        var resp = await _stdout.ReadLineAsync();

        using var doc = JsonDocument.Parse(resp);

        return doc.RootElement;

    }


    // MCP 初始化(必须调用)

    static async Task InitializeMcpAsync()

    {

        await SendMcpMessageAsync("initialize", new { protocolVersion = "2024-11-05" });

        Console.WriteLine("MCP 初始化完成");

    }


    // 调用 Tool

    static async Task<string> CallToolAsync(string toolName, object args)

    {

        var resp = await SendMcpMessageAsync("tools/call", new

        {

            name = toolName,

            arguments = args

        });


        return resp.GetProperty("result").GetProperty("content")[0].GetProperty("text").GetString();

    }


    // 读取 Resource

    static async Task<string> ReadResourceAsync(string uri)

    {

        var resp = await SendMcpMessageAsync("resources/read", new { uri = uri });

        return resp.GetProperty("result").GetProperty("content").GetString();

    }

}

三、运行结果

plaintext

MCP 进程已启动(STDIO 模式)

MCP 初始化完成

工具调用结果:30

资源内容:这是MCP资源数据

四、关键知识点(你必须懂)

1. 为什么不用第三方库?

因为 STDIO MCP = 子进程 + JSON-RPC 2.0

C# 原生:

Process → 启动服务

StreamWriter/StreamReader → 读写 stdin/stdout

System.Text.Json → 解析协议

完全不需要任何库。

2. MCP 协议固定格式(所有客户端都一样)

json

{

  "jsonrpc": "2.0",

  "id": 1,

  "method": "方法名",

  "params": {}

}

固定方法:

initialize → 初始化(必须第一个调用)

tools/call → 调用工具

resources/read → 读取资源

3. C# 调用 Resource(你问的重点)

csharp

运行

await ReadResourceAsync("info://test");

对应 MCP 定义:

python

运行

@mcp.resource("info://test")

五、你只需要改 2 个地方就能跑

pythonPath:你的 Python 路径

serverScriptPath:你的 mcp_server.py 路径


.NET Core编写MCP服务,AI赋能

你是一名优秀的AI研发工程师,同时熟悉常用开发语言

你知道MCP服务吧

给一个 .NET Core编写的Stdio 标准托管 MCP 服务

给一个ASP.NET Core Streamable HTTP 远程 MCP 服务


FastMCP编写MCP,支持websocket通讯方式

1. 安装 WebSocket 支持

在安装 FastMCP 时,需要指定安装 websockets 扩展依赖:

bash

uv pip install fastmcp[websockets]


2. 客户端通过 WebSocket 连接服务器

FastMCP 的客户端设计非常智能,可以根据你提供的 URL 自动判断并使用正确的传输协议。

python

import asyncio

from fastmcp import Client

async def main():

    # 当 URL 以 ws:// 或 wss:// 开头时,Client 会自动使用 WebSocket 传输

    async with Client("ws://localhost:8000") as client:

        # 在这里调用工具、读取资源等

        tools = await client.list_tools()

        print(tools)

asyncio.run(main())


3. 服务端启用 WebSocket 传输

在启动 FastMCP 服务器时,可以通过指定 transport 参数来启用 WebSocket。

python

from fastmcp import FastMCP

mcp = FastMCP("My MCP Server")

# 定义工具、资源等

@mcp.tool

def hello(name: str) -> str:

    return f"Hello, {name}!"

if __name__ == "__main__":

    # 启用 WebSocket 传输,监听在 8000 端口

    mcp.run(transport="websocket", host="127.0.0.1", port=8000)


大模型调用websocket MCP例子

方式一:使用 FastMCP 原生 WebSocket 支持

1. 服务端代码示例

这是一个使用 FastMCP 库创建的简单 MCP 服务器,它注册了一个用于查询天气的工具,并通过 WebSocket 提供服务。关键在于启动时指定 transport="websocket"。

python

# server.py

import asyncio

from fastmcp import FastMCP


# 1. 创建 MCP 服务器实例

mcp = FastMCP("Weather MCP Server")


# 2. 定义一个工具 (Tool)

@mcp.tool

def get_weather(location: str) -> str:

    """获取指定地点的当前天气信息。"""

    # 这里只是一个模拟实现,你可以替换为真实的API调用

    weather_db = {

        "北京": "晴天,25°C",

        "上海": "多云,22°C",

        "深圳": "雷阵雨,28°C"

    }

    return weather_db.get(location, f"未找到 '{location}' 的天气信息")


if __name__ == "__main__":

    # 3. 以 WebSocket 方式启动服务器,监听 8000 端口

    mcp.run(transport="websocket", host="127.0.0.1", port=8000)

运行此脚本即可启动 WebSocket MCP 服务器。


2. 客户端调用示例

fastmcp.Client 提供高级接口,当传入 ws:// 开头的 URL 时,会自动使用 WebSocket 传输。


python

# client.py

import asyncio

from fastmcp import Client


async def main():

    # 连接到 WebSocket MCP 服务器

    async with Client("ws://localhost:8000") as client:

        # 列出所有可用工具

        tools = await client.list_tools()

        print(f"可用工具: {tools}")


        # 调用 'get_weather' 工具

        result = await client.call_tool("get_weather", {"location": "北京"})

        print(f"工具调用结果: {result}")


if __name__ == "__main__":

    asyncio.run(main())

这个客户端会连接到本地 WebSocket MCP 服务器,并调用 get_weather 工具。


🔌 方式二:使用 mcpsock 库

mcpsock 是一个专门为 FastMCP 提供 WebSocket 客户端和服务器实现的库。它提供了更底层的控制。


1. 安装

bash

pip install mcpsock

或


bash

uv add mcpsock


2. 服务端代码示例 (与 FastAPI 集成)

mcpsock 可以非常方便地与 FastAPI 集成,通过 WebSocketServer 路由注册工具。


python

# server_with_fastapi.py

from fastapi import FastAPI

from mcpsock import WebSocketServer

import uvicorn


# 1. 创建 FastAPI 应用和 WebSocketServer 路由器

app = FastAPI()

router = WebSocketServer()


# 2. 注册一个工具处理器

@router.tool("/tools/get_weather")

async def get_weather_tool(message, websocket):

    """处理获取天气的工具调用"""

    # 从 message 中解析参数

    params = message.get("params", {})

    location = params.get("location", "未知地点")

    # 模拟的天气数据

    weather_data = {"location": location, "temperature": "25°C", "condition": "晴朗"}

    return {"result": weather_data}


# 3. 将路由器挂载到 FastAPI 应用上

router.attach_to_app(app, "/ws")


if __name__ == "__main__":

    # 4. 使用 uvicorn 运行 FastAPI 应用

    uvicorn.run(app, host="0.0.0.0", port=8000)

3. 客户端代码示例

mcpsock 提供了 WebSocketClient 类,可以直接与上述服务器交互。


python

# client_mcpsock.py

import asyncio

from mcpsock import WebSocketClient


async def main():

    # 连接到 FastMCP WebSocket 服务器

    async with WebSocketClient("ws://localhost:8000/ws") as client:

        # 列出可用工具

        tools = await client.list_tools()

        print(f"可用工具: {tools}")


        # 调用工具

        result = await client.call_tool("/tools/get_weather", {"location": "上海"})

        print(f"工具调用结果: {result}")


if __name__ == "__main__":

    asyncio.run(main())


🤖 将 MCP 集成到大模型 Agent

要让大模型(如 OpenAI 的模型)使用这些工具,你需要一个 Agent 框架来桥接。

一个常见的模式是使用 openai-agents 等库。在 openai-agent-mcp-ws 这个示例项目中,客户端会:

1.通过 WebSocket 连接到 MCP 服务器,并获取其提供的工具列表。

2.将这些工具“翻译”成大模型(如 OpenAI Agent)可以理解的格式。

3.当用户提问时,大模型 Agent 会决策并调用这些工具。

4.这种模式使得大模型可以像调用本地函数一样,调用通过 WebSocket 暴露的远程 MCP 服务。


LangChain 调用不同通讯方式MCP例子

服务端示例(统一的服务逻辑)

为便于对比,所有服务端使用相同的工具定义(add 和 get_weather),仅 mcp.run() 的 transport 参数不同。

python

# server.py

from fastmcp import FastMCP


mcp = FastMCP("DemoServer")


@mcp.tool()

def add(a: int, b: int) -> int:

    """Add two numbers"""

    return a + b


@mcp.tool()

async def get_weather(location: str) -> str:

    """Get weather for a location"""

    # 模拟实现,实际可替换为真实 API 调用

    weather_db = {

        "北京": "晴天,25°C",

        "上海": "多云,22°C",

        "深圳": "雷阵雨,28°C"

    }

    return weather_db.get(location, f"未找到 '{location}' 的天气信息")


if __name__ == "__main__":

    # 根据下方不同方式替换 transport 参数

    mcp.run(transport="stdio")  # 或其他 transport


各通信方式的服务端启动与客户端调用

1. STDIO(本地进程通信)

STDIO 通过启动本地子进程通信,是本地工具的默认选择。

服务端启动:

python

# 在 server.py 中

if __name__ == "__main__":

    mcp.run(transport="stdio")  # [reference:6]

命令行运行:


bash

python server.py


FastMCP 客户端调用:

python

# client_stdio.py

import asyncio

from fastmcp import Client

from fastmcp.client.transports import StdioTransport


async def main():

    transport = StdioTransport(

        command="python",

        args=["server.py"]

    )

    async with Client(transport=transport) as client:

        await client.ping()

        result = await client.call_tool("add", {"a": 3, "b": 5})

        print(f"3 + 5 = {result}")


asyncio.run(main())


LangChain 调用(使用 langchain-mcp-adapters):

python

# langchain_stdio.py

import asyncio

from mcp import ClientSession, StdioServerParameters

from mcp.client.stdio import stdio_client

from langchain_mcp_adapters.tools import load_mcp_tools

from langchain.agents import create_agent

from langchain_openai import ChatOpenAI


model = ChatOpenAI(model="gpt-4o")


server_params = StdioServerParameters(

    command="python",

    args=["/path/to/server.py"],  # 替换为实际路径

)


async def main():

    async with stdio_client(server_params) as (read, write):

        async with ClientSession(read, write) as session:

            await session.initialize()

            tools = await load_mcp_tools(session)

            agent = create_agent(model, tools)

            response = await agent.ainvoke({"messages": "3 + 5 等于多少?"})

            print(response)


asyncio.run(main())


2. SSE(Server-Sent Events)

SSE 适合基于 HTTP 的远程服务,但官方已标记为弃用,新项目推荐使用 Streamable HTTP。

服务端启动:

python

if __name__ == "__main__":

    mcp.run(transport="sse", host="127.0.0.1", port=8000)

命令行运行:


bash

python server.py

# 服务将在 http://127.0.0.1:8000/sse 提供 SSE 连接


FastMCP 客户端调用:

python

# client_sse.py

import asyncio

from fastmcp import Client

from fastmcp.client.transports import SSETransport


async def main():

    transport = SSETransport(url="http://127.0.0.1:8000/sse")

    async with Client(transport=transport) as client:

        await client.ping()

        result = await client.call_tool("get_weather", {"location": "北京"})

        print(f"北京天气: {result}")


asyncio.run(main())


LangChain 调用(通过 MultiServerMCPClient):

python

# langchain_sse.py

import asyncio

from langchain_mcp_adapters.client import MultiServerMCPClient

from langchain.agents import create_agent

from langchain_openai import ChatOpenAI


model = ChatOpenAI(model="gpt-4o")


async def main():

    async with MultiServerMCPClient({

        "weather": {

            "url": "http://127.0.0.1:8000/sse",

            "transport": "sse",

        }

    }) as client:

        agent = create_agent(model, client.get_tools())

        response = await agent.ainvoke({"messages": "北京的天气如何?"})

        print(response)


asyncio.run(main())


3. WebSocket(全双工实时通信)

WebSocket 提供双向实时通信,适合需要持续交互的场景。

安装依赖:

bash

pip install fastmcp[websockets]

服务端启动:

python

if __name__ == "__main__":

    mcp.run(transport="websocket", host="127.0.0.1", port=8000)

命令行运行:


bash

python server.py

# 服务将在 ws://127.0.0.1:8000 提供 WebSocket 连接


FastMCP 客户端调用(使用 mcpsock 库):

python

# client_websocket.py

import asyncio

from mcpsock import WebSocketClient


async def main():

    async with WebSocketClient("ws://127.0.0.1:8000") as client:

        tools = await client.list_tools()

        print(f"可用工具: {tools}")

        result = await client.call_tool("add", {"a": 10, "b": 20})

        print(f"10 + 20 = {result}")


asyncio.run(main())


LangChain 调用(配置 WebSocket 连接):

python

# langchain_websocket.py

import asyncio

from langchain_mcp_adapters.client import MultiServerMCPClient

from langchain.agents import create_agent

from langchain_openai import ChatOpenAI


model = ChatOpenAI(model="gpt-4o")


async def main():

    async with MultiServerMCPClient({

        "ws_server": {

            "url": "ws://127.0.0.1:8000",

            "transport": "websocket",

        }

    }) as client:

        agent = create_agent(model, client.get_tools())

        response = await agent.ainvoke({"messages": "计算 10 + 20"})

        print(response)


asyncio.run(main())


4. Streamable HTTP(推荐用于 Web 部署)

Streamable HTTP 是官方推荐的 Web 部署方式,支持流式响应。

服务端启动:

python

if __name__ == "__main__":

    mcp.run(transport="streamable-http", host="127.0.0.1", port=8000)

命令行运行:


bash

python server.py

# 服务将在 http://127.0.0.1:8000/mcp/ 提供 Streamable HTTP 服务


FastMCP 客户端调用(支持流式响应):

python

# client_streamable_http.py

import asyncio

from fastmcp import Client

from fastmcp.client.transports import StreamableHttpTransport


async def main():

    transport = StreamableHttpTransport("http://127.0.0.1:8000/mcp/")

    async with Client(transport=transport) as client:

        await client.ping()

        result = await client.call_tool("get_weather", {"location": "上海"})

        print(f"上海天气: {result}")


asyncio.run(main())


支持流式响应的工具定义(服务端):

python

from typing import AsyncGenerator

from fastmcp import FastMCP


mcp = FastMCP("StreamingServer")


@mcp.tool()

async def generate_report(params: dict) -> AsyncGenerator[str, None]:

    """生成流式报告,逐块返回数据"""

    raw = str(params)

    chunk_size = 100

    for i in range(0, len(raw), chunk_size):

        yield f"chunk: {raw[i:i+chunk_size]}\n"

        await asyncio.sleep(0.05)


if __name__ == "__main__":

    mcp.run(transport="streamable-http", host="127.0.0.1", port=8000)

流式客户端调用:

python

async def stream_example():

    transport = StreamableHttpTransport("http://127.0.0.1:8000/mcp/")

    async with Client(transport=transport) as client:

        stream = await client.call_tool("generate_report", {"params": {"title": "报告"}})

        async for chunk in stream:

            print(chunk)


LangChain 调用:

python

# langchain_streamable_http.py

import asyncio

from langchain_mcp_adapters.client import MultiServerMCPClient

from langchain.agents import create_agent

from langchain_openai import ChatOpenAI


model = ChatOpenAI(model="gpt-4o")


async def main():

    async with MultiServerMCPClient({

        "demo": {

            "url": "http://127.0.0.1:8000/mcp/",

            "transport": "http",  # 或 "streamable-http"

        }

    }) as client:

        agent = create_agent(model, client.get_tools())

        response = await agent.ainvoke({"messages": "上海的天气怎么样?"})

        print(response)


asyncio.run(main())


***LangChain 调用各类 MCP 例子***

# 核心原理一句话

LangChain + MCP:**LangChain 充当 MCP Host**;MCP SDK 负责底层 transport 通信;`langchain-mcp-adapters` 把 MCP Server 暴露的工具自动转换成 LangChain 的`BaseTool`,直接丢给 ReAct Agent 做工具调用PyPI。

> 链路:用户问题 → LLM(LangChain)→ 判断调用 MCP 工具 → LangChain 内部 MCP Client(stdio/Streamable HTTP)→ MCP Server 执行真实逻辑 → 返回结果 → LLM 汇总回答。

> 前置:继续用前面我们写好的 `server.py`(stdio MCP Server,add、concat_str 工具)


## 安装依赖

```

pip install mcp langchain langgraph langchain-mcp-adapters openai

```


## 示例 1:LangChain 调用 stdio MCP(本地子进程,最常用)

> stdio:LangChain 自动拉起 `python server.py` 作为子进程,管道通信,**不需要端口**PyPI


```

import asyncio

from mcp import ClientSession, StdioServerParameters

from mcp.client.stdio import stdio_client

from langchain_mcp_adapters.tools import load_mcp_tools

from langgraph.prebuilt import create_react_agent

from langchain_openai import ChatOpenAI


async def main():

    # ========== stdio MCP Server参数 ==========

    server_params = StdioServerParameters(

        command="python",

        # 改成你本机server.py绝对路径

        args=["/path/to/server.py"],

    )


    async with stdio_client(server_params) as (read, write):

        async with ClientSession(read, write) as session:

            # MCP握手初始化

            await session.initialize()

            # 核心API:把MCP工具列表转为LangChain工具

            tools = await load_mcp_tools(session)


            # 初始化LLM,也可以换Ollama本地模型

            llm = ChatOpenAI(model="gpt-4o", api_key="xxx")

            # 创建ReAct智能体,自动做工具循环调用

            agent = create_react_agent(llm, tools)


            # 提问,Agent会自动判断调用add工具

            result = await agent.ainvoke({

                "messages": "计算 123 + 456,然后拼接字符串结果:答案="

            })

            print("====输出====")

            print(result["messages"][-1].content)


if __name__ == "__main__":

    asyncio.run(main())

```


## 示例 2:LangChain 调用 Streamable HTTP MCP(远程 MCP 服务)

> Streamable HTTP:MCP Server 独立跑 Web 服务,LangChain 通过 HTTP POST 连接,支持跨机器、多客户端共享 MCP 服务PyPI


```

import asyncio

from mcp import ClientSession

from mcp.client.streamable_http import streamablehttp_client

from langchain_mcp_adapters.tools import load_mcp_tools

from langgraph.prebuilt import create_react_agent

from langchain_openai import ChatOpenAI


async def main():

    # MCP服务地址:提前单独启动Streamable HTTP版本MCP Server

    mcp_url = "http://127.0.0.1:3000/mcp/"


    async with streamablehttp_client(mcp_url) as (read, write, _):

        async with ClientSession(read, write) as session:

            await session.initialize()

            tools = await load_mcp_tools(session)


            llm = ChatOpenAI(model="gpt-4o", api_key="xxx")

            agent = create_react_agent(llm, tools)


            result = await agent.ainvoke({

                "messages": "计算 99 + 1,拼接字符串:总和="

            })

            print(result["messages"][-1].content)


if __name__ == "__main__":

    asyncio.run(main())

```


> 

> 启动 Streamable HTTP MCP Server(基于 FastMCP)

```

# server_http.py

from fastmcp import FastMCP


mcp = FastMCP("math-server")


@mcp.tool()

def add(a:int,b:int)->int:

    """两数相加"""

    return a+b


@mcp.tool()

def concat_str(s1:str,s2:str)->str:

    """拼接字符串"""

    return s1+s2


if __name__ == "__main__":

    mcp.run(transport="streamable-http", port=3000)

```

运行:`python server_http.py`,然后再跑 LangChain 客户端代码。


## 示例 3:MultiServerMCPClient 同时连接**多个 MCP 服务**(stdio + Streamable HTTP 混合)

> 一个 Agent 同时接入多个 MCP Server(本地文件 MCP、远程数据库 MCP),自动合并所有工具,工具名自动隔离,企业场景常用


```

import asyncio

from langchain_mcp_adapters.client import MultiServerMCPClient

from langgraph.prebuilt import create_react_agent

from langchain_openai import ChatOpenAI


async def main():

    client = MultiServerMCPClient({

        # 本地stdio MCP

        "math_local": {

            "transport": "stdio",

            "command": "python",

            "args": ["/path/to/server.py"],

        },

        # 远程Streamable HTTP MCP

        "math_remote": {

            "transport": "http",

            "url": "http://127.0.0.1:3000/mcp/",

        }

    })


    async with client:

        tools = await client.get_tools()

        llm = ChatOpenAI(model="gpt-4o", api_key="xxx")

        agent = create_react_agent(llm, tools)

        resp = await agent.ainvoke({"messages": "用本地数学工具计算5+7"})

        print(resp["messages"][-1].content)


if __name__ == "__main__":

    asyncio.run(main())

```


# 底层流程拆解(LangChain 视角)

1. LangChain 启动 MCP Client(stdio/streamable http),建立 transport 通道;

2. `session.initialize()`:MCP 握手协议,交换双方能力;

3. `load_mcp_tools(session)`:调用 MCP `list_tools`,拿到 MCP 服务的工具定义(名字、描述、参数 JSON Schema),**转换成 LangChain BaseTool**;

4. create_react_agent:LLM 拿到工具列表,推理什么时候调用哪个 MCP 工具;

5. Agent 触发工具调用时,内部会执行 MCP `call_tool` 请求,发给 MCP Server;

6. MCP Server 执行函数,返回结果;

7. 结果塞回对话上下文,LLM 继续推理,循环直到任务结束。


# 关键踩坑点

1. **MCP 全是异步**,不能直接同步调用,必须用`async/await`;

2. stdio 模式下 MCP Server**严禁 print 日志**,日志输出 stderr;

3. `langchain-mcp-adapters` 是适配器层;新版 LangChain 1.4 + 内置`langchain.mcp`(beta),不再依赖单独 adapter 包;

4. Streamable HTTP 远程部署一定要加鉴权(Bearer Token),防止暴露工具;

5. MCP 工具异常:MCP Server 抛异常,会被封装成 ToolMessage 返回给大模型,Agent 能看到错误信息继续处理。


# 选型总结

- 本地开发单 MCP 服务:stdio

- 远程 / 局域网共享 MCP 服务:Streamable HTTP

- 多个 MCP 服务混合接入:MultiServerMCPClient


***一个操作鼠标 STDIO 通讯方式的 MCP 例子***

这个例子**可以直接操控本机鼠标**!测试时如果失控,**把鼠标快速甩到屏幕任意角落,PyAutoGUI 自带 FailSafe 安全机制会立刻抛出异常终止自动化**,千万不要关闭 FAILSAFE。

> stdio 模式:LangChain/Claude/Cursor 作为 MCP Host,自动拉起下面这个 python 脚本作为子进程,走 stdin/stdout 管道通信,**不占用端口**。

## 1. 安装依赖

```

pip install mcp pyautogui langchain langgraph langchain-mcp-adapters openai

```

> Linux 额外需要:`sudo apt install python3-xlib`;macOS 需要给终端授予辅助功能权限。


## 2. mouse_mcp_server.py(stdio MCP Server,鼠标服务)

```

import sys

import pyautogui

from mcp.server import MCPServer


# 安全设置,保留紧急停止

pyautogui.FAILSAFE = True

pyautogui.PAUSE = 0.3


mcp = MCPServer("mouse-control-mcp")


@mcp.tool()

def get_mouse_position() -> str:

    """获取当前鼠标坐标

    Returns:

        当前鼠标x,y像素坐标

    """

    x, y = pyautogui.position()

    return f"鼠标当前位置:x={x}, y={y}"


@mcp.tool()

def move_mouse(x: int, y: int, duration: float = 0.3) -> str:

    """移动鼠标到指定屏幕坐标

    Args:

        x: 屏幕横坐标(像素)

        y: 屏幕纵坐标(像素)

        duration: 移动耗时,单位秒,越大移动越顺滑

    """

    pyautogui.moveTo(x=x, y=y, duration=duration)

    return f"鼠标已经移动到 x={x}, y={y}"


@mcp.tool()

def click_mouse(x:int=None, y:int=None, button:str="left", clicks:int=1) -> str:

    """鼠标点击

    Args:

        x: 可选,点击坐标;不传则在当前位置点击

        y: 可选,点击坐标;不传则在当前位置点击

        button: 按键 left / right / middle

        clicks: 点击次数

    """

    if x is not None and y is not None:

        pyautogui.click(x=x, y=y, button=button, clicks=clicks)

    else:

        pyautogui.click(button=button, clicks=clicks)

    return f"完成{button}键点击 {clicks}次"


@mcp.tool()

def scroll_mouse(amount:int) -> str:

    """鼠标滚轮滚动

    Args:

        amount: 正数向上滚,负数向下滚

    """

    pyautogui.scroll(amount)

    return f"滚轮滚动 {amount}"


if __name__ == "__main__":

    # 默认 transport=stdio,走标准输入输出

    mcp.run()

```


## 3. LangChain 客户端 host.py(MCP Host,调用上面鼠标 MCP)

```

import asyncio

from mcp import ClientSession, StdioServerParameters

from mcp.client.stdio import stdio_client

from langchain_mcp_adapters.tools import load_mcp_tools

from langgraph.prebuilt import create_react_agent

from langchain_openai import ChatOpenAI


async def main():

    # 配置:Host会自动拉起 mouse_mcp_server.py 子进程

    server_params = StdioServerParameters(

        command="python",

        # 改成你本机mouse_mcp_server.py绝对路径!

        args=["D:/code/mouse_mcp_server.py"],

    )


    async with stdio_client(server_params) as (read, write):

        async with ClientSession(read, write) as session:

            await session.initialize()

            tools = await load_mcp_tools(session)


            # 替换成你的OpenAI Key,也可以换成Ollama本地模型

            llm = ChatOpenAI(model="gpt-4o", api_key="sk-xxx")

            agent = create_react_agent(llm, tools)


            # 测试提问,Agent会自动调用鼠标MCP工具

            user_query = "先获取鼠标当前位置,然后把鼠标移动到 x=300,y=300,然后左键单击一次"

            result = await agent.ainvoke({"messages": user_query})


            print("\n==== Agent输出 ====")

            print(result["messages"][-1].content)


if __name__ == "__main__":

    asyncio.run(main())

```


## 4. 在 Cursor / Claude Desktop 配置(Host 配置 json)

```

{

  "mcpServers": {

    "mouse-control": {

      "command": "python",

      "args": ["D:/code/mouse_mcp_server.py"]

    }

  }

}

```


保存后重启客户端,就可以直接对话:

> "帮我移动鼠标到 500,500,点击左键"


## 5. MCP Inspector 调试(单独测试 MCP 服务,不用 LangChain)

```

mcp dev mouse_mcp_server.py

```

打开网页,可以直接调用`move_mouse`、`click_mouse`,验证 MCP 服务是否正常。


## 6. stdio 模式重点踩坑点

1. **禁止 print ()**:所有调试日志必须输出`sys.stderr`,print 会污染 stdout,MCP 协议直接崩溃。

```

print("debug log", file=sys.stderr)

```

2. stdio 是**一对一进程**:Host 关闭 → MCP Server 进程自动被杀掉。

3. 权限:macOS 必须给终端 / Cursor 授予「辅助功能」权限;远程环境无桌面(headless)不能跑 pyautogui。

4. 坐标:是**屏幕绝对像素坐标**,多显示器注意坐标范围。


## 7. 完整链路回顾

1. LangChain(Host)启动子进程`python mouse_mcp_server.py`

2. Host 和 Server 通过操作系统管道 stdin/stdout 建立 MCP JSON-RPC 通信

3. Agent(大模型)判断需要移动鼠标 → Host 发送 MCP `call_tool`请求

4. MCP Server 收到请求,调用 pyautogui 操作真实鼠标

5. 操作结果原路返回给大模型,继续对话







Top