Metadata-Version: 2.5
Name: room-stu-fault-mcp
Version: 0.1.3
Summary: 教室故障排查 MCP：教室日志、网络信息、教室工单、千问诊断
Author: room-stu-fault
License: MIT
Keywords: aliyun,bailian,classroom,mcp
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.10
Requires-Dist: aliyun-log-python-sdk>=0.9.0
Requires-Dist: cryptography<44,>=42
Requires-Dist: fastmcp==2.8.0
Requires-Dist: httpx>=0.27.0
Requires-Dist: pydantic==2.11.3
Requires-Dist: python-dotenv>=1.0.0
Description-Content-Type: text/markdown

# room-stu-fault-mcp

教室故障排查 MCP 服务，面向阿里云百炼 **uvx / PyPI** 部署。

提供四个工具（业务逻辑在 `src/room_stu_fault_mcp/tools/`）：

| 工具 | 说明 | 填充位置 |
| --- | --- | --- |
| `query_classroom_logs` | 阿里云教室日志（SLS SDK） | `tools/classroom_logs.py` → `fetch_classroom_logs` |
| `get_room_network_info` | 自有服务器 Mongo 网络信息（HTTP） | `tools/network_info.py` → `fetch_room_network_info` |
| `get_classroom_tickets` | 教室工单信息（HTTP） | `tools/tickets.py` → `fetch_classroom_tickets` |
| `diagnose_classroom_fault` | 按问题描述（`description`）结合日志和上下行网络做千问诊断（不拉工单；查工单用 `get_classroom_tickets`） | `tools/diagnose.py` → `diagnose_classroom_fault` |

未接好真实接口时，工具会返回模拟数据，便于本地和百炼联调。

## 本地开发

需要 **Python 3.10+**（本机默认 `python3` 若是 3.9，不要用它建 venv）。推荐用 uv：

```bash
uv python install 3.12
uv venv --python 3.12
source .venv/bin/activate
uv pip install -e .
cp .env.example .env   # 按需填写
```

或指定解释器：

```bash
/path/to/python3.12 -m venv .venv
source .venv/bin/activate
pip install -U pip
pip install -e .
```

本地以 stdio 启动：

```bash
room-stu-fault-mcp
# 或
python -m room_stu_fault_mcp
# 或
fastmcp run src/room_stu_fault_mcp/server.py:mcp
```

## 怎么调用测试

stdio 服务本身不会打印结果，要用 Client 去调工具。

**1. FastMCP 内存调用（推荐，最快）**

```bash
source .venv/bin/activate
python examples/call_tools.py
```

等价手写：

```python
import asyncio
from fastmcp import Client
from room_stu_fault_mcp.server import mcp

async def main():
    async with Client(mcp) as client:
        print(await client.list_tools())
        print(await client.call_tool("query_classroom_logs", {"serial": "R101", "userid": "414325797", "sdkversion": "5.1.0", "osversion": "ios"}))
        print(await client.call_tool("get_room_network_info", {
            "company_id": 10097,
            "serial": "1000292304",
            "room_unit_id": 575718,
            "userid": "379180147",
            "receive_userid": "1b3e2441-b89d-2ef9-fa97-431d101daa51",
        }))
        print(await client.call_tool("get_classroom_tickets", {
            "company_id": 120554,
            "serial": "1248513074",
            "userid": "379180147",
            "starttime": 1788364800,
            "endtime": 1788451200,
        }))
        print(await client.call_tool("diagnose_classroom_fault", {
            "company_id": 120554,
            "serial": "120554",
            "userid": "379180147",
            "room_unit_id": 575718,
            "receive_userid": "1b3e2441-b89d-2ef9-fa97-431d101daa51",
            "sdkversion": "5.1.0",
            "osversion": "ios",
            "starttime": 1788364800,
            "endtime": 1788451200,
            "description": "看不到老师画面",
        }))

asyncio.run(main())
```

**2. 只测业务方法（不经过 MCP）**

```bash
python -c "from room_stu_fault_mcp.tools.classroom_logs import fetch_classroom_logs; print(fetch_classroom_logs('R101', '414325797', '5.1.0', 'ios'))"
python -c "from room_stu_fault_mcp.tools.network_info import fetch_room_network_info; print(fetch_room_network_info(10097, '1000292304', 575718, '379180147', '1b3e2441-b89d-2ef9-fa97-431d101daa51'))"
python -c "from room_stu_fault_mcp.tools.tickets import fetch_classroom_tickets; print(fetch_classroom_tickets(120554, '1248513074', '379180147', 1788364800, 1788451200))"
python -c "from room_stu_fault_mcp.tools.diagnose import diagnose_classroom_fault; print(diagnose_classroom_fault(120554, '120554', '379180147', 575718, '1b3e2441-b89d-2ef9-fa97-431d101daa51', '5.1.0', 'ios', description='看不到老师画面')['diagnosis'])"
```

**3. MCP Inspector 可视化调试**

```bash
fastmcp dev src/room_stu_fault_mcp/server.py:mcp
```

浏览器打开后，在 Tools 里点工具即可。综合诊断用 `diagnose_classroom_fault`，需配置 `DASHSCOPE_API_KEY`。

Cursor / Claude Desktop 本地调试配置：

```json
{
  "mcpServers": {
    "room-stu-fault": {
      "command": "uvx",
      "args": ["--from", ".", "room-stu-fault-mcp"],
      "env": {
        "ALIBABA_CLOUD_ACCESS_KEY_ID": "",
        "ALIBABA_CLOUD_ACCESS_KEY_SECRET": "",
        "ALIYUN_SLS_ENDPOINT": "cn-beijing.log.aliyuncs.com",
        "ALIYUN_SLS_PROJECT": "tk-client-log",
        "ALIYUN_SLS_TOPIC_ALL_CLIENTS": "log-all-clients",
        "ALIYUN_SLS_TOPIC_IOS": "log-ios",
        "ALIYUN_SLS_TOPIC_ANDROID": "log-androidstore",
        "ALIYUN_SLS_TOPIC_JS": "log-js",
        "NETWORK_API_URL": "https://testing-dash-api.talk-cloud.com",
        "NETWORK_API_PATH": "/room/{serial}/user/figure",
        "NETWORK_API_TOKEN": "",
        "TICKET_API_URL": "https://testing.talk-cloud.net",
        "TICKET_API_PATH": "/ClientAPI/workOrderListByAI",
        "TICKET_API_TOKEN": "",
        "DASHSCOPE_API_KEY": "",
        "QWEN_MODEL": "qwen3.8-max",
        "QWEN_API_BASE": "https://dashscope.aliyuncs.com/compatible-mode/v1"
      }
    }
  }
}
```

## 发布到 PyPI

包名必须全局唯一。发布前把 `pyproject.toml` 里的 `name` / `version` 改成你的。

不要用系统自带的 `pip`（本机默认常是 Python 3.9，会和 botocore / selenium 抢 `urllib3`）。用项目虚拟环境或 uv：

```bash
source .venv/bin/activate
uv pip install build twine
python -m build
python -m twine upload dist/*
```

更省事：

```bash
uv build
uv publish --token pypi-xxxxxxxx
```

## 部署到阿里云百炼

1. 控制台 → **MCP 管理** → **创建 MCP 服务** → **使用脚本部署**
2. 安装方式选 **uvx**
3. 配置粘贴如下（把包名换成你发布到 PyPI 的名字）：

