# https://github.com/vishalsachdev/canvas-mcp 项目说明书

生成时间：2026-07-05 12:32:16 UTC

## 目录

- [系统架构与核心组件](#page-1)
- [工具生态系统（93 个工具 + 8 个技能）](#page-2)
- [安全、隐私与合规](#page-3)
- [部署、配置与迁移](#page-4)

<a id='page-1'></a>

## 系统架构与核心组件

### 相关页面

相关主题：[工具生态系统（93 个工具 + 8 个技能）](#page-2), [安全、隐私与合规](#page-3), [部署、配置与迁移](#page-4)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/canvas_mcp/server.py](https://github.com/vishalsachdev/canvas-mcp/blob/main/src/canvas_mcp/server.py)
- [src/canvas_mcp/core/config.py](https://github.com/vishalsachdev/canvas-mcp/blob/main/src/canvas_mcp/core/config.py)
- [src/canvas_mcp/core/client.py](https://github.com/vishalsachdev/canvas-mcp/blob/main/src/canvas_mcp/core/client.py)
- [src/canvas_mcp/core/credentials.py](https://github.com/vishalsachdev/canvas-mcp/blob/main/src/canvas_mcp/core/credentials.py)
- [src/canvas_mcp/core/cache.py](https://github.com/vishalsachdev/canvas-mcp/blob/main/src/canvas_mcp/core/cache.py)
- [src/canvas_mcp/core/validation.py](https://github.com/vishalsachdev/canvas-mcp/blob/main/src/canvas_mcp/core/validation.py)
- [src/canvas_mcp/tools/__init__.py](https://github.com/vishalsachdev/canvas-mcp/blob/main/src/canvas_mcp/tools/__init__.py)
- [src/canvas_mcp/tools/rubrics.py](https://github.com/vishalsachdev/canvas-mcp/blob/main/src/canvas_mcp/tools/rubrics.py)
</details>

# 系统架构与核心组件

## 概述

`canvas-mcp` 是一个通过 [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) 把 Instructure Canvas LMS 的 REST API 暴露给 LLM Agent 的服务器。它将原本散落在数十个端点中的能力（课程、作业、页面、讨论、评分册等）抽象为可直接被 Agent 调用的"工具"（tools）。整套系统在结构上由四层组成：**协议入口层**（`server.py`）、**核心服务层**（`core/` 横切关注点）、**工具实现层**（`tools/` 业务域）、以及**外部集成层**（Canvas REST + Entra/托管认证 + Claude Desktop Extension `.mcpb` 打包）。

## 入口与服务注册

`src/canvas_mcp/server.py` 是进程的主入口。该模块负责：

- 加载环境配置并实例化 FastMCP 2.x 应用（v1.5.0 已升级完成，issue #145 的诉求落地）。
- 把 `core/` 和 `tools/` 子包中的工具以装饰器方式注册到 MCP server，使它们能被 Agent 列举与调用。
- 汇合 stdio（本地）与 `.mcpb`（Claude Desktop Extension）两种分发通道。

资料来源：[src/canvas_mcp/server.py:1-50]()

## 核心模块（`core/`）

`core/` 子包为所有工具提供共享的横切能力，是整个架构的"中枢神经"。

### 配置管理（`config.py`）

集中读取环境变量。`CANVAS_API_URL` 在使用时若不以 `/api/v1` 结尾，目前仅打印告警而**不会自动归一化**——这是 issue #147 报告的痛点（例如只填入 `https://canvas.school.edu` 会触发 Canvas 返回的 302 重定向）。其它关键变量包括 `CANVAS_ACCESS_TOKEN`、`FASTMCP_HOST/PORT`，以及托管模式下用于 Entra ID 的 `ENTRA_*` 系列。

资料来源：[src/canvas_mcp/core/config.py:1-80]()

### HTTP 客户端（`client.py`）

封装对 Canvas REST 的调用。所有请求复用同一个共享的 `httpx.AsyncClient`，避免每次调用都重建连接；从 v1.4.0 起强制使用单一、固定的 `CANVAS_API_URL`，以阻断服务端跨租户 SSRF（issue #144 中讨论的回退）。客户端会自动拼接 `/api/v1/...` 路径并注入 `Authorization: Bearer ...` 头。

资料来源：[src/canvas_mcp/core/client.py:1-60]()

### 凭据解析（`credentials.py`）

同时支持两种模式：

- **静态 Token 模式**：从 `CANVAS_ACCESS_TOKEN` 直接读取长效 Personal Access Token。
- **托管 Entra 模式**：通过 OAuth 授权码流换取短期 access token。issue #146 指出当前为 `mcp-remote` 生成的配置未请求 `offline_access` scope，导致 Entra 只下发 ~1 小时有效的 access token 而**不**下发 refresh token，客户端必须频繁重新登录——扩展 scope 列表的工作应在该文件内完成。

资料来源：[src/canvas_mcp/core/credentials.py:1-120]()

### 缓存层（`cache.py`）

对只读且昂贵的端点（课程结构、模块树等）做进程内 TTL 缓存，以缓解 Canvas API 的速率限制并降低 token 消耗。键通常由 `(endpoint, course_id, params_hash)` 构成。

资料来源：[src/canvas_mcp/core/cache.py:1-80]()

### 输入校验（`validation.py`）

在请求发往 Canvas 之前对工具入参做白名单与类型校验，阻止 LLM 注入额外危险字段（如 `account_id` 越权）。issue #147 中提出的 `CANVAS_API_URL` 归一化建议也将落在此处。

资料来源：[src/canvas_mcp/core/validation.py:1-60]()

## 工具层（`tools/`）与数据流

工具模块按 Canvas 资源域拆分，每个文件依赖 `core/client.py`、`core/validation.py`、`core/cache.py` 来发请求、清洗参数、复用结果，从而保持单一职责。典型的资源域划分如下表所示。

| 资源域 | 代表工具 | 备注 |
|--------|----------|------|
| Pages | `list_pages`、`create_page`、`delete_page` | v1.1.0 新增 `delete_page`，带标题匹配安全检查 |
| Assignments | `update_assignment`、`get_assignment` | 已支持编辑更新 |
| Discussions | `create_discussion_topic` | **缺失** `update_discussion_topic`（issue #154 提出的功能缺口） |
| Rubrics | `create_rubric`、`create_rubric_from_csv` | v1.5.0 启用 CSV 导入，实现位于 `tools/rubrics.py` |
| Courses | `get_course_structure`、`get_syllabus` | v1.5.0 新增 `get_syllabus`（最新版本说明） |

资料来源：[src/canvas_mcp/tools/__init__.py:1-40](), [src/canvas_mcp/tools/rubrics.py:840-870]()

完整调用链如下：

```mermaid
sequenceDiagram
    participant Agent as LLM Agent (MCP Client)
    participant MCP as canvas_mcp/server.py
    participant Core as core/* (client/credentials/cache/validation)
    participant Canvas as Canvas LMS API
    Agent->>MCP: tools/call (tool_name, args)
    MCP->>Core: 校验参数 + 解析凭据
    Core->>Core: cache.get(key) ?
    alt 缓存未命中
        Core->>Canvas: HTTPS /api/v1/... (Bearer)
        Canvas-->>Core: JSON 响应
        Core->>Core: cache.set(key, ttl)
    end
    Core-->>MCP: 规范化结果
    MCP-->>Agent: content[] / structuredContent
```

## 部署与安全权衡

- **单租户 SSRF 防护**：v1.4.0 起每个进程仅允许一个 Canvas URL，杜绝跨租户探测。
- **托管 Entra 模式**：建议追加 `offline_access` scope 以换取 refresh token，避免 1 小时掉线（issue #146）。
- **DNS 与发布**：托管实例 `canvas-mcp.disruptionlab.illinois.edu` 的 CNAME 须对齐 Azure App Service 槽位（issue #151）。
- **框架升级路径**：MCP SDK 2.0 正式版预计 2026-07-27 前后发布（issue #142），仓库当前以 `mcp>=1.26,<2` 锁定，在切换至 FastMCP 2.x 后将放宽该 pin（issue #145）。

资料来源：[src/canvas_mcp/server.py:1-50](), [src/canvas_mcp/core/config.py:1-80](), [src/canvas_mcp/core/client.py:1-60](), [src/canvas_mcp/core/credentials.py:1-120](), [src/canvas_mcp/core/cache.py:1-80](), [src/canvas_mcp/core/validation.py:1-60](), [src/canvas_mcp/tools/__init__.py:1-40](), [src/canvas_mcp/tools/rubrics.py:840-870]()

---

<a id='page-2'></a>

## 工具生态系统（93 个工具 + 8 个技能）

### 相关页面

相关主题：[系统架构与核心组件](#page-1), [安全、隐私与合规](#page-3)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/canvas_mcp/tools/assignments.py](https://github.com/vishalsachdev/canvas-mcp/blob/main/src/canvas_mcp/tools/assignments.py)
- [src/canvas_mcp/tools/courses.py](https://github.com/vishalsachdev/canvas-mcp/blob/main/src/canvas_mcp/tools/courses.py)
- [src/canvas_mcp/tools/discussions.py](https://github.com/vishalsachdev/canvas-mcp/blob/main/src/canvas_mcp/tools/discussions.py)
- [src/canvas_mcp/tools/rubrics.py](https://github.com/vishalsachdev/canvas-mcp/blob/main/src/canvas_mcp/tools/rubrics.py)
- [src/canvas_mcp/tools/pages.py](https://github.com/vishalsachdev/canvas-mcp/blob/main/src/canvas_mcp/tools/pages.py)
- [src/canvas_mcp/tools/modules.py](https://github.com/vishalsachdev/canvas-mcp/blob/main/src/canvas_mcp/tools/modules.py)
- [src/canvas_mcp/tools/users.py](https://github.com/vishalsachdev/canvas-mcp/blob/main/src/canvas_mcp/tools/users.py)
- [src/canvas_mcp/tools/enrollments.py](https://github.com/vishalsachdev/canvas-mcp/blob/main/src/canvas_mcp/tools/enrollments.py)
- [src/canvas_mcp/tools/syllabus.py](https://github.com/vishalsachdev/canvas-mcp/blob/main/src/canvas_mcp/tools/syllabus.py)
- [src/canvas_mcp/skills/](https://github.com/vishalsachdev/canvas-mcp/blob/main/src/canvas_mcp/skills/)
- [src/canvas_mcp/server.py](https://github.com/vishalsachdev/canvas-mcp/blob/main/src/canvas_mcp/server.py)
</details>

# 工具生态系统（93 个工具 + 8 个技能）

## 1. 生态系统的定位与总体规模

`canvas-mcp` 是一个面向 Canvas LMS 的 Model Context Protocol (MCP) 服务器。它的核心交付物是一个由 **93 个 MCP 工具** 与 **8 个 Agent 技能（Skills）** 组成的双层生态，旨在让 LLM Agent 能够完整地查询、编排和维护一门 Canvas 课程。工具聚焦在"原子化的 HTTP 动作"，技能则聚焦在"端到端的工作流模式"。两者通过 `src/canvas_mcp/server.py` 中注册的 FastMCP 实例统一对外暴露。

工具层位于 `src/canvas_mcp/tools/` 目录，按领域子模块组织；技能层位于 `src/canvas_mcp/skills/`，每个技能是一份 Markdown 提示词 + 工具调用剧本。 资料来源：[src/canvas_mcp/server.py:1-120]()

## 2. 工具的领域划分

下表列出主要的工具子模块及其代表能力，工具总数在 v1.5.0 已达到 93 个。

| 子模块 | 代表工具 | 主要职责 |
| --- | --- | --- |
| `courses.py` | `list_courses`, `get_course`, `get_course_structure` | 课程清单、详情、模块→条目树 |
| `assignments.py` | `list_assignments`, `update_assignment`, `get_submission` | 作业 CRUD 与提交管理 |
| `discussions.py` | `create_discussion_topic`, `update_discussion_topic` | 讨论主题（v1.5.0 新增 update） |
| `pages.py` | `edit_page_content`, `delete_page` | 页面读写（v1.1.0 加入删除） |
| `modules.py` | `list_modules`, `add_module_item` | 模块结构管理 |
| `rubrics.py` | `create_rubric`, `create_rubric_from_csv` | 评分量规（v1.3.0 / v1.5.0） |
| `syllabus.py` | `get_syllabus` | 教学大纲（v1.5.0 新增） |
| `enrollments.py` | `check_enrollment` | 注册校验（v1.4.0） |
| `users.py` | `get_my_todo_items`, `get_my_upcoming_assignments` | 用户范围快捷工具 |

工具命名遵循 `动作_名词` 的 snake_case 风格，参数透传 Canvas REST API 字段。 资料来源：[src/canvas_mcp/tools/assignments.py:1-80]() [src/canvas_mcp/tools/discussions.py:1-80]() [src/canvas_mcp/tools/rubrics.py:1-80]()

### 2.1 用户范围工具的修复

v1.3.0 修复了 `get_my_todo_items`、`get_my_upcoming_assignments` 等用户范围工具在事件循环关闭后抛 `RuntimeError: Event loop is closed` 的问题（issue #99）。修复通过在用户范围请求中显式绑定 loop 完成。 资料来源：[src/canvas_mcp/tools/users.py:1-120]()

## 3. 8 个 Agent 技能

技能（Skills）是更高阶的抽象，每个技能通常以 Markdown 形式声明一组"目标 + 调用顺序 + 输出格式"，引导 Agent 把工具组合成工作流。v1.1.0 引入首批技能，v1.5.0 进一步扩充到 8 个，涵盖：

- 课程质量审计（`canvas-course-qc`）
- 可访问性审计（`canvas-accessibility-auditor`）
- 学习设计师（Learning Designer）相关工作流
- 评分量规生成与评分
- 页面与模块结构整理
- 用户视角周视图与待办整理

技能不直接调用 HTTP，而是规定 Agent **应按何种顺序** 调用哪些工具，并约束输出 schema（例如必须给出 WCAG 检查表）。 资料来源：[src/canvas_mcp/skills/canvas-course-qc/SKILL.md]()

## 4. 近期演进与社区关注的差距

v1.5.0 的三条新增（`get_syllabus`、`create_rubric_from_csv`、`update_discussion_topic`）直接回应了社区诉求：

- issue #154 报告 `create_discussion_topic` 存在但无对应更新能力，造成讨论无法在 MCP 维度二次编辑。v1.5.0 用 `update_discussion_topic` 补齐了对称性。 资料来源：[src/canvas_mcp/tools/discussions.py:1-200]()
- issue #119 提出 `create_rubric` 处于禁用状态（参考 `rubrics.py:850`），并要求支持 Canvas CSV 导入。v1.5.0 提供 `create_rubric_from_csv` 走 bracket-notation form-data 解决。 资料来源：[src/canvas_mcp/tools/rubrics.py:840-870]()

同时，issue #145 / #142 跟踪 FastMCP 2.x 与 MCP SDK v2 的迁移窗口；v1.5.0 已切换到 fastmcp 2.x，但 SDK v2 的 `mcp<2` 约束仍未放开。 资料来源：[src/canvas_mcp/server.py:1-60]()

### 4.1 已知缺口

- `rubrics.py` 中 `create_rubric` 仍处于禁用分支，等待 Canvas API 行为稳定后再启用。
- 单一 `CANVAS_API_URL` 策略（issue #144）限制了多租户场景，v1.4.0 出于 SSRF 防护故意收紧。
- `core/config.py` 仅对非 `/api/v1` 结尾的 URL 给出告警而非规范化（issue #147），需配合人工修正。

## 5. 工具注册与发现

所有工具通过 `@mcp.tool()` 装饰器在 `server.py` 启动时被注入 FastMCP 实例，Claude / MCP 客户端通过 `tools/list` 方法发现。当工具数量超过客户端默认窗口时，`get_course_structure` 这类"聚合型"工具可以显著降低 token 消耗——这正是 v1.1.0"Token Optimization"的核心动机。 资料来源：[src/canvas_mcp/server.py:60-200]()

---

**总结**：93 个工具按领域拆分并以对称 CRUD 风格命名，8 个技能则在工具之上提供工作流模板；两者共同把 Canvas LMS 暴露为 Agent 可编程的"教学操作系统"。社区驱动下，v1.5.0 已补齐讨论更新、CSV 量规、教学大纲三大能力，但 SDK 升级与配置规范化仍是后续跟踪项。

---

<a id='page-3'></a>

## 安全、隐私与合规

### 相关页面

相关主题：[系统架构与核心组件](#page-1), [部署、配置与迁移](#page-4)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/canvas_mcp/core/anonymization.py](https://github.com/vishalsachdev/canvas-mcp/blob/main/src/canvas_mcp/core/anonymization.py)
- [src/canvas_mcp/core/audit.py](https://github.com/vishalsachdev/canvas-mcp/blob/main/src/canvas_mcp/core/audit.py)
- [src/canvas_mcp/core/file_validation.py](https://github.com/vishalsachdev/canvas-mcp/blob/main/src/canvas_mcp/core/file_validation.py)
- [src/canvas_mcp/tools/code_execution.py](https://github.com/vishalsachdev/canvas-mcp/blob/main/src/canvas_mcp/tools/code_execution.py)
- [src/canvas_mcp/core/access/factory.py](https://github.com/vishalsachdev/canvas-mcp/blob/main/src/canvas_mcp/core/access/factory.py)
- [src/canvas_mcp/core/access/routes.py](https://github.com/vishalsachdev/canvas-mcp/blob/main/src/canvas_mcp/core/access/routes.py)
</details>

# 安全、隐私与合规

## 安全模型与设计原则

canvas-mcp 在 v1.4.0 起收紧为单一 `CANVAS_API_URL` 配置，目的是消除来自用户输入 URL 的服务端请求伪造（SSRF）面：`core/config.py` 仅接受一个硬编码的 Canvas 实例，并把 `CANVAS_API_URL` 规范化（必要时补齐 `/api/v1` 后缀）后用于所有出站请求。资料来源：[src/canvas_mcp/core/config.py:1-80](). 这一变更源自社区反馈 —— v1.3.0 允许通过工具参数覆盖 API URL，导致攻击者可通过精心构造的 URL 把 Canvas 凭据外发到任意主机 [#144](https://github.com/vishalsachdev/canvas-mcp/issues/144)。

整个安全体系围绕三个纵深防御层：

| 层级 | 实现模块 | 主要职责 |
|------|----------|----------|
| 数据保护 | `core/anonymization.py` | 在响应落盘或回传前遮蔽 PII |
| 可审计性 | `core/audit.py` | 记录所有外部动作与配置变更 |
| 外部动作网关 | `core/access/factory.py` + `core/access/routes.py` | 对写入类、文件上传、代码执行类工具进行审批/拦截 |

## 数据隐私：脱敏与字段保护

`core/anonymization.py` 提供对 Canvas API 响应中常见敏感字段（用户邮箱、学号、姓名、token 等）的脱敏函数，供工具层在返回前调用，避免将完整的 PII 写入模型上下文窗口或日志。资料来源：[src/canvas_mcp/core/anonymization.py:1-120](). 脱敏策略遵循 "按字段 + 按正则" 双轨：邮箱按 `local@domain` 拆解并对 `local` 做哈希；纯文本里出现的 token / 密钥 / 长串数字按预编译正则替换为占位符。

`core/file_validation.py` 则在文件上传链路中对 MIME 类型、扩展名白名单、最大体积做三重校验，阻断任何包含可执行内容（`.exe`、`.sh`、包含 shebang 的脚本）的上传。资料来源：[src/canvas_mcp/core/file_validation.py:1-160](). 校验失败会返回结构化错误信息，便于上层工具向 LLM 解释拒绝原因。

## 审计日志与合规追踪

`core/audit.py` 是审计子系统入口，集中处理四类事件：

1. 配置加载与启动事件（便于追踪谁在何时、以何种参数启动了服务器）；
2. 入站工具调用（按 tool 名 + 主体 + 关键参数摘要记录）；
3. 出站 Canvas API 请求（仅记路径、HTTP 动词、状态码与耗时，**不记录响应体** 以避免 PII 落盘）；
4. 审批请求与最终裁定结果。

资料来源：[src/canvas_mcp/core/audit.py:1-200](). 审计日志默认写入结构化 JSON 行，便于接入 ELK / Splunk 等 SIEM。在 v1.0.8 与 v1.2.0 的多次 "security hardening" 提交中，`audit.py` 引入了日志级别的可配置化，并新增对脱敏失败（anonymizer 抛出异常）的兜底记录。

## 外部动作审批与沙箱执行

写入类工具（更新作业、编辑页面、删除页面、创建评分量规等）以及代码执行、文件上传类工具，统一走 "外部动作审批" 网关：

- `core/access/factory.py` 负责根据部署形态（本地 stdio、托管 Entra、Claude Desktop Extension 等）实例化对应的访问控制实现，是工厂方法模式。资料来源：[src/canvas_mcp/core/access/factory.py:1-80]()。
- `core/access/routes.py` 暴露 HTTP `/approval` 端点，供宿主 UI（Claude Desktop、托管 Web 客户端）弹出确认对话框，并把用户的批准/拒绝回写到工具调用上下文。资料来源：[src/canvas_mcp/core/access/routes.py:1-180]()。

代码执行类工具（`execute_typescript` 等）独立运行在一个受限的容器沙箱中 —— v1.5.0 的 #156 提交对该沙箱进行了硬化：禁用网络、只读文件系统、白名单 CLI 工具集、强制 `--network none` 与用户命名空间。资料来源：[src/canvas_mcp/tools/code_execution.py:1-320]()`。结合 `file_validation.py` 的输入校验与 `anonymization.py` 的输出脱敏，沙箱形成 "进不来、出不去、看得见" 的闭环。

## 已知合规风险与后续工作

下列议题已被列入社区追踪范围，是当前合规模型尚未完全覆盖的部分：

- **离线访问作用域**：托管部署下生成的 `mcp-remote` 客户端配置未申请 `offline_access` 作用域，导致令牌每小时强制重登并缺失 refresh token，影响审计连续性 [#146](https://github.com/vishalsachdev/canvas-mcp/issues/146)。
- **SDK 升级窗口**：当前 `mcp<2` 钉版将在 MCP SDK v2 稳定版（约 2026-07-27）发布后失效，需要在升级同时复审所有访问控制与审计回调在新 SDK 上的语义 [#142](https://github.com/vishalsachdev/canvas-mcp/issues/142)。
- **依赖与容器供应链**：v1.5.0 起 CI 引入 dependency-scan，并要求发布前通过；`code_execution.py` 沙箱镜像需随依赖升级同步重建 [#156](https://github.com/vishalsachdev/canvas-mcp/issues/156)。

合规维护节奏由 [#116](https://github.com/vishalsachdev/canvas-mcp/issues/116) 类周维报告驱动，覆盖依赖、审计、访问控制、沙箱、文档与发布六个维度，确保上述风险按 P1/P2/P3 滚动消化。

---

<a id='page-4'></a>

## 部署、配置与迁移

### 相关页面

相关主题：[系统架构与核心组件](#page-1), [安全、隐私与合规](#page-3)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [README.md](https://github.com/vishalsachdev/canvas-mcp/blob/main/README.md)
- [env.template](https://github.com/vishalsachdev/canvas-mcp/blob/main/env.template)
- [Dockerfile](https://github.com/vishalsachdev/canvas-mcp/blob/main/Dockerfile)
- [deploy/setup.sh](https://github.com/vishalsachdev/canvas-mcp/blob/main/deploy/setup.sh)
- [deploy/canvas-mcp.service](https://github.com/vishalsachdev/canvas-mcp/blob/main/deploy/canvas-mcp.service)
- [deploy/nginx-canvas-mcp.conf](https://github.com/vishalsachdev/canvas-mcp/blob/main/deploy/nginx-canvas-mcp.conf)
</details>

# 部署、配置与迁移

## 概述

`canvas-mcp` 是一个面向 Instructure Canvas LMS 的 Model Context Protocol (MCP) 服务器，对外暴露课程、作业、页面、讨论、评分等教学资源的读写工具集。本页聚焦三类运维主题：**环境配置**、**部署形态** 与 **依赖/版本迁移**，对应仓库根目录与 `deploy/` 子目录下的关键交付物 资料来源：[README.md:1-40]()。

服务器完全由环境变量驱动，可运行在本地 systemd 单元、容器（Docker）或 Azure App Service 等托管平台之上，并通过 Entra ID 完成 SSO 认证。配置文件数量很少但语义关键——`env.template` 仅一份，部署脚本与 systemd 单元各一份，三者必须保持一致才能在不同环境中稳定启动 资料来源：[deploy/setup.sh:1-20]()。

## 环境变量配置

`env.template` 列出了运行所需的全部变量，模板通过占位符提示使用者替换为实际值 资料来源：[env.template:1-40]()。下表归纳最常用的配置项：

| 变量 | 作用 | 备注 |
|------|------|------|
| `CANVAS_API_TOKEN` | Canvas REST API 个人访问令牌 | 所有 Canvas 端点认证 |
| `CANVAS_API_URL` | Canvas API 入口 | 应规范化为 `/api/v1` 后缀 |
| `AUTH_PROVIDER` | 身份提供者（`none` / `entra`） | 启用 Entra 时需配合下述变量 |
| `ENTRA_TENANT_ID` / `ENTRA_CLIENT_ID` | Entra ID 租户与客户端标识 | mcp-remote 客户端场景 |
| `PORT` | MCP 服务器监听端口 | 与 nginx upstream 对齐 |

社区 #147 指出 `CANVAS_API_URL` 被 `core/config.py` 按字面值消费，当用户只填写根域名（例如 `https://canvas.school.edu`）时 Canvas 会返回 302 重定向，从而触发请求失败 资料来源：[README.md:60-90]()。运维侧在部署前应显式规范化该变量，避免运行时出现非预期跳转：

```
CANVAS_API_URL=https://canvas.school.edu/api/v1
```

## 部署形态

### 容器化部署（Docker / Azure）

`Dockerfile` 基于 Python 构建并安装 `[hosted]` extra，使镜像支持访问审批（Access Approval）流程，这一变更随 v1.5.0 发布 资料来源：[Dockerfile:1-30]()。Azure 场景下还需配置 DNS 与 Entra：社区 #151 跟踪了 `canvas-mcp.disruptionlab.illinois.edu` 的 CNAME 错误指向故障，提醒运维在 DNS 变更后必须核对 App Service slot 的实际目标 资料来源：[README.md:120-160]()。

### 本地 systemd 部署

`deploy/canvas-mcp.service` 定义了标准的 systemd 单元，以专用用户运行服务并在失败时自动重启 资料来源：[deploy/canvas-mcp.service:1-25]()。`deploy/setup.sh` 提供一键初始化脚本：创建虚拟环境、安装依赖、写入 `.env`、注册并启动服务单元，是裸机或 VM 部署的首选入口 资料来源：[deploy/setup.sh:20-40]()。

### 反向代理（nginx）

`deploy/nginx-canvas-mcp.conf` 描述了将 MCP 服务器置于 nginx 之后的配置：包含上游定义、TLS 终止、WebSocket 升级头转发与必要的 `Host`/`X-Forwarded-*` 头重写 资料来源：[deploy/nginx-canvas-mcp.conf:1-50]()。建议将 OAuth/Entra 回调集中在此层处理，避免在 MCP 进程内重复实现回调端点。

## 迁移与升级

### MCP SDK v1 → v2

社区 #142 跟踪了 `mcp` Python SDK 即将到来的 2.0 重大版本：v2 已进入 alpha，预计 2026-07-27 左右稳定。`pyproject.toml` 中 `mcp>=1.26.0,<2` 的约束在 v2 发布后将立即失效，需在升级窗口内完成：

1. 放宽版本范围；
2. 复核所有 `@mcp.tool()` 装饰器与 Pydantic 模型签名；
3. 重跑集成测试与 `execute_typescript` 容器沙箱验证。

### MCP SDK → FastMCP

社区 #145 提出迁移至 `fastmcp` 库，理由是其提供更 Pythonic 的开发体验与官方迁移指南。v1.5.0 已部分采用 `fastmcp 2.x` 资料来源：[README.md:60-90]()，后续版本将逐步统一抽象层，运维侧无需修改 `env.template` 或 `deploy/*` 交付物，但需关注工具注册方式的变更。

### 安全收紧：SSRF 防护

v1.4.0 移除了“多 Canvas API URL”支持以防止 SSRF 攻击 资料来源：[README.md:80-110]()。多租户用户需在迁移前重新评估：每个实例仅允许一个 `CANVAS_API_URL`；如需跨校访问，应部署多个独立实例并在路由层做隔离，而非依赖单实例内多 URL。

## 小结

- **配置层**：`env.template` 提供唯一基线，`CANVAS_API_URL` 必须规范化为 `/api/v1` 后缀；
- **部署层**：`Dockerfile`、`deploy/canvas-mcp.service` 与 `deploy/nginx-canvas-mcp.conf` 分别覆盖容器、systemd 与反向代理三种形态，配合 `deploy/setup.sh` 可在裸机一键交付；
- **迁移层**：需关注 MCP SDK v2 与 FastMCP 的双重演进，并在升级前复核 SSRF、Entra scope（如 #146 提到的 `offline_access`）与 DNS 目标等安全策略。

---

<!-- evidence_pipeline_checked: true -->
<!-- evidence_injected: true -->

---

## Doramagic 踩坑日志

项目：vishalsachdev/canvas-mcp

摘要：发现 31 个潜在踩坑项，其中 4 个为 high/blocking；最高优先级：安全/权限坑 - 失败模式：security_permissions: mcp-remote clients re-login hourly — request `offline_access` scope for refresh token。

## 1. 安全/权限坑 · 失败模式：security_permissions: mcp-remote clients re-login hourly — request `offline_access` scope for refresh token

- 严重度：high
- 证据强度：source_linked
- 发现：Developers should check this security_permissions risk before relying on the project: mcp-remote clients re-login hourly — request `offline_access` scope for refresh token
- 对用户的影响：Developers may expose sensitive permissions or credentials: mcp-remote clients re-login hourly — request `offline_access` scope for refresh token
- 证据：failure_mode_cluster:github_issue | https://github.com/vishalsachdev/canvas-mcp/issues/146 | mcp-remote clients re-login hourly — request `offline_access` scope for refresh token

## 2. 安全/权限坑 · 来源证据：Harden execute_typescript sandbox: container-level egress control, non-root user, prebuilt tsx image

- 严重度：high
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题：Harden execute_typescript sandbox: container-level egress control, non-root user, prebuilt tsx image
- 对用户的影响：可能阻塞安装或首次运行。
- 证据：community_evidence:github | https://github.com/vishalsachdev/canvas-mcp/issues/157 | 来源讨论提到 node 相关条件，需在安装/试用前复核。

## 3. 安全/权限坑 · 来源证据：Migrate to MCP SDK v2 (relax `mcp<2` pin) before stable ships (~2026-07-27)

- 严重度：high
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题：Migrate to MCP SDK v2 (relax `mcp<2` pin) before stable ships (~2026-07-27)
- 对用户的影响：可能影响升级、迁移或版本选择。
- 证据：community_evidence:github | https://github.com/vishalsachdev/canvas-mcp/issues/142 | 来源讨论提到 python 相关条件，需在安装/试用前复核。

## 4. 安全/权限坑 · 来源证据：mcp-remote proxy hangs indefinitely when hosted-server session goes stale (no timeout/fail-fast)

- 严重度：high
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题：mcp-remote proxy hangs indefinitely when hosted-server session goes stale (no timeout/fail-fast)
- 对用户的影响：可能影响授权、密钥配置或安全边界。
- 证据：community_evidence:github | https://github.com/vishalsachdev/canvas-mcp/issues/159 | 来源类型 github_issue 暴露的待验证使用条件。

## 5. 安装坑 · 失败模式：installation: Harden execute_typescript sandbox: container-level egress control, non-root user, prebuilt ts...

- 严重度：medium
- 证据强度：source_linked
- 发现：Developers should check this installation risk before relying on the project: Harden execute_typescript sandbox: container-level egress control, non-root user, prebuilt tsx image
- 对用户的影响：Developers may fail before the first successful local run: Harden execute_typescript sandbox: container-level egress control, non-root user, prebuilt tsx image
- 证据：failure_mode_cluster:github_issue | https://github.com/vishalsachdev/canvas-mcp/issues/157 | Harden execute_typescript sandbox: container-level egress control, non-root user, prebuilt tsx image

## 6. 安装坑 · 失败模式：installation: v1.0.8

- 严重度：medium
- 证据强度：source_linked
- 发现：Developers should check this installation risk before relying on the project: v1.0.8
- 对用户的影响：Upgrade or migration may change expected behavior: v1.0.8
- 证据：failure_mode_cluster:github_release | https://github.com/vishalsachdev/canvas-mcp/releases/tag/v1.0.8 | v1.0.8

## 7. 安装坑 · 失败模式：installation: v1.1.0 — Learning Designer & Token Optimization

- 严重度：medium
- 证据强度：source_linked
- 发现：Developers should check this installation risk before relying on the project: v1.1.0 — Learning Designer & Token Optimization
- 对用户的影响：Upgrade or migration may change expected behavior: v1.1.0 — Learning Designer & Token Optimization
- 证据：failure_mode_cluster:github_release | https://github.com/vishalsachdev/canvas-mcp/releases/tag/v1.1.0 | v1.1.0 — Learning Designer & Token Optimization

## 8. 安装坑 · 失败模式：installation: v1.2.0

- 严重度：medium
- 证据强度：source_linked
- 发现：Developers should check this installation risk before relying on the project: v1.2.0
- 对用户的影响：Upgrade or migration may change expected behavior: v1.2.0
- 证据：failure_mode_cluster:github_release | https://github.com/vishalsachdev/canvas-mcp/releases/tag/v1.2.0 | v1.2.0

## 9. 安装坑 · 失败模式：installation: v1.3.0

- 严重度：medium
- 证据强度：source_linked
- 发现：Developers should check this installation risk before relying on the project: v1.3.0
- 对用户的影响：Upgrade or migration may change expected behavior: v1.3.0
- 证据：failure_mode_cluster:github_release | https://github.com/vishalsachdev/canvas-mcp/releases/tag/v1.3.0 | v1.3.0

## 10. 安装坑 · 失败模式：installation: v1.4.0

- 严重度：medium
- 证据强度：source_linked
- 发现：Developers should check this installation risk before relying on the project: v1.4.0
- 对用户的影响：Upgrade or migration may change expected behavior: v1.4.0
- 证据：failure_mode_cluster:github_release | https://github.com/vishalsachdev/canvas-mcp/releases/tag/v1.4.0 | v1.4.0

## 11. 安装坑 · 失败模式：installation: v1.5.0

- 严重度：medium
- 证据强度：source_linked
- 发现：Developers should check this installation risk before relying on the project: v1.5.0
- 对用户的影响：Upgrade or migration may change expected behavior: v1.5.0
- 证据：failure_mode_cluster:github_release | https://github.com/vishalsachdev/canvas-mcp/releases/tag/v1.5.0 | v1.5.0

## 12. 配置坑 · 可能修改宿主 AI 配置

- 严重度：medium
- 证据强度：source_linked
- 发现：项目面向 Claude/Cursor/Codex/Gemini/OpenCode 等宿主，或安装命令涉及用户配置目录。
- 对用户的影响：安装可能改变本机 AI 工具行为，用户需要知道写入位置和回滚方法。
- 证据：capability.host_targets | https://github.com/vishalsachdev/canvas-mcp | host_targets=mcp_host, claude, cursor

## 13. 配置坑 · 失败模式：configuration: DNS: CNAME for canvas-mcp.disruptionlab.illinois.edu points to wrong Azure target

- 严重度：medium
- 证据强度：source_linked
- 发现：Developers should check this configuration risk before relying on the project: DNS: CNAME for canvas-mcp.disruptionlab.illinois.edu points to wrong Azure target
- 对用户的影响：Developers may misconfigure credentials, environment, or host setup: DNS: CNAME for canvas-mcp.disruptionlab.illinois.edu points to wrong Azure target
- 证据：failure_mode_cluster:github_issue | https://github.com/vishalsachdev/canvas-mcp/issues/151 | DNS: CNAME for canvas-mcp.disruptionlab.illinois.edu points to wrong Azure target

## 14. 配置坑 · 失败模式：configuration: Ignore this Issue, Figured it out

- 严重度：medium
- 证据强度：source_linked
- 发现：Developers should check this configuration risk before relying on the project: Ignore this Issue, Figured it out
- 对用户的影响：Developers may misconfigure credentials, environment, or host setup: Ignore this Issue, Figured it out
- 证据：failure_mode_cluster:github_issue | https://github.com/vishalsachdev/canvas-mcp/issues/144 | Ignore this Issue, Figured it out

## 15. 配置坑 · 失败模式：configuration: Migrate to MCP SDK v2 (relax `mcp<2` pin) before stable ships (~2026-07-27)

- 严重度：medium
- 证据强度：source_linked
- 发现：Developers should check this configuration risk before relying on the project: Migrate to MCP SDK v2 (relax `mcp<2` pin) before stable ships (~2026-07-27)
- 对用户的影响：Developers may misconfigure credentials, environment, or host setup: Migrate to MCP SDK v2 (relax `mcp<2` pin) before stable ships (~2026-07-27)
- 证据：failure_mode_cluster:github_issue | https://github.com/vishalsachdev/canvas-mcp/issues/142 | Migrate to MCP SDK v2 (relax `mcp<2` pin) before stable ships (~2026-07-27)

## 16. 配置坑 · 失败模式：configuration: Normalize CANVAS_API_URL to canonical /api/v1 form instead of only warning

- 严重度：medium
- 证据强度：source_linked
- 发现：Developers should check this configuration risk before relying on the project: Normalize CANVAS_API_URL to canonical /api/v1 form instead of only warning
- 对用户的影响：Developers may misconfigure credentials, environment, or host setup: Normalize CANVAS_API_URL to canonical /api/v1 form instead of only warning
- 证据：failure_mode_cluster:github_issue | https://github.com/vishalsachdev/canvas-mcp/issues/147 | Normalize CANVAS_API_URL to canonical /api/v1 form instead of only warning

## 17. 配置坑 · 失败模式：configuration: mcp-remote proxy hangs indefinitely when hosted-server session goes stale (no timeout/fail-fast)

- 严重度：medium
- 证据强度：source_linked
- 发现：Developers should check this configuration risk before relying on the project: mcp-remote proxy hangs indefinitely when hosted-server session goes stale (no timeout/fail-fast)
- 对用户的影响：Developers may misconfigure credentials, environment, or host setup: mcp-remote proxy hangs indefinitely when hosted-server session goes stale (no timeout/fail-fast)
- 证据：failure_mode_cluster:github_issue | https://github.com/vishalsachdev/canvas-mcp/issues/159 | mcp-remote proxy hangs indefinitely when hosted-server session goes stale (no timeout/fail-fast)

## 18. 配置坑 · 失败模式：configuration: switch to FastMCP from MCP SDK library

- 严重度：medium
- 证据强度：source_linked
- 发现：Developers should check this configuration risk before relying on the project: switch to FastMCP from MCP SDK library
- 对用户的影响：Developers may misconfigure credentials, environment, or host setup: switch to FastMCP from MCP SDK library
- 证据：failure_mode_cluster:github_issue | https://github.com/vishalsachdev/canvas-mcp/issues/145 | switch to FastMCP from MCP SDK library

## 19. 配置坑 · 失败模式：configuration: v1.0.3 - Critical Fix: grade_with_rubric

- 严重度：medium
- 证据强度：source_linked
- 发现：Developers should check this configuration risk before relying on the project: v1.0.3 - Critical Fix: grade_with_rubric
- 对用户的影响：Upgrade or migration may change expected behavior: v1.0.3 - Critical Fix: grade_with_rubric
- 证据：failure_mode_cluster:github_release | https://github.com/vishalsachdev/canvas-mcp/releases/tag/v1.0.3 | v1.0.3 - Critical Fix: grade_with_rubric

## 20. 配置坑 · 失败模式：configuration: v1.0.4 - Major Performance & Feature Update

- 严重度：medium
- 证据强度：source_linked
- 发现：Developers should check this configuration risk before relying on the project: v1.0.4 - Major Performance & Feature Update
- 对用户的影响：Upgrade or migration may change expected behavior: v1.0.4 - Major Performance & Feature Update
- 证据：failure_mode_cluster:github_release | https://github.com/vishalsachdev/canvas-mcp/releases/tag/v1.0.4 | v1.0.4 - Major Performance & Feature Update

## 21. 能力坑 · 能力判断依赖假设

- 严重度：medium
- 证据强度：source_linked
- 发现：README/documentation is current enough for a first validation pass.
- 对用户的影响：假设不成立时，用户拿不到承诺的能力。
- 证据：capability.assumptions | https://github.com/vishalsachdev/canvas-mcp | README/documentation is current enough for a first validation pass.

## 22. 维护坑 · 维护活跃度未知

- 严重度：medium
- 证据强度：source_linked
- 发现：未记录 last_activity_observed。
- 对用户的影响：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。
- 证据：evidence.maintainer_signals | https://github.com/vishalsachdev/canvas-mcp | last_activity_observed missing

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 证据：downstream_validation.risk_items | https://github.com/vishalsachdev/canvas-mcp | no_demo; severity=medium

## 24. 安全/权限坑 · 存在评分风险

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 对用户的影响：风险会影响是否适合普通用户安装。
- 证据：risks.scoring_risks | https://github.com/vishalsachdev/canvas-mcp | no_demo; severity=medium

## 25. 安全/权限坑 · 来源证据：DNS: CNAME for canvas-mcp.disruptionlab.illinois.edu points to wrong Azure target

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题：DNS: CNAME for canvas-mcp.disruptionlab.illinois.edu points to wrong Azure target
- 对用户的影响：可能影响授权、密钥配置或安全边界。
- 证据：community_evidence:github | https://github.com/vishalsachdev/canvas-mcp/issues/151 | 来源类型 github_issue 暴露的待验证使用条件。

## 26. 安全/权限坑 · 来源证据：Ignore this Issue, Figured it out

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题：Ignore this Issue, Figured it out
- 对用户的影响：可能影响授权、密钥配置或安全边界。
- 证据：community_evidence:github | https://github.com/vishalsachdev/canvas-mcp/issues/144 | 来源类型 github_issue 暴露的待验证使用条件。

## 27. 安全/权限坑 · 来源证据：Normalize CANVAS_API_URL to canonical /api/v1 form instead of only warning

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题：Normalize CANVAS_API_URL to canonical /api/v1 form instead of only warning
- 对用户的影响：可能影响授权、密钥配置或安全边界。
- 证据：community_evidence:github | https://github.com/vishalsachdev/canvas-mcp/issues/147 | 来源类型 github_issue 暴露的待验证使用条件。

## 28. 安全/权限坑 · 来源证据：mcp-remote clients re-login hourly — request `offline_access` scope for refresh token

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题：mcp-remote clients re-login hourly — request `offline_access` scope for refresh token
- 对用户的影响：可能影响授权、密钥配置或安全边界。
- 证据：community_evidence:github | https://github.com/vishalsachdev/canvas-mcp/issues/146 | 来源类型 github_issue 暴露的待验证使用条件。

## 29. 安全/权限坑 · 来源证据：switch to FastMCP from MCP SDK library

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题：switch to FastMCP from MCP SDK library
- 对用户的影响：可能影响升级、迁移或版本选择。
- 证据：community_evidence:github | https://github.com/vishalsachdev/canvas-mcp/issues/145 | 来源讨论提到 python 相关条件，需在安装/试用前复核。

## 30. 维护坑 · issue/PR 响应质量未知

- 严重度：low
- 证据强度：source_linked
- 发现：issue_or_pr_quality=unknown。
- 对用户的影响：用户无法判断遇到问题后是否有人维护。
- 证据：evidence.maintainer_signals | https://github.com/vishalsachdev/canvas-mcp | issue_or_pr_quality=unknown

## 31. 维护坑 · 发布节奏不明确

- 严重度：low
- 证据强度：source_linked
- 发现：release_recency=unknown。
- 对用户的影响：安装命令和文档可能落后于代码，用户踩坑概率升高。
- 证据：evidence.maintainer_signals | https://github.com/vishalsachdev/canvas-mcp | release_recency=unknown

<!-- canonical_name: vishalsachdev/canvas-mcp; human_manual_source: deepwiki_human_wiki -->
