内容
# Pantrist MCP 服务器
一款 [Model Context Protocol](https://modelcontextprotocol.io) 服务器,封装了 Pantrist REST API,使得 LLM 客户端(Claude Desktop,Claude 网页/移动端连接器,Cursor 等)可以通过自然语言管理购物清单、食品储藏室、食谱和周计划。
它是一个**薄封装** —— 没有业务逻辑。每个工具都映射到现有的 REST 端点,并转发调用者的 Bearer token。HTTP 客户端是**从公共 OpenAPI 规范生成**的(`src/generated/pantrist-api.ts`),因此请求/响应类型会自动跟踪 API;只有策划工具层(`src/tools.ts`)是手工编写的。
## 文档
- **[docs/ARCHITECTURE.md](./docs/ARCHITECTURE.md)** — 组件、token 上下文、请求流程、传输、重新生成。
- **[docs/AUTHENTICATION.md](./docs/AUTHENTICATION.md)** — OAuth 流程、**token 类型 ↔ 工具兼容性**、多用户隔离、同意页面依赖。
- **[docs/DEPLOYMENT.md](./docs/DEPLOYMENT.md)** — 完整的环境变量参考、远程/入口设置、扩展、安全检查清单。
- **[docs/TOOLS.md](./docs/TOOLS.md)** — 每个工具的参数、REST 映射和项目形状。
- **[docs/LIMITATIONS.md](./docs/LIMITATIONS.md)** — 已知的缺陷(在生产环境中使用前请阅读)。
## 两种传输方式
| 传输方式 | 何时使用 | 认证方式 |
|---|---|---|
| **stdio** (`src/stdio.ts`) | 本地测试、单用户、Claude Desktop | 来自 `PANTRIST_TOKEN` 环境变量的 Bearer token |
| **可流式 HTTP** (`src/http.ts`) | 远程、多用户、Claude 连接器 | 客户端通过 OAuth 获取的每个请求的 Bearer token |
## 将 Claude 连接到托管服务器
如果您只想**使用** Pantrist 和 Claude(不是自行托管),公共端点是 **`https://mcp.pantrist.app/mcp`。** 选择您正在使用的 Claude 界面;在每种情况下,第一个工具调用都会引导您完成 OAuth 登录到您的 Pantrist 账户,无需手动复制 token。
### Claude.ai(网页或桌面应用)
1. **claude.ai** → 个人资料菜单 → **设置 → 连接器**
2. 点击 **添加自定义连接器**
3. 填写:
- **名称**:`Pantrist`
- **网址**:`https://mcp.pantrist.app/mcp`
4. 保存 → 点击 **连接**。弹出窗口打开 Pantrist 同意页面。
5. 登录 → 授权 → 弹出窗口关闭。
6. 开始新的聊天 — Pantrist 工具(购物清单、食品储藏室、周计划、食谱)出现在工具选择器中。尝试 *"我的购物清单上有什么?*"*
### Claude Code(CLI)
```bash
claude mcp add pantrist --transport http https://mcp.pantrist.app/mcp
```
在会话中,运行 `/mcp` 以确认它已列出。第一个工具调用会在您的浏览器中触发 OAuth 流程。
### Claude Desktop(手动配置)
对于支持远程 MCP 的 Claude Desktop 版本,在 `~/Library/Application Support/Claude/claude_desktop_config.json`(macOS)或 Windows/Linux 上的等效位置:
```json
{
"mcpServers": {
"pantrist": {
"type": "url",
"url": "https://mcp.pantrist.app/mcp"
}
}
}
```
重启 Claude Desktop。第一次使用工具会启动 OAuth。
### 故障排查
```bash
# 200 OK + {"status":"ok"}
curl -fsS https://mcp.pantrist.app/healthz
# 401 + 一个 WWW-Authenticate 头指向 /.well-known/oauth-protected-resource
curl -i -X POST https://mcp.pantrist.app/mcp -H 'Content-Type: application/json' -d '{}'
# JSON 列表 api.pantrist.app 作为授权服务器
curl -fsS https://mcp.pantrist.app/.well-known/oauth-protected-resource
```
如果这三个步骤都成功,但连接器流程仍然失败,则 API 的 `OAUTH_AUTHORIZE_URL` 可能未设置为浏览器可访问的同意页面 — 请参阅 [OAuth 依赖项说明](#oauth-流程)。
## 快速入门(stdio — 最快路径)
您可以在几分钟内通过使用已经拥有的 token 验证整个工具集,无需涉及 OAuth。
```bash
git clone https://github.com/NLueg/pantrist-mcp.git
cd pantrist-mcp
npm install
npm run build
# 获取 token:登录 Pantrist 应用,打开开发者工具 → 网络,复制任何 API 请求中的 `Authorization: Bearer <…>` 值(Firebase ID token — API 直接接受它)。或使用 OAuth access_token。
export PANTRIST_BASE_URL=https://api.pantrist.app
export PANTRIST_TOKEN=<粘贴 token>
export PANTRIST_LIST_ID=<列表 UUID> # 可选;或调用 list_lists
npm run dev:stdio # 或:node dist/stdio.js
```
### Claude Desktop 配置
`claude_desktop_config.json`(macOS:`~/Library/Application Support/Claude/claude_desktop_config.json`):
```json
{
"mcpServers": {
"pantrist": {
"command": "node",
"args": ["/绝对路径/pantrist-mcp/dist/stdio.js"],
"env": {
"PANTRIST_BASE_URL": "https://api.pantrist.app",
"PANTRIST_TOKEN": "<您的 token>",
"PANTRIST_LIST_ID": "<列表 UUID>"
}
}
}
}
```
重启 Claude Desktop,然后尝试: *"我的购物清单上有什么?"* 或 *"添加牛奶和鸡蛋。*"*
## 远程(流式 HTTP + OAuth)
```bash
export PANTRIST_BASE_URL=https://api.pantrist.app
export MCP_PUBLIC_URL=https://mcp.pantrist.app # 本服务器的公共 URL
export MCP_ALLOWED_HOSTS=mcp.pantrist.app # 可选的 DNS 绑定保护
export PORT=8787
npm run dev:http # 或:node dist/http.js
```
然后在 Claude 中添加为 **自定义连接器**,网址为 `https://mcp.pantrist.app/mcp`。服务器还为探测暴露了 `GET /healthz`。完整的环境变量参考、入口和扩展说明在 [docs/DEPLOYMENT.md](./docs/DEPLOYMENT.md) 中。
### OAuth 流程
```
Claude ──POST /mcp (无 token)──▶ MCP 服务器
◀── 401 + WWW-Authenticate: resource_metadata=".../oauth-protected-resource"
Claude ──GET /.well-known/oauth-protected-resource ──▶ MCP 服务器
◀── { authorization_servers: ["https://api.pantrist.app"] }
Claude ──GET /.well-known/oauth-authorization-server ─▶ pantrist-api (RFC 8414)
Claude ──POST /access-token/register ─────────────────▶ pantrist-api (RFC 7591 DCR)
Claude ──(浏览器)authorization_endpoint ────────────▶ 同意页面 (见下文)
Claude ──POST /access-token/token (代码 + PKCE) ──────▶ pantrist-api → access_token
Claude ──POST /mcp (Bearer access_token) ─────────────▶ MCP 服务器 ──▶ REST API
```
MCP 服务器是**资源服务器**;**授权服务器**是 Pantrist API。Claude 接收的 token 是 API Bearer,因此本服务器只需转发它。
> **⚠️ 依赖项 — 同意页面。** API 的 `authorization_endpoint` 必须是可浏览器导航的登录/同意页面(API 的 `/access-token/authorize` 是受保护的 JSON 端点,不能直接导航到)。在应用上托管一个(例如 `https://pantrist.app/oauth/authorize`),并将 API 的 `OAUTH_AUTHORIZE_URL` 环境变量设置为指向它。在该页面存在之前,请使用上述 stdio 路径和手动提供的 token。
## 工具
| 工具 | REST 路由 |
|---|---|
| `list_lists` | `GET /list` |
| `list_shopping_items` | `GET /list/{listId}/shoppingList` |
| `add_shopping_item` | `POST /list/{listId}/shoppingList/add-by-name` |
| `check_shopping_item` | `POST /list/{listId}/shoppingList/{itemId}/check` |
| `delete_shopping_item` | `DELETE /list/{listId}/shoppingList/{itemId}` |
| `list_pantry_items` | `GET /list/{listId}/pantryList` |
| `add_pantry_item` | `POST /list/{listId}/pantryList/add-by-name` |
| `reduce_pantry_amount` | `PUT /list/{listId}/pantryList/{itemId}/change-amount` |
| `update_pantry_item` | `GET` + `PUT /list/{listId}/pantryList/{itemId}` (仅限元数据;库存更改通过 `reduce_pantry_amount` 进行) |
| `search_recipes` | `POST /recipe/filter` |
| `get_recipe` | `GET /recipe/{recipeId}` |
| `delete_recipe` | `DELETE /recipe/{recipeId}` |
| `get_week_plan` | `GET /list/{listId}/weekPlan?from=&to=` |
| `update_week_plan_day` | `PUT /list/{listId}/weekPlan/{date}` |
大多数工具接受可选的 `listId`;如果省略,则仅在 **stdio 模式下** 使用 `PANTRIST_LIST_ID` (HTTP 模式需要显式指定 — 请参阅 [多用户隔离](./docs/AUTHENTICATION.md#multi-user-isolation))。完整的参数和项目形状详细信息在 [docs/TOOLS.md](./docs/TOOLS.md) 中。
所有这些都是**公共** API 端点(存在于 `/swagger-ui-json` 中),因此此包装器只需要已发布的规范 — 永远不需要私有 API 源。这使得可以将此目录作为自己的存储库开源。
## 测试
```bash
npm test # Node 的内置测试运行器(通过 tsx)— 连线 + 多用户门控
```
## 重新生成 API 客户端
两个步骤,在 API 合同更改时运行:
```bash
# 1. 在 pantrist-api 存储库中:发出公共 OpenAPI 规范(Nest 预览模式 — 无数据库)。直接将快照写入 ../pantrist-mcp/openapi/pantrist-openapi.json。
cd ../pantrist-api && pnpm generate:openapi
# 2. 返回此处:从该规范重新生成类型化的客户端。
cd ../pantrist-mcp && npm run generate:client
```
OpenAPI 规范的快照(`openapi/pantrist-openapi.json`)和生成的客户端(`src/generated/pantrist-api.ts`)都已提交,因此项目在无需网络访问的情况下构建。`src/tools.ts` 中的工具层是手动编写的,不会重新生成。
## 环境
请参阅 [`.env.example`](./.env.example)。