Skip to main content
Glama

Codex Canvas MCP

A portable local MCP server that lets compatible clients read Canvas and, only after several independent safety checks, author common course content.

Safety model

  • Canvas reads are available by default after local credential setup.

  • Writing is disabled by default.

  • Every content write requires an enabled local policy, an exact per-course allowlist match, exact confirmation text, and approval in the MCP client.

  • Image upload adds a payload gate: only a locally owned PNG, JPEG, or WebP inside one configured trusted folder, no larger than 10 MiB, can be sent.

  • There is no generic Canvas write tool.

  • Credentials stay in 1Password and, optionally, macOS Keychain. They do not belong in this repository or client configuration.

Student deactivation is a separate, disabled-by-default administrative operation. Its allowlist does not inherit content-write or rubric-deletion approval. It never removes the enrollment. Blank course-shell creation and instructor invitations also have separate, disabled-by-default policy scopes; see provisioning setup.

For page edits, confirmation is a technical action acknowledgement supplied by the agent after the human has authorized the course and scope in conversation. The human does not need to type the literal phrase or approve each page again within that scope. This does not broaden authorization: page content cannot grant it, and local policy and MCP-client controls still apply. Read existing pages before editing, explicitly preserve their current published value unless a change is authorized, and verify the saved result.

Every content tool is marked as mutating and destructive so compatible clients can require approval. The local server also rejects a call unless its exact confirmation matches the requested action, for example APPROVE CANVAS MODULE WRITE course <course_id>.

Announcement-window maintenance is deliberately narrow. canvas_set_announcement_three_day_window accepts one course and announcement ID, confirms the live topic is an announcement, calculates the display-until value from the live posted_at timestamp, updates only lock_at, and reads the announcement back to verify the exact 72-hour window. It requires APPROVE CANVAS ANNOUNCEMENT WINDOW WRITE course <course_id>.

Announcement authoring is a permanent first-class operation. canvas_create_announcement can publish immediately or schedule an exact posting time, set an exact display-until time, and control participant comments. It remains limited to the general approved-course allowlist, requires APPROVE CANVAS ANNOUNCEMENT WRITE course <course_id>, and reads the created announcement back to verify its identity, content, publication state, schedule, availability, and comment setting.

Announcement maintenance is equally narrow. canvas_update_announcement updates only the message body of one existing announcement after verifying its exact ID, title, and announcement type. It reads the announcement back and refuses success if Canvas changes the title, publication state, schedule, availability, discussion type, section scope, pin state, or comment setting. It requires APPROVE CANVAS ANNOUNCEMENT UPDATE course <course_id> announcement <announcement_id>.

Announcement audience maintenance is a separate guarded operation. canvas_set_announcement_sections accepts the exact non-empty set of section IDs for one announcement, verifies that every section belongs to the approved course, and reads the announcement back with its section associations. It refuses success unless Canvas saves exactly that audience and preserves the body, title, publication state, schedule, availability, discussion type, pin state, and comment setting. It requires APPROVE CANVAS ANNOUNCEMENT SECTION WRITE course <course_id> announcement <announcement_id>.

Assignment maintenance is also narrowly scoped. canvas_update_assignment updates only the description of one existing assignment after verifying its exact ID and name. It reads the assignment back, confirms the description after Canvas's known link-attribute normalization, and refuses success if Canvas changes protected settings such as points, submission type, dates, group, or publication state. It requires APPROVE CANVAS ASSIGNMENT UPDATE course <course_id> assignment <assignment_id>.

Rubric maintenance uses a separate operation-specific course allowlist and a stronger identity gate. canvas_delete_rubric requires APPROVE CANVAS RUBRIC DELETE course <course_id> rubric <rubric_id>, an exact expected title, course ownership, editable state, and an empty live used_locations result. Authorizing rubric deletion does not authorize any page, assignment, module, discussion, or quiz write. The tool returns the complete pre-deletion rubric definition and verifies that the rubric no longer appears in the active course list.

