当前位置: 首页 > news >正文

MCP(Model Context Protocol)的介绍与开发初体验

MCP 是什么

Model Context Protocol, 模型上下文协议,是一种开放协议,用于标准化应用程序向大型语言模型(LLM)提供上下文的方式。可以将 MCP 视为 AI 应用的 USB-C 接口:正如 USB-C 为设备连接各种外设和配件提供了标准化方式,MCP 也为 AI 模型连接不同数据源和工具提供了统一标准。

为什么要用MCP呢?

MCP 可帮助在 LLM (Large Language Model,大语言模型)基础上构建智能代理和复杂工作流。由于 LLM 常需与数据和工具集成,MCP 提供了以下优势:

  • 不断增长的预构建集成列表:让 LLM 可直接接入多种服务
  • 灵活切换 LLM 供应商:支持多厂商模型的即插即用
  • 数据安全保障最佳实践:在基础设施内安全管控敏感信息

MCP的架构

MCP 的核心是客户端-服务器架构,主机应用可连接多个服务器:

  • Host(MCP 主机):需通过 MCP 访问数据的应用程序(如 Claude 桌面端、IDE 或 AI 工具)
  • MCP Client(MCP 客户端):与服务器保持 1:1 连接的协议客户端
  • MCP Server(MCP 服务器):通过标准化协议暴露特定能力的轻量级程序
  • Local Data Source(本地数据源):服务器可安全访问的设备文件、数据库和服务
  • Remote Service(远程服务):服务器可通过互联网连接的外部系统(如 API)

示例演示

对于大模型而言,默认是不具备回答天气预报的功能的,包含Chat GPT,DeepSeek等。比如在DeepSeek 中,如果询问天气的话,会让你去查询天气预报网站。

当然,现在的LLM的Web页面提供了联网搜索的功能, 勾选的话,也是可以查询天气的。但是对于调用API接口的方式,是没有这种功能的。 于是,可以使用MCP了。

本篇接下来的示例就是演示一个MCP实现天气预报的功能。

MCP目前提供了NodeJS,Python和Java 三种SDK,本篇使用NodeJS进行演示。

MCP服务端开发

创建NodeJS的项目

在命令行依次输入如下命令:

# 创建项目目录
mkdir weather
cd weather

# 使用npm初始化项目
npm init -y

# 安装依赖
npm install @modelcontextprotocol/sdk zod
npm install -D @types/node typescript

# 创建文件
mdir src
new-item src\index.ts

这里在VS Code的终端输入,执行的效果如下:

创建完成的项目目录结构如下:

修改 package.json
  • 新增 “type”: “module”,

  • 添加构建脚本

创建tsconfig.json

内容如下:

{
    "compilerOptions": {
        "target": "ES2022",
        "module": "Node16",
        "moduleResolution": "Node16",
        "outDir": "./build",
        "rootDir": "./src",
        "strict": true,
        "esModuleInterop": true,
        "skipLibCheck": true,
        "forceConsistentCasingInFileNames": true
    },
    "include": [
        "src/**/*"
    ],
    "exclude": [
        "node_modules"
    ]
}
index.js

编写获取天气预报的代码:

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

const NWS_API_BASE = "https://api.weather.gov";
const USER_AGENT = "weather-app/1.0";

// Create server instance
const server = new McpServer({
    name: "weather",
    version: "1.0.0",
});


// Helper function for making NWS API requests
async function makeNWSRequest<T>(url: string): Promise<T | null> {
    const headers = {
        "User-Agent": USER_AGENT,
        Accept: "application/geo+json",
    };

    try {
        const response = await fetch(url, { headers });
        if (!response.ok) {
            throw new Error(`HTTP error! status: ${response.status}`);
        }
        return (await response.json()) as T;
    } catch (error) {
        console.error("Error making NWS request:", error);
        return null;
    }
}

interface AlertFeature {
    properties: {
        event?: string;
        areaDesc?: string;
        severity?: string;
        status?: string;
        headline?: string;
    };
}

// Format alert data
function formatAlert(feature: AlertFeature): string {
    const props = feature.properties;
    return [
        `Event: ${props.event || "Unknown"}`,
        `Area: ${props.areaDesc || "Unknown"}`,
        `Severity: ${props.severity || "Unknown"}`,
        `Status: ${props.status || "Unknown"}`,
        `Headline: ${props.headline || "No headline"}`,
        "---",
    ].join("\n");
}

interface ForecastPeriod {
    name?: string;
    temperature?: number;
    temperatureUnit?: string;
    windSpeed?: string;
    windDirection?: string;
    shortForecast?: string;
}

interface AlertsResponse {
    features: AlertFeature[];
}

interface PointsResponse {
    properties: {
        forecast?: string;
    };
}

interface ForecastResponse {
    properties: {
        periods: ForecastPeriod[];
    };
}


// Register weather tools
server.tool(
    "get-alerts",
    "Get weather alerts for a state",
    {
        state: z.string().length(2).describe("Two-letter state code (e.g. CA, NY)"),
    },
    async ({ state }) => {
        const stateCode = state.toUpperCase();
        const alertsUrl = `${NWS_API_BASE}/alerts?area=${stateCode}`;
        const alertsData = await makeNWSRequest<AlertsResponse>(alertsUrl);

        if (!alertsData) {
            return {
                content: [
                    {
                        type: "text",
                        text: "Failed to retrieve alerts data",
                    },
                ],
            };
        }

        const features = alertsData.features || [];
        if (features.length === 0) {
            return {
                content: [
                    {
                        type: "text",
                        text: `No active alerts for ${stateCode}`,
                    },
                ],
            };
        }

        const formattedAlerts = features.map(formatAlert);
        const alertsText = `Active alerts for ${stateCode}:\n\n${formattedAlerts.join("\n")}`;

        return {
            content: [
                {
                    type: "text",
                    text: alertsText,
                },
            ],
        };
    },
);

server.tool(
    "get-forecast",
    "Get weather forecast for a location",
    {
        latitude: z.number().min(-90).max(90).describe("Latitude of the location"),
        longitude: z.number().min(-180).max(180).describe("Longitude of the location"),
    },
    async ({ latitude, longitude }) => {
        // Get grid point data
        const pointsUrl = `${NWS_API_BASE}/points/${latitude.toFixed(4)},${longitude.toFixed(4)}`;
        const pointsData = await makeNWSRequest<PointsResponse>(pointsUrl);

        if (!pointsData) {
            return {
                content: [
                    {
                        type: "text",
                        text: `Failed to retrieve grid point data for coordinates: ${latitude}, ${longitude}. This location may not be supported by the NWS API (only US locations are supported).`,
                    },
                ],
            };
        }

        const forecastUrl = pointsData.properties?.forecast;
        if (!forecastUrl) {
            return {
                content: [
                    {
                        type: "text",
                        text: "Failed to get forecast URL from grid point data",
                    },
                ],
            };
        }

        // Get forecast data
        const forecastData = await makeNWSRequest<ForecastResponse>(forecastUrl);
        if (!forecastData) {
            return {
                content: [
                    {
                        type: "text",
                        text: "Failed to retrieve forecast data",
                    },
                ],
            };
        }

        const periods = forecastData.properties?.periods || [];
        if (periods.length === 0) {
            return {
                content: [
                    {
                        type: "text",
                        text: "No forecast periods available",
                    },
                ],
            };
        }

        // Format forecast periods
        const formattedForecast = periods.map((period: ForecastPeriod) =>
            [
                `${period.name || "Unknown"}:`,
                `Temperature: ${period.temperature || "Unknown"}°${period.temperatureUnit || "F"}`,
                `Wind: ${period.windSpeed || "Unknown"} ${period.windDirection || ""}`,
                `${period.shortForecast || "No forecast available"}`,
                "---",
            ].join("\n"),
        );

        const forecastText = `Forecast for ${latitude}, ${longitude}:\n\n${formattedForecast.join("\n")}`;

        return {
            content: [
                {
                    type: "text",
                    text: forecastText,
                },
            ],
        };
    },
);

