basic-mcp
by Raine-ovo
README.md
# Basic MCP Server
一个小而完整的 MCP(Model Context Protocol)示例项目,基于 TypeScript 和官方 MCP SDK v2。
这个仓库既提供可直接运行的最终服务器,也提供从一个 Tool 开始的渐进课程:
- [学习路径](docs/learning-path.md):六个可独立运行的课程示例;
- [架构与协议边界](docs/architecture.md):组件图、原语对比和交互时序;
- [练习与验收标准](docs/exercises.md):从基础到 OAuth/Tasks 扩展;
- [贡献指南](CONTRIBUTING.md):教学示例的代码与测试约定。
第一次接触 MCP 时,建议从 `examples/01-minimal-tool.ts` 开始,不要直接阅读完整的 `src/server.ts`。
## 已实现能力
- Tools:`add`、`echo`、`current-time`、`multiply`、进度/取消示例 `process_steps`,以及持久化 Todo 工具 `create_task`、`list_tasks`、`complete_task`、`delete_task`。
- Resources:示例资源 `demo://about`、`demo://greeting/{name}`,以及任务资源 `tasks://board`、`tasks://items/{id}`。
- Subscriptions:任务变化时发布 Resource 内容更新和列表变化通知,支持 stdio 与 Streamable HTTP。
- Prompts:`summarize-text`、`review-code`。
- Completions:为 `review-code.language` 提供参数候选值。
- Transports:本地客户端常用的 stdio,以及远程/服务化使用的 Streamable HTTP。
- HTTP 安全:Bearer Token 身份认证,并按用户隔离 Tool、Resource 和订阅通知。
- Storage:Node.js 内置 SQLite;默认数据库文件为 `data/tasks.db`,可通过 `MCP_DB_PATH` 修改。所有任务查询都带 `user_id`。
- 工程质量:TypeScript 严格模式、集成测试、健康检查、优雅退出、stdio 日志隔离。
## 环境
- Node.js 24+(当前 WSL 已通过 nvm 安装 Node 24 LTS)
- npm
新开终端后如果 `node --version` 仍显示旧版本,请执行:
```bash
source ~/.nvm/nvm.sh
nvm use --lts
```
## 安装与验证
```bash
cd /absolute/path/to/mcp
npm install
npm run check
npm test
npm run build
```
运行教学客户端,一次观察 Tool、Resource、Prompt、Completion、Progress 和 `input_required`:
```bash
npm run demo
```
生成内置测试覆盖率报告:
```bash
npm run test:coverage
```
## 运行
开发模式(stdio):
```bash
npm run dev
```
首次启动会自动创建 `data/tasks.db` 和 `tasks` 表。可以指定其他数据库位置:
```bash
MCP_DB_PATH=/absolute/path/tasks.db npm run dev
```
`delete_task` 会先通过 MCP `input_required` 请求客户端向用户确认,再执行永久删除。生产环境建议配置一个至少 32 字节的签名密钥:
```bash
REQUEST_STATE_SECRET='replace-with-at-least-32-bytes-secret' npm run dev
```
这个密钥用于给确认流程中的 `requestState` 签名,防止客户端篡改“正在确认删除哪条任务”。未配置时进程会生成临时随机密钥,适合本地开发,但服务重启后尚未完成的确认会失效;多进程部署必须共享同一个密钥。
编译后运行(stdio):
```bash
npm run build
npm start
```
运行 Streamable HTTP 服务:
```bash
MCP_AUTH_TOKENS_JSON='{"alice":"replace-with-a-random-token-of-at-least-32-bytes"}' \
REQUEST_STATE_SECRET='replace-with-at-least-32-bytes-secret' \
npm run start:http
# MCP: http://127.0.0.1:3000/mcp
# Health: http://127.0.0.1:3000/health
```
`MCP_AUTH_TOKENS_JSON` 是“用户 id → Bearer Token”的 JSON 对象,可以配置多个用户:
可以用 `openssl rand -hex 32` 生成随机 Token,然后配置:
```bash
export MCP_AUTH_TOKENS_JSON='{
"alice":"alice-random-token-with-at-least-32-bytes",
"bob":"bob-random-token-with-at-least-32-bytes--"
}'
```
客户端访问 `/mcp` 时必须发送对应凭据:
```http
Authorization: Bearer alice-random-token-with-at-least-32-bytes
```
`/health` 保持公开,方便本地健康检查。stdio 不经过 HTTP 认证,固定使用 `local` 用户。已有数据库升级时会自动增加 `user_id`,升级前的任务归入 `local` 用户;如果希望通过 HTTP 继续访问这些任务,请为 `local` 配置 Token。
可通过环境变量修改监听地址:
```bash
MCP_HOST=127.0.0.1 MCP_PORT=8080 npm run start:http
```
非回环监听必须同时配置允许的 Host 与 Origin,值为不带 scheme 和端口的逗号分隔 hostname:
```bash
MCP_HOST=0.0.0.0 \
MCP_ALLOWED_HOSTS=mcp.example.com \
MCP_ALLOWED_ORIGINS=app.example.com \
npm run start:http
```
默认仅监听回环地址。目前的静态 Token 方案用于学习和受控环境,它不是完整的 MCP OAuth 实现。若要暴露到公网,还应使用 TLS、真正的 OAuth/OIDC 身份提供方、密钥管理、限流、审计,并配置正确的 Host/Origin 白名单。可复制 `.env.example` 查看所有环境变量。
## 任务 Tool 与 Resource
- `create_task`、`complete_task`、`delete_task` 修改 SQLite 中的任务。
- `list_tasks` 让模型主动调用工具查询任务。
- `tasks://board` 把整个任务板作为只读 JSON 上下文提供给客户端。
- `tasks://items/{id}` 通过稳定 URI 读取单个任务,例如 `tasks://items/1`。
`delete_task` 的调用是两轮完成的:
1. 客户端第一次调用时,服务器返回 `input_required`,其中包含确认表单和已签名的 `requestState`,此时数据库还没有变化。
2. 客户端取得用户选择后,MCP SDK 自动带着 `inputResponses` 和原样的 `requestState` 重试同一个 Tool。
3. 服务器验证签名、任务 id、任务标题和确认结果;只有明确接受且 `confirm: true` 时才删除。
这不是服务器私自弹窗:显示确认界面的是支持 Elicitation 的 MCP 客户端。客户端若不支持该能力,就不能完成这项交互式删除。
Tool 和 Resource 共享同一个 `TaskStore`,所以 Tool 修改任务后,再次读取 Resource 会立即得到最新数据。
HTTP 模式会从已验证 Token 中取得 `userId`,并把它注入 MCP Server。任务的创建、读取、完成和删除都使用 `user_id` 作为 SQL 条件;每个用户还有独立的 MCP handler,因此 Resource 订阅通知也不会广播给其他用户。
客户端订阅后,服务器会发布以下通知:
- `create_task`:`tasks://board` 和新任务 URI 的内容更新,同时通知 Resource 列表发生变化。
- `complete_task`:`tasks://board` 和对应任务 URI 的内容更新。
- `delete_task`:`tasks://board` 和被删除任务 URI 的内容更新,同时通知 Resource 列表发生变化。
通知只表示某个 URI 已变化,不携带完整任务数据。客户端收到通知后,可以立即重新读取 Resource,也可以只把本地缓存标记为过期。
## 使用 MCP Inspector
先编译,再启动官方检查器:
```bash
npm run build
npm run inspect
```
运行单独课程示例:
```bash
npx @modelcontextprotocol/inspector npx tsx examples/01-minimal-tool.ts
```
## 客户端配置示例
Codex/Claude Desktop/Cursor 等支持 stdio 的 MCP Host 可使用等价配置:
```json
{
"mcpServers": {
"basic-mcp": {
"command": "/absolute/path/to/node",
"args": ["/absolute/path/to/mcp/dist/src/stdio.js"],
"env": {
"MCP_DB_PATH": "/absolute/path/to/mcp/data/tasks.db"
}
}
}
}
```
建议先执行 `npm run build`。把占位路径替换为 `which node` 和项目目录返回的绝对路径;也可以写一个固定启动脚本,由它加载 nvm。
如果 MCP Host 运行在 Windows(而服务器代码位于 WSL),可使用:
```json
{
"mcpServers": {
"basic-mcp": {
"command": "wsl.exe",
"args": [
"-d",
"Ubuntu-24.04",
"--",
"env",
"MCP_DB_PATH=/absolute/wsl/path/to/mcp/data/tasks.db",
"/absolute/wsl/path/to/node",
"/absolute/wsl/path/to/mcp/dist/src/stdio.js"
]
}
}
}
```
## 项目结构
```text
src/server.ts # MCP 能力注册和服务器工厂
src/auth.ts # 静态 Bearer Token 配置与验证
src/task-store.ts # SQLite 任务存储层
src/stdio.ts # stdio 入口
src/http.ts # Streamable HTTP 入口
src/http-server.ts # HTTP 认证、用户路由与服务器装配
test/ # 真实 MCP Client 驱动的集成测试
examples/ # 从最小 Tool 到教学 Client 的渐进示例
docs/ # 学习路径、架构和练习
```
扩展时通常只需要在 `src/server.ts` 中增加 `registerTool`、`registerResource` 或 `registerPrompt`。
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues