MCP最佳实践
#OpenClaw# #MCP#
MCP协议
移步:https://www.runoob.com/np/mcp-protocol.html 更详细的协议标准
MCP(Model Context Protocol,模型上下文协议)是由 Anthropic 推出的开源协议,旨在实现大型语言模型(LLM)与外部数据源和工具的无缝集成,用来在大模型和数据源之间建立安全双向的链接。
MCP工具调用流程
用户发送问题 -> LLM 分析可用工具 -> 客户端通过 MCP 服务器来执行所选工具 -> 将结果发送回 LLM -> LLM根据工具返回结果和用户问题进行回答。

MCP 定义了三种标准化交互方式,覆盖不同控制主体:
| 原语 | 控制权 | 能力 | 典型场景 |
|---|---|---|---|
| Resources | 应用 / 服务器 | 只读数据访问 | 读取本地文件、查询数据库、获取知识库 |
| Tools | 模型 | 主动执行操作 | 发送邮件、运行代码、调用 API、控制设备 |
| Prompts | 用户 | 复用工作流 | 代码生成模板、报告撰写模板、客服话术 |
实战
自己编写(大部分是Trae SOLO 完成)天气预报的MCP服务(Tools交互类型)
以weather MCP服务为例,源码:https://gitcode.com/SUI517/gitcode_knowledge
项目截图(weather,mysql[实现三种模式:Tools,Resources,Prompts交互])