```json
{
  "mcpServers": {
    "room-stu-fault": {
      "type": "stdio",
      "timeout": 600,
      "command": "uvx",
      "args": [
        "--python",
        "3.12",
        "--default-index",
        "https://pypi.org/simple",
        "--from",
        "room-stu-fault-mcp==0.1.1",
        "room-stu-fault-mcp"
      ],
      "env": {
        "ALIBABA_CLOUD_ACCESS_KEY_ID": "你的 AccessKey ID",
        "ALIBABA_CLOUD_ACCESS_KEY_SECRET": "你的 AccessKey Secret",
        "ALIYUN_SLS_ENDPOINT": "cn-beijing.log.aliyuncs.com",
        "ALIYUN_SLS_PROJECT": "tk-client-log",
        "ALIYUN_SLS_TOPIC_ALL_CLIENTS": "log-all-clients",
        "ALIYUN_SLS_TOPIC_IOS": "log-ios",
        "ALIYUN_SLS_TOPIC_ANDROID": "log-androidstore",
        "ALIYUN_SLS_TOPIC_JS": "log-js",
        "NETWORK_API_URL": "https://testing-dash-api.talk-cloud.com",
        "NETWORK_API_PATH": "/room/{serial}/user/figure",
        "NETWORK_API_TOKEN": "",
        "TICKET_API_URL": "https://testing.talk-cloud.net",
        "TICKET_API_PATH": "/ClientAPI/workOrderListByAI",
        "TICKET_API_TOKEN": "",
        "DASHSCOPE_API_KEY": "你的百炼 API Key",
        "QWEN_MODEL": "qwen3.8-max",
        "QWEN_API_BASE": "https://dashscope.aliyuncs.com/compatible-mode/v1"
      }
    }
  }
}
```

4. 部署方式选 **极速模式**（不要用按次计费的基础模式）。uvx 首次拉包很慢，基础模式实例很容易被回收，随后就会 503。
5. 部署成功后，在智能体 / 工作流里勾选该 MCP。日常排查可调 `diagnose_classroom_fault`（按 `description` 结合日志和上下行诊断；查工单用 `get_classroom_tickets`）。

若出现 `503 No active SSE connection for session`：先重试 2～3 次；仍失败则到函数计算 FC 打开日志服务看 uvx 是否启动失败，然后停掉服务、改成极速模式并加上 `"timeout": 600` 后重新部署。

## 环境变量

| 变量 | 用途 |
| --- | --- |
| `ALIBABA_CLOUD_ACCESS_KEY_ID` | 阿里云 AK |
| `ALIBABA_CLOUD_ACCESS_KEY_SECRET` | 阿里云 SK |
| `ALIYUN_SLS_ENDPOINT` | SLS 地域入口 |
| `ALIYUN_SLS_PROJECT` | SLS Project |
| `ALIYUN_SLS_TOPIC_ALL_CLIENTS` | SDK >= 5 使用的日志库 topic，默认 `log-all-clients` |
| `ALIYUN_SLS_TOPIC_IOS` | SDK < 5 且 iOS 的日志库 topic，默认 `log-ios` |
| `ALIYUN_SLS_TOPIC_ANDROID` | SDK < 5 且 Android 的日志库 topic，默认 `log-androidstore` |
| `ALIYUN_SLS_TOPIC_JS` | SDK < 5 且其他端的日志库 topic，默认 `log-js` |
| `NETWORK_API_URL` | 网络信息服务地址 |
| `NETWORK_API_PATH` | 网络信息接口路径，可用 `{serial}` / `{room_unit_id}` 占位 |
| `NETWORK_API_TOKEN` | 网络信息接口 Token（可选） |
| `TICKET_API_URL` | 工单服务地址，如 `https://testing.talk-cloud.net` |
| `TICKET_API_PATH` | 工单接口路径，如 `/ClientAPI/workOrderListByAI` |
| `TICKET_API_TOKEN` | 工单接口 Token（可选） |
| `DASHSCOPE_API_KEY` | 百炼 / DashScope API Key，诊断工具调用千问时必填 |
| `QWEN_MODEL` | 千问模型名，默认 `qwen3.8-max` |
| `QWEN_API_BASE` | 兼容模式地址，默认 `https://dashscope.aliyuncs.com/compatible-mode/v1` |
