Canvas MCP server presents a moderate-quality implementation with 30 tools covering Canvas LMS features. Strengths: all tools have descriptions and input schemas with typed parameters. Weaknesses: descriptions lack depth and strategic guidance for LLM selection; output schemas are undocumented; error handling is absent; no parameter validation examples; tool composition could be tighter. The server implements basic JSON Schema structure but falls short of production-grade polish. Average tool score is 62/100.
Output schemas are completely undocumented. No tool declares what fields it returns, their types, or relationships. LLMs cannot plan multi-step sequences without knowing what data comes back (e.g., does list_courses return course_id? course_name? both?). This forces agents into guesswork and requires 'try and see' exploration.
Document output schemas for all 30 tools in code comments or a schema file. Each schema should specify field names, types, and which fields are required for downstream tool chaining. Example: 'Returns {course_id (int), course_name (string), enrollment_state (string)}'.
Expand tool descriptions to 100 - 150 characters. Add WHEN and WHY context. Example: 'List all assignments for a course. Call this first to see available assignments before submitting. If you only have a course name, use list_courses() to get the course_id.'
Add pagination support to all list_* tools: parameters (limit=20, offset=0 or cursor='<next>') and return fields (total_count, has_more, next_cursor).
Implement error handling. Wrap API calls in try-catch blocks. For 404 errors, return: 'Course not found (ID: 123). Available courses: Math 101, Physics 201.' For validation errors, return: 'Invalid submission_type: got "file", must be one of: online_text_entry, online_url, online_upload'.
Add confirmation or dry-run for destructive tools. delete_conversation should accept a 'confirm=true' flag. If false (default), return a preview: 'Would delete conversation with [recipient names] from [date]. Pass confirm=true to proceed.'
Add tool annotations to tool definitions. Example: `Tool { name: 'delete_conversation', ..., destructiveHint: true }`, so MCP clients can apply UI warnings.
Combine fine-grained conversation state tools into a single 'update_conversation' tool: parameters (conversation_id, action='mark_read'|'mark_unread'|'star'|'unstar'|'archive'), returning updated conversation state.
Descriptions are too generic and lack strategic context. Examples: 'Get information about the currently authenticated user' does not explain WHEN to call this vs. alternatives, what fields it returns, or whether it requires authentication checks. Baseline from rubric: descriptions should be 10 - 1024 characters and answer WHAT, WHEN, and prerequisites. Most Canvas descriptions are 40 - 70 characters and answer only WHAT.
No error handling or recovery guidance. If a call fails (e.g., 'course not found', 'submission invalid'), the LLM has no instruction on what to do next. Rubric requires error responses to say: 'User not found. Try search_users() with a partial name.' Current implementation likely returns raw API errors or generic 500 responses.
Parameter validation rules are missing. For example, list_conversations has an enum on 'scope' (inbox, unread, starred, sent, archived), which is good, but list_calendar_events accepts 'start_date' and 'end_date' as strings with no format constraint, range check, or example. LLMs will pass invalid dates (e.g., '2024-13-45'). Descriptions should state: 'ISO 8601 format only (YYYY-MM-DD), start_date must be before end_date'.
Destructive operations lack confirmation or dry-run. delete_conversation is marked DESTRUCTIVE but has no confirmation step, dry-run option, or warning in the description. Agents make mistakes, a single hallucinated call can delete a user's conversation. Rubric requires: 'Irreversible operations should support a dry-run or confirmation step.'
No pagination support visible in list tools. list_courses, list_assignments, list_conversations, list_files, list_quizzes, list_todos, and list_announcements have no limit, offset, or cursor parameters. If a user has 500+ courses, the response will bloat context. Rubric baseline: list tools should accept page/offset and limit (default ~20), and return a total count or next_cursor.
No tool annotations (readOnlyHint, destructiveHint, idempotentHint) visible. Tools like delete_conversation, submit_assignment, and create_conversation should declare destructiveHint: true so MCP clients can warn or confirm before execution. Tool annotations are part of the current 2026-07-28 spec.
Conversation management tools (mark_read, mark_unread, star, unstar, archive) are too fine-grained. Five separate tools to manipulate a single conversation state invite orchestration overhead and LLM confusion. Consider combining into a single 'update_conversation' tool with action enums, or batch operations.
Required parameters lack human-friendly identifiers. Many tools require numeric IDs (course_id, assignment_id, conversation_id) but users speak in names ('Math 101', 'Calculus Midterm', 'Chat with Professor'). Tools should accept both IDs and names, or the server should provide a search/lookup first. Current design forces extra discovery calls.
Missing context in multi-step workflows. For example, list_courses returns courses, but does it return course_id, course_name, and enrollment_state in the response? If get_course requires course_id, the list response MUST include course_id. Undocumented output schemas make tool chaining unclear.
Accept human-friendly identifiers alongside IDs. Example: get_course should accept (course_id: int) OR (course_name: string). Internally, search for the match, or document that callers must use list_courses() to look up IDs first.
Add validation examples to parameter descriptions. Example: 'submission_type (required, string): must be one of online_text_entry, online_url, or online_upload. For online_text_entry, populate body parameter.'
Add field-level dependency documentation. Example: 'If submission_type is online_text_entry, body is required. If online_url, url is required. If online_upload, file_ids is required.' Currently ambiguous which fields apply to which submission types.