Skip to main content
Glama
RyK57

canvas-mcp-server

by RyK57

canvas-mcp-server

Canvas LMS REST API用のMCPサーバー。LLMにコース、課題、成績、提出物、お知らせ、ディスカッション、モジュール、ページ、ファイルへの読み取りアクセスを提供します。

20個のツール、すべて読み取り専用。

要件

  • Node.js 18+

  • 任意の教育機関のCanvasアカウント

  • Canvas Web UIのAccount → Settings → New Access Tokenから取得したアクセストークン

Related MCP server: Canvas LMS MCP Server

インストール

npm install
npm run build

設定

Canvasには共通のAPIホストはありません — 各教育機関が独自に運営しています。以下の2つの変数は必須です。

{
  "mcpServers": {
    "canvas": {
      "command": "node",
      "args": ["/absolute/path/to/canvas-mcp-server/dist/index.js"],
      "env": {
        "CANVAS_BASE_URL": "https://bcourses.berkeley.edu",
        "CANVAS_ACCESS_TOKEN": "your-token-here"
      }
    }
  }
}

変数

必須

デフォルト

目的

CANVAS_BASE_URL

はい

—

あなたの教育機関のCanvasホスト。スキームを含み、末尾のパスはなし

CANVAS_ACCESS_TOKEN

はい

—

Account → Settings → New Access Token

CANVAS_REQUEST_TIMEOUT_MS

いいえ

30000

リクエストごとのタイムアウト

TRANSPORT

いいえ

stdio

stdioまたはhttp

PORT / HOST

いいえ

3000 / 127.0.0.1

HTTPトランスポートのバインドアドレス

MCP_PATH_SECRET

ホスト時

—

エンドポイントを/mcp/<secret>で提供します。HOSTがループバックでない場合は必須

ALLOWED_ORIGINS

いいえ

localhost + claude.ai

カンマ区切りのオリジン許可リスト

ツールを対話的に確認する:

CANVAS_BASE_URL=https://your.canvas CANVAS_ACCESS_TOKEN=your-token npm run inspect

デプロイ(Claude mobile / claude.aiコネクタ用)

ClaudeはデバイスからではなくAnthropicのクラウドからカスタムコネクタに接続するため、モバイルとclaude.aiではこれを公開HTTPS経由で到達可能にする必要があります。Claude CodeとClaude Desktopはその必要はありません — そこではstdioを使用してください。

1. パスシークレットを生成

openssl rand -hex 32

サーバーはMCP_PATH_SECRETが設定されていない場合、非ループバックインターフェースでの起動を拒否します。Canvasトークンを保持する公開エンドポイントは、あなたのアカウントへのオープンプロキシになるためです。設定すると、エンドポイントは/mcp/<secret>に移動し、他のすべてのパスは404を返します — 間違ったシークレットも含めて、ホストを調べてもMCPサーバーが存在することを明かしません。

2. デプロイ

同梱のDockerfileとrailway.jsonは、Railway、Render、Flyでそのまま動作します。イメージはTRANSPORT=httpとHOST=0.0.0.0を設定し、非rootユーザーとして実行されます。プラットフォームのダッシュボードで3つの変数を設定してください:

変数

値

CANVAS_BASE_URL

あなたの教育機関のCanvasホスト

CANVAS_ACCESS_TOKEN

あなたのトークン

MCP_PATH_SECRET

ステップ1の値

PORTはプラットフォームによって注入されます。/healthzは認証なしの死活プローブです。

3. 確認

curl -s https://your-app.up.railway.app/healthz

4. コネクタを追加

claude.aiでブラウザ上で — コネクタはモバイルアプリからは追加できません:

  1. Customize → Connectors → Add custom connector

  2. URL: https://your-app.up.railway.app/mcp/<secret>

  3. スマートフォンでチャットを開き、+ → Connectorsの下で有効にします。

そのURLはパスワードのように扱ってください。漏れた場合はMCP_PATH_SECRETをローテーションし、コネクタを再追加してください。

ツール

コース — canvas_list_courses, canvas_get_course, canvas_get_grades, canvas_list_enrollments, canvas_get_profile

課題 — canvas_list_assignments, canvas_get_assignment, canvas_get_submission, canvas_list_quizzes

プランナー — canvas_list_planner_items, canvas_list_upcoming, canvas_list_calendar_events

お知らせとディスカッション — canvas_list_announcements, canvas_list_discussions, canvas_get_discussion

コースコンテンツ — canvas_list_modules, canvas_list_module_items, canvas_list_pages, canvas_get_page, canvas_list_files

すべての読み取りツールはresponse_format: "markdown" | "json"を受け取ります。Markdownがデフォルトで、LLMが読むのに最適化されています。JSONは完全な構造化ペイロードです。structuredContentは形式に関係なく常に設定されます。

例

「今週の締め切りは?」 → canvas_list_planner_itemsをend_dateを1週間後に設定して使用します。1回の呼び出しで全コースを対象とし、提出状態を報告します。デフォルトでは今日から開始するため、「何が遅れているか」を知りたい場合は、明示的に過去のstart_dateを渡してください。

「私の成績は?」 → canvas_get_grades。1回の呼び出しで、すべてのアクティブなコースの現在のスコアと評定を取得します。

「今週教授たちは何を発表した?」 → まずcanvas_list_coursesでIDを取得し、次にcanvas_list_announcementsにそれらをすべて一度に渡します。

「プロジェクト2で実際に何をすべき?」 → search_term="project 2"を指定してcanvas_list_assignmentsでIDを取得し、次にcanvas_get_assignmentで完全な指示を取得します。

設計メモ

設計上読み取り専用。 すべてのツールはreadOnlyHint: trueとdestructiveHint: falseを持ち、クライアントには書き込みパスが公開されていません。Canvasトークンはアカウントの完全な権限を持ちます — 課題の提出、ディスカッションへの投稿、プロフィール設定の変更が可能です — そのためサーバーは意図的にそれらを公開しません。テストがこれを保証します: 書き込みツールが追加された場合、スイートは失敗します。

ベースURLは必須であり、デフォルトはありません。 シングルテナントAPIとは異なり、Canvasは教育機関ごとに1つのインスタンスを実行します。妥当なデフォルトは存在せず、ある学校のCanvasが発行したトークンは別の学校では無意味です。そのため、サーバーは後で401で誤解させるのではなく、起動時に失敗します。

ページネーションはヘッダーにあります。 CanvasはRFC 5988のLinkヘッダーで「次のページがあるか」を報告し、総数は返しません。これらのURLは不透明として文書化されているため、has_moreはヘッダーから読み取られ、page/per_pageは呼び出し側の制御として残ります — エージェントはスレッド化するカーソルではなく、単純なnext_pageを追跡します。

IDは文字列として要求されます。 CanvasのIDは64ビット整数であり、JavaScriptでは正確に表現できません。クライアントはAccept: application/json+canvas-string-idsを送信し、CanvasはすべてのIDを文字列として返すことでこれに応じます。そのため、IDはJSONラウンドトリップを無傷で通過します。

HTMLはモデルに到達する前に平坦化されます。 課題の説明、お知らせ、ディスカッションの投稿、ページはすべてHTMLとして保存されます。それをそのまま渡すとマークアップに膨大なコンテキストを消費するため、タグは改行になり、エンティティはデコードされ、長い本文はhtml_urlを保持して抜粋されます。

include[]は公開されていません。 Canvasには24のインクルードオプションがあり、リストエンドポイントと単一コースエンドポイントで異なり、そのほとんどはエージェントが使用しないフィールドを制御します。各ツールは必要なものを要求し、ユーザーが見るものを変更するトグルのみを公開します — include_syllabus、include_grades、include_submission。

コースIDはコンテキストコードに正規化されます。 一部のCanvasエンドポイントはコースを1234ではなくcourse_1234として扱います。両方の形式がどこでも受け入れられ変換されるため、エージェントはどのエンドポイントがどちらを必要とするかを覚える必要がありません。

エラーは次のアクションに解決されます。 404はそのリソースの有効なIDを生成するツールを指名します。403は権限の問題とレート制限の枯渇を区別します。Canvasはこれらを同じステータスで返すため紛らわしいです。401は、ある学校のCanvasのトークンが別の学校では機能しないことを指摘します。

2つのCanvasの癖はそのまま渡さずに処理されます。 コースがenrollments[].computed_current_scoreで報告する成績は、Enrollments APIがgrades.current_scoreと呼ぶ数値と同じです。両方が読み取られます。また、プランナーアイテムのsubmissionsフィールドは、提出可能なものがない場合、オブジェクトではなくブール値のfalseであり、読み取る前にチェックされます。

注意事項

  • お知らせはグローバルに一覧表示できません: Canvasは少なくとも1つのコースIDを必要とするため、canvas_list_coursesを最初に実行する必要があります。

  • canvas_list_discussionsはscopeフィルターをページネーション後に適用するため、フィルターされたページはper_pageより短くなることがありますが、結果の終わりではありません。

  • Canvasは大きいとみなすモジュールのリスト応答からモジュールアイテムを省略します。canvas_list_module_itemsがそれらを取得します。

  • ページはタイトルではなくURLスラッグ(week-1-reading)でアドレス指定されます。canvas_list_pagesはurlフィールドにスラッグを返します。

  • カレンダーエンドポイントは最大10コースを受け入れ、残りを静かに無視します。canvas_list_calendar_eventsは切り詰めるときに報告します。

  • 成績はインストラクターが投稿したもののみを反映し、最終成績を非表示に設定されたコースでは完全に省略されます。

プロジェクト構成

src/
├── index.ts               # entry point, transport selection
├── constants.ts           # enum values, limits, character limit
├── types.ts               # interfaces for every Canvas entity
├── services/
│   └── canvas-client.ts   # fetch wrapper, auth, Link pagination, error → guidance mapping
├── schemas/
│   ├── inputs.ts          # Zod input schemas
│   └── outputs.ts         # structuredContent schemas
├── formatters/
│   ├── response.ts        # pagination, truncation, HTML flattening, format dispatch
│   └── entities.ts        # per-entity markdown rendering
└── tools/
    ├── courses.ts
    ├── assignments.ts
    ├── planner.ts
    ├── announcements.ts
    └── content.ts

テスト

npm run build
npm test            # 43 checks: MCP handshake, tools, pagination, formatting, errors (mocked API)
npm run test:http   # 19 checks: config validation, path-secret gating, method handling, origins

両方のスイートはローカルモックに対して実行されるため、トークンやネットワークアクセスは不要です。

Related MCP Connectors

Related MCP Servers