tool_get_grading_progress
Monitor grading progress for an assignment by viewing question-level status, graded submissions count, assigned graders, and completion percentages.
Instructions
Get the grading progress dashboard for an assignment.
Shows each question's grading status: how many submissions have been graded,
assigned graders, and completion percentage. Requires instructor/TA access.
Args:
course_id: The Gradescope course ID.
assignment_id: The assignment ID.Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| course_id | Yes | ||
| assignment_id | Yes |
Implementation Reference
- Implementation of the `get_grading_progress` tool, which fetches the grading dashboard for an assignment and returns a markdown summary of grading progress per question.
def get_grading_progress(course_id: str, assignment_id: str) -> str: """Get the grading progress dashboard for an assignment. Shows each question's grading status: how many submissions have been graded, assigned graders, and completion percentage. Requires instructor/TA access. Args: course_id: The Gradescope course ID. assignment_id: The assignment ID. """ if not course_id or not assignment_id: return "Error: both course_id and assignment_id are required." try: conn = get_connection() url = f"{conn.gradescope_base_url}/courses/{course_id}/assignments/{assignment_id}/grade.json" resp = conn.session.get(url) except AuthError as e: return f"Authentication error: {e}" except Exception as e: return f"Error fetching grading progress: {e}" if resp.status_code != 200: return f"Error: Cannot access grading dashboard (status {resp.status_code})." try: data = resp.json() except Exception: return "Error: Failed to parse grading dashboard response." # Extract assignment data assignments = data.get("assignments", {}) if not assignments: return f"No grading data found for assignment `{assignment_id}`." # assignments can be dict or list if isinstance(assignments, dict): assignment_data = assignments.get(assignment_id, {}) if not assignment_data: # Try first value assignment_data = next(iter(assignments.values()), {}) elif isinstance(assignments, list): assignment_data = assignments[0] if assignments else {} else: assignment_data = {} questions = assignment_data.get("questions", {}) if not questions: return f"No questions found in grading dashboard for assignment `{assignment_id}`." lines = [f"## Grading Progress — Assignment {assignment_id}\n"] # Build question tree for nice formatting total_graded = 0 total_count = 0 lines.append("| Question | Type | Graded | Total | Progress | Graders |") lines.append("|----------|------|--------|-------|----------|---------|") # Group questions — two passes to handle any ordering question_groups = {} # parent_id -> group data with children child_map = {} # parent_id -> list of child questions standalone = [] # First pass: identify groups and collect children for qid, q in questions.items(): if q.get("question_group"): question_groups[q["id"]] = {**q, "children": []} elif q.get("parent_id"): child_map.setdefault(q["parent_id"], []).append(q) else: standalone.append(q) # Second pass: attach children to their groups for parent_id, children in child_map.items(): if parent_id in question_groups: question_groups[parent_id]["children"].extend(children) else: # Parent not found as a group — treat as standalone standalone.extend(children) group_num = 0 for gid, group in sorted(question_groups.items(), key=lambda x: x[1].get("index", 0)): group_num += 1 group_title = group.get("title", "") children = sorted(group.get("children", []), key=lambda x: x.get("index", 0)) for i, child in enumerate(children, 1): graded = child.get("total_graded_count", 0) count = child.get("total_count", 0) total_graded += graded total_count += count pct = f"{graded / count * 100:.0f}%" if count > 0 else "N/A" graders = ", ".join(g.get("name", "?") for g in child.get("graders", [])) child_title = child.get("title", "") label = f"Q{group_num}.{i}" if child_title: label += f" {child_title}" qtype = child.get("type", "") lines.append( f"| {label} (`{child['id']}`) | {qtype} | {graded} | {count} | {pct} | {graders or 'Unassigned'} |" ) for idx, sq in enumerate(sorted(standalone, key=lambda x: x.get("index", 0)), 1): graded_count = sq.get("total_graded_count", 0) count = sq.get("total_count", 0) total_graded += graded_count total_count += count pct = f"{graded_count / count * 100:.0f}%" if count > 0 else "N/A" graders = ", ".join(g.get("name", "?") for g in sq.get("graders", [])) sq_title = sq.get("title", "") label = f"Q{group_num + idx}" if sq_title: label += f" {sq_title}" lines.append( f"| {label} (`{sq['id']}`) | {sq.get('type', '')} | {graded_count} | {count} | {pct} | {graders or 'Unassigned'} |" ) lines.append("") # Summary if total_count > 0: overall_pct = total_graded / total_count * 100 lines.append(f"**Overall progress:** {total_graded}/{total_count} ({overall_pct:.0f}%)") # Action button action = data.get("action_button", {}) if action: lines.append(f"\n**Next step:** [{action.get('text', 'Continue')}]({action.get('link', '')})") return "\n".join(lines) - src/gradescope_mcp/server.py:316-327 (registration)Registration of the `tool_get_grading_progress` MCP tool in the server definition.
@mcp.tool() def tool_get_grading_progress(course_id: str, assignment_id: str) -> str: """Get the grading progress dashboard for an assignment. Shows each question's grading status: how many submissions have been graded, assigned graders, and completion percentage. Requires instructor/TA access. Args: course_id: The Gradescope course ID. assignment_id: The assignment ID. """ return get_grading_progress(course_id, assignment_id)