一组用于通过AI助手(如Claude Desktop、Cursor和其他MCP客户端)访问Pokémon数据的**模型上下文协议(MCP)**服务器。
# 克隆仓库
git clone https://github.com/frabatx/pokemon-mcp-servers.git
cd pokemon-mcp-servers
# 运行设置(自动完成所有操作!)
## PowerShell
.\setup.ps1
# 如果脚本在您的电脑上不可执行:
# --> 在当前会话中授权
Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process
# --> 对于您用户的本地脚本授权
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
您可以使用 .\setup_pretty.ps1,但需要以下内容: https://www.nerdfonts.com/
该项目实现了一个模块化的MCP服务器架构,通过标准化工具暴露Pokémon数据。每个服务器专门处理特定的数据类型,并使用高级的注册表模式进行可扩展的工具管理。
| 服务器 | 描述 | 数据源 | 工具 |
|---|---|---|---|
| 传记服务器 | 详细的Pokémon传记 | biographies.json | 4个工具 |
| 统计服务器 | 战斗统计数据 | statistics.csv | 3+个工具 |
| 图服务器 | 进化关系 | 图数据库 | 即将推出 |
pokemon-mcp-servers/
├── data/ # 中心共享数据
│ ├── biographies.json # 809个Pokémon传记
│ ├── statistics.csv # 战斗统计数据(41列)
│ ├── pokemon_anime_data.json # 包含嵌入的动漫剧集
│ └── pokemon.cypher # 图数据库脚本
│
├── servers/ # 独立的MCP服务器
│ ├── biography-server/
│ │ ├── main.py # 服务器入口点
│ │ ├── src/
│ │ │ ├── tools/ # MCP工具
│ │ │ │ ├── __init__.py # 自动注册
│ │ │ │ ├── register.py # 注册表模式
│ │ │ │ └── [tool_files].py
│ │ │ └── utils/
│ │ │ └── load_data.py # 数据加载
│ │ ├── pyproject.toml
│ │ └── README.md
│ │
│ ├── statistics-server/
│ │ ├── main.py # 服务器入口点
│ │ ├── src/
│ │ │ ├── tools/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── register.py
│ │ │ │ └── [tool_files].py
│ │ │ └── utils/
│ │ │ ├── load_data.py
│ │ │ └── helpers.py # 共享实用工具
│ │ ├── pyproject.toml
│ │ └── README.md
│ │
│ └── [your-new-server]/ # 可重复模式
│ ├── main.py # 标准入口点
│ └── src/ # 源代码
│
└── notebooks/
└── ingestion.ipynb # 数据准备脚本
# macOS/Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
# Windows
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
# 使用pip
pip install uv
下载并安装Node.js(Windows安装程序.msi): https://nodejs.org/en/download
测试安装:
nvm -v
npm -v
npx -v
# 1. 克隆仓库
git clone https://github.com/your-username/pokemon-mcp-servers.git
cd pokemon-mcp-servers
# 2. 设置传记服务器
cd servers/biography-server
uv sync
# 3. 测试服务器
cd src
uv run main.py
# 预期输出:
# [OK] 加载了809个传记
# [START] Pokémon传记MCP服务器
# [READY] 服务器正在监听stdio
# 4. 安装MPC Inspector进行测试(新终端 - 同一路径)
npm install -g @modelcontextprotocol/inspector
# 5. 使用Inspector测试
npx @modelcontextprotocol/inspector uv run main.py
或
mcp-inspector uv run main.py
# 打开 http://localhost:5173(应该会自动打开)
没有注册表模式,每个工具需要在3+处进行修改:
问题:复制和耦合
1. 在main.py中定义带有工具名称的枚举
2. 在tools/my_tool.py中实现工具函数
3. 添加到list_tools()中(手动!)
4. 添加到call_tool()中的情况(手动!)
5. 保持名称/元数据同步(容易出错!)
结果:
- 代码复制
- 容易出错
- 维护困难
- 不好扩展
使用注册表模式,每个工具是自包含的:
解决方案:单一事实来源
1. 创建带有装饰器的工具文件 <- tools/my_tool.py
2. 自动导入 <- tools/__init__.py
3. 完成!
结果:
- 零复制
- 工具自包含
- 容易添加工具
- 完美扩展
┌─────────────────────────────────────────────────────┐
│ 层1:服务器入口点 │
│ (main.py) │
│ │
│ @server.list_tools() │
│ async def list_tools(): │
│ return get_all_tools() <- 从注册表获取 │
│ │
│ @server.call_tool() │
│ async def call_tool(name, args): │
│ return await call_tool_from_registry(...) │
│ │
│ 零业务逻辑 - 只有委托! │
└──────────────────┬──────────────────────────────────┘
│
│ 委托给
│
┌──────────────────▼──────────────────────────────────┐
│ 层2:注册表与调度器 │
│ (src/tools/register.py) │
│ │
│ tool_registry = {} <- 全局字典 │
│ │
│ @register_tool(name, description, schema) │
│ def decorator(fn): │
│ tool_registry[name] = RegisteredTool(...) │
│ return fn │
│ │
│ get_all_tools() -> 生成工具列表 │
│ call_tool_from_registry() -> 调度器 │
│ │
│ 自动发现:查找所有已注册的工具 │
└──────────────────┬──────────────────────────────────┘
│
│ 注册
│
┌──────────────────▼──────────────────────────────────┐
│ 层3:工具实现 │
│ (src/tools/my_tool.py等) │
│ │
│ @register_tool( │
│ name=ToolNames.MY_TOOL, │
│ description="...", │
│ input_schema={...} │
│ ) │
│ async def my_tool(args, data): │
│ # ... 特定逻辑 ... │
│ return [TextContent(...)] │
│ │
│ 自包含:一切在一个文件中! │
└─────────────────────────────────────────────────────┘
服务器启动时会发生什么:
服务器导入
Python 执行:python main.py
服务器导入工具包
Python 执行:from src.tools.register import ...
Python 执行:src/tools/__init__.py
工具包导入每个工具
# 在 src/tools/__init__.py 中:
from . import my_first_tool
from . import my_second_tool
from . import my_third_tool
每次导入都会执行装饰器
# 执行 my_first_tool.py
@register_tool(...) <- 装饰器现在执行!
async def my_first_tool(...): ...
# 装饰器添加到注册表:
tool_registry["my_first_tool"] = RegisteredTool(...)
注册表填充
tool_registry = {
"my_first_tool": RegisteredTool(...),
"my_second_tool": RegisteredTool(...),
"my_third_tool": RegisteredTool(...)
}
服务器就绪
get_all_tools() -> 从 tool_registry 读取
call_tool_from_registry() -> 自动调度器
# Python 3.12 类型声明
type ToolArguments = dict[str, Any]
type ToolResult = list[TextContent]
type ToolFn = Callable[..., Awaitable[ToolResult]]
优点:
class ToolNames(StrEnum):
MY_FIRST_TOOL = "my_first_tool"
MY_SECOND_TOOL = "my_second_tool"
优点:
@dataclass
class ToolMetadata:
name: str
description: str
input_schema: dict[str, Any]
@dataclass
class RegisteredTool:
func: ToolFn
metadata: ToolMetadata
优点:
def register_tool(name, description, input_schema):
def decorator(fn):
# 创建元数据
metadata = ToolMetadata(...)
# 注册到全局字典
tool_registry[name] = RegisteredTool(
func=fn,
metadata=
)
return fn
return decorator
优点:
def get_all_tools() -> list[Tool]:
"""从注册表生成MCP工具列表"""
return [
Tool(
name=reg.metadata.name,
description=reg.metadata.description,
inputSchema=reg.metadata.input_schema
)
for reg in tool_registry.values()
]
async def call_tool_from_registry(name, args, data):
"""具有内省功能的智能调度器"""
if name not in tool_registry:
return error_response(...)
func = tool_registry[name].func
# 内省:1个还是2个参数?
sig = inspect.signature(func)
params = list(sig.parameters.keys())
if len(params) == 1:
return await func(data)
else:
return await func(args, data)
| 方面 | 传统 | 注册表模式 |
|---|---|---|
| 添加工具 | 修改4+个文件 | 创建1个文件 |
| 同步 | 手动 | 自动 |
| 服务器主 | 100+行 | 20行 |
| 复制 | 高 | 无 |
| 维护性 | 困难 | 容易 |
| 可扩展性 | 有限 | 无限 |
| 错误 | 频繁 | 很少 |
DRY(不要重复自己)
单一职责
开放/封闭原则
可扩展性
开发者体验
我们希望创建一个新的MCP服务器,通过标准化工具暴露数据。
创建新的服务器结构:
cd servers/
uv init my-server
# my-server/
# ├── main.py # 入口点(标准名称)
# ├── pyproject.toml
# ├── .python-version
# └── README.md
cd my-server
mkdir src src/tools src/utils
如果需要,修改 pyproject.toml 和 .python-version 文件以设置所需的Python版本(3.12)。
目标结构:
my-server/
├── main.py # 入口点(标准名称)
├── src/
│ ├── tools/
│ │ ├── __init__.py # 包 + 自动注册
│ │ ├── register.py # 注册表模式
│ │ ├── my_first_tool.py # 工具实现
│ │ └── my_second_tool.py # 工具实现
│ └── utils/
│ ├── __init__.py
│ └── load_data.py # 数据加载/连接
├── pyproject.toml
├── .python-version
└── README.md
注意: main.py 在服务器目录的根部,不在 src/ 中。这种标准化允许所有服务器之间一致的Docker和命令模式。
创建项目配置文件(应由uv自动完成,但检查一下):
最小配置:
[project]
name = "my-server"
version = "0.1.0"
description = "MCP服务器用于[您的数据]"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"mcp",
# 添加您的特定依赖项 - 应使用 `uv add {依赖项名称}` 命令
]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
关键点:
[project.scripts] 入口点(我们直接使用 uv run main.py)要创建的组件:
类型别名
type 语句以简洁语法ToolNames 枚举
StrEnum 作为字符串类型的枚举值元数据数据类
ToolMetadata:名称、描述、输入模式RegisteredTool:函数 + 元数据一起全局注册表
RegisteredTool 对象的字典装饰器函数
@register_tool 装饰器实用函数
get_all_tools():从注册表生成MCP工具列表call_tool_from_registry():具有参数内省功能的智能调度器模式与现有服务器相同 - 促进一致性!
文件结构:
导入语句
带元数据的装饰器
@register_tool 装饰器函数实现
基本原则: