llm-toolkit
构建你自己的 MCP 服务器(并部署它)
一个完整、可运行的 MCP 服务器,能将 LLM API 转化为 MCP 工具——专为教学而构建。 它通过 stdio 在本地运行,适用于 Claude Desktop / Claude Code,并且一旦部署, 可通过 HTTP 远程访问。
由 Groq 提供支持——推理速度快,兼容 OpenAI API,免费套餐足以承受 满教室学生在工作坊中同时使用。
所有内容都位于一个文件中:server.py。包括注释在内约 170 行。
第 0 部分——一分钟了解 MCP
MCP(模型上下文协议)是一种为 AI 客户端赋予新能力的标准方式。 你编写一个服务器;任何 MCP 客户端都可以使用它。
一个服务器可以暴露三种东西:
原语 | 它是什么 | 谁控制它 |
工具 | 模型可以调用的函数 | 模型决定 |
资源 | 客户端可以拉取的只读数据 | 客户端/应用决定 |
提示 | 可复用的提示模板 | 用户选择 |
两种传输方式:
stdio — 客户端将你的服务器作为子进程启动,并通过 stdin/stdout 通信。仅限本地。零网络。这是 90% 的 MCP 服务器的运行方式。
可流式 HTTP — 你的服务器是一个位于 URL 的 Web 服务。这是你部署后供其他人(或托管客户端)使用的方式。
同一个 server.py 同时支持两者。这就是全部诀窍。
第 1 部分——我们要构建什么
llm-toolkit:一个 MCP 服务器,为任何 MCP 客户端提供四个由 LLM 驱动的工具。
工具 | 功能 |
| 提问,选择简洁 / 详细 / 通俗易懂 |
| 文本 → N 个要点 |
| 翻译,保留 Markdown 和代码块 |
| 非结构化文本 → 结构化 JSON |
外加一个资源(config://server-info)和一个提示(code_review),以便学生
看到所有三种原语。
第 2 部分——在本地运行
设置
python -m venv .venvWindows:.\\.venv\Scripts\activate — macOS/Linux:source .venv/bin/activate
pip install -r requirements.txt在 console.groq.com → API Keys 获取免费密钥。然后复制
.env.example 为 .env 并粘贴进去:
cp .env.example .env.env 已被 gitignore。服务器会从其自身目录自动加载它,因此无论客户端从何处启动它,它都能正常工作。
在连接之前检查它
MCP Inspector 是最好的教学工具——它显示工具列表,并允许你手动调用工具,无需 AI 客户端。
npx @modelcontextprotocol/inspector python server.py打开打印的 URL,点击 Connect,然后点击 List Tools。你将看到所有四个工具。
第 3 部分——将其连接到客户端
Claude Code
claude mcp add llm-toolkit -e GROQ_API_KEY=gsk_... -- python /absolute/path/to/server.py或者在你的项目根目录中提交一个 .mcp.json,以便整个团队都能使用它——请参阅
.mcp.json.example。
Claude Desktop
编辑 claude_desktop_config.json:
macOS —
~/Library/Application Support/Claude/claude_desktop_config.jsonWindows —
%APPDATA%\Claude\claude_desktop_config.json
粘贴来自 .mcp.json.example 的 mcpServers 块,然后完全退出并重新打开
Claude Desktop。这些工具会出现在工具图标下。
仅限绝对路径。 本地 MCP 服务器“不显示”的首要原因是 相对路径——客户端的工作目录不是你的工作目录。请使用 python 二进制文件(
.venv/bin/python)和server.py的完整路径。
第 4 部分——部署它
使用一个标志切换到 HTTP 模式:
python server.py --http服务器现在位于 http://localhost:8000/mcp。在容器中运行相同的命令。
选项 A — Render,无需 Docker(推荐)
Render 具有原生 Python 运行时。无需 Dockerfile,无需容器构建。它会安装
requirements.txt 并直接运行你的启动命令。这是从笔记本电脑到公共 URL 的最快路径。
第 1 步——将代码放到 GitHub 上。
git init && git add -A && git commit -m "MCP server"在 github.com/new 创建一个空仓库,然后:
git remote add origin https://github.com/<you>/llm-toolkit-mcp.git && git push -u origin main第 2 步——创建服务。
Render 仪表板 → New → Web Service → 连接仓库。Render 会读取
render.yaml 并自行配置:
设置 | 值 |
运行时 | Python(不是 Docker) |
构建命令 |
|
启动命令 |
|
第 3 步——设置密钥。 仪表板 → Environment → 添加 GROQ_API_KEY。它在 render.yaml 中被标记为
sync: false,因此仅存在于仪表板中,永远不会出现在 git 中。
第 4 步——部署。 你的公共端点是 https://<your-app>.onrender.com/mcp。
故意不设置健康检查。
GET /mcp会打开一个 SSE 流,该流会保持打开状态。 指向它的健康检查会挂起,Render 会将超时视为服务死亡并重启循环。省略healthCheckPath后,Render 仅验证进程是否绑定了$PORT——这是此服务器的正确检查。
免费层实例在空闲约 15 分钟后会休眠。休眠后的第一次调用需要约 30-50 秒才能唤醒。某些 MCP 客户端在此之前超时,并将服务器报告为损坏。在上课前用 curl 预热它。
选项 B — 其他无需 Docker 的主机
主机 | 如何操作 |
Railway | 连接仓库。Nixpacks 会自动检测 Python。将启动命令设置为 |
Hugging Face Spaces | 免费,不休眠。Docker Space,或带有自定义 |
Google Cloud Run |
|
任何 VPS |
|
选项 C — Fly.io
fly launch --no-deployfly secrets set GROQ_API_KEY=gsk_...fly deploy端点:https://<your-app>.fly.dev/mcp
选项 D — 任何容器主机
Dockerfile 是为需要容器的主机保留的。适用于 Railway、Cloud Run、ECS、VPS:
docker build -t llm-toolkit-mcp .docker run -p 8000:8000 -e GROQ_API_KEY=gsk_... llm-toolkit-mcp验证部署
一个 curl 命令即可证明服务器正在运行并支持 MCP:
curl -X POST https://your-app.onrender.com/mcp -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"1"}}}'你应该会收到一个 serverInfo 块,其中包含 llm-toolkit。
将客户端连接到已部署的服务器
claude mcp add --transport http llm-toolkit https://your-app.onrender.com/mcp学生粘贴这一行,就能立即拥有你的四个工具。这是整个工作坊的回报时刻——无需安装,无需密钥,他们的机器上无需 Python。
公开分享——请先阅读此内容
一个没有身份验证的已部署 MCP 服务器是向整个互联网开放的。任何知道 URL 的人都可以调用你的工具,每次调用都会消耗你的 Groq 配额。
对于工作坊来说,这通常没问题,而 Groq 的免费套餐正是使其可行的原因:当配额用完时,你会收到 HTTP 429 错误,而不是账单。失败模式是“工具停止响应”,而不是“意外发票”。
一旦你在后面放了一个付费密钥,情况就不再如此。然后在分享 URL 之前添加身份验证——使用 MCP SDK 的 auth 参数,或在其前面放置 API 网关。
无论如何,有两个习惯值得保持:
将 URL 视为半机密。在课堂上分享,不要公开发布。
在工作坊后轮换密钥。只需在仪表板上点击一下。
第 5 部分——值得明确教授的内容
文档字符串就是 API。 模型通过读取文档字符串和类型提示来选择工具。模糊的文档字符串意味着工具永远不会被调用。这是整个文件中杠杆率最高的一件事。
一个函数拥有提供者。 每个工具都调用 call_llm()。将 Groq 换成 OpenAI、Anthropic 或本地 Ollama 意味着只需编辑这一个函数——四个工具永远不会改变。现场演示这个;效果很好。
将错误作为字符串返回,不要抛出。 call_llm 捕获 GroqError 并将消息作为文本返回。客户端向用户显示真实的错误,而不是一个死掉的工具调用。
stateless_http=True 意味着没有粘性会话,因此服务器可以在负载均衡器后面扩展。仅当你添加每个会话状态时才将其关闭。
永远不要提交密钥。 .env 已被 gitignore,render.yaml 使用 sync: false,Fly 使用 fly secrets。
公共 HTTP 服务器默认是开放的。 这个没有身份验证——适合演示,不适合生产。真正的部署通过 SDK 的 auth 参数添加 OAuth,或位于 API 网关后面。
版本漂移是真实存在的。 MCP Python SDK 2.0 将 FastMCP 重命名为 MCPServer。网上的大多数教程仍然显示 FastMCP,并且在全新安装时会失败。这是教授阅读已安装包而不是相信博客文章的好时机。
第 6 部分——课堂练习
添加一个
sentiment(text)工具。(复制summarize,更改系统提示。)让
ask_llm接受一个max_tokens参数,并在 Inspector 中观察模式自动更新。在不接触任何工具的情况下,将
call_llm指向不同的提供者。添加一个资源
config://usage,报告进程已服务了多少次工具调用。(提示:一个模块级计数器。)故意破坏一个文档字符串,然后让模型使用该工具。观察它无法选择该工具。这就是教训。
第 7 部分——让其他人使用它
将工具交给其他人是三个独立的问题:可访问、可连接、可发现。按此顺序解决它们。
1. 可访问。 localhost 上的服务器只能由一个人使用。部署它(第 4 部分),你就有了一个公共 URL。在完成此操作之前,以下所有内容都不起作用。
2. 可连接。 给人们 USING-IT.md——一个独立的页面,包含 Claude Code、Claude Desktop 和 Cursor 的复制粘贴配置,以及一个故障排除表。对于工作坊,远程路由是应该使用的:学生粘贴一行代码,就能拥有可用的工具,无需 Python、无需仓库、也无需他们自己的 API 密钥。
3. 可发现。 仅当你希望陌生人找到它,而不仅仅是你的班级时:
渠道 | 它能给你带来什么 |
GitHub 主题 | 免费搜索流量 |
官方 MCP 注册表 | 列在客户端“浏览服务器” UI 中 |
| PR 以添加你的仓库 |
Smithery / Glama 及类似目录 | 托管安装按钮 |
注册表要求变化很快——在发布前检查当前的 MCP 注册表文档以了解清单格式。
关于诚实上限的说明。 当人们采用一个 MCP 服务器时,是因为它能做他们自己无法做到的事情。这个服务器包装了一个通用的 LLM,大多数客户端已经内置了——非常适合教授协议,但作为产品则很弱。一个能够访问你的数据库、你的内部 API 或你的专有数据的服务器才是能获得真正用户的服务器。值得在课堂上大声说出来。
第 8 部分——什么使其达到生产就绪
工作坊版本和生产版本之间的差异与 MCP 无关。这是列表,每个项目都是因为在构建此服务器时实际发生的故障而存在的。
保护密钥
一个公共的 MCP 端点就是一个公共的消费端点:每次调用都会花费你的钱。
防护措施 | 环境变量 | 默认值 | 原因 |
Bearer 认证 |
| 空 = 开放 | 一旦付费密钥在其后,则门控访问 |
速率限制 |
| 30/IP | 单个脚本无法耗尽你的配额 |
输入上限 |
| 20000 | 粘贴的小说在消耗令牌之前就被拒绝 |
请求体上限 |
| 1 MB | 过大的负载在解析之前就失败 |
认证默认关闭,以便服务器在免费密钥上为工作坊保持开放。在将付费密钥指向公共 URL 之前,请将其打开:
MCP_AUTH_TOKEN=$(python -c "import secrets;print(secrets.token_urlsafe(32))") python server.py --http客户端随后发送 Authorization: Bearer <token>。
应对提供商
模型会在没有通知的情况下退役。 Groq 在开发过程中移除了 llama-3.3-70b-versatile ——它在 07:15 还能工作,一小时后返回 404。所有工具同时崩溃,404 看起来像是“你的服务器坏了”,而不是“供应商迁移了”。
MODEL_CHAIN 解决了这个问题:在模型未找到错误时,调用会回退到下一个模型而不是失败。其他错误——错误的密钥、速率限制——会快速失败,因为在五个模型上重试这些错误只会浪费时间。
超时(LLM_TIMEOUT_SECONDS)和重试(LLM_MAX_RETRIES)交给供应商 SDK 处理,它们已经正确实现了退避。
健康检查
/health 返回纯 JSON。永远不要对 /mcp 进行健康检查——它是一个设计上保持打开的 SSE 流,因此探测会挂起,平台会认为服务已死,你会得到一个看起来像崩溃的重启循环。这在这里花费了一个真实的调试周期。
日志
所有内容都输出到 stderr,绝不输出到 stdout。在 stdio 模式下,stdout 承载 JSON-RPC 流,因此一个多余的 print() 会破坏协议。这是调试 MCP 服务器时最常见的破坏方式。
MCP 级别的中间件会记录每个方法及其持续时间,并且适用于两种传输方式。
测试和 CI
pytest tests/ 离线运行,无需 API 密钥,不花费任何费用。它涵盖了速率限制器的窗口过期、输入上限、模型回退、工具模式保留和配置验证。
GitHub Actions 在 3.11 和 3.12 上运行测试套件,启动服务器,并扫描整个 git 历史以查找提交的 API 密钥——这是不可恢复的失败,因为推送的密钥一旦落地就公开了。
已知限制
值得对班级坦诚说明仍然缺少什么:
速率限制是每个进程的。 扩展到 N 个实例,你就允许了 N 倍的限制。在问题出现之前换成 Redis。
一个共享令牌,不是每个用户的密钥。 对班级来说没问题,但对客户不行。
没有使用计量。 你无法知道谁花了什么。
免费层的冷启动 在空闲后仍然需要 30-50 秒。
文件映射
文件 | 存在原因 |
| 整个服务器——工具、资源、提示 |
|
|
| 适用于任何主机的容器 |
| 一键 Render 部署 |
| Fly.io 部署 |
| 存在哪些环境变量 |
| 要复制的客户端配置 |
| 提供给用户的独立页面 |
| 认证、速率限制、大小上限、日志 |
| 离线测试套件,无需 API 密钥 |
| CI:测试、启动检查、密钥扫描 |
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
MCP server for AI dialogue using various LLM models via AceDataCloud
MCP server providing access to the Scorecard API to evaluate and optimize LLM systems.
MCP server for Pentest-Tools.com: run scans, manage findings and reports via your preffered LLM.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/aihunter9892/mcpserver'
If you have feedback or need assistance with the MCP directory API, please join our Discord server