// 主函数
async function main() {
    const transport = new StdioServerTransport();
    await server.connect(transport);
    console.error("Weather MCP Server running on stdio");
}

main().catch((error) => {
    console.error("Fatal error in main():", error);
    process.exit(1);
});

上面的代码实现了天气服务。它通过调用美国National Weather Service (NWS) API 获取

  • 天气警报:get-alerts
  • 天气预报:get-forecast
构建
npm run build

运行构建命令后会在build 目录下产生一个构建的 index.js 文件。

使用MCP Inspector 查看MCP服务

MCP提供了一个检查器,这是一款交互式开发者工具,专为测试和调试 MCP 服务器设计。

使用方式很简单,执行如下命令

npx @modelcontextprotocol/inspector node build/index.js

执行完成,会启动一个Web 服务。

在浏览器中打开控制台输出的地址: http://localhost:5173/

点击Connect 之后,就可以看到在代码中写的两个服务了,选择 get-alert,在State 输入NY ,也就是查询纽约州的天气警报, 最后点击Run Tool 就可以看到纽约州的一些天气的警报。

到这里,聪明的你可能要问了,这不就是调用一个在线API实现的一个Web服务吗? 和LLM有什么关系呢?

别急,这里只是演示MCP服务的效果,关键的是这个服务可以提供给LLM使用,因为它定义了一些和LLM交互的信息格式。通过MCP服务端的演示之后就会豁然开朗了。

MCP客户端使用

这里使用Roo Code作为MCP客户端来演示。

首先需要在VS Code 中安装Roo Code,认证授权之后打开Roo Code。

  1. 点击上方的 “MCP Servers”

  1. 点击 Edit MCP Settings 之后,会在编辑器打开一个配置文件,

补充下面的mcpServers 的配置:

"mcpServers": {
    "my-weather-server": {
      "command": "node",
      "args": [
        "D:/devworkspace/vs/ai_ency/mcp/weather/build/index.js"
      ],
      "env": {},
      "autoApprove": []
    }
  }

保存之后,在左侧的区块就会多出一个MCP 的Server了,如下图:

回到Roo Code 的Chat 对话框,输入天气相关的对话,则这里就可以自动执行相关的任务并输出。这里因为网络的原因,这台机器没有完整的跑出结果,但还是贴一个执行中的图。


相关文章:

  • Java面试黄金宝典4
  • Clion远程开发配置
  • 【QA】C和C++有哪些常用的调用约定
  • 记录一次,rabbitmq开启stomp插件之后,还是连不上15674端口的问题
  • Baklib企业CMS元数据与协作管理优化
  • Java Spring 中循环依赖的解决之道
  • npm error gyp info
  • AI里的RAG到底是什么?
  • 春天遇到了冬天的吻
  • 《解锁元宇宙构建:AI与云原生区块链的协同奥秘》
  • Web爬虫利器FireCrawl:全方位助力AI训练与高效数据抓取。本地部署方式
  • openEuler24.03 LTS下安装Hive3
  • 十四、OSG学习笔记-事件响应
  • WEB攻防-PHP反序列化-字符串逃逸
  • 如何测试交换机数据回流
  • C#中修饰符——abstract、virtual
  • 天梯赛 PTAL2-009 抢红包
  • Hugging Face模型国内镜像HF Mirror下载
  • Python Pyecharts面试题及参考答案
  • OpenHarmony 开源鸿蒙北向开发——linux使用make交叉编译第三方库
  • 美乌矿产协议签署被曝“临门一脚”时生变,美方提附加条件
  • 美乌矿产协议预计最早于今日签署
  • 滨江集团:一季度营收225.07亿元,净利润9.75亿元
  • “80后”商洛市委副书记、市政府党组副书记赵孝任商洛市副市长
  • 黄育奇当选福建惠安县人民政府县长
  • 新华保险一季度净赚58.82亿增19%,保费收入增28%