MCP工具开发完全指南:从零构建实时新闻工具
🎯 前言
MCP(Model Context Protocol)工具是现代AI应用开发中的重要组件,它允许我们为AI模型提供特定的功能和数据获取能力。本文将通过一个完整的实时新闻MCP工具项目,带你从零开始学习MCP工具的开发。
🔗 项目地址: GitHub - realtime-news
无论你是编程新手还是想了解MCP工具开发的开发者,这篇文章都会为你提供详细的指导和实践经验。
📚 什么是MCP工具?
MCP基础概念
MCP(Model Context Protocol)是一种标准化协议,用于AI模型与外部工具、数据源之间的通信。简单来说:
- AI模型:类似大脑,负责理解和推理
- MCP工具:类似工具箱,为AI提供特定能力
- 协议:规定了AI和工具之间如何"对话"
MCP工具的作用
用户请求 → AI理解 → 调用MCP工具 → 获取数据/执行操作 → 返回结果给用户
例如:
- 用户:"今天有什么重要新闻?"
- AI调用新闻MCP工具获取最新新闻
- 返回格式化的新闻列表给用户
🛠️ 项目概述:实时新闻MCP工具
我们要构建的实时新闻MCP工具具备以下功能:
核心功能
- 📰 获取实时新闻:支持10种新闻分类
- 🔍 关键词搜索:智能搜索相关新闻
- 📋 分类管理:完整的新闻分类系统
- 🛡️ 错误处理:完善的异常处理机制
技术特点
- 基于Node.js开发
- 使用聚合数据API
- 支持环境变量配置
- 完整的模块化设计
🏗️ 项目结构详解
让我们先了解整个项目的组织结构:
realtime-news-mcp/
├── realtime-news-mcp.js # 主工具文件(核心逻辑)
├── package.json # 项目配置文件
├── example.js # 使用示例
├── interactive-demo.js # 交互式演示
├── .env.local # 环境变量配置
├── .gitignore # Git忽略文件
├── README.md # 项目说明文档
├── CHANGELOG.md # 更新日志
├── CONTRIBUTING.md # 贡献指南
└── LICENSE # 开源许可证
文件职责分析
| 文件 | 作用 | 重要程度 |
|---|---|---|
realtime-news-mcp.js | 核心工具逻辑 | ⭐⭐⭐⭐⭐ |
package.json | 项目配置和依赖管理 | ⭐⭐⭐⭐⭐ |
example.js | 学习和测试示例 | ⭐⭐⭐⭐ |
.env.local | 安全的配置管理 | ⭐⭐⭐⭐ |
🔧 开发环境准备
1. 环境要求
# 检查Node.js版本(需要14.0.0以上)
node --version
# 检查npm版本(需要6.0.0以上)
npm --version
2. 项目初始化
# 创建项目目录
mkdir realtime-news-mcp
cd realtime-news-mcp
# 初始化npm项目
npm init -y
# 安装核心依赖
npm install axios dotenv
3. API密钥申请
- 访问聚合数据官网
- 注册账号并实名认证
- 申请"新闻头条"API服务
- 获取API密钥
📝 核心代码实现
1. 项目配置文件 (package.json)
{
"name": "realtime-news-mcp",
"version": "1.0.0",
"description": "中国实时新闻MCP工具",
"main": "realtime-news-mcp.js",
"scripts": {
"start": "node realtime-news-mcp.js",
"test": "node -e "const tool = require('./realtime-news-mcp.js'); tool.mcpNewsTool('categories').then(console.log);"",
"demo": "node example.js"
},
"dependencies": {
"axios": "^1.6.0",
"dotenv": "^16.6.1"
},
"engines": {
"node": ">=14.0.0"
}
}
2. 环境变量配置 (.env.local)
# 聚合数据API密钥
JUHE_API_KEY=你的API密钥
# 可选配置
API_TIMEOUT=10000
MAX_RESULTS=30
3. 主工具文件结构分析
让我们逐步分析核心文件realtime-news-mcp.js的实现:
A. 基础配置和依赖
#!/usr/bin/env node
// 加载环境变量
require('dotenv').config({ path: '.env.local' });
const axios = require('axios');
// 工具配置
const TOOL_NAME = "中国实时新闻MCP工具";
const API_KEY = process.env.JUHE_API_KEY || "请设置API密钥";
const BASE_URL = "http://v.juhe.cn/toutiao/index";
// 新闻分类映射
const NEWS_CATEGORIES = {
'top': '头条',
'shehui': '社会',
'guonei': '国内',
'guoji': '国际',
'yule': '娱乐',
'tiyu': '体育',
'junshi': '军事',
'keji': '科技',
'caijing': '财经',
'shishang': '时尚'
};
设计要点:
- 使用环境变量保护API密钥
- 清晰的配置集中管理
- 中文分类映射提升用户体验
B. 核心功能函数
1. 获取最新新闻
async function getLatestNews(category = 'top', limit = 10) {
try {
// 1. 参数验证
if (category && !NEWS_CATEGORIES[category]) {
return `❌ 错误:不支持的新闻分类 "${category}"`;
}
// 2. 构建请求参数
const params = {
key: API_KEY,
type: category
};
// 3. 发送API请求
const response = await axios.get(BASE_URL, {
params,
timeout: 10000 // 10秒超时
});
// 4. 检查响应状态
if (response.data.error_code !== 0) {
return `❌ API错误:${response.data.reason}`;
}
// 5. 处理和格式化数据
const newsData = response.data.result.data || [];
const limitedNews = newsData.slice(0, limit);
const formattedNews = formatNewsData(limitedNews, category);
return `✅ 获取成功\n\n${formattedNews}`;
} catch (error) {
// 6. 错误处理
return handleApiError(error);
}
}
设计亮点:
- 完整的错误处理流程
- 参数验证确保安全性
- 超时控制防止请求挂起
- 数据限制避免信息过载
2. 关键词搜索功能
async function searchNews(keyword, limit = 5) {
try {
if (!keyword || keyword.trim() === '') {
return "❌ 错误:搜索关键词不能为空";
}
// 并行搜索多个分类
const categories = ['top', 'shehui', 'guonei', 'guoji', 'keji'];
const searchResults = [];
for (const category of categories) {
try {
const response = await axios.get(BASE_URL, {
params: { key: API_KEY, type: category },
timeout: 5000
});
if (response.data.error_code === 0) {
const newsData = response.data.result.data;
// 筛选包含关键词的新闻
const filteredNews = newsData.filter(news =>
news.title.includes(keyword) ||
(news.content && news.content.includes(keyword))
);
searchResults.push(...filteredNews);
}
} catch (err) {
console.log(`搜索 ${category} 分类时出错:`, err.message);
}
}
// 排序和格式化结果
const sortedResults = searchResults
.sort((a, b) => new Date(b.date) - new Date(a.date))
.slice(0, limit);
return formatSearchResults(sortedResults, keyword);
} catch (error) {
return `❌ 搜索失败: ${error.message}`;
}
}
实现特色:
- 多分类并行搜索
- 标题和内容双重匹配
- 时间排序确保时效性
- 容错机制保证稳定性
C. 数据格式化和用户体验
function formatNewsData(newsData, category) {
const categoryName = NEWS_CATEGORIES[category] || '搜索结果';
let formatted = `📰 ${categoryName}新闻 (${newsData.length}条)\n`;
formatted += "=".repeat(50) + "\n\n";
newsData.forEach((news, index) => {
formatted += `${index + 1}. 📢 ${news.title}\n`;
if (news.author_name) {
formatted += ` 👤 来源:${news.author_name}\n`;
}
if (news.date) {
formatted += ` 🕒 时间:${news.date}\n`;
}
if (news.content) {
const summary = news.content.length > 100
? news.content.substring(0, 100) + "..."
: news.content;
formatted += ` 📝 摘要:${summary}\n`;
}
formatted += "\n" + "-".repeat(40) + "\n\n";
});
// 添加统计信息
formatted += `📊 数据统计:\n`;
formatted += `• 获取时间:${new Date().toLocaleString('zh-CN')}\n`;
formatted += `• 新闻数量:${newsData.length}条\n`;
return formatted;
}
用户体验设计:
- 清晰的视觉分隔符
- 丰富的emoji图标
- 合理的信息层次
- 实用的统计信息
D. MCP工具接口
async function mcpNewsTool(action = 'latest', param = 'top', limit = 10) {
try {
console.log(`🚀 执行操作: ${action}, 参数: ${param}, 限制: ${limit}`);
switch (action.toLowerCase()) {
case 'latest':
return await getLatestNews(param, limit);
case 'search':
return await searchNews(param, limit);
case 'categories':
return getNewsCategories();
default:
return `❌ 不支持的操作: ${action}\n支持的操作: latest, search, categories`;
}
} catch (error) {
return `❌ 工具执行失败: ${error.message}`;
}
}
接口设计原则:
- 统一的调用入口
- 清晰的参数约定
- 标准的错误响应
- 完整的操作日志
🎯 使用示例和测试
1. 基础使用示例
创建example.js文件:
const { mcpNewsTool } = require('./realtime-news-mcp.js');
async function runExamples() {
try {
// 示例1: 获取头条新闻
console.log('📰 获取头条新闻:');
const headlines = await mcpNewsTool('latest', 'top', 3);
console.log(headlines);
// 示例2: 搜索科技新闻
console.log('\n💻 获取科技新闻:');
const techNews = await mcpNewsTool('latest', 'keji', 2);
console.log(techNews);
// 示例3: 关键词搜索
console.log('\n🔍 搜索关键词:');
const searchResults = await mcpNewsTool('search', 'AI', 2);
console.log(searchResults);
// 示例4: 查看分类
console.log('\n📋 查看分类:');
const categories = await mcpNewsTool('categories');
console.log(categories);
} catch (error) {
console.error('示例执行失败:', error);
}
}
runExamples();
2. 批量操作示例
// 批量获取多分类新闻
async function batchGetNews() {
const categories = ['top', 'keji', 'caijing'];
const results = {};
for (const category of categories) {
try {
const news = await mcpNewsTool('latest', category, 2);
results[category] = '✅ 获取成功';
} catch (error) {
results[category] = `❌ 获取失败: ${error.message}`;
}
}
console.log('批量获取结果:', results);
}
3. 自定义应用场景
// 创建个性化新闻摘要
async function getMyDailyNews() {
const results = {};
// 获取各类新闻
results.headlines = await mcpNewsTool('latest', 'top', 3);
results.tech = await mcpNewsTool('latest', 'keji', 2);
results.finance = await mcpNewsTool('latest', 'caijing', 2);
// 搜索感兴趣的话题
results.ai = await mcpNewsTool('search', '人工智能', 1);
return results;
}
🛡️ 错误处理和最佳实践
1. 完善的错误处理
function handleApiError(error) {
if (error.code === 'ECONNABORTED') {
return "❌ 请求超时,请检查网络连接";
} else if (error.response) {
return `❌ API请求失败: HTTP ${error.response.status}`;
} else if (error.code === 'ENOTFOUND') {
return "❌ 网络连接失败,请检查网络设置";
} else {
return `❌ 网络错误: ${error.message}`;
}
}
2. API密钥验证
async function validateApiKey() {
if (!process.env.JUHE_API_KEY) {
console.error("❌ 请先设置JUHE_API_KEY环境变量");
return false;
}
try {
const response = await axios.get(BASE_URL, {
params: { key: API_KEY, type: 'top' },
timeout: 5000
});
return response.data.error_code === 0;
} catch (error) {
return false;
}
}
3. 安全最佳实践
- 环境变量管理:敏感信息不直接写在代码中
- 输入验证:所有用户输入都进行验证
- 超时控制:防止请求无限等待
- 错误日志:记录详细的错误信息
🚀 部署和分发
1. 项目打包
# 创建发布版本
npm version patch
# 生成package-lock.json
npm install
# 检查文件完整性
npm pack --dry-run
2. 依赖管理
{
"dependencies": {
"axios": "^1.6.0",
"dotenv": "^16.6.1"
},
"engines": {
"node": ">=14.0.0",
"npm": ">=6.0.0"
}
}
3. 文档完善
重要文档包括:
README.md:详细的使用说明CHANGELOG.md:版本更新记录CONTRIBUTING.md:贡献指南LICENSE:开源许可证
🔄 持续改进
1. 功能扩展思路
- 缓存机制:减少API调用次数
- 数据持久化:保存历史新闻记录
- 多语言支持:支持英文等其他语言
- 推送通知:重要新闻实时推送
2. 性能优化
// 实现简单缓存
const newsCache = new Map();
async function getCachedNews(category, limit) {
const cacheKey = `${category}-${limit}`;
if (newsCache.has(cacheKey)) {
const { data, timestamp } = newsCache.get(cacheKey);
// 缓存有效期5分钟
if (Date.now() - timestamp < 5 * 60 * 1000) {
return data;
}
}
const news = await getLatestNews(category, limit);
newsCache.set(cacheKey, {
data: news,
timestamp: Date.now()
});
return news;
}
3. 监控和调试
// 添加性能监控
function measurePerformance(func) {
return async function(...args) {
const start = Date.now();
const result = await func.apply(this, args);
const duration = Date.now() - start;
console.log(`函数 ${func.name} 执行耗时: ${duration}ms`);
return result;
};
}
// 使用示例
const monitoredGetNews = measurePerformance(getLatestNews);
📖 学习总结
通过这个实时新闻MCP工具项目,我们学习了:
核心技能
- MCP工具架构设计:理解工具的基本结构和接口设计
- API集成开发:学会与第三方API安全交互
- 错误处理机制:构建健壮的异常处理系统
- 用户体验设计:创建友好的数据展示格式
开发流程
- 需求分析 → 确定工具功能和接口
- 架构设计 → 规划模块结构和数据流
- 核心实现 → 编写主要功能代码
- 测试验证 → 确保功能正确性和稳定性
- 文档完善 → 提供完整的使用指南
最佳实践
- 模块化设计,职责分离
- 环境变量管理敏感信息
- 完善的错误处理和日志记录
- 用户友好的接口和反馈
- 详细的文档和示例
🎯 下一步计划
基于这个基础项目,你可以继续扩展:
- 集成更多新闻源:增加其他新闻API支持
- 开发Web界面:创建可视化的管理界面
- 构建微服务:将工具部署为独立服务
- 机器学习集成:添加新闻分类和情感分析
- 移动应用开发:创建配套的移动端应用
这个项目为你提供了MCP工具开发的完整框架,希望能帮助你在AI工具开发的道路上更进一步!
💡 提示: 如果你在学习过程中遇到问题,欢迎查看项目的Issues页面或提交新问题。记住,最好的学习方法就是实践和分享!