Rubric creation accepts a same-origin Canvas assignment URL, an assignment module-item URL, or a course URL containing an assignment_id query parameter. Query strings and fragments are ignored after the course and assignment are resolved. The URL never bypasses course policy: its course ID must still be explicitly allowlisted, and rubric creation requires APPROVE CANVAS RUBRIC WRITE course <course_id>. The tool refuses to replace an existing assignment rubric, requires descriptions for every criterion and rating, and requires grading-rubric points to match the assignment points.

Related MCP server: canvas-lms

What is included

Tool

Capability

Default

canvas_get_current_user

Read the authenticated profile

Available

canvas_list_modules

Read modules and items for one course

Available

canvas_read_api

GET a normalized Canvas API v1 path

Available

canvas_inspect_rubric

Read one rubric, its complete definition, usage locations, and deletion preflight

Available

canvas_get_write_policy

Inspect local policy state

Available

canvas_preview_course_creation

Preview a blank shell and check its account, term, and duplicates

Available

canvas_create_course_shell

Create and verify a private unpublished shell

Blocked

canvas_preview_instructor_enrollment

Verify an existing instructor identity, section, and role

Available

canvas_enroll_instructor

Invite and verify one instructor with an approved teacher role

Blocked

canvas_preview_student_enrollment

Verify one student's identity, course, section, role, and existing enrollment

Available

canvas_enroll_student

Invite and verify one exact student after an explicit request

Blocked

canvas_preview_student_deactivation

Read one exact student enrollment and preview deactivation

Available

canvas_deactivate_student_enrollment

Deactivate and verify one active student enrollment

Blocked

canvas_upload_powerpoint

Upload one validated macro-free PPTX from its trusted folder

Blocked

canvas_upload_image

Upload one verified image from the configured trusted folder

Blocked

canvas_write_page

Create or update one page

Blocked

canvas_update_syllabus

Preview, replace, and verify only a course syllabus body

Blocked

canvas_create_module

Create one module

Blocked

canvas_create_module_item

Place one content item in a module

Blocked

canvas_create_assignment

Create one assignment

Blocked

canvas_update_assignment

Update and verify one assignment description

Blocked

canvas_create_assignment_rubric

Create and attach one assignment rubric from a Canvas URL

Blocked

canvas_create_discussion

Create one discussion

Blocked

canvas_create_announcement

Create and verify one immediate or scheduled announcement

Blocked

canvas_update_announcement

Update and verify one exact announcement body

Blocked

canvas_set_announcement_sections

Set and verify one announcement's exact section audience

Blocked

canvas_set_announcement_three_day_window

Set one announcement to a verified 72-hour display window

Blocked

canvas_create_classic_quiz

Create one Classic Quiz

Blocked

canvas_create_classic_quiz_question

Add one question to a Classic Quiz

Blocked

canvas_delete_page

Delete one page

Blocked

canvas_delete_assignment

Delete one assignment

Blocked

canvas_delete_discussion

Delete one discussion

Blocked

canvas_delete_classic_quiz

Delete one Classic Quiz

Blocked

canvas_delete_module

Delete one module and its item placements

Blocked

canvas_delete_rubric

Delete one exact, course-owned rubric only when Canvas reports zero usage locations

Blocked

Set up a new Mac

