内容
---
title: 挂人游戏 MCP 服务器
description: 一个教学示例,将经典的挂人游戏作为 MCP 服务器,通过 MCP 应用在 VS Code 中内联渲染棋盘,并通过 MCP 采样提供提示。
---
## 概述
这是一个小型 Python [MCP](https://modelcontextprotocol.io/) 服务器,将挂人游戏作为一组工具公开,并利用 MCP 的两个更有趣的功能,使体验在 VS Code Copilot Chat 中感觉原生:
* **MCP 应用**(规范 `2026-01-26`)在聊天面板中内联渲染交互式挂人游戏棋盘。棋盘具有可点击的键盘、分数显示和提示按钮。点击 `postMessage` 回到主机,主机将其调度为工具调用。
* **MCP 采样** 为 `get_hint` 提供支持。服务器不持有自己的 LLM 密钥,而是请求主机(VS Code Copilot)代表其运行采样往返。难度驱动提示样式 - 简单时提供易于理解的线索,困难时提供类似密码的线索。
目的是 *看到* 主机 ↔ 服务器 ↔ 采样循环端到端,LLM 承担服务器无法完成的工作。
## 各组件运行位置
```mermaid
sequenceDiagram
participant User
participant VSCode as VS Code (Copilot host)
participant Server as hangman_server (stdio)
User->>VSCode: /play_hangman easy
VSCode->>Server: tools/call new_game
Server-->>VSCode: GameState + ui://hangman/board/{id}
VSCode-->>User: Inline board (iframe)
User->>VSCode: 点击字母 "E"
VSCode->>Server: tools/call guess_letter
Server-->>VSCode: 更新的 GameState + 新棋盘
User->>VSCode: 点击提示
VSCode->>Server: tools/call get_hint
Server->>VSCode: sampling/createMessage(请求主机的 LLM)
VSCode->>User: 一次性同意对话框(仅首次调用)
VSCode-->>Server: 模型回复
Server-->>VSCode: 提示文本 + 更新的 GameState + 新棋盘
VSCode-->>User: 提示在聊天中显示,棋盘重新渲染
```
## 快速入门
先决条件:Python 3.11+,[`uv`](https://docs.astral.sh/uv/),带有 GitHub Copilot Chat 的 VS Code。
```pwsh
# 从存储库根目录
uv sync
```
然后在 VS Code 中:
1. 重新加载窗口,以便主机拾取 [`.vscode/mcp.json`](.vscode/mcp.json) - 它将 `hangman` stdio 服务器注册为工具。
2. 打开 Copilot Chat 并调用 `play_hangman` 提示(斜杠菜单),或只需输入 *"开始一个挂人游戏"*。
3. 点击渲染的棋盘上的字母。点击 **提示** 时,您需要 LLM 帮助。
在第一次点击提示时,您将看到来自 VS Code 的一次性 **采样同意对话框**,询问是否允许服务器使用 Copilot 生成文本。批准一次,随后的提示将无缝进行。
## 使用 MCP 检验器手动驱动
用于工具形状或渲染 HTML 迭代的无主机开发循环 - 在此循环中非常有用:
```pwsh
npx @modelcontextprotocol/inspector uv run python -u -m hangman_server
```
在检验器 UI 中:
* **工具** 选项卡 - 调用 `new_game`,然后使用返回的 `game_id` 调用 `guess_letter` / `guess_word` / `get_state` / `give_up`。每个响应都包含 `structuredContent`(`GameState`)和 `_meta.ui.resourceUri`。
* **资源** 选项卡 - 获取 `ui://hangman/board/{id}` 以查看渲染的 HTML。
* `get_hint` 在检验器中不起作用,因为检验器不满足采样请求 - 请使用 VS Code 完成完整的提示路径。
## 计分
| 事件 | 积分变化 |
|--------------------|------------------------|
| 正确字母 | `+10 × 匹配数 × 倍率` |
| 解谜奖励(单词) | `+50 × 倍率` |
| 错误字母 | `-1 × 倍率` |
| 错误单词猜测 | `-5 × 倍率` |
| 提示 | `-5 × 倍率` |
`倍率` 在困难模式下为 `2`,在简单模式下为 `1`。分数可以为负。
## 难度
* **简单** - 短小、常见的单词(APPLE、RIVER、PIANO…);提示直接("孩子们午餐喜欢的一种红色水果")。
* **困难** - 长度较长、不常见的单词(CHIAROSCURO、PHLEGMATIC…);提示神秘且具有暗示性,积分变化每点倍率增加一倍。
## 存储库布局
```text
src/hangman_server/
__main__.py # 入口点 -> mcp.run()
server.py # FastMCP 工具 + 提示 + 采样支持的 get_hint
game.py # 纯规则:GameState,_Game,计分
ui.py # render_board(state) -> 沙盒 iframe HTML
tests/
test_game.py # 规则 + 计分套件(pytest)
.vscode/
mcp.json # 将 hangman 注册为 stdio 服务器
```
## 运行测试
```pwsh
uv sync --extra dev
uv run pytest -q
```
## 第二阶段指针:单页应用通过 Streamable HTTP
此 v1 示例使用 **stdio** 传输,因为 VS Code 启动了服务器。要将相同的游戏玩法放在单页 Web 应用后面:
1. 将 [`__main__.py`](src/hangman_server/__main__.py) 修改为 `mcp.run(transport="streamable-http")`。
2. 建立一个小型前端,通过 HTTP 驱动 MCP 协议,并针对您选择的 LLM(Azure AI Foundry、OpenAI、Ollama…)实现 `sampling/createMessage`。
3. `game.py`、`ui.py` 和 `@mcp.tool()` 定义中的所有内容保持不变。
`.copilot-tracking/research/2026-05-20/` 下的研究笔记记录了该路径的设计权衡。
## 故障排除
* **VS Code 显示服务器但工具调用挂起** - 确认 `.vscode/mcp.json` 仍然传递 `python -u` 并设置 `PYTHONUNBUFFERED=1`。如果没有它们,Python 子进程将在 Windows 上缓冲 stdout,`initialize` 握手将停滞。
* **Iframe 在各回合之间不重新渲染** - 一些 MCP 应用客户端通过资源 URI 缓存。如果您遇到此问题,请在 [`server.py`](src/hangman_server/server.py) 中将 `resource_uri` 附加一个回合计数器查询字符串(例如 `ui://hangman/board/{id}?t={turn}`)。
* **提示按钮无反应** - 确保您已批准采样同意对话框。检查服务器的 stderr(VS Code 的 MCP 输出通道)中是否有 `采样失败:…`。