内容
# MCP 笔记应用
一个全栈的笔记应用,具备 React 用户界面、Express/SQLite 后端、实时服务器发送事件(SSE)、JWT 认证以及通过模型上下文协议(MCP)的 AI 代理集成。
## 您将获得
- 在现代 React 界面中创建、编辑、删除、标记和搜索笔记。
- 当笔记通过 REST 或 MCP 工具更改时,通过 SSE 实现实时用户界面刷新。
- 使用本地 API 密钥登录的 JWT 保护的 REST 笔记路由。
- 用于 AI 客户端和 Python Gemini 客户端的 MCP SSE 传输。
- 通过存储库层实现 SQLite 持久化。
## 架构
```text
┌─────────────────┐ MCP/SSE ┌──────────────────┐
│ Python 代理 │ ◄──────────────► │ │
│ (Gemini AI) │ │ Node.js 服务器 │
│ │ 工具 │ (MCP + REST) │
└─────────────────┘ │ │
│ SQLite 数据库 │
┌─────────────────┐ REST/SSE │ │
│ React 前端 │ ◄──────────────► │ │
│ (Vite+Tailwind) │ └──────────────────┘
└─────────────────┘
```
- **后端**:TypeScript、Express、MCP 服务器、SQLite (`better-sqlite3`)、Zod、JWT。
- **前端**:React 18、Vite、Tailwind CSS、TanStack React Query、Zustand、SSE。
- **代理**:连接到 Google Gemini 的 Python MCP 客户端(默认 `gemini-2.5-flash`)。
## 先决条件
- 推荐 Node.js 20+。
- npm。
- 推荐 Python 3.10+。
- 用于可选 Python 代理的 Gemini API 密钥。
## 快速开始
### 1. 安装依赖项
从仓库根目录安装所有依赖项:
```bash
npm run install:all
```
或手动安装每个层:
```bash
npm install --prefix server
npm install --prefix client-ui
python3 -m venv agent/.venv
agent/.venv/bin/python -m pip install -r agent/requirements.txt
```
仅在需要时安装根编排依赖项:
```bash
npm install
```
### 2. 配置环境
创建 `server/.env`:
```env
PORT=3000
NODE_ENV=development
JWT_SECRET=change-this-to-a-long-random-secret-at-least-32-chars
JWT_EXPIRY=15m
JWT_REFRESH_EXPIRY=7d
DATABASE_PATH=./data/notes.db
CORS_ORIGIN=http://localhost:5173
AUTH_TOKEN=dev-auth-token-change-in-production
```
如果您计划使用 Gemini 代理,请创建 `agent/.env`:
```env
GEMINI_API_KEY=your-gemini-api-key
```
代理的标准输入传输变量(可选):
```env
MCP_STDIO_CMD=npx
MCP_STDIO_ARGS=tsx,server/src/index.ts
```
> 不要提交 `.env` 文件、API 密钥、JWT 机密或本地 SQLite 数据库文件。
### 3. 启动应用
同时启动后端和前端:
```bash
npm run dev
```
或单独运行:
```bash
npm run dev:server
npm run dev:client
```
然后在 `http://localhost:5173` 打开前端。
### 4. 启动 AI 代理
确保后端正在运行,然后运行:
```bash
npm run dev:agent
```
一次性示例:
```bash
agent/.venv/bin/python agent/agent.py --one-shot "Create a note titled Demo with content Hello from Gemini"
```
## 脚本
从仓库根目录运行这些脚本,除非另有说明。
| 命令 | 描述 |
|--------|-------------|
| `npm run install:all` | 安装服务器、客户端和 Python 代理依赖项。 |
| `npm run install:agent` | 创建 `agent/.venv` 并安装 Python 依赖项。 |
| `npm run dev` | 同时启动后端和前端。 |
| `npm run dev:server` | 仅启动 Express/MCP 服务器。 |
| `npm run dev:client` | 仅启动 Vite 前端。 |
| `npm run dev:agent` | 启动 Python Gemini MCP 代理。 |
| `npm run build` | 构建服务器和客户端。 |
| `npm run build --prefix server` | 类型检查/构建后端。 |
| `npm run build --prefix client-ui` | 类型检查/构建前端。 |
| `npm run test --prefix client-ui` | 使用 Vitest 运行前端单元测试。 |
| `npm run test:e2e --prefix client-ui` | 运行 Playwright 端到端测试。 |
## 项目结构
```text
mcp-note-app/
├── server/ # Express REST API, MCP 服务器, SQLite 持久化
│ ├── src/
│ │ ├── auth/ # JWT 签名和验证
│ │ ├── config/ # 环境验证
│ │ ├── db/ # SQLite 连接和模式
│ │ ├── events/ # 事件总线和 SSE 处理程序
│ │ ├── mcp/ # MCP 工具服务器和传输
│ │ ├── middleware/ # 认证、CORS、错误处理
│ │ ├── repositories/ # NoteRepository + SQLite 实现
│ │ ├── routes/ # 笔记 REST 路由和实时更新
│ │ ├── types.ts # Zod 模式和共享后端类型
│ │ └── index.ts # Express 入口点
│ └── package.json
├── client-ui/ # React 前端
│ ├── e2e/ # Playwright 测试
│ ├── src/
│ │ ├── components/ # 表示性和 UI 组件
│ │ ├── hooks/ # React Query 和 SSE 钩子
│ │ ├── services/ # API 客户端和查询客户端
│ │ ├── stores/ # Zustand 认证/UI 状态
│ │ ├── test/ # Vitest 设置和组件测试
│ │ ├── types/ # 前端笔记类型
│ │ ├── App.tsx
│ │ └── main.tsx
│ └── package.json
├── agent/ # Python MCP + Gemini CLI 代理
│ ├── agent.py
│ ├── mcp_gemini_adapter.py
│ └── requirements.txt
├── AGENTS.md # 代码代理项目指南
├── README.md
└── package.json # 根编排脚本
```
## 环境变量
### 服务器
| 变量 | 默认值 | 描述 |
|----------|---------|-------------|
| `PORT` | `3000` | Express 服务器端口。 |
| `NODE_ENV` | `development` | 运行时环境。 |
| `JWT_SECRET` | 必需 | JWT 签名的机密。必须至少 32 个字符。 |
| `JWT_EXPIRY` | `15m` | 访问令牌生命周期。 |
| `JWT_REFRESH_EXPIRY` | `7d` | 刷新令牌生命周期。 |
| `DATABASE_PATH` | `./data/notes.db` | SQLite 数据库路径,相对于 `server/` 运行服务器脚本时。 |
| `CORS_ORIGIN` | `http://localhost:5173` | 允许的前端源。 |
| `AUTH_TOKEN` | 必需 | `/api/login` 使用的开发 API 密钥。 |
### 代理
| 变量 | 默认值 | 描述 |
|----------|---------|-------------|
| `GEMINI_API_KEY` | 代理必填 | Google Gemini API 密钥。 |
| `MCP_STDIO_CMD` | `npx` | 代理标准输入传输使用的命令。 |
| `MCP_STDIO_ARGS` | `tsx,server/src/index.ts` | 以逗号分隔的标准输入命令参数。 |
## API 端点
| 方法 | 路径 | 认证 | 描述 |
|--------|------|------|-------------|
| `POST` | `/api/login` | API 密钥 | 使用 `{ "apiKey": "..." }` 登录;返回访问和刷新令牌。 |
| `POST` | `/api/refresh` | 刷新令牌 | 正文: `{ "refreshToken": "..." }`;返回新的访问令牌。 |
| `GET` | `/api/notes` | JWT | 列出笔记。查询参数: `query`、`limit`、`offset`。 |
| `POST` | `/api/notes` | JWT | 创建一个带有 `title`、可选 `content` 和可选 `tags` 的笔记。 |
| `GET` | `/api/notes/:id` | JWT | 获取一个笔记。 |
| `PUT` | `/api/notes/:id` | JWT | 更新笔记字段。 |
| `DELETE` | `/api/notes/:id` | JWT | 删除一个笔记。 |
| `GET` | `/api/live-updates` | 无 | 前端刷新事件的 SSE 流。 |
| `GET` | `/sse` | 无 | MCP SSE 连接端点。 |
| `POST` | `/messages` | 无 | MCP JSON-RPC 消息端点。 |
| `GET` | `/api/health` | 无 | 健康检查。 |
### 笔记有效载体
创建笔记:
```json
{
"title": "会议笔记",
"content": "讨论启动计划",
"tags": ["工作", "计划"]
}
```
更新笔记:
```json
{
"title": "更新的标题",
"content": "更新的内容",
"tags": ["更新"]
}
```
## MCP 工具
MCP 服务器向 AI 客户端公开这些工具:
| 工具 | 描述 |
|------|-------------|
| `list_notes` | 列出带有可选搜索查询、`limit` 和 `offset` 的笔记。 |
| `read_note` | 通过 ID 读取单个笔记。 |
| `create_note` | 创建带有标题、内容和可选标签的笔记。 |
| `update_note` | 更新现有笔记的选定字段。 |
| `delete_note` | 通过 ID 删除笔记。 |
REST 和 MCP 变更都发出笔记更新事件,以便连接的前端可以通过 SSE 刷新。
## 代理用法
交互模式:
```bash
npm run dev:agent
```
直接 Python 调用:
```bash
agent/.venv/bin/python agent/agent.py --transport sse --url http://localhost:3000/sse
```
一次性模式:
```bash
agent/.venv/bin/python agent/agent.py --one-shot "List my notes about planning"
```
输出格式:
```bash
# 脚本友好文本,--one-shot 的默认格式
agent/.venv/bin/python agent/agent.py --one-shot "List my notes" --format plain
# 富 Markdown、工具状态和笔记表格
agent/.venv/bin/python agent/agent.py --one-shot "List my notes" --format pretty
# 脚本和集成的 JSON 对象
agent/.venv/bin/python agent/agent.py --one-shot "List my notes" --format json
```
交互模式默认使用丰富的终端渲染器。它支持持久的命令历史记录、斜线命令的补全和多行提示:按 `Esc` 然后 `Enter` 插入换行符,按 `Enter` 提交。同一运行进程中的提示共享对话上下文,包括相关的工具调用和结果。使用 `/reset` 忘记模型上下文,或使用 `/history` 检查有界摘要。当上下文超过内存预算时,会在完整的回合边界自动修剪;当进程退出时,上下文会丢失。使用 `/help` 查看可用命令。
注意 ID 是完整的 UUID。对于删除、更新或读取请求,您可以用标题标识笔记,而不是复制 ID:代理将使用 `list_notes` 搜索并使用该结果的精确 ID。从手动复制的表格值中永远不要使用缩短的 ID。
选项:
```text
--transport sse|stdio 传输协议(默认:sse)
--url URL MCP 服务器 URL(默认:http://localhost:3000/sse)
--model MODEL Gemini 模型(默认:gemini-2.5-flash)
--api-key KEY Gemini API 密钥;优先使用 agent/.env 中的 GEMINI_API_KEY
--one-shot QUERY 单次查询模式
--format FORMAT 输出格式:plain、pretty 或 json
--verbose 显示连接、回合和工具结果的详细信息
--no-color 在 pretty 输出中禁用 ANSI 颜色
--history-file PATH 重写交互式提示历史记录路径
--memory-max-chars N 近似的最大模型上下文大小(默认:24000)
```
交互式命令:
```text
/help 显示命令帮助
/tools 列出可用的 MCP 工具
/clear 清除终端
/reset 忘记当前的模型对话
/history 显示模型对话内存的摘要
/format [FORMAT] 查看或设置纯文本、精美文本或 JSON 输出
/model [MODEL] 查看或设置未来的提示的 Gemini 模型
/verbose [on|off] 查看或设置详细日志记录
/quit 退出代理
```
## 前端笔记
- Vite 开发服务器在 `http://localhost:5173` 上运行,并将 API 调用代理到后端。
- 应用默认使用开发 API 密钥登录,用于本地使用。
- 笔记操作使用 React Query,并在变异后使 `['notes']` 无效。
- `useSSE` 监听后端更新事件,并实时刷新笔记查询。
## 验证
应用更改前的推荐检查:
```bash
npm run build
npm run test --prefix client-ui
npm run test:e2e --prefix client-ui
```
针对定向更改:
```bash
npm run build --prefix server
npm run build --prefix client-ui
```
## 故障排除
### 服务器启动时出现环境错误
检查 `server/.env`。`JWT_SECRET` 必须至少 32 个字符,`AUTH_TOKEN` 必须设置。
### 前端无法加载笔记
确保后端在 `http://localhost:3000` 上运行,前端通过 Vite 运行,并且 `CORS_ORIGIN` 与 `http://localhost:5173` 匹配。
### 代理询问 Gemini 密钥
创建 `agent/.env` 并设置 `GEMINI_API_KEY=...`,或为一次性运行传递 `--api-key`。
### 代理无法连接到 MCP
首先启动后端并验证 `http://localhost:3000/api/health` 返回 `{"status":"ok",...}`。默认 MCP 端点是 `http://localhost:3000/sse`。
## 开发登录
默认本地 API 密钥:
```text
dev-auth-token-change-in-production
```
在非本地环境中,请在 `server/.env` 中更改此设置。