1、创建McpServer
const server=new McpServer({
name:"weather-server",
version:"1.0.0"
});
2、注册服务(MCP工具类型交互)
server.registerTool('get_weather',{
description:'获取城市的天气预报MCP服务',
inputSchema:{
city:z.string().describe('城市名称,如:北京、上海'),
days:z.number().min(1).max(7).default(3).describe('预报天数(1-7天)')
}
}),asyns({city,days}) => {
...
return {
content:[
{
type:'text',
text:JSON.stringify(weatherData, null, 2)
}
}
};
}
catch(error) {
return {
content:[{type:'text',text:' ${error.message}'}]
};
}
3、入口函数
async function main(){
//创建标准I/O通信,用于本地进程通信
const transport=new StudioServerTransport();
//开始连接
await server.connet(transport);
}
//捕获主函数异常
main().catch((error)=>{})
index.js
#!/usr/bin/env node
/**
* Weather MCP Server
* 提供天气预报查询功能的MCP服务器
* 支持查询指定城市的1-7天天气预报
*/
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import * as z from 'zod/v4';
import { getWeatherForecast } from './weather.js';
// 创建MCP服务器实例
const server = new McpServer({
name: 'weather-server',
version: '1.0.0'
}, {
capabilities: {
tools: {}
}
});
// 注册天气预报工具
server.registerTool('get_weather', {
description: '获取指定城市的天气预报信息',
inputSchema: {
city: z.string().describe('城市名称(例如:北京、上海、广州)'),
days: z.number().min(1).max(7).default(3).describe('预报天数(1-7天)')
}
}, async ({ city, days }) => {
try {
if (!city) {
throw new Error('城市名称不能为空');
}
const weatherData = await getWeatherForecast(city, days);
return {
content: [
{
type: 'text',
text: JSON.stringify(weatherData, null, 2),
},
],
};
} catch (error) {
return {
content: [
{
type: 'text',
text: `获取天气预报失败: ${error.message}`,
},
],
isError: true,
};
}
});
// 主函数:启动服务器
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);
});
2、weather.js
/**
* 天气预报模块
* 提供从Open-Meteo API获取天气数据的功能
*/
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
import { dirname, join } from 'path';
import { fileURLToPath } from 'url';
/**
* 持久化缓存实现
*/
class WeatherCache {
constructor() {
this.cacheTimeout = 30 * 60 * 1000; // 30分钟缓存过期时间
this.cacheFile = this.getCacheFilePath();
this.cache = this.loadCacheFromFile();
}
/**
* 获取缓存文件路径
* @returns {string} 缓存文件路径
*/
getCacheFilePath() {
try {
const __filename = fileURLToPath(import.meta.url);
const cacheDir = join(dirname(__filename), '.cache');
// 确保缓存目录存在
if (!existsSync(cacheDir)) {
mkdirSync(cacheDir, { recursive: true });
}
return join(cacheDir, 'weather-cache.json');
} catch (error) {
// 如果无法获取文件路径,使用临时目录
return join(process.cwd(), '.cache', 'weather-cache.json');
}
}
/**
* 从文件加载缓存
* @returns {Map} 缓存Map
*/
loadCacheFromFile() {
try {
if (!existsSync(this.cacheFile)) {
return new Map();
}
const data = readFileSync(this.cacheFile, 'utf-8');
const parsed = JSON.parse(data);
const cache = new Map();
// 清除过期缓存
const now = Date.now();
for (const [key, value] of Object.entries(parsed)) {
if (now - value.timestamp <= this.cacheTimeout) {
cache.set(key, value);
}
}
// 保存清理后的缓存
this.saveCacheToFile(cache);
return cache;
} catch (error) {
console.error('加载缓存失败:', error.message);
return new Map();
}
}
/**
* 保存缓存到文件
* @param {Map} cache - 缓存Map
*/
saveCacheToFile(cache) {
try {
const data = Object.fromEntries(cache.entries());
writeFileSync(this.cacheFile, JSON.stringify(data, null, 2), 'utf-8');
} catch (error) {
console.error('保存缓存失败:', error.message);
}
}
/**
* 生成缓存键
* @param {string} city - 城市名称
* @param {number} days - 预报天数
* @returns {string} 缓存键
*/
getCacheKey(city, days) {
return `${city}_${days}`;
}
/**
* 获取缓存数据
* @param {string} city - 城市名称
* @param {number} days - 预报天数
* @returns {Object|null} 缓存数据或null
*/
get(city, days) {
const key = this.getCacheKey(city, days);
const cached = this.cache.get(key);
if (!cached) {
return null;
}
// 检查是否过期
if (Date.now() - cached.timestamp > this.cacheTimeout) {
this.cache.delete(key);
this.saveCacheToFile(this.cache);
return null;
}
return cached.data;
}
/**
* 设置缓存数据
* @param {string} city - 城市名称
* @param {number} days - 预报天数
* @param {Object} data - 天气数据
*/
set(city, days, data) {
const key = this.getCacheKey(city, days);
this.cache.set(key, {
data,
timestamp: Date.now()
});
this.saveCacheToFile(this.cache);
}
/**
* 清除所有缓存
*/
clear() {
this.cache.clear();
this.saveCacheToFile(this.cache);
}
/**
* 清除过期缓存
*/
clearExpired() {
const now = Date.now();
for (const [key, cached] of this.cache.entries()) {
if (now - cached.timestamp > this.cacheTimeout) {
this.cache.delete(key);
}
}
this.saveCacheToFile(this.cache);
}
}
// 创建全局缓存实例
const weatherCache = new WeatherCache();
/**
* 获取指定城市的天气预报
* @param {string} city - 城市名称
* @param {number} days - 预报天数(默认3天)
* @returns {Promise<Object>} 天气预报数据
*/
async function getWeatherForecast(city, days = 3) {
try {
// 先检查缓存
const cachedData = weatherCache.get(city, days);
if (cachedData) {
console.error(`使用缓存数据: ${city},未来${days}天`);
return cachedData;
}
console.error(`正在查询城市: ${city},未来${days}天的天气预报...`);
// 第一步:调用地理编码API获取城市坐标
const geoResponse = await fetch(
`https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(city)}&count=1&language=zh&format=json`
);
if (!geoResponse.ok) {
throw new Error('地理编码API请求失败');
}
const geoData = await geoResponse.json();
if (!geoData.results || geoData.results.length === 0) {
throw new Error(`未找到城市: ${city}`);
}
// 提取城市位置信息
const location = geoData.results[0];
const { latitude, longitude, name, country, admin1 } = location;
// 第二步:使用坐标调用天气API获取预报数据
const weatherResponse = await fetch(
`https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}&daily=weathercode,temperature_2m_max,temperature_2m_min,precipitation_sum,windspeed_10m_max&timezone=auto&forecast_days=${days}`
);
if (!weatherResponse.ok) {
throw new Error('天气API请求失败');
}
const weatherData = await weatherResponse.json();
// 将天气数据转换为更友好的格式
const forecast = weatherData.daily.time.map((date, index) => {
return {
date: date,
weather: getWeatherDescription(weatherData.daily.weathercode[index]),
temperature: {
max: weatherData.daily.temperature_2m_max[index],
min: weatherData.daily.temperature_2m_min[index],
},
precipitation: weatherData.daily.precipitation_sum[index],
windSpeed: weatherData.daily.windspeed_10m_max[index],
};
});
// 返回格式化的天气数据
const result = {
location: {
name: name,
country: country,
province: admin1 || '',
coordinates: {
latitude: latitude,
longitude: longitude,
},
},
forecast: forecast,
};
// 存入缓存
weatherCache.set(city, days, result);
return result;
} catch (error) {
throw new Error(`获取天气预报失败: ${error.message}`);
}
}
/**
* 根据WMO天气代码返回中文天气描述
* @param {number} code - WMO天气代码
* @returns {string} 中文天气描述
*/
function getWeatherDescription(code) {
const weatherCodes = {
0: '晴朗',
1: '主要晴朗',
2: '部分多云',
3: '阴天',
45: '雾',
48: '雾凇',
51: '毛毛雨',
53: '中度毛毛雨',
55: '大毛毛雨',
61: '小雨',
63: '中雨',
65: '大雨',
66: '冻雨',
67: '大冻雨',
71: '小雪',
73: '中雪',
75: '大雪',
77: '雪粒',
80: '小阵雨',
81: '中阵雨',
82: '大阵雨',
85: '小阵雪',
86: '大阵雪',
95: '雷暴',
96: '雷暴伴冰雹',
99: '强雷暴伴冰雹',
};
return weatherCodes[code] || '未知天气';
}
export { getWeatherForecast };
package.json
{
"name": "mcp-weather-server",
"version": "1.0.0",
"description": "MCP server for weather forecast",
"type": "module",
"main": "src/index.js",
"scripts": {
"start": "node src/index.js",
"dev": "node --watch src/index.js"
},
"keywords": ["mcp", "weather", "forecast"],
"author": "",
"license": "MIT",
"dependencies": {
"@modelcontextprotocol/sdk": "^1.0.4"
}
}
readme.md
# MCP 天气预报服务器
这是一个基于MCP(Model Context Protocol)协议的天气预报服务器,可以获取指定城市的天气预报信息。
## 功能特性
- 支持全球城市天气预报查询
- 支持1-7天的天气预报
- 提供详细的天气信息,包括温度、降水、风速等
- 使用免费的Open-Meteo API,无需API密钥
## 安装
1. 克隆或下载此项目
2. 安装依赖:
```bash
npm install
```
## 使用方法
### 启动服务器
```bash
npm start
```
### 在MCP客户端中配置
在你的MCP客户端配置文件中添加以下配置:
```json
{
"mcpServers": {
"weather": {
"command": "node",
"args": ["c:\\work\\ai\\mcp\\src\\index.js"]
}
}
}
```
### 可用工具
#### get_weather
获取指定城市的天气预报信息。
**参数:**
- `city` (必需): 城市名称,例如:北京、上海、广州、New York、Tokyo等
- `days` (可选): 预报天数,默认为3天,范围1-7天
**示例请求:**
```json
{
"name": "get_weather",
"arguments": {
"city": "北京",
"days": 5
}
}
```
**示例响应:**
```json
{
"location": {
"name": "Beijing",
"country": "China",
"province": "Beijing",
"coordinates": {
"latitude": 39.9042,
"longitude": 116.4074
}
},
"forecast": [
{
"date": "2026-03-10",
"weather": "晴朗",
"temperature": {
"max": 15,
"min": 3
},
"precipitation": 0,
"windSpeed": 12
}
]
}
```
## 项目结构
```
mcp-weather-server/
├── package.json # 项目配置文件
├── src/
│ ├── index.js # MCP服务器主文件
│ └── weather.js # 天气预报功能实现
└── README.md # 项目说明文档
```
## 技术栈
- Node.js
- @modelcontextprotocol/sdk - MCP SDK
- Open-Meteo API - 免费的天气API
- Open-Meteo Geocoding API - 地理编码API
## API说明
本项目使用以下免费API:
1. **Open-Meteo Geocoding API**
- 用于将城市名称转换为经纬度坐标
- 文档: https://open-meteo.com/en/docs/geocoding-api
2. **Open-Meteo Weather API**
- 用于获取天气预报数据
- 文档: https://open-meteo.com/en/docs
## 注意事项
- 使用的是免费API,有请求频率限制
- 需要网络连接才能获取天气数据
- 支持中文和英文城市名称
## 开发
### 开发模式
```bash
npm run dev
```
### 添加新工具
1. 在 `src/index.js` 中的 `ListToolsRequestSchema` 处理器中添加工具定义
2. 在 `CallToolRequestSchema` 处理器中添加工具实现逻辑
3. 如需要,在 `src/` 目录下创建新的功能模块
## 许可证
MIT License
TRAE_SOLO_INTEGRATION.md(MCP服务添加到Trae中)
# TRAE SOLO 集成指南
本文档详细说明如何将天气预报MCP服务器集成到TRAE SOLO中。
## 什么是TRAE SOLO?
TRAE SOLO是一个支持MCP协议的AI开发平台,可以轻松集成各种MCP服务器来扩展AI助手的能力。通过MCP协议,TRAE SOLO可以调用外部工具和服务。
## 集成方式
TRAE SOLO提供了两种配置MCP服务器的方式:
1. **从MCP市场直接添加** - 适合使用预置的MCP服务器
2. **手动配置MCP Server** - 适合自定义MCP服务器(推荐用于本项目)
## 方法一:手动配置MCP Server(推荐)
### 步骤1:准备MCP服务器
确保你的天气预报MCP服务器已经准备就绪:
```bash
cd c:\work\ai\mcp
npm install
npm start
```
### 步骤2:在TRAE SOLO中添加MCP服务器
1. 打开TRAE SOLO IDE
2. 点击左侧边栏的"MCP"图标或进入设置
3. 点击"添加MCP Server"按钮
4. 选择"手动配置"选项
### 步骤3:配置MCP服务器
在配置界面中,输入以下配置信息:
**服务器名称:** `weather-server`
**命令:** `node`
**参数:** `["c:\\work\\ai\\mcp\\src\\index.js"]`
**完整JSON配置示例:**
```json
{
"name": "weather-server",
"command": "node",
"args": ["c:\\work\\ai\\mcp\\src\\index.js"],
"env": {}
}
```
### 步骤4:保存并测试
1. 点击"保存"或"确认"按钮
2. TRAE SOLO会自动启动MCP服务器
3. 查看服务器状态,确保显示"已连接"或"运行中"
## 方法二:通过配置文件集成
### 创建TRAE配置文件
在TRAE SOLO项目根目录创建 `.trae/mcp.json` 文件:
```json
{
"mcpServers": {
"weather": {
"command": "node",
"args": ["c:\\work\\ai\\mcp\\src\\index.js"],
"env": {}
}
}
}
```
### 重启TRAE SOLO
保存配置文件后,重启TRAE SOLO以加载新的MCP服务器配置。
## 使用天气预报功能
集成完成后,你可以在TRAE SOLO中使用天气预报功能:
### 示例对话
**用户:** 查询北京未来3天的天气预报
**TRAE SOLO:** 会自动调用weather MCP服务器的get_weather工具,返回详细的天气预报信息。
### 可用工具
- **get_weather**: 获取指定城市的天气预报
- 参数:
- `city` (必需): 城市名称,如"北京"、"上海"、"New York"
- `days` (可选): 预报天数,默认3天,范围1-7天
## 验证集成
### 方法1:通过TRAE SOLO界面验证
1. 在TRAE SOLO的聊天界面输入:"查询北京的天气预报"
2. 观察是否正确调用weather服务器并返回结果
### 方法2:通过日志验证
1. 查看TRAE SOLO的控制台输出
2. 确认看到类似以下的日志:
```
Weather MCP Server running on stdio
```
### 方法3:通过测试脚本验证
运行项目中的测试脚本:
```bash
cd c:\work\ai\mcp
node test.js
```
## 故障排除
### 问题1:MCP服务器无法启动
**解决方案:**
- 检查Node.js是否已安装:`node --version`
- 确认依赖已安装:`npm install`
- 检查文件路径是否正确
### 问题2:连接超时
**解决方案:**
- 确保MCP服务器正在运行
- 检查防火墙设置
- 验证配置文件中的路径是否正确
### 问题3:工具调用失败
**解决方案:**
- 检查网络连接(天气API需要网络)
- 验证城市名称是否正确
- 查看MCP服务器的错误日志
### 问题4:返回的天气数据不准确
**解决方案:**
- 确认城市名称拼写正确
- 尝试使用英文城市名称
- 检查Open-Meteo API服务状态
## 高级配置
### 环境变量配置
如果需要配置环境变量,可以在配置文件中添加:
```json
{
"mcpServers": {
"weather": {
"command": "node",
"args": ["c:\\work\\ai\\mcp\\src\\index.js"],
"env": {
"NODE_ENV": "production",
"LOG_LEVEL": "debug"
}
}
}
}
```
### 工作目录配置
指定MCP服务器的工作目录:
```json
{
"mcpServers": {
"weather": {
"command": "node",
"args": ["src\\index.js"],
"cwd": "c:\\work\\ai\\mcp",
"env": {}
}
}
}
```
## 性能优化
### 1. 启用缓存
在 `src/weather.js` 中添加缓存逻辑,减少API调用:
```javascript
const cache = new Map();
const CACHE_TTL = 3600000; // 1小时
async function getWeatherForecast(city, days = 3) {
const cacheKey = `${city}-${days}`;
const cached = cache.get(cacheKey);
if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
return cached.data;
}
// ... 原有的API调用逻辑
cache.set(cacheKey, {
data: result,
timestamp: Date.now()
});
return result;
}
```
### 2. 批量查询优化
如果需要查询多个城市的天气,可以实现批量查询功能。
## 安全建议
1. **API密钥保护**:虽然本项目使用免费API,但如果将来使用需要密钥的API,请妥善保管密钥
2. **输入验证**:验证用户输入的城市名称,防止注入攻击
3. **错误处理**:妥善处理API错误,避免泄露敏感信息
4. **访问控制**:如果部署到生产环境,考虑添加访问控制
## 扩展功能
### 添加更多天气工具
你可以扩展MCP服务器,添加更多天气相关工具:
```javascript
// 在 src/index.js 中添加新工具
{
name: 'get_air_quality',
description: '获取指定城市的空气质量指数',
inputSchema: {
type: 'object',
properties: {
city: {
type: 'string',
description: '城市名称'
}
},
required: ['city']
}
}
```
### 集成其他数据源
除了Open-Meteo,你还可以集成其他天气API:
- WeatherAPI
- OpenWeatherMap
- 和风天气
## 相关资源
- [MCP协议文档](https://modelcontextprotocol.io/)
- [TRAE SOLO官方文档](https://docs.trae.ai/)
- [Open-Meteo API文档](https://open-meteo.com/en/docs)
## 总结
通过以上步骤,你已经成功将天气预报MCP服务器集成到TRAE SOLO中。现在你可以在TRAE SOLO中使用强大的天气预报功能,提升AI助手的能力。
如果遇到任何问题,请参考故障排除部分或查看项目的README.md文档。
weather-client.js(客户端测试)
这个js是用户测试mcp服务用的,当IDE加载了 mpc-weather 服务后,你在聊天窗口查询天气时,IDE会 直接调用MCP工具, 为了理解整个MCP的调用过程是必须要了解的内容;
1、启动服务进程 构造函数
//- pipe :创建管道,用于JSON-RPC通信
//- inherit :直接输出日志到终端
this.server.spawn(command,args,stdio:['pipe','pipe','inherit']);
2、监听服务器输出
// 每行都是独立的JSON-RPC消息
// 通过id匹配请求和响应
this.rl.on('line', (line) => {...});
3、发送请求
sendRequest(request) {
return new Promise((resolve, reject) => {
this.pendingRequests.set(request.id, { resolve, reject });
this.server.stdin.write(JSON.stringify(request) + '\n');
});
}
4、MCP握手
async initialize() {
// 步骤1:发送initialize请求
const result = await this.sendRequest({
jsonrpc: '2.0',
id: this.requestId++,
method: 'initialize',
params: { /* ... */ }
});
// 步骤2:发送initialized通知
this.sendNotification({
jsonrpc: '2.0',
method: 'initialized'
});
return result;
}
总结
客户端 服务器
│ │
│ 1. spawn() │
├───────────────────────>│ 启动进程
│ │
│ 2. initialize请求 │
├───────────────────────>│ 处理初始化
│ │
│ 3. initialize响应 │
│<───────────────────────┤
│ │
│ 4. initialized通知 │
├───────────────────────>│ 握手完成
│ │
│ 5. tools/call请求 │
├───────────────────────>│ 执行工具
│ │
│ 6. tools/call响应 │
│<───────────────────────│ 返回结果
│ │
│ 7. 关闭连接 │
├───────────────────────>│ 进程退出
#!/usr/bin/env node
/**
* Weather MCP Client
* 用于测试Weather MCP服务器的客户端程序
* 可以直接从命令行查询天气预报
*/
import { spawn } from 'child_process';
import { createInterface } from 'readline';
/**
* MCP客户端类
* 负责与MCP服务器进行通信
*/
class MCPClient {
constructor(command, args) {
// 启动MCP服务器进程
// stdio配置:
// - 'pipe': stdin, stdout - 用于JSON-RPC通信
// - 'inherit': stderr - 继承父进程的stderr,用于日志输出
this.server = spawn(command, args, {
stdio: ['pipe', 'pipe', 'inherit']
});
// 创建readline接口读取服务器输出
this.rl = createInterface({
input: this.server.stdout,
crlfDelay: Infinity
});
// 使用时间戳作为requestId的基础,避免ID冲突
this.requestId = Date.now();
this.pendingRequests = new Map();
// 监听服务器输出的每一行
this.rl.on('line', (line) => {
try {
const response = JSON.parse(line);
const { id, result, error } = response;
// 查找对应的pending请求并处理响应
if (this.pendingRequests.has(id)) {
const { resolve, reject } = this.pendingRequests.get(id);
this.pendingRequests.delete(id);
if (error) {
reject(new Error(error.message));
} else {
resolve(result);
}
}
} catch (e) {
console.error('Failed to parse response:', e);
}
});
// 监听服务器错误
this.server.on('error', (error) => {
console.error('Server error:', error);
});
// 监听服务器退出
this.server.on('exit', (code) => {
console.log(`Server exited with code ${code}`);
});
}
/**
* 初始化MCP连接
* @returns {Promise<Object>} 初始化结果
*/
async initialize() {
// 发送initialize请求并等待响应
const result = await this.sendRequest({
jsonrpc: '2.0',
id: this.requestId++,
method: 'initialize',
params: {
protocolVersion: '2024-11-05',
capabilities: {},
clientInfo: {
name: 'weather-client',
version: '1.0.0'
}
}
});
// 发送initialized通知,完成握手流程
this.sendNotification({
jsonrpc: '2.0',
method: 'initialized'
});
return result;
}
/**
* 调用MCP工具
* @param {string} name - 工具名称
* @param {Object} args - 工具参数
* @returns {Promise<Object>} 工具执行结果
*/
async callTool(name, args) {
return this.sendRequest({
jsonrpc: '2.0',
id: this.requestId++,
method: 'tools/call',
params: {
name,
arguments: args
}
});
}
/**
* 发送MCP请求
* @param {Object} request - 请求对象
* @returns {Promise<Object>} 响应结果
*/
sendRequest(request) {
return new Promise((resolve, reject) => {
this.pendingRequests.set(request.id, { resolve, reject });
this.server.stdin.write(JSON.stringify(request) + '\n');
});
}
/**
* 发送MCP通知(无需等待响应)
* @param {Object} notification - 通知对象
*/
sendNotification(notification) {
this.server.stdin.write(JSON.stringify(notification) + '\n');
}
/**
* 关闭MCP客户端
*/
close() {
this.server.kill();
}
}
/**
* 主函数
* 解析命令行参数并执行天气查询
*/
async function main() {
// 解析命令行参数
const args = process.argv.slice(2);
// 检查参数
if (args.length === 0) {
console.log('用法: node weather-client.js <城市名> [天数]');
console.log('示例:');
console.log(' node weather-client.js 北京');
console.log(' node weather-client.js 上海 5');
console.log(' node weather-client.js Hefei 3');
process.exit(1);
}
const city = args[0];
const days = parseInt(args[1]) || 3;
console.log('连接到Weather MCP服务器...\n');
// 创建MCP客户端实例
const client = new MCPClient('node', ['src/index.js']);
try {
// 初始化连接
await client.initialize();
console.log('✓ 已连接到MCP服务器\n');
console.log(`正在查询 ${city} 未来${days}天的天气预报...\n`);
// 调用天气查询工具
const result = await client.callTool('get_weather', {
city: city,
days: days
});
// 解析并显示天气数据
if (result.content && result.content[0]) {
const weatherData = JSON.parse(result.content[0].text);
console.log('='.repeat(60));
console.log('📍 位置信息');
console.log('='.repeat(60));
console.log(`城市: ${weatherData.location.name}`);
console.log(`国家: ${weatherData.location.country}`);
console.log(`省份: ${weatherData.location.province || ''}`);
console.log(`坐标: ${weatherData.location.coordinates.latitude}, ${weatherData.location.coordinates.longitude}`);
console.log('\n' + '='.repeat(60));
console.log(`🌤️ 未来${days}天天气预报`);
console.log('='.repeat(60));
weatherData.forecast.forEach((day, index) => {
console.log(`\n第${index + 1}天 (${day.date}):`);
console.log(` 天气: ${day.weather}`);
console.log(` 温度: ${day.temperature.min}°C - ${day.temperature.max}°C`);
console.log(` 降水: ${day.precipitation}mm`);
console.log(` 风速: ${day.windSpeed}km/h`);
});
console.log('\n' + '='.repeat(60));
console.log('✓ 查询完成!');
console.log('='.repeat(60));
}
} catch (error) {
console.error('错误:', error.message);
} finally {
// 确保关闭客户端连接
client.close();
}
}
main().catch(console.error);
手动添加到SOLO mcp服务中


查询结果

附注:
源码地址:https://gitcode.com/SUI517/gitcode_knowledge其中包含 MCP resource 类型交互的实例:mcp-mysql服务
下面是怎么在IDE ->LLM 中使用MySQL MCP服务
MySQL MCP的两种交互方式 方式1:自然语言对话(推荐) 您可以直接用自然语言描述需求,我会自动理解并调用合适的功能: 示例: - "查看数据库中有哪些表" → 我自动访问 db://tables - "显示users表的结构" → 我自动访问 db://table/users - "查询所有活跃用户" → 我调用 execute_query 工具 - "统计订单数量" → 我调用 execute_query 工具 ### 方式2:直接使用URI 您也可以直接使用Resource URI格式: 示例: - db://tables → 获取表列表 - db://table/users → 获取users表结构 - db://data/users → 获取users表数据
🎯 天气MCP的Resource实现建议
有兴趣的可以让LLM帮你实现
基于您的天气预报MCP,可以添加以下Resource:当前天气 实时天气数据 weather://current/{city} 天气预报 N天预报数据 weather://forecast/{city}/{days}days 历史天气 历史天气记录 weather://historical/{city}/{date} 天气预警 天气预警信息 weather://alert/{city} 缓存状态 缓存统计信息 weather://cache/status
我与Trae的聊天
你是怎么判断需要调用 tools prompt还是resource的?
好问题!让我详细解释我是如何判断调用 tools、prompts 还是 resources 的: ## 🧠 我的判断逻辑 ### 第一步:分析用户意图 | 用户意图 | 推荐类型 | 示例 | |---------|-----------|------| | **浏览/查看数据** | Resources | "查看users表的数据" | | **执行自定义查询** | Tools | "执行:SELECT * FROM users WHERE age > 25" | | **常用快捷操作** | Prompts | "查询活跃用户" | ### 第二步:判断查询复杂度 | 复杂度 | 推荐类型 | 示例 | |---------|-----------|------| | **简单常用** | Prompts | "统计订单数量" | | **复杂自定义** | Tools | "SELECT u.*, COUNT(o.id) FROM users u JOIN orders o ON u.id = o.user_id GROUP BY u.id" | | **浏览查看** | Resources | "db://data/users" | ### 第三步:考虑参数需求 | 参数类型 | 推荐类型 | 示例 | |---------|-----------|------| | **无参数/固定参数** | Prompts | "查询活跃用户" | | **动态参数** | Tools | "查询年龄大于25的用户" | | **URI格式** | Resources | "db://table/users" | ## 📊 详细判断流程图 ``` 用户输入 ↓ 分析意图 ↓ ┌─────────────┬─────────────┬─────────────┐ │ │ │ │ 浏览数据 执行操作 常用查询 │ │ │ │ ↓ ↓ ↓ ↓ Resources Tools Prompts ``` ## 🎯 具体判断规则 ### ✅ 优先使用 Prompts 的情况 **条件1:常用操作** ``` "查询活跃用户" → query_active_users "统计订单数量" → count_orders "查看产品库存" → product_inventory ``` **条件2:无参数或简单参数** ``` "查询活跃用户" → 无参数,直接调用 "查看alice的订单汇总" → 单个参数,调用 prompt ``` **条件3:明确的功能名称** ``` 用户明确说出功能名称,优先匹配Prompt ``` ### ✅ 使用 Tools 的情况 **条件1:自定义SQL** ``` "执行:SELECT * FROM users WHERE age > ?" "执行SQL:SELECT u.username, COUNT(o.id) FROM users u JOIN orders o ON u.id = o.user_id" ``` **条件2:复杂查询** ``` 多表JOIN、子查询、聚合函数等复杂操作 ``` **条件3:参数化查询** ``` "查询年龄大于25的用户" → 需要参数化,使用Tools "查询状态为active且年龄大于20的用户" → 多个条件 ``` ### ✅ 使用 Resources 的情况 **条件1:浏览数据** ``` "查看users表的数据" "显示orders表的结构" "数据库中有哪些表" ``` **条件2:URI格式** ``` "db://data/users" "db://table/orders" ``` **条件3:探索性查询** ``` "看看数据库里有什么" "浏览一下users表" ``` ## 💡 实际判断示例 ### 示例1:用户说"查询活跃用户" **我的分析**: 1. ✅ 意图:查询数据 2. ✅ 复杂度:简单 3. ✅ 参数:无参数 4. ✅ 常用操作:有对应的Prompt **判断结果**:使用 `query_active_users` Prompt --- ### 示例2:用户说"执行SQL:SELECT * FROM users WHERE age > 25" **我的分析**: 1. ✅ 意图:执行操作 2. ✅ 复杂度:自定义SQL 3. ✅ 参数:动态参数(25) 4. ✅ 明确指定SQL **判断结果**:使用 `execute_query` Tool --- ### 示例3:用户说"查看users表的数据" **我的分析**: 1. ✅ 意图:浏览数据 2. ✅ 复杂度:简单查看 3. ✅ 参数:URI格式(db://data/users) **判断结果**:使用 `db://data/users` Resource --- ### 示例4:用户说"统计订单数量" **我的分析**: 1. ✅ 意图:统计数据 2. ✅ 复杂度:简单 3. ✅ 参数:无参数 4. ✅ 常用操作:有对应的Prompt **判断结果**:使用 `count_orders` Prompt --- ### 示例5:用户说"查询年龄大于25的用户" **我的分析**: 1. ✅ 意图:查询数据 2. ✅ 复杂度:中等(需要参数) 3. ✅ 参数:动态参数(25) 4. ✅ 无对应Prompt **判断结果**:使用 `execute_query` Tool ## 🎯 判断优先级 ``` 1. Prompts(最高优先级) ↓ 有匹配的Prompt? ↓ 是 → 使用Prompt ↓ 否 → 继续 2. Resources ↓ 是浏览/查看数据? ↓ 是 → 使用Resource ↓ 否 → 继续 3. Tools(默认) ↓ 使用execute_query ``` ## 📝 总结 | 类型 | 使用场景 | 判断依据 | |------|---------|---------| | **Prompts** | 常用快捷操作 | 有对应Prompt + 简单参数 | | **Tools** | 自定义查询 | 明确SQL或复杂查询 | | **Resources** | 浏览数据 | 查看表数据/结构 | ## 💡 最佳实践 **对用户来说**: - ✅ 用自然语言描述需求 - ✅ 不需要记住具体功能名称 - ✅ 不需要知道URI格式 - ✅ 不需要写SQL语句 **对我来说**: - ✅ 分析用户意图 - ✅ 判断查询复杂度 - ✅ 选择最合适的方式 - ✅ 自动调用对应功能 所以您只需要用自然语言表达需求,我会自动判断并选择最合适的调用方式!
更多推荐

所有评论(0)