mcp笑话服务器
MCP工具服务器,公开与笑话相关的工具。它从外部HTTP API获取笑话,并通过FastMCP将其提供给兼容MCP的客户端。策略模式支持多种传输方式:stdio(默认)、HTTP和SSE。
概述
此存储库使用以下代码实现MCP服务器 fastmcp 将关注点清晰地分开:
- 工具在
main.py向MCP客户端公开笑话操作。 - 下面的存储库层
repositories/获取并缓存笑话。 - 运输战略
strategies/在运行时选择stdio/HTTP/SSE。 - 公用事业
utils/提供HTTP客户端、模型、格式化和日志记录。
暴露的工具(同步):
tool_get_consistent_joke()--每次返回相同的硬编码笑话。tool_get_joke()-从外部API获取一个随机笑话。tool_get_joke_by_id(joke_id)--通过数字ID获取笑话。tool_get_joke_by_type(joke_type)--按类别提取笑话(general,knock-knock,programming,dad).
异步变体也可用: tool_aget_joke, tool_aget_joke_by_id, tool_aget_joke_by_type.
笑话API基本URL通过 API_BASE_URL.运输方式由以下人员选择 MCP_PROTOCOL (stdio, http, sse).
堆栈
- 语言:Python 3.13+
- 框架:
fastmcp(MCP通过stdio/HTTP/SSE) - HTTP客户端:
httpx - 配置/验证:
pydantic,pydantic-settings - Env装载机:
python-dotenv(通过pydantic-settings) - 日志/用户体验:
loguru,rich - 包管理器:
uv(锁文件uv.lock目前)。pip也工作。 - 入口点:
main.py
需求
- Python 3.13+
uv(推荐)或pip- 网络访问已配置的笑话API(
API_BASE_URL)
项目结构
.
├── LICENSE
├── README.md
├── main.py # MCP server entry point (starts FastMCP)
├── pyproject.toml # Project metadata and dependencies
├── uv.lock # uv lockfile
├── repositories/ # Repository pattern (HTTP + cached repositories)
│ ├── base.py
│ ├── cached_repository.py
│ ├── factory.py
│ ├── http_repository.py
│ └── __init__.py
├── strategies/ # Strategy pattern for transports (stdio/http/sse)
│ ├── base.py
│ ├── factory.py
│ ├── http_strategy.py
│ ├── sse_strategy.py
│ ├── stdio_strategy.py
│ └── __init__.py
├── utils/
│ ├── RequestAPIJokes.py # HTTP/async client for the jokes API
│ ├── config.py # Settings via pydantic-settings
│ ├── constants.py # URL, joke types, consistent joke
│ ├── exceptions.py
│ ├── formatters.py # pure helpers (e.g., extract_joke)
│ ├── logger.py
│ ├── logging_config.py
│ ├── logging_interfaces.py
│ ├── rich_renderers.py
│ └── model.py # dataclasses for Joke/Jokes
├── tests/ # Pytest suite
├── docs/ # Architecture/testing docs
├── examples/ # Example MCP client and demos
├── Makefile # Developer commands (see Scripts)
├── docker-compose.yml # HTTP/SSE/stdio services
├── Dockerfile # Multi-stage Docker build
└── htmlcov/ # Coverage HTML (generated)环境变量
装载了 pydantic-settings; .env 支持项目根目录。
必修的:
API_BASE_URL-API笑话的基本URL。例子:https://official-joke-api.appspot.com
- 使用的端点 utils/RequestAPIJokes.py: - GET /random_joke - GET /random_ten - GET /jokes/{id} - GET /jokes/{type}/random
LOCAL_TOKEN--HTTP/SSE传输的身份验证令牌。用于通过承载令牌身份验证保护工具访问。
- 例子: LOCAL_TOKEN=-KB6aoXeiF-Qjor3LSEGh4-OOdJLCYrs5uqvUO9NCys - 注: STDIO传输不需要身份验证,因为它在受信任的本地环境中运行。
可选(默认值为 utils/config.py):
MCP_PROTOCOL(默认值stdio) —stdio,http,或sseMCP_SERVER_HOST(默认值0.0.0.0)--HTTP/SSE主机MCP_SERVER_PORT(默认值8000)--HTTP/SSE端口LOG_LEVEL(默认值INFO)LOG_FILE(默认值logs/mcp_server.log)LOG_ROTATION(默认值10 MB)LOG_RETENTION(默认值7 days)SESSION_TIMEOUT(默认值3600)SESSION_CLEANUP_INTERVAL(默认值300)
示例 .env:
API_BASE_URL=https://official-joke-api.appspot.com
LOCAL_TOKEN=-KB6aoXeiF-Qjor3LSEGh4-OOdJLCYrs5uqvUO9NCys
MCP_PROTOCOL=http
LOG_LEVEL=INFO笔记:
utils/constants.py绑定URL = Settings.API_BASE_URL在进口时;集API_BASE_URL在临时脚本/测试中导入网络模块之前。
设置
使用紫外线(推荐):
uv sync使用pip/venv:
python -m venv .venv
. .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -U pip
pip install -e .跑
入口点: main.py.选择运输方式 MCP_PROTOCOL.
- stdio(默认):
MCP_PROTOCOL=stdio uv run python main.py- HTTP:
MCP_PROTOCOL=http uv run python main.py # uses Settings.MCP_SERVER_HOST/PORT- 上海证券交易所
MCP_PROTOCOL=sse uv run python main.py # uses Settings.MCP_SERVER_HOST/PORT使用pip/venv,替换 uv run 随着 python 根据需要。
提示:对于stdio,配置MCP客户端以将上述命令作为子进程启动。
Claude桌面配置
Claude Desktop可以使用stdio传输连接到此MCP服务器。通过编辑Claude Desktop配置文件进行配置。
配置文件位置
配置文件的位置取决于您的操作系统:
macOS:
~/Library/Application Support/Claude/claude_desktop_config.json窗户:
%APPDATA%\Claude\claude_desktop_config.jsonLinux:
~/.config/Claude/claude_desktop_config.json如果文件不存在,请使用下面的适当内容创建它。
紫外线配置(推荐)
将此添加到您的 claude_desktop_config.json:
{
"mcpServers": {
"joke-server": {
"command": "uv",
"args": [
"--directory",
"/absolute/path/to/mcp-joke-server",
"run",
"python",
"main.py"
],
"env": {
"API_BASE_URL": "https://official-joke-api.appspot.com",
"LOCAL_TOKEN": "your-secret-token-here",
"MCP_PROTOCOL": "stdio",
"LOG_LEVEL": "INFO"
}
}
}
}重要提示: 替换 /absolute/path/to/mcp-joke-server 使用项目目录的实际绝对路径。
使用Python虚拟环境进行配置
如果使用虚拟环境而不是uv:
{
"mcpServers": {
"joke-server": {
"command": "/absolute/path/to/mcp-joke-server/.venv/bin/python",
"args": [
"main.py"
],
"cwd": "/absolute/path/to/mcp-joke-server",
"env": {
"API_BASE_URL": "https://official-joke-api.appspot.com",
"LOCAL_TOKEN": "your-secret-token-here",
"MCP_PROTOCOL": "stdio",
"LOG_LEVEL": "INFO"
}
}
}
}Windows示例:
{
"mcpServers": {
"joke-server": {
"command": "C:\\Users\\YourName\\Projects\\mcp-joke-server\\.venv\\Scripts\\python.exe",
"args": [
"main.py"
],
"cwd": "C:\\Users\\YourName\\Projects\\mcp-joke-server",
"env": {
"API_BASE_URL": "https://official-joke-api.appspot.com",
"LOCAL_TOKEN": "your-secret-token-here",
"MCP_PROTOCOL": "stdio",
"LOG_LEVEL": "INFO"
}
}
}
}环境变量
必修的:
API_BASE_URL:API笑话的URLLOCAL_TOKEN:身份验证令牌(服务器初始化所需,但在stdio模式下未验证)
可选:
MCP_PROTOCOL:设置为stdio适用于Claude Desktop(默认)LOG_LEVEL:记录冗长(DEBUG,INFO,WARNING,ERROR)LOG_FILE:日志文件的路径(默认值:logs/mcp_server.log)
验证配置
配置Claude Desktop后:
- 重新启动克劳德桌面 完全(退出并重新打开)
- 检查服务器状态:
- 打开克劳德桌面 - 查找MCP图标(通常在工具栏或设置中) - 验证“笑话服务器”是否出现在可用服务器列表中 - 检查它是否显示为“已连接”或“正在运行”
- 测试连接:
- 让克劳德使用笑话工具 - 示例提示:“你能用现有的工具给我一个随机的笑话吗?” - 克劳德应该可以打电话来 tool_get_joke 以及其他已注册的工具
克劳德桌面连接故障排除
服务器未出现在Claude Desktop中:
- 检查中的JSON语法
claude_desktop_config.json(使用JSON验证器) - 验证文件是否保存在操作系统的正确位置
- 确保文件具有正确的名称:
claude_desktop_config.json - 更改后重新启动Claude Desktop
服务器出现,但显示为“失败”或“错误”:
- 检查路径是否为绝对路径(而非相对路径)
- 验证指定路径中是否存在Python可执行文件或uv命令
- 确保所有环境变量设置正确
- 检查Claude Desktop日志以获取详细的错误消息
Claude桌面日志位置:
- macOS:
~/Library/Logs/Claude/mcp*.log - 窗户:
%APPDATA%\Claude\logs\mcp*.log - Linux:
~/.config/Claude/logs/mcp*.log
工具正常工作,但返回错误:
- 验证
API_BASE_URL可从您的网络访问 - 检查一下
LOCAL_TOKEN已设置(即使stdio不验证它,服务器也需要它) - 查看服务器登录
logs/mcp_server.log有关详细的错误信息
权限问题(macOS/Linux):
# Make sure the Python executable is executable
chmod +x /path/to/.venv/bin/python
# Ensure the project directory is readable
chmod -R 755 /path/to/mcp-joke-server使用多个MCP服务器
您可以在Claude Desktop中配置多个MCP服务器:
{
"mcpServers": {
"joke-server": {
"command": "uv",
"args": ["--directory", "/path/to/mcp-joke-server", "run", "python", "main.py"],
"env": {
"API_BASE_URL": "https://official-joke-api.appspot.com",
"LOCAL_TOKEN": "token-1",
"MCP_PROTOCOL": "stdio"
}
},
"another-server": {
"command": "/path/to/another-server",
"args": ["--config", "config.json"],
"env": {
"SOME_VAR": "value"
}
}
}
}开发技巧
查看服务器输出:
由于Claude Desktop将服务器作为后台进程运行,因此您不会直接看到stdout。检查日志:
# Monitor server logs in real-time
tail -f logs/mcp_server.log添加到Claude桌面之前测试配置:
首先手动测试您的配置:
# Run the exact command Claude Desktop will use
uv --directory /absolute/path/to/mcp-joke-server run python main.py
# Or with venv
/absolute/path/to/.venv/bin/python main.py如果此命令有效,Claude Desktop配置也应有效。
热重新加载:
当您更改代码时:
- 必须重新启动Claude Desktop才能重新加载服务器
- 或者从Claude Desktop设置中断开并重新连接服务器
- 每次服务器进程都会被终止并重新启动
脚本(Makefile)
开发人员友好的命令在 Makefile:
make install→uv syncmake install-dev→uv sync --extra devmake test→ 运行覆盖率(HTML/XML/term)的pytestmake test-quick→ 运行pytest,第一次失败时停止make lint/make lint-fix→ Ruff检查(和自动修复)make format/make format-check→ 褶边格式+黑色make type-check→ mypymake ci-local→ lint、格式检查、类型检查、测试- Docker助手:
docker-build,docker-up,docker-up-sse,docker-up-stdio,docker-up-detached,docker-down,docker-logs,docker-clean - 在本地运行:
make run(stdio),或run-http/run-sse/run-stdio
测试
Pytest与覆盖率报告一起使用(pytest.ini).该套件根据需要模拟网络和文件日志记录;可以安全离线运行。
紫外线:
uv sync --extra dev
uv run -m pytest -q使用pip/venv:
pip install -e .[dev]
pytest -q重点子集:
- 单个文件:
pytest -q tests/test_factory.py - 单项试验:
pytest -q tests/test_factory.py::test_http_repository_is_default - 关键词:
pytest -q -k http
快速纯功能烟雾(无网络):
python -c "from utils.formatters import extract_joke; print(extract_joke({'setup':'Why?','punchline':'Because.'}))"覆盖率HTML被写入 htmlcov/.
码头工人
提供多级Dockerfile和Compose。
快速启动:
docker compose up mcp-server-http # HTTP transport on :8000
docker compose --profile sse up mcp-server-sse # SSE transport on :8001
docker compose --profile stdio up mcp-server-stdio # stdio (dev)看 DOCKER.md 了解更多详情。
认证
服务器通过自定义中间件实现HTTP和SSE传输的承载令牌身份验证(LocalTokenAuthMiddleware 在 main.py).
原理
- HTTP/SSE传输:所有工具调用都需要在
Authorization头球 - STDIO传输:无需身份验证(在受信任的本地环境中运行)
用法
在HTTP请求中包含令牌:
# Example: Call a tool with authentication
curl -X POST http://localhost:8000/call-tool \
-H "Authorization: Bearer -KB6aoXeiF-Qjor3LSEGh4-OOdJLCYrs5uqvUO9NCys" \
-H "Content-Type: application/json" \
-d '{"name": "tool_get_joke"}'有关带有身份验证的完整Python客户端示例,请参阅 examples/authenticated_http_client.py.
令牌验证
这 LocalTokenValidator 班级(utils/auth.py)通过将令牌与 LOCAL_TOKEN 环境变量。身份验证失败返回 ToolError 带有描述性信息。
安全说明
- 始终在生产中使用HTTPS来保护传输中的令牌
- 定期旋转令牌
- 从不将令牌提交到版本控制
- 使用环境变量或机密管理系统
MCP检验员测试
MCP检查器允许您以交互方式探索和调用服务器工具。它支持stdio和HTTP传输,需要Node.js 18+才能使用 npx.
安装
检查员不要求永久安装:
npx @modelcontextprotocol/inspector@latest --help选项A:sdio传输(无需身份验证)
检查器将服务器作为子进程启动。必须传递环境变量 --env.
紫外线:
npx @modelcontextprotocol/inspector@latest \
--command "uv run python main.py" \
--env API_BASE_URL=https://official-joke-api.appspot.com \
--env LOCAL_TOKEN=your-secret-token-here \
--env MCP_PROTOCOL=stdio使用pip/venv:
npx @modelcontextprotocol/inspector@latest \
--command "python main.py" \
--env API_BASE_URL=https://official-joke-api.appspot.com \
--env LOCAL_TOKEN=your-secret-token-here \
--env MCP_PROTOCOL=stdio注: 尽管 LOCAL_TOKEN 服务器启动需要stdio传输,但stdio传输在受信任的本地环境中运行时不会强制进行身份验证。
选项B:HTTP传输(需要身份验证)
对于HTTP传输,您需要两个终端:一个用于运行服务器,另一个用于连接检查器。
终端1:启动HTTP服务器
API_BASE_URL=https://official-joke-api.appspot.com \
LOCAL_TOKEN=-KB6aoXeiF-Qjor3LSEGh4-OOdJLCYrs5uqvUO9NCys \
MCP_PROTOCOL=http \
MCP_SERVER_HOST=127.0.0.1 \
MCP_SERVER_PORT=8000 \
uv run python main.py或者使用pip/venv:
API_BASE_URL=https://official-joke-api.appspot.com \
LOCAL_TOKEN=-KB6aoXeiF-Qjor3LSEGh4-OOdJLCYrs5uqvUO9NCys \
MCP_PROTOCOL=http \
MCP_SERVER_HOST=127.0.0.1 \
MCP_SERVER_PORT=8000 \
python main.py终端2:通过身份验证连接检查器
检查器需要在每次请求时发送Bearer令牌:
# Using environment variable for token
export LOCAL_TOKEN="-KB6aoXeiF-Qjor3LSEGh4-OOdJLCYrs5uqvUO9NCys"
npx @modelcontextprotocol/inspector@latest \
--server-url http://127.0.0.1:8000 \
--header "Authorization: Bearer $LOCAL_TOKEN"或者直接内联:
npx @modelcontextprotocol/inspector@latest \
--server-url http://127.0.0.1:8000 \
--header "Authorization: Bearer -KB6aoXeiF-Qjor3LSEGh4-OOdJLCYrs5uqvUO9NCys"重要提示: 检查员必须包括 Authorization 标头中包含有效的Bearer令牌,否则所有工具调用都将因身份验证错误而失败。
测试什么
连接后,您应该看到已注册的工具。试试这些快速测试:
- 无需网络:
tool_get_consistent_joke - 随机笑话:
tool_get_joke - 按ID:
tool_get_joke_by_id随着joke_id=42 - 按类型:
tool_get_joke_by_type随着joke_type="programming" - 异步变体:
tool_aget_joke,tool_aget_joke_by_id等等。
检查器连接故障排除
身份验证错误(仅限HTTP/SSE):
- 验证
Authorization标题包含在--header - 检查令牌是否与服务器的令牌匹配
LOCAL_TOKEN - 确保令牌格式为:
Bearer
连接超时:
- 验证
API_BASE_URL已设置且可访问 - 确保服务器正在正确的主机/端口上运行和侦听
- 对于HTTP,确认检查器URL与服务器的主机/端口匹配
未找到命令:
- 这
--command必须完全按照您启动服务器的方式 - 如果使用虚拟环境,请包含完整路径
设计说明
- 中间件模式 (
main.py):LocalTokenAuthMiddleware拦截工具调用以强制HTTP/SSE传输的身份验证 - 存储库模式 (
repositories/*):抽象数据访问并启用缓存 - 策略模式 (
strategies/*):选择传输并验证配置 - 公用事业 (
utils/):包括键入的HTTP客户端、模型、日志记录、格式化程序和身份验证
更多文档:请参见 docs/ (架构图、测试笔记、重构摘要)。
许可证
GPL-3.0——见 LICENSE.
全部
- 验证并对齐包版本(
pyproject.toml目前0.1.0)与docs/CHANGELOG.md. - CI:在此仓库列表中找不到工作流文件;如果需要CI,请添加一个工作流并在此处记录。
故障排除
- 如果获取笑话失败,请验证
API_BASE_URL以及网络接入。 - 日志默认为
logs/mcp_server.log;通过环境变量进行调整(LOG_*). - 在临时脚本/测试中,确保
API_BASE_URL在导入网络模块之前设置。
致谢
- FastMCP 对于MCP服务器框架。
- API笑话:https://official-joke-api.appspot.com(公共示例提供者)。
