Skip to main content
Glama

构建你自己的 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 同时支持两者。这就是全部诀窍。


Related MCP server: mcp-cli-catalog

第 1 部分——我们要构建什么

llm-toolkit:一个 MCP 服务器,为任何 MCP 客户端提供四个由 LLM 驱动的工具。

工具

功能

ask_llm

提问,选择简洁 / 详细 / 通俗易懂

summarize

文本 → N 个要点

translate

翻译,保留 Markdown 和代码块

extract_json

非结构化文本 → 结构化 JSON

外加一个资源(config://server-info)和一个提示(code_review),以便学生 看到所有三种原语。


第 2 部分——在本地运行

设置

python -m venv .venv

Windows:.\\.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.json

  • Windows — %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)

构建命令

pip install -r requirements.txt

启动命令

python server.py --http

第 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。将启动命令设置为 python server.py --http。

Hugging Face Spaces

免费,不休眠。Docker Space,或带有自定义 app.py 垫片的 Gradio Space。

Google Cloud Run

gcloud run deploy --source . — 从源代码构建,无需 Dockerfile。

任何 VPS

pip install -r requirements.txt,然后在 systemd 或 tmux 下运行。

选项 C — Fly.io

fly launch --no-deploy
fly 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 部分——课堂练习

  1. 添加一个 sentiment(text) 工具。(复制 summarize,更改系统提示。)

  2. 让 ask_llm 接受一个 max_tokens 参数,并在 Inspector 中观察模式自动更新。

  3. 在不接触任何工具的情况下,将 call_llm 指向不同的提供者。

  4. 添加一个资源 config://usage,报告进程已服务了多少次工具调用。(提示:一个模块级计数器。)

  5. 故意破坏一个文档字符串,然后让模型使用该工具。观察它无法选择该工具。这就是教训。


第 7 部分——让其他人使用它

将工具交给其他人是三个独立的问题:可访问、可连接、可发现。按此顺序解决它们。

1. 可访问。 localhost 上的服务器只能由一个人使用。部署它(第 4 部分),你就有了一个公共 URL。在完成此操作之前,以下所有内容都不起作用。

2. 可连接。 给人们 USING-IT.md——一个独立的页面,包含 Claude Code、Claude Desktop 和 Cursor 的复制粘贴配置,以及一个故障排除表。对于工作坊,远程路由是应该使用的:学生粘贴一行代码,就能拥有可用的工具,无需 Python、无需仓库、也无需他们自己的 API 密钥。

3. 可发现。 仅当你希望陌生人找到它,而不仅仅是你的班级时:

渠道

它能给你带来什么

GitHub 主题 mcp、mcp-server、model-context-protocol

免费搜索流量

官方 MCP 注册表

列在客户端“浏览服务器” UI 中

awesome-mcp-servers 社区列表

PR 以添加你的仓库

Smithery / Glama 及类似目录

托管安装按钮

注册表要求变化很快——在发布前检查当前的 MCP 注册表文档以了解清单格式。

关于诚实上限的说明。 当人们采用一个 MCP 服务器时,是因为它能做他们自己无法做到的事情。这个服务器包装了一个通用的 LLM,大多数客户端已经内置了——非常适合教授协议,但作为产品则很弱。一个能够访问你的数据库、你的内部 API 或你的专有数据的服务器才是能获得真正用户的服务器。值得在课堂上大声说出来。


第 8 部分——什么使其达到生产就绪

工作坊版本和生产版本之间的差异与 MCP 无关。这是列表,每个项目都是因为在构建此服务器时实际发生的故障而存在的。

保护密钥

一个公共的 MCP 端点就是一个公共的消费端点:每次调用都会花费你的钱。

防护措施

环境变量

默认值

原因

Bearer 认证

MCP_AUTH_TOKEN

空 = 开放

一旦付费密钥在其后,则门控访问

速率限制

RATE_LIMIT_PER_MIN

30/IP

单个脚本无法耗尽你的配额

输入上限

MAX_INPUT_CHARS

20000

粘贴的小说在消耗令牌之前就被拒绝

请求体上限

MAX_BODY_BYTES

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 秒。


文件映射

文件

存在原因

server.py

整个服务器——工具、资源、提示

requirements.txt

mcp[cli] + groq + python-dotenv

Dockerfile

适用于任何主机的容器

render.yaml

一键 Render 部署

fly.toml

Fly.io 部署

.env.example

存在哪些环境变量

.mcp.json.example

要复制的客户端配置

USING-IT.md

提供给用户的独立页面

guards.py

认证、速率限制、大小上限、日志

tests/

离线测试套件,无需 API 密钥

.github/workflows/

CI:测试、启动检查、密钥扫描

Related MCP Connectors

Related MCP Servers