Prerequisites: Python 3.11 or newer, the 1Password CLI, a 1Password service account that can read only the intended Canvas credential item, and a Canvas API token with the least privileges practical for your work.

  1. Clone and install into an isolated environment:

    git clone https://github.com/mrchris-ai/codex_canvas_mcp.git
    cd codex_canvas_mcp
    python3 -m venv .venv
    . .venv/bin/activate
    python -m pip install --upgrade pip
    python -m pip install -e .
  2. Create a 1Password item whose concealed field contains the Canvas API token. Give the service account read access only to the containing vault/item. Record the vault name, item name or ID, and concealed field label; do not put their values in this repository.

  3. Choose one service-account-token delivery method:

    • For a short-lived shell session, provide OP_SERVICE_ACCOUNT_TOKEN to the MCP server process through your local secret launcher.

    • On macOS, store that token in Keychain and configure non-secret lookup labels. Example command (it prompts securely; do not put the token on the command line):

      security add-generic-password -U -s "your-service-label" -a "your-account-label" -w
  4. Configure the server process with these non-secret values:

    Variable

    Purpose

    CANVAS_BASE_URL

    Canvas HTTPS origin, such as https://school.instructure.com

    CANVAS_OP_VAULT

    1Password vault name or ID

    CANVAS_OP_ITEM

    Canvas credential item name or ID

    CANVAS_OP_FIELD

    Concealed token field label; defaults to credential

    CANVAS_KEYCHAIN_SERVICE

    macOS Keychain service label when not using OP_SERVICE_ACCOUNT_TOKEN

    CANVAS_KEYCHAIN_ACCOUNT

    macOS Keychain account label when not using OP_SERVICE_ACCOUNT_TOKEN

    CANVAS_IMAGE_UPLOAD_ROOT

    Absolute path to the only local folder from which image upload is allowed

  5. Test only the protocol and security gates, without contacting Canvas or reading credentials:

    python -m unittest discover -s tests -v
    printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | python -m canvas_mcp
  6. Add the stdio server to Codex. The project-level form is:

    [mcp_servers.canvas]
    command = "/absolute/path/to/codex_canvas_mcp/.venv/bin/python"
    args = ["-m", "canvas_mcp"]
    
    [mcp_servers.canvas.env]
    CANVAS_BASE_URL = "https://school.instructure.com"
    CANVAS_OP_VAULT = "your-vault"
    CANVAS_OP_ITEM = "your-item"
    CANVAS_OP_FIELD = "credential"
    CANVAS_KEYCHAIN_SERVICE = "your-service-label"
    CANVAS_KEYCHAIN_ACCOUNT = "your-account-label"
    CANVAS_IMAGE_UPLOAD_ROOT = "/absolute/path/to/reviewed/canvas-images"

    Put this in the trusted project's .codex/config.toml or your personal Codex configuration. Do not add secret values. Restart or open a new task after changing MCP configuration, then verify the listed tools before requesting Canvas data.

ChatGPT compatibility

This repository implements a local stdio MCP server for Codex and other clients that support local stdio MCP, including desktop Work configurations that provide a local executor. A hosted ChatGPT custom app requires a supported private tunnel or a reviewed remote MCP endpoint. Do not expose this process directly to the public internet.

See Developer mode and MCP apps in ChatGPT before attempting ChatGPT setup; availability and approval behavior can change.

Clients that omit configured environment values

Some desktop Work launch paths transfer the names from an MCP server's env table as env_vars to inherit, without transferring the values. The server can therefore report CANVAS_BASE_URL missing even when the saved MCP configuration contains it. A separate terminal or Codex session succeeding does not verify that Work's active MCP has the same configuration.

For this launch path, explicitly provide a private connection JSON file:

{
  "CANVAS_BASE_URL": "https://school.instructure.com",
  "CANVAS_OP_VAULT": "your-vault",
  "CANVAS_OP_ITEM": "your-item",
  "CANVAS_OP_FIELD": "credential",
  "CANVAS_KEYCHAIN_SERVICE": "your-service-label",
  "CANVAS_KEYCHAIN_ACCOUNT": "your-account-label"
}

Keep this file outside the repository. It must be a regular, non-symlink file owned by the current user, with permissions 0600, and no larger than 16 KiB. Set those permissions before adding your lookup references. It contains connection metadata only: never put a Canvas token or a 1Password service-account token in it. Credentials still come from the existing Keychain/1Password lookup flow. The file option requires a platform supporting ownership and no-follow file checks, such as macOS or Linux.

Add the absolute file path to the saved MCP arguments:

[mcp_servers.canvas]
command = "/absolute/path/to/codex_canvas_mcp/.venv/bin/python"
args = ["-m", "canvas_mcp", "--connection-config", "/absolute/private/path/canvas-connection.json"]

