内容
# CMR 客户端健康状况 — MCP 服务器
[](https://www.python.org/downloads/)
[](LICENSE)
> 一个 MCP 服务器,为客户成功团队提供即时、自然语言的健康状况评估,适用于任何客户账户 — 以 Rustici 内容控制器的报告层为模型。
在任何 MCP 客户端(今天的 Claude Desktop,明天的 Slack 机器人)中,提出类似 *"BioPharma Inc. 在续期前表现如何?"* 的问题,即可获得表现不佳的课程、内容是否最新以及他们如何接收内容的信息 — 无需任何人手动拉取和阅读报告。
---
## 问题
CMR Institute 制作了由 SME 审核的生命科学培训,并通过 **Rustici 内容控制器** 将其分发给制药/医疗器械客户。 大约 **40% 的客户没有自己的 LMS** — 他们通过内容控制器 **Launcher** 链接消费内容。 对于这些账户,**CMR 是唯一可以看到学习者参与度的 party**。
该参与度数据存在于需要手动拉取和阅读的报告中。 续期风险 — 没有人完成的课程,合规内容已经过时 — 隐藏在这些数据中,直到续期对话。 该服务器以对话方式显示这些信息。
## 功能
三个工具,可从任何 MCP 客户端以自然语言访问:
| 工具 | 答案 |
|------|---------|
| `get_client_health(account_id)` | "这个客户整体表现如何?" — 每门课程的完成情况、分数、内容新鲜度、交付方式、续期日期,以及计算出的摘要。 |
| `get_lowest_performing_courses(account_id, limit=3)` | "哪里有续期风险?" — 完成情况最差的课程,每个课程都有一个风险备注。 |
| `get_launcher_clients()` | "哪些账户没有 LMS,因此我们是他们的唯一可见性?" — 监控优先级最高的账户。 |
只需构建一次工具;每个 MCP 客户端都可重复使用。
### 超出工具范围 — 完整的 MCP 接口
大多数 MCP 服务器仅限于工具。 这个服务器实现了所有三个 MCP 原语,因为真正的 CSM 工作流程需要的不仅仅是模型触发的动作:
| 原语 | 名称 | 用途 |
|-----------|------|---------------|
| **资源** (应用控制的上下文) | `clients://directory` | 每个账户的只读名录 — ID、名称、交付方式、续期日期、课程数量。 主机应用可以提前附加它,以便模型在不需要进行工具往返的情况下了解有效的、正确拼写的账户名称。 |
| **提示** (用户可调用的模板) | `renewal_health_briefing(account)` | CSM 的标准续期前审查,包装为可重用的、参数化的模板(它作为命名命令出现在客户端)。 它将所有三个工具编排成一个可重复的游戏,因此团队中的任何人都可以按名称运行整个简介,而不是记住问题序列。 |
- **工具** 由模型控制 — LLM 决定何时调用它们。
- **资源** 由应用控制 — 只读上下文由主机附加。
- **提示** 由用户控制 — 命名模板由人员触发。
## 架构
```
┌─────────────────────┐ stdio ┌──────────────────┐ ┌────────────────────────────┐
│ MCP 客户端 │ <───────> │ FastMCP 服务器 │ <────> │ 模拟数据 │
│ (Claude Desktop) │ (JSON-RPC │ (server.py) │ │ (模型内容 │
│ │ 子进程)│ 3 个工具 │ │ 控制器 │
│ │ │ + 1 个资源 │ │ 使用/学习者历史记录) │
│ │ │ + 1 个提示 │ │ │
└─────────────────────┘ └──────────────────┘ └────────────────────────────┘
```
模拟数据查找是 **唯一** 虚假的部分。 用真正的 Content Controller 集成替换它意味着更改 **每个工具的一个函数体** — 用身份验证的自动化 API 调用替换 JSON 查找。 工具契约(名称、参数、文档字符串 — LLM 看到的和推理的部分)保持 **不变**,因此下游没有任何变化。
## 解析后的注释
这是 **报告/分析** 层。 它位于 SCORM/xAPI 解析 **下游**。 从原始内容包中提取结构化课程数据是一个单独的、困难的问题,由 **Rustici 生成器** 解决;该服务器使用已经结构化的、解析后的报告数据。 它故意不对 SCORM 本身做出任何声明。
## 数据中什么是真实的,什么是建模的
可信度赢在 **命名边界**,而不是模糊它:
- **真实** (来自 Rustici 内容控制器 v4.1 版本说明):端点 **名称** (`usage/LearnerHistory`、`usage/RegistrationHistory`、`usage/InteractionHistory`),**字符串 ID** 约定,以及 **CourseVersion** 概念。
- **建模/近似**:`data/mock_data.json` 的确切 **字段形状**。 它是实时响应的合理近似,而不是经过验证的副本。 在生产中,这些字段将根据实际的自动化 API 输出进行映射。
---
## 设置
需要 Python 3.10+ 和 [`uv`](https://docs.astral.sh/uv/) (如果没有 `uv`,则回退到 `pip`)。
```bash
# 从项目目录
uv run server.py # 在 stdio 上启动服务器(Ctrl-C 停止)
uv run test_local.py # 运行所有三个工具的本地烟雾测试
```
> 没有 `uv`?安装 `pip install "fastmcp>=3.4,<4"` 然后运行 `python server.py`。
### 安装到 Claude Desktop
**主要(推荐)— 让 FastMCP 编写配置。** 风险最低;请首先尝试此方法。
它会自动检测 Claude Desktop 配置位置并写入条目(期望 Claude Desktop 在其默认安装位置):
```bash
fastmcp install claude-desktop server.py
```
**备用 — 手动配置。** 如果 CLI 无法找到配置或 Claude Desktop 安装在非标准位置,请使用此方法。 编辑此存储库中的 `claude_desktop_config.json`,用您的 **绝对** 项目路径替换路径,并将其粘贴到 Claude Desktop 的配置文件中。 `--with fastmcp` 标志隔离依赖项,以免全局安装缺失导致启动失败:
```json
{
"mcpServers": {
"cmr-client-health": {
"command": "uv",
"args": ["run", "--with", "fastmcp", "--directory",
"/ABSOLUTE/PATH/TO/cmr-client-health-mcp", "fastmcp", "run", "server.py"]
}
}
}
```
Claude Desktop 的配置文件位于:
- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
可能导致静默破坏的隐患:
- `--directory` 路径 **必须绝对** — 相对路径在 Claude Desktop 中失败。
- **验证 JSON** — 单个尾随逗号会静默破坏整个配置。
- **完全退出并重新打开** Claude Desktop — 关闭窗口是不够的;配置文件仅在冷启动时读取。
- 在依赖服务器之前,请通过 **开发者** 选项卡/工具(🔌)图标验证服务器是否出现。
## 演示提示
在连接服务器后,将以下内容粘贴到 Claude Desktop 中:
> "BioPharma Inc. 的续期即将到来。 给我一个健康检查 — 哪些课程表现不佳,他们的内容是否最新,以及他们是在 Launcher 还是自己的 LMS 上? 然后起草一个简短的检查笔记,您可以将其发送给他们的客户成功经理。"
Claude 将调用 `get_client_health` 和 `get_lowest_performing_courses`,查看两个已播种的问题课程(一个完成率约为 38% 的药监课程和一个过时的 GxP 合规课程),注明 BioPharma 位于 **Launcher** (因此 CMR 是他们的唯一可见性),并起草笔记。
## 路线图/ "生产中"
- **用实时自动化 API 替换模拟数据** — 用身份验证的(Bearer-token)Content Controller 调用替换每个工具的数据查找;工具契约保持不变。
- **`get_content_freshness`** — 跨 **所有** 客户端(而不仅仅是一个)查看新鲜度。
- **可流式 HTTP 传输 + 身份验证** — 这样共享的团队 Slack 机器人可以点击一个服务器,而不是每个 CSM 运行一个本地副本。
- **分层 Rustici 生成器的解析 JSON** — 在参与度报告之上进行内容级问答。
## 免责声明
使用 **模拟数据** 建模以镜像内容控制器的报告模式。 它与任何实时 CMR Institute 或 Rustici 系统 **无关**,也不暴露任何真实的客户数据。