Koskamo

Zovo Gradebook MCP

An MCP server for Zovo Gradebook that allows agents to compute weighted class grades, handle missing or excused work, generate progress reports, and calculate final scores. It supports pasting scores or importing from Google Classroom/Canvas exports, applying category weights, dropping lowest scores, and producing Excel or PDF outputs.

Endpoint and access

No sign-in to connect and list tools. Individual tools may still need a vendor account, credentials, or permissions; check the documented prerequisites.

Zovo Gradebook MCP logo, by ZovoCommunity listingStreamable HTTPNo sign-inEndpoint checked 2026-11-08Published by Zovo
MCP endpoint (Streamable HTTP)
https://gradebook.zovo.one/mcp
Vendor documentation

What its tools do

3 tools, grouped by the hints the server advertises. Hints are self-declared, not verified behavior.

3 of 3 have a description · 3 of 3 declare behavior hints · 3 of 3 with parameters document them all

Checks and signals

Each line is separate evidence, not a trust score.

  • Passed Endpoint answered the live check ·
  • Availability 1 of 1 checks passed in 30 days

What you can do with it

  • Compute weighted final grades for a class
  • Generate printable progress reports per student
  • Calculate required final exam score for a target grade
  • Import and process Canvas or Google Classroom exports

Source and maintenance

Community listingRegistry 1.0.1

Protocol and capabilities

Server
gradebook 1.0.1
MCP protocol negotiated in check
2025-11-25
Tools
3 advertised
Resources
1 advertised
Resource templates
1 advertised
Prompts
Not advertised
Server-advertised capabilities
{
  "tools": {
    "listChanged": true
  },
  "resources": {
    "listChanged": true
  }
}

Server-provided instructions

Untrusted server output shown for inspection. It is not Koskamo guidance and is excluded from knowledge search.

Zovo Gradebook is a weighted grade calculator for teachers and tutors. calculate_class_grades takes a roster of scores (pasted table or a Google Classroom / Canvas CSV or XLSX export) with category weights and returns each student's final percent and letter, class stats, missing work and an Excel gradebook. generate_progress_reports makes one printable progress report page per student (PDF). calculate_grade_needed gives the score needed on the final for a target grade. Pass the user's table verbatim; do not compute grades yourself. Student data is not stored; download links expire in about an hour.

Tools

3 advertised

calculate_class_grades — Calculate class grades
Advertised by the server during the last successful anonymous check.
Advertised read-only

Use this when a teacher or tutor wants a weighted grade calculator for a whole class; list ID and info columns (student number, StudentID, email, SIS, section) in ignore_columns so they stay out of the grades. Examples: final grades from a gradebook, 'calculate my students' grades with Homework 20%, Quizzes 30%, Tests 50%', a gradebook template filled in, class average, or who is missing work. Takes a roster of scores (pasted table, list, or a Google Classroom / Canvas CSV or XLSX export as file) plus optional category weights, points possible, drop lowest per category, blank handling, extra credit and letter scale. Returns each student's final percent and letter (fraction math, rounded only for display), category scores, weights renormalized when a category has no graded work, class mean/median/distribution, missing-work list, and Excel + CSV downloads. Does not store data, connect to a school system, or make progress report PDFs (use generate_progress_reports).