The loader fills missing connection metadata. Matching environment settings are preserved; conflicting values, invalid origins, duplicate keys, and unknown fields fail startup without echoing configuration values. CANVAS_BASE_URL is required in the file. The only other accepted keys are the five lookup settings in the example.

The file cannot set write policy, upload roots, arbitrary environment variables, or credentials. Preserve any existing MCP environment configuration for clients that support it. A client with no separately provisioned write policy remains unable to write; an existing independently configured policy is unchanged. The credential helper executables must still be available on the host's PATH.

For existing clients that cache the old command arguments, the server also checks ~/.config/canvas-mcp/connection.json when no explicit file argument is supplied and CANVAS_BASE_URL is missing or empty. This optional default uses the same strict private-file validation. A missing default leaves the original environment-only behavior unchanged; an unsafe default fails startup. An explicitly specified file never falls back, and a client with an existing base URL does not consult the default.

After changing the arguments, reload the connector in the affected client and verify a real read through its active MCP. Also inspect canvas_get_write_policy to confirm the connection repair has not changed write access.

Enabling content-authoring tools

Keep writing off unless a specific task requires it.

  1. Copy config/write-policy.example.json to a location outside the repository.

  2. Add only the exact Canvas course IDs approved for content authoring to approved_course_ids. Add courses approved only for zero-dependency rubric deletion to approved_rubric_delete_course_ids, and courses approved for student deactivation to approved_student_deactivation_course_ids. Each list is independent.

  3. Set enabled to true and restrict the file:

    chmod 600 /absolute/private/path/write-policy.json
  4. Add CANVAS_WRITE_POLICY=/absolute/private/path/write-policy.json to the MCP server environment.

  5. Restart the client if the environment variable was added or changed, then call canvas_get_write_policy to verify the effective policy. Edits to an already configured policy file are read on each guarded operation and do not require a restart.

  6. For each content write, review the exact target and payload and honor MCP-client approval controls. For page edits already authorized by the human, the agent supplies the action-specific confirmation field; do not ask the human to repeat a literal phrase for each page or batch.

  7. Disable the policy again when the task is complete.

Work clients that omit the write-policy environment value

Version 0.18.2 also checks ~/.config/canvas-mcp/write-policy.json when CANVAS_WRITE_POLICY is absent or blank. This is a separate, explicitly provisioned write policy, not connection metadata. Nothing creates or enables it automatically. Use the same policy schema and exact task-authorized grants described above; keep private policy files outside Git.

An explicit CANVAS_WRITE_POLICY path always takes precedence, even if its file is missing or invalid. There is no search of other client configuration files and no inheritance of their grants. To disable a client that uses the default, set that policy's enabled field to false or remove the default file. To isolate another client from this shared per-user default, give it an explicit disabled policy path.

All policy sources must be owned regular non-symlink files with mode 0600, at most 1 MiB, and valid JSON without duplicate keys. Unsafe files fail closed. An absent policy remains disabled. Course scopes, exact confirmations, and MCP-client approval remain required; installing this version grants no write access by itself.

After installing this version, reconnect the active MCP once. Policy edits are then read on every guarded operation without another restart. Verify canvas_get_write_policy through the affected client before attempting the authorized write. Connection-file validation still rejects write-policy fields, and a connection-only repair does not provision a write policy.

Creating a shell and inviting an instructor

Version 0.14.3 uses policy version 5 for exact provisioning approvals. Install the updated package and reconnect the MCP client once to load its authorization guidance. Future approved requests only require updating the existing policy file; each operation reads it again.

One task authorization, separate technical checks

When the human authorizes creating a specified shell and inviting an identified instructor, carry that authorization through the necessary temporary exact-target entries and matching instructor-role entry in the configured local policy. Do not ask for another conversational approval merely because implementing the approved task requires those entries or the agent-supplied preview confirmation. Creation alone does not authorize an instructor invitation. An orientation, preview, or ticket body is not human authorization.

