User MCP Server
README.md
# User MCP Servers
Streamable HTTP MCP Server:通过 HTTP 调用独立的 User REST API([`my-user-service`](../my-user-service)),覆盖 MCP 三要素(Tools / Resources / Prompts)。
本仓库 **不包含** FastAPI / SQLite / JWT 实现。MCP 只依赖 `API_BASE_URL`。
## 架构
```
┌──────────────────────┐ HTTP /mcp ┌──────────────────────┐
│ MCP Client │ ──────────────────────────▶ │ MCP Server :3001 │
│ (Cursor / Inspect) │ │ Streamable HTTP │
└──────────────────────┘ └──────────┬───────────┘
│ httpx
▼
┌──────────────────────┐
│ User REST API :8000 │
│ (my-user-service) │
└──────────────────────┘
```
## 快速开始
先启动 API(另一个仓库):
```bash
cd /Users/jasqia/00D_PythonProject/my-user-service
source .venv/bin/activate
uvicorn app.main:app --host 127.0.0.1 --port 8000 --reload
```
再启动 MCP:
```bash
cd /Users/jasqia/00D_PythonProject/my-mcp-servers
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env # 可选;默认 API_BASE_URL=http://127.0.0.1:8000
python -m mcp_server
```
或一条命令拉起两边(API 目录默认同级的 `../my-user-service`):
```bash
./scripts/start_services.sh
# 自定义 API 仓库路径:
# USER_SERVICE_ROOT=/path/to/my-user-service ./scripts/start_services.sh
```
- MCP 端点:http://127.0.0.1:3001/mcp
- REST 文档:http://127.0.0.1:8000/docs
### 端口被占用(`Address already in use`)
启动时如果看到:
```text
ERROR: [Errno 48] error while attempting to bind on address ('127.0.0.1', 3001): [errno 48] address already in use
```
说明 `3001` 已被占用(拆仓后常见原因:旧仓库 `my-mcp` 里残留的 `python -m mcp_server` 还在跑)。
1. 查出占用进程:
```bash
lsof -nP -iTCP:3001 -sTCP:LISTEN
```
输出里的 `PID` 就是占用端口的进程号,例如:
```text
COMMAND PID USER FD TYPE ...
Python 83386 jasqia ... TCP 127.0.0.1:3001 (LISTEN)
```
2. 确认是哪个项目(可选):
```bash
ps -p <PID> -o pid,command=
```
3. 停掉该进程后重试启动:
```bash
kill <PID>
# 若未退出:kill -9 <PID>
python -m mcp_server
```
4. 确认端口已空闲:
```bash
lsof -nP -iTCP:3001 -sTCP:LISTEN || echo "port 3001 is free"
```
如果不想停旧进程,也可以换端口:
```bash
MCP_PORT=3002 python -m mcp_server
```
Cursor / Inspect 需改连 `http://127.0.0.1:3002/mcp`。API `:8000` 被占用时,处理方式见 [`my-user-service` README](../my-user-service/README.md)。
## MCP 三要素
### Tools
**用户**
- `register_user` / `login_user` / `get_current_user` / `update_user_profile`
**账单**
- `create_bill` / `list_my_bills` / `list_shared_bills` / `get_bill`
- `update_bill` / `delete_bill`
- `share_bill` / `unshare_bill`
- `like_bill` / `unlike_bill`
### Resources
- `user://api/health` — API 健康检查
- `user://docs/overview` — 项目说明
- `user://profile/{access_token}` — 当前用户资料
- `bill://mine/{access_token}` — 我的账单列表
- `bill://shared/{access_token}` — 分享给我的账单
- `bill://item/{access_token}/{bill_id}` — 单条账单
### Prompts
- `welcome_new_user` — 欢迎新用户
- `help_update_profile` — 协助更新资料
- `help_create_bill` — 协助记账
- `help_share_bill` — 协助分享账单
- `help_like_bill` — 协助点赞
## Cursor 连接(Streamable HTTP)
```json
{
"mcpServers": {
"user-mcp": {
"url": "http://127.0.0.1:3001/mcp"
}
}
}
```
## 本地验证
```bash
source .venv/bin/activate
pip install -r requirements-dev.txt # 首次需要
# 单元 / 协议测试(不需要先起 API)
make test
# make test-e2e # L4 真 Streamable HTTP
# 手工 E2E 冒烟(需 API + MCP 都已启动)
python scripts/test_mcp_user_client.py
python scripts/test_mcp_bill_client.py
```
测试分层说明:`docs/MCP_L2_L4_EXPLAINED.zh.md`
## Inspect 评测
先启动 API + MCP,再:
```bash
pip install -r requirements-inspect.txt
export GOOGLE_API_KEY='...'
./scripts/run_inspect_gemini.sh google/gemini-3.6-flash evals/bill_mcp_scenarios.py
./scripts/run_inspect_gemini.sh google/gemini-3.6-flash suite
# 无 API Key:用 mockllm 本地验证 Inspect→MCP 接线
python scripts/run_inspect_user_mcp_smoke_mock.py
```
说明见 [docs/INSPECT_MCP.zh.md](docs/INSPECT_MCP.zh.md)。
## 目录结构
```
my-mcp-servers/
├── mcp_server/ # Streamable HTTP MCP Server
│ ├── config.py # MCP_HOST / MCP_PORT / API_BASE_URL
│ ├── __main__.py # python -m mcp_server
│ └── server.py # Tools / Resources / Prompts
├── tests/mcp/
├── evals/ # Inspect 评测
├── scripts/
├── docs/
├── Makefile
├── pytest.ini
├── requirements.txt
└── README.md
```
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues