内容
# 猜数字游戏 MCP 服务器
[](https://opensource.org/licenses/MIT)
一个使用 TypeScript 实现的动态模型上下文协议(MCP)服务器演示。它展示了一种基于会话的动态架构,每个用户都有自己的工具和资源集,由中央控制器管理。该服务器托管一个简单的猜数字游戏。
访问地址:[https://mcp.number-guessing-game.portal.one/mcp](https://mcp.number-guessing-game.portal.one/mcp)
更多远程服务器请访问:[https://remote-mcp-servers.com/](https://remote-mcp-servers.com/)
阅读我们的文章,讨论动态 MCP 服务器的优势:
[https://portal.one/blog/dynamic-mcp-servers-tame-complexity/](https://portal.one/blog/dynamic-mcp-servers-tame-complexity/)
以下是手动与服务器交互的示例。注意,根据当前游戏状态,工具会发生变化。
https://github.com/user-attachments/assets/8bb15870-2adc-4412-a072-4fc4eb14bbef
以及代理与服务器交互的视频。您在视频中看不到,但根据游戏状态,可用的工具也会发生变化。
https://github.com/user-attachments/assets/d7d338a2-8a93-46c3-b4a9-1a6b4caf9dc0
本项目旨在作为学习资源和构建动态多用户 MCP 应用程序的实用示例。
## 目录
1. [关键功能](#关键功能)
2. [架构概述](#架构概述)
3. [前提条件](#前提条件)
4. [开始使用](#开始使用)
5. [运行服务器](#运行服务器)
6. [与服务器交互](#与服务器交互)
7. [项目结构](#项目结构)
8. [演示的关键概念](#演示的关键概念)
9. [贡献](#贡献)
10. [许可证](#许可证)
## 关键功能
- **真正的多用户会话:** 每个连接的用户都获得自己的隔离游戏状态和 MCP 实体集。
- **动态 MCP 工具:** 工具(`start_game`、`guess_number`、`give_up`)根据用户的基础游戏状态启用或禁用。
- **动态 MCP 资源:** `game_state` 资源在用户开始和结束游戏时为每个用户创建和销毁。
- **清洁、可扩展的架构:**
- **单个全局 `McpServer`:** 处理所有连接。
- **Express.js 控制器:** 管理每个用户会话的生命周期。
- **会话范围的实体:** (工具、资源、游戏逻辑)按需创建。
- **状态模式:** 管理每个用户的游戏流程(大厅、玩耍)。
- **TypeScript 实现:** 完全类型化,以提高可维护性和开发人员体验。
- **Firestore 集成:** 持久化游戏状态和高分,使服务器无状态且可扩展。
## 架构概述
服务器遵循一种现代的可扩展模式,其中中央控制器管理短暂的、特定于会话的资源。
1. **全局服务器配置(`src/mcp_setup/index.ts`):** 在应用程序启动时创建一个 **McpServer** 实例。它充当一个“空白”连接管理器,不包含任何工具或资源。
2. **HTTP 控制器(`src/controllers/mcp.controller.ts`):** 这是应用程序的大脑。
- 它处理所有传入的 HTTP 请求到 `/mcp` 端点。
- 当新用户连接时,它创建一个 `StreamableHTTPServerTransport`。
- 它使用传输的生命周期钩子(`onsessioninitialized` 和 `onclose`)来管理用户的会话。
3. **会话初始化(`onsessioninitialized`):** 当用户的传输就绪时,控制器:
- 通过调用 `src/mcp_setup/tools` 和 `src/mcp_setup/resources` 中的设置函数,为该用户创建一组新的、独特的 MCP 实体。
- 创建一个新的 `GameContext` 实例,将其链接到用户的会话 ID 和他们独特的 MCP 实体。
- 从 Firestore 加载用户的状态(通过 `GameSessionService`)并使用状态模式(`LobbyState` 或 `PlayingState`)为他们的会话启用/禁用正确的工具。
4. **会话销毁(`onclose`):** 当用户断开连接时,控制器:
- **注销并销毁** 为该特定用户创建的所有工具和资源,以防止内存泄漏。
- 从其活动连接列表中清理传输。
这种架构确保每个用户的 UI 状态(例如哪些工具已启用)是完全隔离的、有状态的并且动态管理,而服务器本身保持可扩展。
## 前提条件
- Node.js(推荐 v18.x 或更高版本)
- npm 或 yarn
- 访问具有启用 Firestore 的 Google Cloud 项目。
## 开始使用
### 安装
1. **克隆仓库:**
```bash
git clone https://github.com/portal-labs-infrastructure/number-guessing-game-mcp-server
cd number-guessing-game-mcp-server
```
2. **安装依赖项:**
```bash
npm install
# 或
yarn install
```
### 配置
1. **设置 Google Cloud 身份验证:** 确保您的环境已对您的 Google Cloud 项目进行身份验证。对于本地开发,您可以使用 gcloud CLI:
```bash
gcloud auth application-default login
```
2. **创建 `.env` 文件:** 复制示例文件。
```bash
cp .env.example .env
```
3. **编辑 `.env`:** 填写所需的环境变量。
- `PORT`:服务器运行的端口(例如 `8083`)。
- `GCP_PROJECT_ID`:您的 Google Cloud 项目 ID。
- `BASE_URL`:服务器的公开 URL(例如 `http://localhost:8083`)。
- `OAUTH_ISSUER_URL`:您的 OAuth 提供商的基本 URL。
- `DOCS_URL`:指向您服务的文档的链接。
## 运行服务器
### 开发模式(适用于带有热重载的开发):
```bash
npm run dev
```
### 生产模式:
**编译 TypeScript:**
```bash
npm run build
```
**启动服务器:**
```bash
npm start
```
您应该会看到输出指示服务器正在运行并连接到 Firestore。
## 与服务器交互
### 直播服务器
您需要一个支持以下功能的 MCP 客户端:
- OAuth2(带有动态客户端注册)
- 工具通知
- 资源通知
您可以使用 [MCP Inspector](https://github.com/modelcontextprotocol/inspector),但它没有工具和资源通知,因此您必须手动刷新工具和资源。
您可以使用 [Portal One](https://portal.one) 网络客户端,并在可用 MCP 服务器列表中找到服务器,然后单击“连接”。
在 [MCP SDK 示例客户端](https://modelcontextprotocol.io/clients) 中查看其他支持动态 MCP 工具和资源(发现)的客户端。
### 本地
确保客户端可以访问服务器。如果您在本地运行服务器并使用基于 Web 的客户端,可以使用 [ngrok](https://ngrok.com/) 将服务器暴露给互联网:
```bash
ngrok http http://localhost:8083
```
如果您在 localhost 上使用客户端,可以直接连接到 `http://localhost:8083/mcp`。
## 项目结构
```
src/
├── config/
│ └── index.ts # 加载并导出环境变量
├── controllers/
│ └── mcp.controller.ts # 管理会话生命周期并按需创建实体
├── game/
│ ├── commands/ # 命令模式:封装用户操作
│ │ ├── command.interface.ts
│ │ ├── give-up.command.ts
│ │ ├── guess-number.command.ts
│ │ └── start-game.command.ts
│ ├── core/
│ │ ├── game-context.ts # 单个会话的中央游戏逻辑协调器
│ │ ├── game-session-service.ts # 处理所有 Firestore 交互(获取/设置状态)
│ │ ├── game-types.ts # 游戏的核心 TypeScript 接口
│ │ ├── resource-factory.ts # (当前设置中未使用,但可用)
│ │ └── tool-factory.ts # (当前设置中未使用,但可用)
│ ├── states/ # 状态模式:管理游戏流程(大厅、玩耍)
│ │ ├── game-state.interface.ts
│ │ ├── lobby.state.ts
│ │ └── playing.state.ts
│ └── utils/
│ └── game-constants.ts # 共享的游戏常量
├── index.ts # 应用程序的主要入口点(Express 服务器设置)
├── mcp_setup/
│ ├── index.ts # 创建单个全局 McpServer 实例
│ ├── resources/ # 创建 MCP 资源的功能工厂
│ │ ├── index.ts # 用于导出所有资源设置的桶文件
│ │ └── ... (setup-banner-image-resource.ts 等)
│ └── tools/ # 创建 MCP 工具的功能工厂
│ ├── index.ts # 用于导出所有工具设置的桶文件
│ └── ... (setup-guess-number-tool.ts 等)
├── routes/
│ └── mcp.routes.ts # 为 /mcp 定义 Express 路由
└── services/
└── firestore.service.ts # 初始化全局 Firestore 客户端
```
## 演示的关键概念
- **动态、会话范围的 MCP:** 此架构的核心。工具和资源不是全局的;它们为每个用户会话创建和销毁。
- **生命周期管理:** 使用传输钩子(`onsessioninitialized`、`onclose`)管理会话资源的设置和拆除。
- **HTTP 上的有状态服务:** 在无状态协议上实现持久的、隔离的用户会话。
- **状态模式:** 管理每个用户的游戏流程的复杂状态转换。
- **Firestore 用于状态持久性:** 将服务器的运行时与游戏状态分离,允许水平扩展和弹性。
- **TypeScript 最佳实践:** 在现实世界的可扩展应用程序结构中使用类型编写健壮的代码。
## 贡献
欢迎贡献!如果您有改进的想法、新功能或发现任何错误,请随时提出问题或拉取请求。
## 许可证
该项目根据 MIT 许可证获得许可 - 有关详细信息,请参阅 [LICENSE](LICENSE) 文件。