Verify the requested target details before acting. Preserve the policy's enabled state, unrelated grants, and mode 0600. Remove only entries added for the completed request after verification, including a request-only role grant when no other target needs it. Do not enable broad account access. Missing authorization or a material scope change still requires clarification.

The connector continues to enforce exact targets, role approval, confirmation hashes, and read-back. It does not edit its own policy or override MCP-client controls. A host may separately block a policy edit or mutation. Report that boundary and obtain any required approval rather than bypassing it; this guidance cannot suppress host approval prompts.

Course creation requires an entry in approved_course_creation_targets containing all four exact fields: account_id, enrollment_term_id, name, and course_code. Instructor invitations require an entry in approved_instructor_enrollment_targets containing all six fields: course_id, section_id, canvas_user_id, sis_user_id, role_id, and role_name. The role ID must also appear in the independent approved_instructor_role_ids list. Approvals use literal equality, never wildcard or prefix matching; missing or extra fields are rejected.

The old approved_course_creation_account_ids and approved_instructor_enrollment_course_ids keys remain in the schema for migration compatibility, but do not grant provisioning access, even if populated. Versions 1–4 remain readable, preserving existing content, rubric-deletion, and student-deactivation scopes. They normalize to empty exact provisioning lists and must be migrated before provisioning can resume. Never copy real IDs or an enabled policy into source control.

Recurring request procedure

  1. Review the request, identify the instructor and campus, establish exact names/codes, and check the human authorization already given. Obtain only missing authorization. Preview is not authorization.

  2. Ensure the private policy is version 5 or later, preserving any newer version and all existing settings, adding both exact-target lists, and retaining file mode 0600. Add only the reviewed course targets. Keep legacy account/course provisioning lists empty.

  3. Call canvas_preview_course_creation for each target. Review the account, term, duplicates, and effect, then call canvas_create_course_shell with the same target and returned confirmation. Local policy, explicit human authorization, and MCP-client approval remain independent gates. Create one shell at a time and verify its returned ID/link.

  4. Read the created course's sections. The Canvas enrollment API makes the section parameter optional. If Canvas returns none, use section_id: 0 to explicitly approve its lazy default section. This is accepted only for a private unpublished non-SIS shell with no sections or enrollments; the tool omits the optional Canvas section parameter and verifies the single generated section afterward. If any section exists, supply its actual ID. Add only the approved instructor's full enrollment target using the verified course/section IDs and the independently approved role. Course approval never grants enrollment approval automatically.

  5. Call canvas_preview_instructor_enrollment, then canvas_enroll_instructor with that exact target and its returned confirmation. The instructor is invited and Canvas notification is requested; delivery is not independently confirmed.

  6. Verify the enrollment and course link. Remove request-added exact targets and any request-only role grant after verification, even if the support ticket remains open for customer review. The installed schema version stays in place for subsequent requests; no broad subaccount enablement is needed.

Provisioning list reads follow Canvas pagination links instead of guessing numbered pages. Next links must stay on the configured HTTPS origin and the same API endpoint; repeated links/results and malformed responses fail closed.

A changed name, code, term, campus, instructor, section, or role requires its own reviewed exact target. Fresh confirmation text cannot expand policy scope. An uncertain write must be inspected before any retry; never automatically retry or delete its result.

Deactivating one student enrollment

First confirm the official enrollment disposition outside Canvas. Use canvas_preview_student_deactivation with the course ID, section ID, enrollment ID, Canvas user ID, and SIS user ID. It shows the live state and makes no change. The mutation accepts the same exact IDs plus APPROVE CANVAS STUDENT DEACTIVATION course <course_id> enrollment <enrollment_id> after human authorization and MCP-client approval. The local policy must be version 3 or later and the course must appear in approved_student_deactivation_course_ids; version 1 and 2 policies remain readable but grant no deactivation access. The Canvas credential also needs permission to view SIS IDs and manage course student enrollments; use a token limited to the needed API scopes where supported.

The tool refuses a mismatched identity or a non-active enrollment, sends only Canvas's task=deactivate action to the exact enrollment, and confirms the resulting inactive state through a second read. An already inactive enrollment returns a verified no-change result. If verification fails after the request, inspect the Canvas roster before retrying. Canvas's Enrollments API documents deactivation as distinct from deletion; restoring access requires a separately authorized reactivation action, which this connector does not provide.

Authoring in a Blueprint course

A Blueprint course uses the same exact-course content allowlist as any other course. Approving an associated course does not approve its Blueprint, and approving a Blueprint does not approve its associated courses. Keep real course IDs in the private policy file, never in the repository or example configuration.

Before editing, use canvas_read_api to verify the target course's blueprint flag and, when needed, its associated courses at /api/v1/courses/<course_id>/blueprint_templates/default/associated_courses. Add the explicitly authorized Blueprint ID to the existing private approved_course_ids list, preserving the other entries and file mode 0600. Verify the effective list with canvas_get_write_policy.

Preserve the original content, use the resource-specific write tool and exact confirmation phrase, and read the saved resource back through the MCP. Publishing or updating a page in the Blueprint is separate from syncing it to associated courses. This connector does not provide Blueprint synchronization.

The course syllabus is not a Canvas Page. Inspect it with canvas_read_api at /api/v1/courses/<course_id> using include[]=syllabus_body, then use canvas_update_syllabus for body-only changes. The endpoint is documented in the Canvas Courses API.

The syllabus tool requires the exact course allowlist, APPROVE CANVAS SYLLABUS WRITE course <course_id>, client approval, and expected_sha256 calculated from the reviewed current UTF-8 syllabus body. It defaults to dry_run: true, returning the original body for recovery. Save that recovery content before explicitly setting dry_run: false. The only outgoing field is course[syllabus_body]; extra arguments and empty bodies are rejected. It reads the course back and verifies exact body equality and protected course settings. If Canvas normalizes the HTML or a setting differs, the tool reports a verification failure after the write; inspect live state before retrying. The hash check detects changes before the PUT but is not an atomic Canvas concurrency lock.

To restore a saved syllabus, review the live version, compute its current hash, and submit the saved body through the same guarded tool. The tool never publishes a course or syncs a Blueprint.

Enabling PowerPoint upload (0.16.0)

Set CANVAS_POWERPOINT_UPLOAD_ROOT to an absolute, current-user-owned folder containing reviewed .pptx files. Restart or reconnect existing MCP clients to discover canvas_upload_powerpoint. The tool uses the enabled local write policy's exact course allowlist and requires APPROVE CANVAS POWERPOINT UPLOAD WRITE course <course_id> after explicit human authorization. Enabling this tool does not authorize uploading unrelated files.

Only standard macro-free .pptx packages up to 25 MiB are accepted. Legacy .ppt, .pptm, arbitrary ZIP files, symlinks, unsafe filenames, encrypted entries, VBA and ActiveX content are rejected. Validation checks the package content type, presentation XML, and root office-document relationship; bounds expanded content and XML metadata; and freezes the validated bytes before any network write. This validates the package format, not the accuracy or safety of every slide's content.

Uploads use the existing authenticated Canvas initialization and token-free HTTPS multipart storage exchange. Completion uses a same-origin authenticated GET as specified in the Canvas file upload documentation. A course-scoped read verifies the file ID, MIME type and size before returning a stable course download URL and the local payload SHA-256. Existing filenames are renamed, never overwritten. If an upload outcome is uncertain, inspect course Files before attempting another upload. No automatic retries or page-publication changes occur.

Enabling image upload

Image upload uses the same local write policy and exact course allowlist, plus CANVAS_IMAGE_UPLOAD_ROOT. The tool refuses relative paths, symlinks, files outside that root, files not owned by the current user, unsupported image types, files whose binary signature disagrees with the extension, and files larger than 10 MiB. The exact confirmation is APPROVE CANVAS IMAGE UPLOAD course <course_id>.

Canvas uses a documented three-step upload exchange: initialize the course file through the authenticated API, send the image without the Canvas access token to Canvas's returned HTTPS storage URL, and authenticate the returned same-origin Canvas completion location. The tool then reads /api/v1/courses/<course_id>/files/<file_id> and checks the MIME type and size before returning a persistent course preview path. It never returns storage signatures or the file-download verifier URL.

Current authoring boundary

This project is the source of truth for the shared local Canvas MCP used by supported chats on this Mac. It can author Pages, Modules and module items, Assignments and assignment Rubrics, Discussions, Announcements, and Classic Quizzes with questions after the normal policy and approval gates. It also provides resource-specific deletion tools for Pages, Assignments, Discussions, Classic Quizzes, Modules, and zero-dependency course-owned Rubrics; deleting a Module removes its item placements but not the underlying course content. Its local-file capabilities are the payload-gated image and PowerPoint uploaders described above. Guarded student deactivation, blank-shell creation, and instructor invitations are supported. Generic file upload, New Quizzes, other enrollment changes, cross-listing, template copying, and broader account/course administration remain unsupported.

See docs/2026-08-06-content-authoring-extension.md for the implementation and end-to-end validation record. See docs/2026-08-16-image-upload-extension.md for the image-upload threat model and validation record. See docs/2026-08-24-support-maintenance-extension.md for the first support-maintenance tool contract and validation record. See docs/2026-09-17-announcement-authoring-extension.md for the scheduled-announcement contract and validation record.

Development

python -m pip install -e .
python -m unittest discover -s tests -v
python -m compileall -q src tests

Tests mock network and credential boundaries. See AGENTS.md for invariants contributors must preserve and ROADMAP.md for intentionally deferred administrative features.

Usernames, primary email, and SIS IDs (0.15.0)

Use canvas_preview_user_update followed by canvas_update_user_account for explicitly requested changes to one existing user. Policy version 6 adds approved_user_update_targets; each grant binds the exact account/user/login, field, current value, and replacement value. An explicit human request authorizes the temporary target entry without another conversational confirmation. The server still honors local policy and MCP-client approval. Existing policies remain readable; their user-update list defaults to empty.

Install the new source and reconnect the client once for tool discovery. Future requests only need the temporary exact target in the private policy, removed after verification. A username change does not automatically change email or SIS ID. See contract, authorization, recovery, and API references.

Guarded student invitation (0.17.1)

canvas_preview_student_enrollment checks the exact Canvas user, SIS user, SIS course, section, and built-in StudentEnrollment role. After an explicit human request for that student and course, canvas_enroll_student requires the preview confirmation, an enabled local write policy, and MCP-client approval. No per-student policy entry is needed. The request binds course_id, section_id, canvas_user_id, sis_user_id, sis_course_id, and role_id. An identical active or invited enrollment returns a verified no-op. One deleted enrollment with all six target fields matching can be re-enrolled; any other conflicting enrollment blocks the write. A new invitation notifies the student and is read back, allowing Canvas either to revive the deleted record or to retain it alongside one matching live record. An uncertain result must be inspected before any retry. Policy version 8 omits approved_student_enrollment_targets; older policies remain readable, but version 7 entries no longer authorize or restrict student invitations.

Guarded student account creation (0.18.0)

Verify the student's identity, institutional email, and eligibility in the institution's records before requesting account creation. canvas_preview_user_creation takes account_id, name, short_name, sortable_name, email, and a ten-digit sis_user_id string. It checks the active Canvas root account, the operator's login and SIS permissions, and possible duplicate accounts. The same email is used as the login and contact address. Canvas receives a request to send the account notification.

For an explicitly authorized account, add the preview's approval_fingerprint to approved_user_creation_fingerprints in the private version 9 policy, preserving its enabled state and other grants. Earlier policy versions remain readable and grant no account creation. Call canvas_create_user_account with the same fields and the preview's confirmation under MCP-client approval. The write checks for duplicates again and reads back the names, active login, SIS ID, and contact channel. If the write outcome is uncertain, inspect Canvas before any new attempt. Remove the temporary fingerprint after the attempt. Course enrollment is a separate operation.