calculate_class_grades input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "properties": {
    "file": {
      "type": "object",
      "required": [
        "download_url",
        "file_id"
      ],
      "properties": {
        "file_id": {
          "type": "string",
          "description": "ChatGPT file id, e.g. file_abc123."
        },
        "file_name": {
          "type": "string",
          "description": "Original file name if known, e.g. statement.pdf."
        },
        "mime_type": {
          "type": "string",
          "description": "Media type if known, e.g. application/pdf."
        },
        "download_url": {
          "type": "string",
          "description": "Temporary download link for the file, supplied by ChatGPT."
        }
      },
      "description": "A gradebook export as CSV or XLSX, e.g. the Google Classroom grades CSV or the Canvas gradebook export. One row per student, one column per assignment."
    },
    "term": {
      "type": "string",
      "maxLength": 60,
      "description": "Grading period, e.g. Fall 2026 Quarter 1."
    },
    "roster": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 300000
        },
        {
          "type": "array",
          "items": {},
          "maxItems": 3000
        },
        {
          "type": "object",
          "propertyNames": {
            "type": "string"
          },
          "additionalProperties": {}
        }
      ],
      "description": "The scores, one row per student: a pasted table (CSV, tab-separated or a markdown table) with a header row of assignment names, e.g. \"Student, HW1, HW2, Quiz 1, Test 1\\nAna Diaz, 18, 20, 9, 45\\nBen Ito, 15, EX, 7, M\". Also accepts a list of rows or [{\"name\":\"Ana Diaz\",\"scores\":{\"HW1\":18,\"Quiz 1\":9}}]. Send this or file."
    },
    "blank_as": {
      "type": "string",
      "maxLength": 30,
      "description": "How to treat empty cells: not_graded (default, left out) or zero (count as 0). EX means excused (left out); M or missing counts as 0."
    },
    "students": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 300000
        },
        {
          "type": "array",
          "items": {},
          "maxItems": 3000
        },
        {
          "type": "object",
          "propertyNames": {
            "type": "string"
          },
          "additionalProperties": {}
        }
      ],
      "description": "Same as roster (either name works), e.g. [{\"name\":\"Ana Diaz\",\"scores\":{\"HW1\":18}}]."
    },
    "id_column": {
      "type": "string",
      "maxLength": 120,
      "description": "The header of the student ID / student number column, if any, e.g. \"StudentID\". It is ignored (same as ignore_columns)."
    },
    "categories": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 300000
        },
        {
          "type": "array",
          "items": {},
          "maxItems": 3000
        },
        {
          "type": "object",
          "propertyNames": {
            "type": "string"
          },
          "additionalProperties": {}
        }
      ],
      "description": "Category weights, e.g. \"Homework 20%, Quizzes 30%, Tests 50%\" or [{\"name\":\"Quizzes\",\"weight\":30,\"drop_lowest\":1}]. Assignments are matched to categories by name (HW 3 -> Homework, Quiz 2 -> Quizzes, Unit Test -> Tests). Leave out for a total-points grade."
    },
    "class_name": {
      "type": "string",
      "maxLength": 120,
      "description": "Class name for the files, e.g. Algebra 1, Period 3."
    },
    "plus_minus": {
      "anyOf": [
        {
          "type": "boolean"
        },
        {
          "type": "string",
          "maxLength": 10
        }
      ],
      "description": "true for +/- letters (A+ 97, A 93, A- 90, ...). Default false."
    },
    "assignments": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 300000
        },
        {
          "type": "array",
          "items": {},
          "maxItems": 3000
        },
        {
          "type": "object",
          "propertyNames": {
            "type": "string"
          },
          "additionalProperties": {}
        }
      ],
      "description": "Optional details per assignment when names do not show the category or the points: [{\"name\":\"Unit 1\",\"category\":\"Tests\",\"points_possible\":50}], or lines like \"Unit 1, Tests, 50\". Mark bonus work with \"extra_credit\": true."
    },
    "drop_lowest": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "string",
          "maxLength": 400
        },
        {
          "type": "object",
          "propertyNames": {
            "type": "string"
          },
          "additionalProperties": {}
        },
        {
          "type": "array",
          "items": {},
          "maxItems": 30
        }
      ],
      "description": "Drop each student's lowest scores per category, e.g. {\"Quizzes\": 1} or \"Quizzes 1, Homework 2\". A plain number applies to every category."
    },
    "letter_scale": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 300000
        },
        {
          "type": "array",
          "items": {},
          "maxItems": 3000
        },
        {
          "type": "object",
          "propertyNames": {
            "type": "string"
          },
          "additionalProperties": {}
        }
      ],
      "description": "Letter cutoffs. Default A 90, B 80, C 70, D 60, F below 60. Use \"plus_minus\" for A+ 97 / A 93 / A- 90 ... D- 60, or a custom list like \"A 93, B 85, C 75, D 65\"."
    },
    "teacher_name": {
      "type": "string",
      "maxLength": 80,
      "description": "Teacher or tutor name for the reports, e.g. Ms. Rivera."
    },
    "ignore_columns": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 2000
        },
        {
          "type": "array",
          "items": {
            "type": "string",
            "maxLength": 120
          },
          "maxItems": 50
        }
      ],
      "description": "Columns that are not scores and must not be graded or copied, by header name: student IDs, student numbers, SIS/login/email, section, notes. Example: [\"Student Number\", \"Email\"] or \"StudentID, Nr albumu\". Always name ID and info columns here."
    },
    "points_possible": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "string",
          "maxLength": 4000
        },
        {
          "type": "array",
          "items": {},
          "maxItems": 300
        },
        {
          "type": "object",
          "propertyNames": {
            "type": "string"
          },
          "additionalProperties": {}
        }
      ],
      "description": "Points possible when the table does not say: one number for every assignment (e.g. 100), a list in column order (e.g. \"20, 20, 10, 50\"), or {\"Quiz 1\": 10}. A 'Points possible' row in the table or headers like \"Quiz 1 (10)\" also work. Default 100."
    },
    "category_scoring": {
      "type": "string",
      "maxLength": 20,
      "description": "How a category score is built: points (default, total points earned / possible in the category) or average (each assignment counts equally)."
    },
    "round_for_letter": {
      "anyOf": [
        {
          "type": "boolean"
        },
        {
          "type": "string",
          "maxLength": 10
        }
      ],
      "description": "true to round the final percent to a whole number before picking the letter (89.5 -> 90 -> A). Default false: 89.5 is a B."
    }
  }
}
calculate_class_grades output schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "kind",
    "class_name",
    "grading",
    "letter_scale",
    "students_count",
    "graded_count",
    "assignments_count",
    "stats",
    "distribution",
    "categories",
    "students",
    "students_shown",
    "missing_work",
    "missing_total",
    "notes",
    "warnings",
    "downloads",
    "privacy"
  ],
  "properties": {
    "kind": {
      "type": "string"
    },
    "notes": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "pages": {
      "type": "number"
    },
    "stats": {
      "type": "object",
      "required": [
        "mean",
        "median",
        "min",
        "max",
        "stdev"
      ],
      "properties": {
        "max": {
          "type": [
            "number",
            "null"
          ]
        },
        "min": {
          "type": [
            "number",
            "null"
          ]
        },
        "mean": {
          "type": [
            "number",
            "null"
          ]
        },
        "stdev": {
          "type": [
            "number",
            "null"
          ]
        },
        "median": {
          "type": [
            "number",
            "null"
          ]
        }
      },
      "additionalProperties": false
    },
    "grading": {
      "type": "string"
    },
    "privacy": {
      "type": "string"
    },
    "students": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "name",
          "final",
          "letter",
          "missing"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "final": {
            "type": [
              "number",
              "null"
            ]
          },
          "letter": {
            "type": "string"
          },
          "missing": {
            "type": "number"
          }
        },
        "additionalProperties": false
      }
    },
    "warnings": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "downloads": {
      "type": "object",
      "properties": {
        "csv": {
          "type": "string"
        },
        "pdf": {
          "type": "string"
        },
        "xlsx": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "categories": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "name",
          "weight",
          "drop_lowest",
          "class_average",
          "assignments"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "weight": {
            "type": [
              "number",
              "null"
            ]
          },
          "assignments": {
            "type": "number"
          },
          "drop_lowest": {
            "type": "number"
          },
          "class_average": {
            "type": [
              "number",
              "null"
            ]
          }
        },
        "additionalProperties": false
      }
    },
    "class_name": {
      "type": [
        "string",
        "null"
      ]
    },
    "distribution": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "letter",
          "count"
        ],
        "properties": {
          "count": {
            "type": "number"
          },
          "letter": {
            "type": "string"
          }
        },
        "additionalProperties": false
      }
    },
    "graded_count": {
      "type": "number"
    },
    "letter_scale": {
      "type": "string"
    },
    "missing_work": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "student",
          "assignments"
        ],
        "properties": {
          "student": {
            "type": "string"
          },
          "assignments": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "additionalProperties": false
      }
    },
    "missing_total": {
      "type": "number"
    },
    "students_count": {
      "type": "number"
    },
    "students_shown": {
      "type": "number"
    },
    "assignments_count": {
      "type": "number"
    }
  },
  "additionalProperties": false
}
calculate_class_grades annotations
{
  "title": "Calculate class grades",
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
generate_progress_reports — Generate progress reports
Advertised by the server during the last successful anonymous check.
Advertised read-only

Use this when the user wants a progress report template filled in for students; list ID and info columns (student number, StudentID, email, SIS, section) in ignore_columns so they stay out of the grades. Examples: printable progress reports, grade reports for parents, 'make a progress report for each student'. Takes the same roster and grading settings as calculate_class_grades plus optional teacher comments per student, class name, teacher, term, report date and a subset of students. Returns one PDF with one page per student (current grade and letter, category scores, each assignment with excused/missing/dropped marks, missing work list, comment) and the Excel gradebook. Does not email or post reports, and does not store data.

generate_progress_reports input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "properties": {
    "file": {
      "type": "object",
      "required": [
        "download_url",
        "file_id"
      ],
      "properties": {
        "file_id": {
          "type": "string",
          "description": "ChatGPT file id, e.g. file_abc123."
        },
        "file_name": {
          "type": "string",
          "description": "Original file name if known, e.g. statement.pdf."
        },
        "mime_type": {
          "type": "string",
          "description": "Media type if known, e.g. application/pdf."
        },
        "download_url": {
          "type": "string",
          "description": "Temporary download link for the file, supplied by ChatGPT."
        }
      },
      "description": "A gradebook export as CSV or XLSX, e.g. the Google Classroom grades CSV or the Canvas gradebook export. One row per student, one column per assignment."
    },
    "term": {
      "type": "string",
      "maxLength": 60,
      "description": "Grading period, e.g. Fall 2026 Quarter 1."
    },
    "paper": {
      "type": "string",
      "maxLength": 20,
      "description": "letter (default) or a4."
    },
    "roster": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 300000
        },
        {
          "type": "array",
          "items": {},
          "maxItems": 3000
        },
        {
          "type": "object",
          "propertyNames": {
            "type": "string"
          },
          "additionalProperties": {}
        }
      ],
      "description": "The scores, one row per student: a pasted table (CSV, tab-separated or a markdown table) with a header row of assignment names, e.g. \"Student, HW1, HW2, Quiz 1, Test 1\\nAna Diaz, 18, 20, 9, 45\\nBen Ito, 15, EX, 7, M\". Also accepts a list of rows or [{\"name\":\"Ana Diaz\",\"scores\":{\"HW1\":18,\"Quiz 1\":9}}]. Send this or file."
    },
    "blank_as": {
      "type": "string",
      "maxLength": 30,
      "description": "How to treat empty cells: not_graded (default, left out) or zero (count as 0). EX means excused (left out); M or missing counts as 0."
    },
    "comments": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 300000
        },
        {
          "type": "array",
          "items": {},
          "maxItems": 3000
        },
        {
          "type": "object",
          "propertyNames": {
            "type": "string"
          },
          "additionalProperties": {}
        }
      ],
      "description": "Optional teacher comment per student, e.g. {\"Ana Diaz\":\"Strong quiz scores; turn in HW 3.\"} or lines \"Ana Diaz: Strong quiz scores\"."
    },
    "students": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 300000
        },
        {
          "type": "array",
          "items": {},
          "maxItems": 3000
        },
        {
          "type": "object",
          "propertyNames": {
            "type": "string"
          },
          "additionalProperties": {}
        }
      ],
      "description": "Same as roster (either name works), e.g. [{\"name\":\"Ana Diaz\",\"scores\":{\"HW1\":18}}]."
    },
    "id_column": {
      "type": "string",
      "maxLength": 120,
      "description": "The header of the student ID / student number column, if any, e.g. \"StudentID\". It is ignored (same as ignore_columns)."
    },
    "categories": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 300000
        },
        {
          "type": "array",
          "items": {},
          "maxItems": 3000
        },
        {
          "type": "object",
          "propertyNames": {
            "type": "string"
          },
          "additionalProperties": {}
        }
      ],
      "description": "Category weights, e.g. \"Homework 20%, Quizzes 30%, Tests 50%\" or [{\"name\":\"Quizzes\",\"weight\":30,\"drop_lowest\":1}]. Assignments are matched to categories by name (HW 3 -> Homework, Quiz 2 -> Quizzes, Unit Test -> Tests). Leave out for a total-points grade."
    },
    "class_name": {
      "type": "string",
      "maxLength": 120,
      "description": "Class name for the files, e.g. Algebra 1, Period 3."
    },
    "plus_minus": {
      "anyOf": [
        {
          "type": "boolean"
        },
        {
          "type": "string",
          "maxLength": 10
        }
      ],
      "description": "true for +/- letters (A+ 97, A 93, A- 90, ...). Default false."
    },
    "assignments": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 300000
        },
        {
          "type": "array",
          "items": {},
          "maxItems": 3000
        },
        {
          "type": "object",
          "propertyNames": {
            "type": "string"
          },
          "additionalProperties": {}
        }
      ],
      "description": "Optional details per assignment when names do not show the category or the points: [{\"name\":\"Unit 1\",\"category\":\"Tests\",\"points_possible\":50}], or lines like \"Unit 1, Tests, 50\". Mark bonus work with \"extra_credit\": true."
    },
    "drop_lowest": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "string",
          "maxLength": 400
        },
        {
          "type": "object",
          "propertyNames": {
            "type": "string"
          },
          "additionalProperties": {}
        },
        {
          "type": "array",
          "items": {},
          "maxItems": 30
        }
      ],
      "description": "Drop each student's lowest scores per category, e.g. {\"Quizzes\": 1} or \"Quizzes 1, Homework 2\". A plain number applies to every category."
    },
    "report_date": {
      "type": "string",
      "maxLength": 40,
      "description": "Date printed on the reports, e.g. October 26, 2026. Default: today (US Eastern)."
    },
    "letter_scale": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 300000
        },
        {
          "type": "array",
          "items": {},
          "maxItems": 3000
        },
        {
          "type": "object",
          "propertyNames": {
            "type": "string"
          },
          "additionalProperties": {}
        }
      ],
      "description": "Letter cutoffs. Default A 90, B 80, C 70, D 60, F below 60. Use \"plus_minus\" for A+ 97 / A 93 / A- 90 ... D- 60, or a custom list like \"A 93, B 85, C 75, D 65\"."
    },
    "teacher_name": {
      "type": "string",
      "maxLength": 80,
      "description": "Teacher or tutor name for the reports, e.g. Ms. Rivera."
    },
    "only_students": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 300000
        },
        {
          "type": "array",
          "items": {},
          "maxItems": 3000
        },
        {
          "type": "object",
          "propertyNames": {
            "type": "string"
          },
          "additionalProperties": {}
        }
      ],
      "description": "Optional subset of student names to print, e.g. \"Ana Diaz, Ben Ito\". Default: every student."
    },
    "ignore_columns": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 2000
        },
        {
          "type": "array",
          "items": {
            "type": "string",
            "maxLength": 120
          },
          "maxItems": 50
        }
      ],
      "description": "Columns that are not scores and must not be graded or copied, by header name: student IDs, student numbers, SIS/login/email, section, notes. Example: [\"Student Number\", \"Email\"] or \"StudentID, Nr albumu\". Always name ID and info columns here."
    },
    "points_possible": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "string",
          "maxLength": 4000
        },
        {
          "type": "array",
          "items": {},
          "maxItems": 300
        },
        {
          "type": "object",
          "propertyNames": {
            "type": "string"
          },
          "additionalProperties": {}
        }
      ],
      "description": "Points possible when the table does not say: one number for every assignment (e.g. 100), a list in column order (e.g. \"20, 20, 10, 50\"), or {\"Quiz 1\": 10}. A 'Points possible' row in the table or headers like \"Quiz 1 (10)\" also work. Default 100."
    },
    "category_scoring": {
      "type": "string",
      "maxLength": 20,
      "description": "How a category score is built: points (default, total points earned / possible in the category) or average (each assignment counts equally)."
    },
    "round_for_letter": {
      "anyOf": [
        {
          "type": "boolean"
        },
        {
          "type": "string",
          "maxLength": 10
        }
      ],
      "description": "true to round the final percent to a whole number before picking the letter (89.5 -> 90 -> A). Default false: 89.5 is a B."
    },
    "show_class_average": {
      "anyOf": [
        {
          "type": "boolean"
        },
        {
          "type": "string",
          "maxLength": 10
        }
      ],
      "description": "Print the class average on each report. Default true."
    }
  }
}
generate_progress_reports output schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "kind",
    "class_name",
    "grading",
    "letter_scale",
    "students_count",
    "graded_count",
    "assignments_count",
    "stats",
    "distribution",
    "categories",
    "students",
    "students_shown",
    "missing_work",
    "missing_total",
    "notes",
    "warnings",
    "downloads",
    "privacy"
  ],
  "properties": {
    "kind": {
      "type": "string"
    },
    "notes": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "pages": {
      "type": "number"
    },
    "stats": {
      "type": "object",
      "required": [
        "mean",
        "median",
        "min",
        "max",
        "stdev"
      ],
      "properties": {
        "max": {
          "type": [
            "number",
            "null"
          ]
        },
        "min": {
          "type": [
            "number",
            "null"
          ]
        },
        "mean": {
          "type": [
            "number",
            "null"
          ]
        },
        "stdev": {
          "type": [
            "number",
            "null"
          ]
        },
        "median": {
          "type": [
            "number",
            "null"
          ]
        }
      },
      "additionalProperties": false
    },
    "grading": {
      "type": "string"
    },
    "privacy": {
      "type": "string"
    },
    "students": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "name",
          "final",
          "letter",
          "missing"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "final": {
            "type": [
              "number",
              "null"
            ]
          },
          "letter": {
            "type": "string"
          },
          "missing": {
            "type": "number"
          }
        },
        "additionalProperties": false
      }
    },
    "warnings": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "downloads": {
      "type": "object",
      "properties": {
        "csv": {
          "type": "string"
        },
        "pdf": {
          "type": "string"
        },
        "xlsx": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "categories": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "name",
          "weight",
          "drop_lowest",
          "class_average",
          "assignments"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "weight": {
            "type": [
              "number",
              "null"
            ]
          },
          "assignments": {
            "type": "number"
          },
          "drop_lowest": {
            "type": "number"
          },
          "class_average": {
            "type": [
              "number",
              "null"
            ]
          }
        },
        "additionalProperties": false
      }
    },
    "class_name": {
      "type": [
        "string",
        "null"
      ]
    },
    "distribution": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "letter",
          "count"
        ],
        "properties": {
          "count": {
            "type": "number"
          },
          "letter": {
            "type": "string"
          }
        },
        "additionalProperties": false
      }
    },
    "graded_count": {
      "type": "number"
    },
    "letter_scale": {
      "type": "string"
    },
    "missing_work": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "student",
          "assignments"
        ],
        "properties": {
          "student": {
            "type": "string"
          },
          "assignments": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "additionalProperties": false
      }
    },
    "missing_total": {
      "type": "number"
    },
    "students_count": {
      "type": "number"
    },
    "students_shown": {
      "type": "number"
    },
    "assignments_count": {
      "type": "number"
    }
  },
  "additionalProperties": false
}
generate_progress_reports annotations
{
  "title": "Generate progress reports",
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
calculate_grade_needed — Calculate grade needed on the final
Advertised by the server during the last successful anonymous check.
Advertised read-only

Use this when someone asks what they need on the final: 'what do I need on my final to get a B', final grade calculator, score needed on the final exam to pass, or a teacher asking what each student needs on the final for a C. Takes the current grade percent (or a list of students with current grades), how much the final is worth, and a target percent or letter (default all letters on the scale). Returns the score needed on the final for each target (and the points needed when final points are given), whether it is reachable, and what-if course grades. Assumes the final is a separate weight on top of the current grade; does not model a final inside a weighted category.

calculate_grade_needed input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "final_weight"
  ],
  "properties": {
    "target": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "string",
          "maxLength": 200
        },
        {
          "type": "array",
          "items": {
            "type": [
              "number",
              "string"
            ]
          },
          "maxItems": 20
        }
      ],
      "description": "The course grade wanted: a percent (90), a letter (\"B\") or several (\"A, B, C\"). Default: every letter on the scale."
    },
    "students": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 20000
        },
        {
          "type": "array",
          "items": {},
          "maxItems": 500
        },
        {
          "type": "object",
          "propertyNames": {
            "type": "string"
          },
          "additionalProperties": {}
        }
      ],
      "description": "For a teacher: several students' current grades, e.g. \"Ana Diaz 84.5, Ben Ito 71\" or [{\"name\":\"Ana Diaz\",\"current_grade\":84.5}]. Send this or current_grade."
    },
    "plus_minus": {
      "anyOf": [
        {
          "type": "boolean"
        },
        {
          "type": "string",
          "maxLength": 10
        }
      ],
      "description": "true for +/- letters. Default false."
    },
    "final_weight": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "string",
          "maxLength": 40
        }
      ],
      "description": "How much the final counts toward the course grade, as a percent, e.g. 20 or \"20%\" (0.2 is read as 20%)."
    },
    "letter_scale": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 300000
        },
        {
          "type": "array",
          "items": {},
          "maxItems": 3000
        },
        {
          "type": "object",
          "propertyNames": {
            "type": "string"
          },
          "additionalProperties": {}
        }
      ],
      "description": "Letter cutoffs for letter targets. Default A 90, B 80, C 70, D 60; \"plus_minus\" or a custom list like \"A 93, B 85, C 75, D 65\"."
    },
    "current_grade": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "string",
          "maxLength": 40
        }
      ],
      "description": "The grade before the final, as a percent, e.g. 84.5 or \"84.5%\"."
    },
    "final_points_possible": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "string",
          "maxLength": 20
        }
      ],
      "description": "Points on the final exam, e.g. 120, to also show the points needed."
    }
  }
}
calculate_grade_needed output schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "kind",
    "final_weight",
    "current_grade",
    "letter_scale",
    "targets",
    "what_if",
    "students",
    "notes"
  ],
  "properties": {
    "kind": {
      "type": "string"
    },
    "notes": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "targets": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "target",
          "target_percent",
          "needed_percent",
          "needed_points",
          "status"
        ],
        "properties": {
          "status": {
            "type": "string"
          },
          "target": {
            "type": "string"
          },
          "needed_points": {
            "type": [
              "number",
              "null"
            ]
          },
          "needed_percent": {
            "type": "number"
          },
          "target_percent": {
            "type": "number"
          }
        },
        "additionalProperties": false
      }
    },
    "what_if": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "final_score",
          "course_grade",
          "letter"
        ],
        "properties": {
          "letter": {
            "type": "string"
          },
          "final_score": {
            "type": "number"
          },
          "course_grade": {
            "type": "number"
          }
        },
        "additionalProperties": false
      }
    },
    "students": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "name",
          "current_grade",
          "needed_percent",
          "status"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "current_grade": {
            "type": "number"
          },
          "needed_percent": {
            "type": "number"
          }
        },
        "additionalProperties": false
      }
    },
    "final_weight": {
      "type": "number"
    },
    "letter_scale": {
      "type": "string"
    },
    "current_grade": {
      "type": [
        "number",
        "null"
      ]
    }
  },
  "additionalProperties": false
}
calculate_grade_needed annotations
{
  "title": "Calculate grade needed on the final",
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}

