Skip to main content
Glama

grade_with_rubric

Submit student grades in Canvas by applying rubric criteria with specific point values and comments for each criterion.

Instructions

Submit grades using rubric criteria.

Args: course_identifier: The Canvas course code (e.g., badm_554_120251_246794) or ID assignment_id: The Canvas assignment ID user_id: The Canvas user ID of the student rubric_assessment: JSON string with rubric assessment data (format: {"criterion_id": {"points": X, "comments": "..."}, ...}) comment: Optional overall comment for the submission

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
assignment_idYes
commentNo
course_identifierYes
rubric_assessmentYes
user_idYes

Implementation Reference

  • Main handler for the 'grade_with_rubric' MCP tool. Validates rubric setup, builds form-encoded data using helper function, and submits grades via Canvas API PUT /submissions/{user_id}.
    @mcp.tool() @validate_params async def grade_with_rubric(course_identifier: str | int, assignment_id: str | int, user_id: str | int, rubric_assessment: dict[str, Any], comment: str | None = None) -> str: """Submit grades using rubric criteria. This tool submits grades for individual rubric criteria. The rubric must already be associated with the assignment and configured for grading (use_for_grading=true). IMPORTANT NOTES: - Criterion IDs often start with underscore (e.g., "_8027") - Use list_assignment_rubrics or get_rubric_details to find criterion IDs and rating IDs - Points must be within the range defined by the rubric criterion - The rubric must be attached to the assignment before grading Args: course_identifier: The Canvas course code (e.g., badm_554_120251_246794) or ID assignment_id: The Canvas assignment ID user_id: The Canvas user ID of the student rubric_assessment: Dict mapping criterion IDs to assessment data Format: { "criterion_id": { "points": <number>, # Required: points awarded "rating_id": "<string>", # Optional: specific rating ID "comments": "<string>" # Optional: feedback comments } } comment: Optional overall comment for the submission Example Usage: { "course_identifier": "60366", "assignment_id": "1440586", "user_id": "9824", "rubric_assessment": { "_8027": { "points": 2, "rating_id": "blank", "comments": "Great work!" } }, "comment": "Nice job on this assignment" } """ course_id = await get_course_id(course_identifier) assignment_id_str = str(assignment_id) user_id_str = str(user_id) # CRITICAL: Verify rubric is configured for grading BEFORE submitting assignment_check = await make_canvas_request( "get", f"/courses/{course_id}/assignments/{assignment_id_str}", params={"include[]": ["rubric_settings"]} ) if "error" not in assignment_check: use_rubric_for_grading = assignment_check.get("use_rubric_for_grading", False) if not use_rubric_for_grading: return ( "⚠️ ERROR: Rubric is not configured for grading!\n\n" "The rubric exists but 'use_for_grading' is set to FALSE.\n" "Grades will NOT be saved to the gradebook.\n\n" "To fix this:\n" "1. Use list_assignment_rubrics to verify rubric settings\n" "2. Use associate_rubric_with_assignment with use_for_grading=True\n" "3. Or configure the rubric in Canvas UI: Assignment Settings → Rubric → Use for Grading\n\n" f"Assignment: {assignment_check.get('name', 'Unknown')}\n" f"Course ID: {course_id}\n" f"Assignment ID: {assignment_id}\n" ) # Build form data in Canvas's expected format form_data = build_rubric_assessment_form_data(rubric_assessment, comment) # Submit the grade with rubric assessment using form encoding response = await make_canvas_request( "put", f"/courses/{course_id}/assignments/{assignment_id_str}/submissions/{user_id_str}", data=form_data, use_form_data=True ) if "error" in response: return f"Error submitting rubric grade: {response['error']}" # Get assignment details for confirmation assignment_response = await make_canvas_request( "get", f"/courses/{course_id}/assignments/{assignment_id_str}" ) assignment_name = assignment_response.get("name", "Unknown Assignment") if "error" not in assignment_response else "Unknown Assignment" # Calculate total points from rubric assessment total_points = sum(criterion.get("points", 0) for criterion in rubric_assessment.values()) course_display = await get_course_code(course_id) or course_identifier result = "Rubric Grade Submitted Successfully!\n\n" result += f"Course: {course_display}\n" result += f"Assignment: {assignment_name}\n" result += f"Student ID: {user_id}\n" result += f"Total Rubric Points: {total_points}\n" result += f"Grade: {response.get('grade', 'N/A')}\n" result += f"Score: {response.get('score', 'N/A')}\n" result += f"Graded At: {format_date(response.get('graded_at'))}\n" if comment: result += f"Overall Comment: {comment}\n" result += "\nRubric Assessment Summary:\n" for criterion_id, assessment in rubric_assessment.items(): points = assessment.get("points", 0) rating_id = assessment.get("rating_id", "") comments = assessment.get("comments", "") result += f" Criterion {criterion_id}: {points} points" if rating_id: result += f" (Rating: {rating_id})" if comments: result += f"\n Comment: {truncate_text(comments, 100)}" result += "\n" return result
  • Helper function that converts the rubric_assessment dictionary into the form-encoded format required by Canvas API for submission grading.
    def build_rubric_assessment_form_data( rubric_assessment: dict[str, Any], comment: str | None = None ) -> dict[str, str]: """Convert rubric assessment dict to Canvas form-encoded format. Canvas API expects rubric assessment data as form-encoded parameters with bracket notation: rubric_assessment[criterion_id][field]=value Args: rubric_assessment: Dict mapping criterion IDs to assessment data Format: {"criterion_id": {"points": X, "rating_id": Y, "comments": Z}} comment: Optional overall comment for the submission Returns: Flattened dict with Canvas bracket notation keys Example: Input: {"_8027": {"points": 2, "rating_id": "blank", "comments": "Great work"}} Output: { "rubric_assessment[_8027][points]": "2", "rubric_assessment[_8027][rating_id]": "blank", "rubric_assessment[_8027][comments]": "Great work" } """ form_data: dict[str, str] = {} # Transform rubric_assessment object into Canvas's form-encoded format for criterion_id, assessment in rubric_assessment.items(): # Points are required if "points" in assessment: form_data[f"rubric_assessment[{criterion_id}][points]"] = str(assessment["points"]) # Rating ID is optional but recommended if "rating_id" in assessment: form_data[f"rubric_assessment[{criterion_id}][rating_id]"] = str(assessment["rating_id"]) # Comments are optional if "comments" in assessment: form_data[f"rubric_assessment[{criterion_id}][comments]"] = str(assessment["comments"]) # Add optional overall comment if comment: form_data["comment[text_comment]"] = comment return form_data
  • The register_all_tools function calls register_rubric_tools(mcp), which in turn defines and registers the grade_with_rubric tool using @mcp.tool() decorator.
    def register_all_tools(mcp: FastMCP) -> None: """Register all MCP tools, resources, and prompts.""" log_info("Registering Canvas MCP tools...") # Register tools by category register_course_tools(mcp) register_assignment_tools(mcp) register_discussion_tools(mcp) register_other_tools(mcp) register_rubric_tools(mcp) register_peer_review_tools(mcp) register_peer_review_comment_tools(mcp) register_messaging_tools(mcp) register_student_tools(mcp) register_accessibility_tools(mcp) register_discovery_tools(mcp) register_code_execution_tools(mcp) # Register resources and prompts register_resources_and_prompts(mcp) log_info("All Canvas MCP tools registered successfully!")
  • TypeScript helper function providing equivalent functionality, used in code_execution tool for bulk operations.
    export async function gradeWithRubric( input: GradeWithRubricInput ): Promise<GradeResponse> { const { courseIdentifier, assignmentId, userId, rubricAssessment, grade, comment } = input; // Validate: Must have either rubricAssessment OR grade if (!rubricAssessment && !grade && grade !== 0) { throw new Error('Must provide either rubricAssessment or grade'); } let formData: Record<string, string> = {}; // Handle rubric-based grading if (rubricAssessment && Object.keys(rubricAssessment).length > 0) { validateRubricAssessment(rubricAssessment); formData = buildRubricAssessmentFormData(rubricAssessment, comment); } // Handle simple grading else if (grade !== undefined) { formData['submission[posted_grade]'] = String(grade); if (comment) { formData['comment[text_comment]'] = comment; } } // Canvas API endpoint for updating submission const endpoint = `/courses/${courseIdentifier}/assignments/${assignmentId}/submissions/${userId}`; try { // Submit the grade with rubric assessment using form encoding const response = await canvasPutForm<GradeResponse>(endpoint, formData); return response; } catch (error: any) { throw new Error( `Failed to grade submission: ${error.message}\n` + `Check that rubric is configured for grading and criterion IDs are correct.` ); } }
  • TypeScript interface defining the input schema for gradeWithRubric, matching the MCP tool parameters.
    export interface GradeWithRubricInput { courseIdentifier: string | number; assignmentId: string | number; userId: string | number; rubricAssessment?: Record<string, { points: number; ratingId?: string; comments?: string; }>; grade?: string | number; comment?: string; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/vishalsachdev/canvas-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server