API-first workflow

Use the connector API for supported reads and authorized changes. Handle exact temporary policy entries and technical confirmation values within the user's existing authorization. If installed tools are missing from the active session, reconnect before using them; do not switch to browser editing solely because of that setup step. Use the in-app browser only for a capability the connector does not expose or for necessary visual inspection, explaining the limitation first. Permission and approval denials apply regardless of the interface and must never be bypassed.

Available Tools

11 tools
canvas_create_assignmentA
Destructive

Create exactly one Canvas assignment in an approved course. Disabled by default and requires explicit confirmation.

Inputs: name (required), course_id (required), confirmation (required), published, +3 more.

canvas_create_classic_quizA
Destructive

Create exactly one Canvas Classic Quiz in an approved course. New Quizzes are not supported by this tool. Disabled by default and requires explicit confirmation.

Inputs: title (required), course_id (required), confirmation (required), published, +2 more.

canvas_create_classic_quiz_questionA
Destructive

Add one question to an existing Canvas Classic Quiz in an approved course. Disabled by default and requires explicit confirmation.

Inputs: quiz_id (required), course_id (required), confirmation (required), question_name (required), +4 more.

canvas_create_discussionA
Destructive

Create exactly one Canvas discussion in an approved course. Disabled by default and requires explicit confirmation.

Inputs: title (required), message (required), course_id (required), confirmation (required), +2 more.

canvas_create_moduleA
Destructive

Create exactly one Canvas module in an approved course. Disabled by default and requires explicit confirmation.

Inputs: name (required), course_id (required), confirmation (required), position, +1 more.

canvas_create_module_itemA
Destructive

Add one existing Canvas content item or external URL to an existing module in an approved course. Disabled by default and requires explicit confirmation.

Inputs: type (required), title (required), course_id (required), module_id (required), +6 more.

canvas_get_current_userA
Read-only

Read the authenticated Canvas user's profile. Read-only.

Inputs: no named parameters.

canvas_get_write_policyA
Read-only

Show write-policy state and approved course IDs. Does not expose credentials.

Inputs: no named parameters.

canvas_list_modulesA
Read-only

List modules and module items for one Canvas course. Read-only.

Inputs: course_id (required).

canvas_read_apiB
Read-only

Read one Canvas REST API v1 path with GET. Cannot make changes.

Inputs: path (required), query.

canvas_write_pageA
Destructive

Create or update exactly one Canvas page. Disabled by default. Requires a local per-course allowlist, exact user confirmation, and approval of this write action in the MCP client. This is not generic Canvas write access.

Inputs: body (required), title (required), course_id (required), confirmation (required), +2 more.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.9/5.0

    Scored across 11 tools

    Disambiguation5/5

    Each tool targets a distinct Canvas resource and action: user info, module listing, generic API read, write policy, and specific create operations for pages, modules, module items, assignments, discussions, and quizzes. The quiz and quiz-question pair are clearly hierarchical, and the generic read tool is distinct from the specific list tool.

    Naming Consistency4/5

    All tools use the 'canvas_' prefix followed by a verb_noun pattern (get_user, list_modules, create_assignment, etc.). Minor deviations include 'read_api' instead of 'get_api' and 'write_page' instead of 'create_page', but the overall pattern is predictable and consistent.

    Tool Count5/5

    With 11 tools, the set is well-scoped for a Canvas LMS integration focused on reading course structure and creating content items. Each tool has a clear purpose, and the count falls comfortably in the ideal 3-15 range without feeling bloated.

    Completeness3/5

    The tool surface covers reading (user, modules, generic API), creation (pages, modules, module items, assignments, discussions, quizzes, quiz questions), and page updates, but lacks explicit update/delete operations for most created entities. The generic canvas_read_api provides a workaround for reads, but delete operations are entirely absent, leaving a noticeable lifecycle gap.

    Maintenance

    ActivityActive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers