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

如何开发一个MCP Server

之前的一篇文章介绍了如何安装cline 来使用应用市场已经安装好的MCP Server ,官网的介绍MCP Server 其实可以使用nodejs 或者python 来编写,最近看到有个spingAIMCP 的开源项目也可以用来写MCP Server ,那么可以三种方式都来实践一下,深入了解一下MCP Server 的底层原理。

官方sdk : Introduction - Model Context Protocol

还是支持了很多种语言的~

1.Python

官网SDK :GitHub - modelcontextprotocol/python-sdk: The official Python SDK for Model Context Protocol servers and clients

需求实现: 官网的计算器小工具

1.初始化python 项目:

//使用UV 管理python项目
uv init mcp-server-demo-python
cd  mcp-server-demo-python// 然后将 MCP 添加到您的项目依赖项中:
uv add "mcp[cli]"   //或者使用pip来安装依赖

2.创建一个简单的server.py 文件

# server.py
from mcp.server.fastmcp import FastMCP# Create an MCP server
mcp = FastMCP("如雪测试MCP For Python")# Add an addition tool
@mcp.tool()
def add(a: int, b: int) -> int:"""Add two numbers"""return a + b - 5# Add a dynamic greeting resource
@mcp.resource("greeting://{name}")
def get_greeting(name: str) -> str:"""Get a personalized greeting"""return f"Hello, {name}!"

3.测试服务和调试:

测试和调试服务器的最快方法是使用 MCP Inspector:mcp dev server.py

报错了 :

排查了一下,一开始依赖没有安装成功,mcp服务一直没有连上,感觉这个uv 命令并不是很稳定

对python 还是不够熟,依赖安装成功后,uv.lock 和.venv 的lib下面会有相关的包信息。

使用 Inspector 进行调试

http://127.0.0.1:6274/#resources ,能够看到server 的工具列表了 ,因为代码里面还对加法做了下处理,答案也能正确给出

4.Cline 端配置

{"mcpServers": {"fengruxue": {"disabled": false,"timeout": 60,"command": "uv","args": ["--directory","/Users/fengruxue/Documents/pythonworkplace/mcp-server-demo-python","run","server.py"],"transportType": "stdio"}}
}

cline 端正确调用了add工具,并给出答案,运行多两次发现cline也不会去调工具了,大概是加法太简单,不会去调

加个随机方法:

2.TypeScript

需求实现: 获取天气

官网例子:For Server Developers - Model Context Protocol

1.安装依赖

# Create a new directory for our project
mkdir weather
cd weather# Initialize a new npm project
npm init -y# Install dependencies
npm install @modelcontextprotocol/sdk zod
npm install -D @types/node typescript# Create our files
mkdir src
touch src/index.ts

2.代码实现

package.json

{"type": "module","bin": {"weather": "./build/index.js"},"scripts": {"build": "tsc && chmod 755 build/index.js"},"files": ["build"],
}

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,创建mcp实例
const server = new McpServer({name: "weather",version: "1.0.0",capabilities: {resources: {},tools: {}, //工具},
});// 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 dataconst 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 dataconst 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 periodsconst 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);
});

3.编译文件

npm run build 

4.cline 端配置服务:

{"mcpServers": {"weather": {"command": "node","args": ["/Users/fengruxue/Documents/VCWorkplace/mcp-demo-js/build/index.js"]}}
}

测试:

获取纽约天气 ,能够正确调用到工具 (国内天气api 不支持)

调用接口后,模型会整合进行输出给出答案。

把服务关了后就查询不到工具了:

3.JAVA

Spring AI Alibaba 开源项目地址:GitHub - alibaba/spring-ai-alibaba: Agentic AI Framework for Java Developers

本文外网博客地址:https://java2ai.com

本示例源码地址:spring-ai-alibaba-examples/spring-ai-alibaba-mcp-example at main · springaialibaba/spring-ai-alibaba-examples · GitHub

官网操作步骤:快速开始-阿里云Spring AI Alibaba官网官网

注意:因为 Spring AI Alibaba 基于 Spring Boot 3.x 开发,因此本地 JDK 版本要求为 17 及以上。

JDK下载链接: Java Downloads | Oracle


需求实现: 获取天气预报

1.代码实现

主要是三个文件,详细的可以看项目源码:spring-ai-alibaba-examples/spring-ai-alibaba-mcp-example at main · springaialibaba/spring-ai-alibaba-examples · GitHub

2.打包编译

mvn clean package -DskipTests

3.配置到cline 端

{"mcpServers": {"weather": {"command": "java","args": ["-Dspring.ai.mcp.server.stdio=true","-Dspring.main.web-application-type=none","-Dlogging.pattern.console=","-jar","/Users/fengruxue/Documents/ideaworkplace/myself/Mcp2Java/target/Mcp2Java-1.0-SNAPSHOT.jar"],"env": {}}}
}

服务也能正常连上了

刚搞明白MCP,发现谷歌又出了个A2A 协议了,协调多个agent之间的通信,这节奏,跟不过,跟不过~

http://www.xdnf.cn/news/7968.html

相关文章:

  • Google机器学习实践指南(梯度下降篇)
  • 关于pgSQL配置后Navicat连接不上的解决方法
  • JAVA开发工具延长方案
  • 大模型在闭合性胫骨平台骨折诊疗全流程中的应用研究报告
  • MySql添加非空字段时的“伪空”问题
  • Elasticsearch搜索排名优化
  • 如何在 Mac M4 芯片电脑上卸载高版本的 Node.js
  • el-radio-group 与 el-dropdown 组合使用的注意事项
  • 根据您的硬件配置(16GB显存+64GB内存)和性能要求(≥80 token/s)
  • 学习路之uniapp--unipush2.0推送功能--给自己发通知
  • 【C++】模板下(泛型编程)
  • 【人工智能发展史】从黎明到曙光02
  • MySQL字符串拼接方法全解析
  • spring cloud config更新配置
  • OpenCV CUDA模块图像过滤------用于创建一个最大值盒式滤波器(Max Box Filter)函数createBoxMaxFilter()
  • 【web全栈】若依框架B站学习视频:基础篇01-04
  • 【Linux我做主】探秘进程与fork
  • docker-compose使用详解
  • 在 Docusaurus 博客中显示文章阅读次数
  • ABAP BADI: ME_PROCESS_PO_CUST~PROCESS_ITEM 报错消息异常处理
  • 信息系统项目管理师考前练习1
  • IOMMU简介
  • 人脸识别备案介绍
  • 权限控制相关实现
  • java小结(一)
  • mybatisplus的分页查询插件
  • 差分探头在DCDC变换器波形测试中的应用
  • 【vue-text-highlight】在vue2的使用教程
  • Java操作数据库,JDBC
  • 白光干涉仪AM系列:量化管控纳米级粗糙度,位移传感器关键零件寿命提升50%