Prompts

Not advertised

No prompt definitions available.

Resources

1 advertised

gradebook-widget — Zovo Gradebook view

Advertised by the server during the last successful anonymous check.

Interactive view for Zovo Gradebook.

gradebook-widget URI
ui://widget/gradebook-v1-1.0.1-f82e865cbcd236a57e4212c4f5a440a1cec132b7028477c949b4cf84b74d4c05.html

MIME type: text/html;profile=mcp-app

gradebook-widget-legacy — Zovo Gradebook view (previous versions)

Advertised by the server during the last successful anonymous check.

gradebook-widget-legacy URI template
ui://widget/gradebook-{version}.html

MIME type: text/html;profile=mcp-app

30-day availability

Aggregated from read-only remote checks; this is not a tool-execution or security guarantee.

Successful checks
1 of 1 (100%)
Average latency
876 ms
95th percentile latency
876 ms

Maintenance history

Public check and source-refresh events. Editorial and ownership records remain private.

  • · probe · passed · 876 ms · metadata changed · 3 tool(s), 1 resource(s), 1 resource template(s)

Connect from your client

Each snippet registers the same endpoint; pick the client you use.

This server is operated by the named third party. Listing and endpoint checks are not an endorsement or a security audit. Review the operator's permissions, terms, and data handling before connecting. How listings are checked and corrected.

Claude Code

Run this once in a terminal. It registers the remote server. Use --scope project to write .mcp.json for the repo.
Claude Code configuration
claude mcp add --transport http zovo-gradebook-mcp https://gradebook.zovo.one/mcp

Codex

Run this once. Codex stores MCP servers in ~/.codex/config.toml (or .codex/config.toml in a trusted project).
Codex configuration
codex mcp add zovo-gradebook-mcp --url https://gradebook.zovo.one/mcp

Cursor

Merge this server into .cursor/mcp.json in your project, then enable zovo-gradebook-mcp in your MCP settings.
Cursor configuration
{
  "mcpServers": {
    "zovo-gradebook-mcp": {
      "url": "https://gradebook.zovo.one/mcp"
    }
  }
}

Cline

Merge this into cline_mcp_settings.json (Cline → MCP Servers → Configure).
Cline configuration
{
  "mcpServers": {
    "zovo-gradebook-mcp": {
      "type": "streamableHttp",
      "url": "https://gradebook.zovo.one/mcp",
      "disabled": false
    }
  }
}

VS Code

Merge this server into .vscode/mcp.json. Use MCP: List Servers to start zovo-gradebook-mcp and inspect its tools.
VS Code configuration
{
  "servers": {
    "zovo-gradebook-mcp": {
      "type": "http",
      "url": "https://gradebook.zovo.one/mcp"
    }
  }
}

Gemini CLI

Run this once. It writes .gemini/settings.json in the current project; pass --scope user for ~/.gemini/settings.json.
Gemini CLI configuration
gemini mcp add --transport http zovo-gradebook-mcp https://gradebook.zovo.one/mcp

Claude Desktop

Open Claude Settings > Connectors > Add custom connector, enter this server URL and enable it for the conversation. This is a manual remote-connector handoff, not a desktop JSON configuration.
Claude Desktop configuration
https://gradebook.zovo.one/mcp

Windsurf

Merge this into ~/.codeium/windsurf/mcp_config.json, then refresh MCP in Cascade. Windsurf remote servers use serverUrl, not url.
Windsurf configuration
{
  "mcpServers": {
    "zovo-gradebook-mcp": {
      "serverUrl": "https://gradebook.zovo.one/mcp"
    }
  }
}

Let your agent find its tools

Find servers like Zovo Gradebook MCP from your agent. Add Koskamo once to search the index for endpoints, access requirements, and client setup. Public discovery needs no key.