PLATO MCP
io.github.jin-1119/plato-mcpjin-1119streamable-httpv0.1.0Scanned
PLATO (Pusan National University LMS) MCP server via Moodle Web Service API + ubboard scraping
67 tools: 11 can delete or cancel things, 1 change things and 55 only read.
- Reads private data · 10
- Reads text others write · 56
- Can send data out · 3
- No findings
Anlyon alternative
12 of these tools change something. Run those as governed actions.
Declare what an action changes, and Anlyon puts it under a shared limit, binds every approval to the exact request, and grades the outcome. It works on any HTTPS API you can describe as an action.
Anlyon does not run, proxy or govern this MCP server. A tool your own code calls directly is not routed through Anlyon and is not governed by it.
Import an OpenAPI spec →Tools
Grouped by what each tool does, most consequential first. Open one for its reasons and full description; descriptions are the publisher's own words.
67 tools
Deletes or cancels 11Claude Code: deny
add_discussionStart a new discussion thread in a forum.Can send data outNo findings
Why it is in this group
- The name "add_discussion" says "add": a word for a change.
- The description says "IRREVERSIBLE".
- The server marks it destructive (destructiveHint: true).
What it can reach
- outboundThe name "add_discussion" says "add" and "discussion": it writes something other people read.
Description, as the server wrote it Start a new discussion thread in a forum. IRREVERSIBLE once dry_run=False. Call with dry_run=True (default) first, show the preview to the user, and only call again with dry_run=False after they explicitly confirm.
Annotations the server declares
- destructiveHint: true
- idempotentHint: false
- readOnlyHint: false
add_discussion_postReply to a forum discussion thread.Can send data outNo findings
Why it is in this group
- The name "add_discussion_post" says "add": a word for a change.
- The description's first verb is "reply": a word for sending, and what is sent cannot be taken back.
- The description says "IRREVERSIBLE".
- The server marks it destructive (destructiveHint: true).
What it can reach
- outboundThe name "add_discussion_post" says "add" and "discussion": it writes something other people read.
Description, as the server wrote it Reply to a forum discussion thread. IRREVERSIBLE once dry_run=False. Call with dry_run=True (default) first, show the preview to the user, and only call again with dry_run=False after they explicitly confirm.
Annotations the server declares
- destructiveHint: true
- idempotentHint: false
- readOnlyHint: false
add_private_fileUpload a file to this account's Moodle private files area.No findings
Why it is in this group
- The name "add_private_file" says "add": a word for a change.
- The description says "IRREVERSIBLE".
- The server marks it destructive (destructiveHint: true).
Description, as the server wrote it Upload a file to this account's Moodle private files area. IRREVERSIBLE once dry_run=False -- no delete tool exists for private files yet, so this permanently adds the file until the user removes it via PLATO's own UI. Only works when this server is running locally (stdio). Call with dry_run=True (default) first, show the preview to the user, and only call again with dry_run=False after they explicitly confirm.
Annotations the server declares
- destructiveHint: true
- idempotentHint: false
- readOnlyHint: false
create_calendar_eventCreate a personal calendar entry.No findings
Why it is in this group
- The name "create_calendar_event" says "create": a word for a change.
- The description says "IRREVERSIBLE".
- The server marks it destructive (destructiveHint: true).
Description, as the server wrote it Create a personal calendar entry. IRREVERSIBLE once dry_run=False. Only personal ("user") events are supported -- course/group events are not something a student account can create. Call with dry_run=True (default) first, show the preview to the user, and only call again with dry_run=False after they explicitly confirm.
Annotations the server declares
- destructiveHint: true
- idempotentHint: false
- readOnlyHint: false
delete_calendar_eventDelete a personal calendar entry this account owns.No findings
Why it is in this group
- The name "delete_calendar_event" says "delete": a word for removing or ending something.
- The description says "IRREVERSIBLE".
- The server marks it destructive (destructiveHint: true).
Description, as the server wrote it Delete a personal calendar entry this account owns. IRREVERSIBLE once dry_run=False. Call with dry_run=True (default) first, show the preview to the user, and only call again with dry_run=False after they explicitly confirm.
Annotations the server declares
- destructiveHint: true
- idempotentHint: false
- readOnlyHint: false
post_qna_questionPost a new question to a course's Q&A board.Can send data outNo findings
Why it is in this group
- The name "post_qna_question" says "post": a word for a change.
- The description says "IRREVERSIBLE".
- The server marks it destructive (destructiveHint: true).
What it can reach
- outboundThe name "post_qna_question" says "post": it sends or publishes something to other people.
Description, as the server wrote it Post a new question to a course's Q&A board. IRREVERSIBLE and VISIBLE to the instructor once dry_run=False (posted as private/secret by default). Call with dry_run=True (default) first, show the preview to the user, and only call again with dry_run=False after they explicitly confirm.
Annotations the server declares
- destructiveHint: true
- idempotentHint: false
- readOnlyHint: false
process_quiz_attemptSubmit answers for a quiz attempt.No findings
Why it is in this group
- The description's first verb is "submit": a word for a change.
- The description says "IRREVERSIBLE".
- The server marks it destructive (destructiveHint: true).
Description, as the server wrote it Submit answers for a quiz attempt. IRREVERSIBLE once dry_run=False AND finish_attempt=True -- that is the final, graded submission and cannot be undone. UNVERIFIED against a real quiz. Call with dry_run=True (default) first, show the preview to the user -- especially before finish_attempt=True -- and only call again with dry_run=False after they explicitly confirm.
Annotations the server declares
- destructiveHint: true
- idempotentHint: false
- readOnlyHint: false
remove_submissionWithdraw/clear this account's own submission for an assignment.No findings
Why it is in this group
- The name "remove_submission" says "remove": a word for removing or ending something.
- The description says "IRREVERSIBLE".
- The server marks it destructive (destructiveHint: true).
Description, as the server wrote it Withdraw/clear this account's own submission for an assignment. IRREVERSIBLE and DESTRUCTIVE once dry_run=False -- this discards already-submitted work (files/text), not a draft. KNOWN ISSUE: live testing found dry_run=False currently fails with an "invalid parameter" error from PLATO every time (the real required parameter shape wasn't determined -- see remove_submission_for's docstring). dry_run=True (preview) works and is safe to call. Do not rely on dry_run=False actually working until this is fixed. Call with dry_run=True (default) first, show the preview to the user, and only call again with dry_run=False after they explicitly confirm.
Annotations the server declares
- destructiveHint: true
- idempotentHint: false
- readOnlyHint: false
save_quiz_attempt_responsesSave in-progress answers WITHOUT finishing the attempt -- can still be changed later.No findings
Why it is in this group
- The name "save_quiz_attempt_responses" says "save": a word for a change.
- The server marks it destructive (destructiveHint: true).
Description, as the server wrote it Save in-progress answers WITHOUT finishing the attempt -- can still be changed later. UNVERIFIED against a real quiz. Call with dry_run=True (default) first, show the preview to the user, and only call again with dry_run=False after they explicitly confirm.
Annotations the server declares
- destructiveHint: true
- idempotentHint: false
- readOnlyHint: false
start_quiz_attemptStart a new attempt at a quiz.No findings
Why it is in this group
- The name "start_quiz_attempt" says "start": a word for a change.
- The description says "IRREVERSIBLE".
- The server marks it destructive (destructiveHint: true).
Description, as the server wrote it Start a new attempt at a quiz. IRREVERSIBLE once dry_run=False -- consumes one of the quiz's limited attempts. UNVERIFIED against a real quiz -- call get_quiz_access_information first and check canattempt/preventaccessreasons. Call with dry_run=True (default) first, show the preview to the user, and only call again with dry_run=False after they explicitly confirm.
Annotations the server declares
- destructiveHint: true
- idempotentHint: false
- readOnlyHint: false
submit_assignmentSubmit text and/or file attachments for an assignment.No findings
Why it is in this group
- The name "submit_assignment" says "submit": a word for a change.
- The description says "IRREVERSIBLE".
- The server marks it destructive (destructiveHint: true).
Description, as the server wrote it Submit text and/or file attachments for an assignment. IRREVERSIBLE once dry_run=False. Call with dry_run=True (default) first, show the preview to the user, and only call again with dry_run=False (same parameters) after they explicitly confirm. Provide text, file_paths/file_contents, or both -- whichever this assignment actually accepts (see get_assignment_detail). file_paths works only when this server is running locally (stdio, e.g. Claude Code/Desktop) -- rejected with a clear error over a remote (streamable-http, e.g. a Claude.ai Connector) connection, mirroring download_course_file's own stdio-vs-remote split. file_contents works over either transport and is the only option remotely, since this server's disk is not reachable by you there.
Annotations the server declares
- destructiveHint: true
- idempotentHint: false
- readOnlyHint: false
Changes things 1Claude Code: ask
download_course_fileDownload a course file (the `fileurl` from get_course_contents).Reads text others writeNo findings
Why it is in this group
- Nothing in its name or description says what it does, so it is counted as a write.
- The server marks it read-only (readOnlyHint: true), but an annotation never lowers a class.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it Download a course file (the `fileurl` from get_course_contents). Running locally (stdio, e.g. Claude Code/Desktop): saves the file to `save_path` on this machine and returns the saved path -- `save_path` is required in this case. Running as a remote/hosted server (streamable-http, e.g. reached via a Claude.ai web/mobile Connector): this server's own disk is not reachable by you, so do NOT pass `save_path` -- it will be rejected. Instead the file is fetched here and returned inline as base64 content for you to decode and present, unless it's too large, in which case a direct authenticated download URL is returned instead (that URL embeds a live PLATO access token: do not share it or a chat transcript containing it). Only common course-material extensions are allowed (pdf, office docs, images, zip, txt); local downloads over the configured size limit are rejected.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
Only reads 55Show 55 read-only tools
get_activity_completion_statusGet this account's completion status for every activity/module in a course -- richer than get_course_contents's per-module `completed` flag (includes tracking rules, e.g.Reads text others writeNo findings
Why it is in this group
- The name "get_activity_completion_status" says "get": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it Get this account's completion status for every activity/module in a course -- richer than get_course_contents's per-module `completed` flag (includes tracking rules, e.g. 'must view' vs 'must spend N minutes'). For `vod` (video lecture) modules specifically, prefer get_course_contents, whose per-module `vod_progress` field also includes watch-percentage and deadline info this function doesn't return.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
get_assignment_detailGet one assignment's details and this account's submission status.Reads text others writeNo findings
Why it is in this group
- The name "get_assignment_detail" says "get": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it Get one assignment's details and this account's submission status.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
get_calendar_access_infoCheck this account's calendar-management permissions -- a student account can typically manage its own personal entries only, not course/group entries.Reads private dataReads text others writeNo findings
Why it is in this group
- The name "get_calendar_access_info" says "get": a word for reading.
What it can reach
- private-dataThe name "get_calendar_access_info" says "get" and "calendar": it reads calendars.
- private-dataThe description's first sentence says "calendar": it reads calendars.
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it Check this account's calendar-management permissions -- a student account can typically manage its own personal entries only, not course/group entries.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
get_course_completion_statusGet this account's overall course-completion status, if the course has course-level completion criteria configured.Reads text others writeNo findings
Why it is in this group
- The name "get_course_completion_status" says "get": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it Get this account's overall course-completion status, if the course has course-level completion criteria configured. Most courses on this platform don't (available=False, with a message explaining why) -- try get_activity_completion_status for per-activity progress instead, or get_course_contents's per-module `completed` flag.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
get_course_contentsGet a course's weekly sections, modules, and file links.Reads private dataReads text others writeNo findings
Why it is in this group
- The name "get_course_contents" says "get": a word for reading.
What it can reach
- private-dataThe description's first sentence says "get" and "file": it reads files.
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it Get a course's weekly sections, modules, and file links.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
get_course_moduleResolve a single course module by its id directly, without fetching and filtering the whole course's contents.Reads text others writeNo findings
Why it is in this group
- The name "get_course_module" says "get": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it Resolve a single course module by its id directly, without fetching and filtering the whole course's contents.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
get_course_updates_sinceGet what changed in a course since a given time -- configuration, completion, grades, submissions, etc.Reads text others writeNo findings
Why it is in this group
- The name "get_course_updates_since" says "get": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it Get what changed in a course since a given time -- configuration, completion, grades, submissions, etc. Only reports modules that implement Moodle's change-tracking (confirmed: the standard `assign` module does; this platform's own custom lecture-file/board/video modules do not, so this won't catch a new ubfile lecture or ubboard post -- use get_course_contents/list_notices to check those instead.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
get_courses_by_timelineList enrolled courses filtered by Moodle's own timeline classification (in-progress/future/past), based on course start/end dates.Reads text others writeNo findings
Why it is in this group
- The name "get_courses_by_timeline" says "get": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it List enrolled courses filtered by Moodle's own timeline classification (in-progress/future/past), based on course start/end dates. Unlike list_courses (which returns everything unfiltered), this answers "what am I actually taking right now" directly.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
get_discussion_postsGet all posts in one forum discussion thread.Reads private dataReads text others writeNo findings
Why it is in this group
- The name "get_discussion_posts" says "get": a word for reading.
What it can reach
- private-dataThe description's first sentence says "get" and "thread": it reads messages.
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
- untrusted-inputThe name "get_discussion_posts" says "get" and "discussion": it reads comments, which other people can write.
- untrusted-inputThe description's first sentence says "get" and "post": it reads posts, which other people can write.
Description, as the server wrote it Get all posts in one forum discussion thread.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
get_enrolled_usersGet the list of users enrolled in a course (classmates and instructors), with their role.Reads text others writeNo findings
Why it is in this group
- The name "get_enrolled_users" says "get": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it Get the list of users enrolled in a course (classmates and instructors), with their role. Same data visible in PLATO's own participant list to any enrolled student.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
get_forum_discussionsList discussion threads in one standard Moodle forum.Reads private dataReads text others writeNo findings
Why it is in this group
- The name "get_forum_discussions" says "get": a word for reading.
What it can reach
- private-dataThe description's first sentence says "list" and "thread": it reads messages.
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
- untrusted-inputThe name "get_forum_discussions" says "get" and "discussion": it reads comments, which other people can write.
- untrusted-inputThe description's first sentence says "list" and "discussion": it reads comments, which other people can write.
Description, as the server wrote it List discussion threads in one standard Moodle forum.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
get_gradesGet this account's grade items for a course, if visible.Reads text others writeNo findings
Why it is in this group
- The name "get_grades" says "get": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it Get this account's grade items for a course, if visible.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
get_grades_access_infoCheck what grade-related permissions this account has in a course -- e.g.Reads text others writeNo findings
Why it is in this group
- The name "get_grades_access_info" says "get": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it Check what grade-related permissions this account has in a course -- e.g. whether it can see its own grades vs. (as a teacher/TA) everyone's grades. Most student accounts will see canviewallgrades=False.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
get_grades_overviewGet this account's overall grade for every enrolled course in one call.Reads text others writeNo findings
Why it is in this group
- The name "get_grades_overview" says "get": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it Get this account's overall grade for every enrolled course in one call. For the individual grade *items* within one course (e.g. each assignment's score), use get_grades instead -- this tool only returns one summary grade per course.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
get_my_course_groupsGet the groups this account belongs to within a course, if any.Reads text others writeNo findings
Why it is in this group
- The name "get_my_course_groups" says "get": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it Get the groups this account belongs to within a course, if any.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
get_notice_detailGet the full text of one notice/announcement.Reads text others writeNo findings
Why it is in this group
- The name "get_notice_detail" says "get": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it Get the full text of one notice/announcement.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
get_private_files_infoGet a summary (file/folder count, total size) of this account's Moodle private files area.Reads private dataReads text others writeNo findings
Why it is in this group
- The name "get_private_files_info" says "get": a word for reading.
What it can reach
- private-dataThe name "get_private_files_info" says "get" and "file": it reads files.
- private-dataThe description's first sentence says "get" and "file": it reads files.
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it Get a summary (file/folder count, total size) of this account's Moodle private files area.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
get_qna_detailGet one Q&A question's text.Reads text others writeNo findings
Why it is in this group
- The name "get_qna_detail" says "get": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it Get one Q&A question's text. Does not include replies -- see issue #23.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
get_quiz_access_informationCheck whether this account can currently attempt a quiz, and why not if blocked (e.g.Reads text others writeNo findings
Why it is in this group
- The name "get_quiz_access_information" says "get": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it Check whether this account can currently attempt a quiz, and why not if blocked (e.g. time window, password, previous attempts exhausted). UNVERIFIED against a real quiz -- call this before start_quiz_attempt and sanity-check the result.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
get_quiz_attempt_dataGet the questions for one page of an in-progress quiz attempt.Reads text others writeNo findings
Why it is in this group
- The name "get_quiz_attempt_data" says "get": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it Get the questions for one page of an in-progress quiz attempt. Each question's `html` is Moodle's own rendered question form -- parse it for the actual answer-field names before calling save_quiz_attempt_responses/process_quiz_attempt. UNVERIFIED against a real quiz.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
get_quiz_attempt_reviewGet the grade and per-question review for a finished quiz attempt.Reads text others writeNo findings
Why it is in this group
- The name "get_quiz_attempt_review" says "get": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
- untrusted-inputThe name "get_quiz_attempt_review" says "get" and "review": it reads comments, which other people can write.
- untrusted-inputThe description's first sentence says "get" and "review": it reads comments, which other people can write.
Description, as the server wrote it Get the grade and per-question review for a finished quiz attempt. UNVERIFIED against a real quiz.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
get_quiz_attempt_summaryGet a summary of all questions in an attempt (answered/ unanswered), across all pages.Reads text others writeNo findings
Why it is in this group
- The name "get_quiz_attempt_summary" says "get": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it Get a summary of all questions in an attempt (answered/ unanswered), across all pages. UNVERIFIED against a real quiz.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
get_quiz_attemptsGet this account's past attempts at one quiz.Reads text others writeNo findings
Why it is in this group
- The name "get_quiz_attempts" says "get": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it Get this account's past attempts at one quiz.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
get_quiz_best_gradeGet this account's best grade on one quiz, if any attempt has been graded.Reads text others writeNo findings
Why it is in this group
- The name "get_quiz_best_grade" says "get": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it Get this account's best grade on one quiz, if any attempt has been graded.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
get_quiz_combined_review_optionsCheck which review details (marks, feedback, right answers) this account is allowed to see for a quiz's attempts.Reads text others writeNo findings
Why it is in this group
- The name "get_quiz_combined_review_options" says "get": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
- untrusted-inputThe name "get_quiz_combined_review_options" says "get" and "review": it reads comments, which other people can write.
- untrusted-inputThe description's first sentence says "review": it reads comments, which other people can write.
Description, as the server wrote it Check which review details (marks, feedback, right answers) this account is allowed to see for a quiz's attempts.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
get_quiz_feedback_for_gradeGet the grade-boundary feedback text configured for a quiz at a given grade (e.g.Reads text others writeNo findings
Why it is in this group
- The name "get_quiz_feedback_for_grade" says "get": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it Get the grade-boundary feedback text configured for a quiz at a given grade (e.g. 'You passed!' / 'Please review chapter 3').
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
get_quiz_required_qtypesList the question types used in a quiz (e.g.Reads text others writeNo findings
Why it is in this group
- The name "get_quiz_required_qtypes" says "get": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it List the question types used in a quiz (e.g. 'multichoice', 'truefalse', 'essay') -- useful to know what kind of answers to expect before starting an attempt.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
get_recent_coursesGet this account's recently-accessed courses, most recent first.Reads text others writeNo findings
Why it is in this group
- The name "get_recent_courses" says "get": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it Get this account's recently-accessed courses, most recent first.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
get_recent_itemsGet this account's recently-accessed course modules (files, assignments, etc.) across all courses, most recent first.Reads private dataReads text others writeNo findings
Why it is in this group
- The name "get_recent_items" says "get": a word for reading.
What it can reach
- private-dataThe description's first sentence says "get" and "file": it reads files.
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it Get this account's recently-accessed course modules (files, assignments, etc.) across all courses, most recent first.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
get_starred_coursesGet this account's starred/favourited courses, if any.Reads text others writeNo findings
Why it is in this group
- The name "get_starred_courses" says "get": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it Get this account's starred/favourited courses, if any.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
get_unread_messagesGet this account's unread PLATO notifications.Reads private dataReads text others writeNo findings
Why it is in this group
- The name "get_unread_messages" says "get": a word for reading.
What it can reach
- private-dataThe name "get_unread_messages" says "get" and "message": it reads messages.
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
- untrusted-inputThe name "get_unread_messages" says "get" and "message": it reads messages, which other people can write.
Description, as the server wrote it Get this account's unread PLATO notifications.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
get_unread_notification_countGet a count of this account's unread notifications (a cheaper check than get_unread_messages when you don't need the content).Reads text others writeNo findings
Why it is in this group
- The name "get_unread_notification_count" says "get": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it Get a count of this account's unread notifications (a cheaper check than get_unread_messages when you don't need the content). Note: PLATO has person-to-person messaging disabled site-wide, so this counts notifications only, not conversation messages.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
get_upcoming_action_eventsGet Moodle's own "what needs action soon" feed -- assignments due, video lectures with a watch deadline, etc.Reads text others writeNo findings
Why it is in this group
- The name "get_upcoming_action_events" says "get": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it Get Moodle's own "what needs action soon" feed -- assignments due, video lectures with a watch deadline, etc. -- sorted by urgency, from now onward. Unlike combining list_assignments + get_calendar_events, this is Moodle's own cross-activity prioritized view and may surface activity types (e.g. vod watch deadlines) those tools don't.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
get_user_preferencesGet this account's Moodle user preferences.Reads text others writeNo findings
Why it is in this group
- The name "get_user_preferences" says "get": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it Get this account's Moodle user preferences. Note: most of these are internal UI state (e.g. which dashboard sections are collapsed), not information meaningful on its own.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
get_user_profileGet a user's profile, scoped to a shared course (not a global user search -- see docs/pii_review.md).Reads text others writeNo findings
Why it is in this group
- The name "get_user_profile" says "get": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it Get a user's profile, scoped to a shared course (not a global user search -- see docs/pii_review.md).
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
list_assignmentsList assignments across one or more courses, with due dates.Reads text others writeNo findings
Why it is in this group
- The name "list_assignments" says "list": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it List assignments across one or more courses, with due dates.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
list_calendar_eventsList upcoming calendar events within the next `days_ahead` days.Reads private dataReads text others writeNo findings
Why it is in this group
- The name "list_calendar_events" says "list": a word for reading.
What it can reach
- private-dataThe name "list_calendar_events" says "list" and "calendar": it reads calendars.
- private-dataThe description's first sentence says "list" and "calendar": it reads calendars.
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it List upcoming calendar events within the next `days_ahead` days.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
list_chatsList Chat (real-time chat room) activities across one or more courses.Reads private dataReads text others writeNo findings
Why it is in this group
- The name "list_chats" says "list": a word for reading.
What it can reach
- private-dataThe name "list_chats" says "list" and "chat": it reads messages.
- private-dataThe description's first sentence says "list" and "chat": it reads messages.
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
- untrusted-inputThe name "list_chats" says "list" and "chat": it reads messages, which other people can write.
- untrusted-inputThe description's first sentence says "list" and "chat": it reads messages, which other people can write.
Description, as the server wrote it List Chat (real-time chat room) activities across one or more courses. Reading/sending chat messages is not supported by this server -- this tool is read-only coverage only.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
list_choicesList Choice (single-question poll) activities across one or more courses.Reads text others writeNo findings
Why it is in this group
- The name "list_choices" says "list": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it List Choice (single-question poll) activities across one or more courses. Voting is not supported by this server -- this tool is read-only coverage only.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
list_coursesList the courses the logged-in PLATO account is enrolled in.Reads text others writeNo findings
Why it is in this group
- The name "list_courses" says "list": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it List the courses the logged-in PLATO account is enrolled in.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
list_database_activitiesList Database ("mod_data") activities across one or more courses.Reads private dataReads text others writeNo findings
Why it is in this group
- The name "list_database_activities" says "list": a word for reading.
What it can reach
- private-dataThe name "list_database_activities" says "list" and "database": it reads databases.
- private-dataThe description's first sentence says "list" and "database": it reads databases.
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it List Database ("mod_data") activities across one or more courses. Reading/adding entries is not supported by this server -- this tool is read-only coverage only.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
list_feedbacksList Feedback (survey) activities across one or more courses.Reads text others writeNo findings
Why it is in this group
- The name "list_feedbacks" says "list": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it List Feedback (survey) activities across one or more courses. Responding to a survey is not supported by this server -- this tool is read-only coverage only.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
list_forumsList standard Moodle forums across one or more courses.Reads text others writeNo findings
Why it is in this group
- The name "list_forums" says "list": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it List standard Moodle forums across one or more courses. NOT the same as PLATO's notice/Q&A board (use list_notices/list_qna for that) -- this covers the separate, less-commonly-used mod_forum module.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
list_glossariesList Glossary activities across one or more courses.Reads text others writeNo findings
Why it is in this group
- The name "list_glossaries" says "list": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it List Glossary activities across one or more courses. Reading/ adding entries is not supported by this server -- this tool is read-only coverage only.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
list_h5p_activitiesList H5P interactive-content activities across one or more courses.Reads text others writeNo findings
Why it is in this group
- The name "list_h5p_activities" says "list": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it List H5P interactive-content activities across one or more courses. Attempt results are not supported by this server -- this tool is read-only coverage only.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
list_lessonsList Lesson activities across one or more courses.Reads text others writeNo findings
Why it is in this group
- The name "list_lessons" says "list": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it List Lesson activities across one or more courses. Taking a lesson (answering pages) is not supported by this server -- this tool is read-only coverage only.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
list_noticesList announcements posted to a course's Notices board.Reads text others writeNo findings
Why it is in this group
- The name "list_notices" says "list": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it List announcements posted to a course's Notices board.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
list_qnaList questions posted to a course's Q&A board.Reads text others writeNo findings
Why it is in this group
- The name "list_qna" says "list": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it List questions posted to a course's Q&A board.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
list_quizzesList quizzes across one or more courses.Reads text others writeNo findings
Why it is in this group
- The name "list_quizzes" says "list": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it List quizzes across one or more courses.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
list_scormsList SCORM packaged-content activities across one or more courses.Reads text others writeNo findings
Why it is in this group
- The name "list_scorms" says "list": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it List SCORM packaged-content activities across one or more courses. Launching/tracking a SCORM attempt is not supported by this server -- this tool is read-only coverage only.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
list_surveysList Survey activities across one or more courses.Reads text others writeNo findings
Why it is in this group
- The name "list_surveys" says "list": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it List Survey activities across one or more courses. Answering is not supported by this server -- this tool is read-only coverage only.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
list_video_conferencesList BigBlueButton video-conference activities across one or more courses.Reads text others writeNo findings
Why it is in this group
- The name "list_video_conferences" says "list": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it List BigBlueButton video-conference activities across one or more courses. Joining a meeting is not supported by this server -- this tool is read-only coverage only. Zoom activities (mod_zoom) are not covered -- no real instance has existed to verify against.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
list_wikisList Wiki activities across one or more courses.Reads text others writeNo findings
Why it is in this group
- The name "list_wikis" says "list": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it List Wiki activities across one or more courses. Reading/ editing pages is not supported by this server -- this tool is read-only coverage only.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
list_workshopsList Workshop (peer assessment) activities across one or more courses.Reads text others writeNo findings
Why it is in this group
- The name "list_workshops" says "list": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it List Workshop (peer assessment) activities across one or more courses. Submitting or assessing work is not supported by this server -- this tool is read-only coverage only.
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
search_coursesSearch PLATO's entire course catalog by name -- not limited to this account's enrolled courses (use list_courses for that).Reads text others writeNo findings
Why it is in this group
- The name "search_courses" says "search": a word for reading.
What it can reach
- untrusted-inputThe server marks it openWorldHint: true: it reaches things outside the server's own data.
Description, as the server wrote it Search PLATO's entire course catalog by name -- not limited to this account's enrolled courses (use list_courses for that).
Annotations the server declares
- openWorldHint: true
- readOnlyHint: true
This is not a safety rating, and no finding is not a safety guarantee. The groups and findings come from fixed checks of the tool definitions the server returned on the date shown, not from its code or what it does when called. How the checks work.
Exfil surface
Which tools read private data, which read text someone else can write, and which can send data out. One of each is a path a prompt injection can use.
1680 paths in this server alone from private data, through text someone else wrote, to a way out. Denying 3 outbound tools breaks every one.
- Reads private data10
- Reads files, mail, messages, databases, secrets, calendars or repositories.
- Reads text others write56
- Brings in text someone else can write: web pages, inbound email, messages, issues and comments.
- Can send data out3
- Can carry data to people or systems: it sends, posts or publishes, or takes a recipient, channel or URL.
{
"permissions": {
"deny": [
"mcp__plato__add_discussion",
"mcp__plato__add_discussion_post",
"mcp__plato__post_qna_question"
]
}
}Other servers in the same agent add their own tools to these paths. Audit your whole setup to see them together.
Findings
Matches of fixed checks, with the text they matched.
No check matched anything in these tool definitions. That is not a safety guarantee.
History
Changes to its tool definitions and to its remote endpoint, newest first.
No change seen yet. Its tools are rescanned every day, and a remote endpoint is looked at once a week.
Install
Pinned to version 0.1.0. Values in angle brackets are yours to fill in.
claude mcp add --transport http plato https://plato-mcp.onrender.com/mcp --header 'pnu_id: <your-pnu-id>' --header 'pnu_password: <your-pnu-password>'claude mcp add --transport http plato https://plato-mcp.onrender.com/mcp --header 'pnu_id: <your-pnu-id>' --header 'pnu_password: <your-pnu-password>'Run in a terminal.
Claude Code permissions
Allow the reads, ask before a change or a way out, deny the deletes. Paste into .claude/settings.json.
{
"permissions": {
"allow": [
"mcp__plato__list_courses",
"mcp__plato__get_course_contents",
"mcp__plato__list_assignments",
"mcp__plato__get_assignment_detail",
"mcp__plato__get_grades",
"mcp__plato__get_grades_access_info",
"mcp__plato__list_calendar_events",
"mcp__plato__get_calendar_access_info",
"mcp__plato__get_unread_messages",
"mcp__plato__get_unread_notification_count",
"mcp__plato__list_notices",
"mcp__plato__get_notice_detail",
"mcp__plato__list_qna",
"mcp__plato__get_qna_detail",
"mcp__plato__get_course_completion_status",
"mcp__plato__get_activity_completion_status",
"mcp__plato__get_upcoming_action_events",
"mcp__plato__get_courses_by_timeline",
"mcp__plato__get_grades_overview",
"mcp__plato__list_quizzes",
"mcp__plato__get_quiz_attempts",
"mcp__plato__get_quiz_best_grade",
"mcp__plato__get_quiz_access_information",
"mcp__plato__get_quiz_required_qtypes",
"mcp__plato__get_quiz_feedback_for_grade",
"mcp__plato__get_quiz_combined_review_options",
"mcp__plato__get_quiz_attempt_data",
"mcp__plato__get_quiz_attempt_summary",
"mcp__plato__get_quiz_attempt_review",
"mcp__plato__list_forums",
"mcp__plato__get_forum_discussions",
"mcp__plato__get_discussion_posts",
"mcp__plato__get_course_updates_since",
"mcp__plato__get_course_module",
"mcp__plato__search_courses",
"mcp__plato__get_recent_courses",
"mcp__plato__get_recent_items",
"mcp__plato__get_starred_courses",
"mcp__plato__list_video_conferences",
"mcp__plato__list_lessons",
"mcp__plato__list_workshops",
"mcp__plato__list_feedbacks",
"mcp__plato__list_choices",
"mcp__plato__list_surveys",
"mcp__plato__list_scorms",
"mcp__plato__list_h5p_activities",
"mcp__plato__list_glossaries",
"mcp__plato__list_database_activities",
"mcp__plato__list_wikis",
"mcp__plato__list_chats",
"mcp__plato__get_user_profile",
"mcp__plato__get_private_files_info",
"mcp__plato__get_user_preferences",
"mcp__plato__get_my_course_groups",
"mcp__plato__get_enrolled_users"
],
"ask": [
"mcp__plato__download_course_file"
],
"deny": [
"mcp__plato__submit_assignment",
"mcp__plato__remove_submission",
"mcp__plato__create_calendar_event",
"mcp__plato__delete_calendar_event",
"mcp__plato__post_qna_question",
"mcp__plato__start_quiz_attempt",
"mcp__plato__save_quiz_attempt_responses",
"mcp__plato__process_quiz_attempt",
"mcp__plato__add_discussion",
"mcp__plato__add_discussion_post",
"mcp__plato__add_private_file"
]
}
}Tools that only read are allowed, tools that change things ask first, tools that delete or cancel are denied. A read that can send data out (it takes a URL, say) asks first too. It assumes the server is installed as plato. Review it before you use it.
Capability tags behind 59 rules
- mcp__plato__list_courses untrusted-input
- mcp__plato__get_course_contents private-data, untrusted-input
- mcp__plato__list_assignments untrusted-input
- mcp__plato__get_assignment_detail untrusted-input
- mcp__plato__get_grades untrusted-input
- mcp__plato__get_grades_access_info untrusted-input
- mcp__plato__list_calendar_events private-data, untrusted-input
- mcp__plato__get_calendar_access_info private-data, untrusted-input
- mcp__plato__get_unread_messages private-data, untrusted-input
- mcp__plato__get_unread_notification_count untrusted-input
- mcp__plato__list_notices untrusted-input
- mcp__plato__get_notice_detail untrusted-input
- mcp__plato__list_qna untrusted-input
- mcp__plato__get_qna_detail untrusted-input
- mcp__plato__post_qna_question outbound
- mcp__plato__download_course_file untrusted-input
- mcp__plato__get_course_completion_status untrusted-input
- mcp__plato__get_activity_completion_status untrusted-input
- mcp__plato__get_upcoming_action_events untrusted-input
- mcp__plato__get_courses_by_timeline untrusted-input
- mcp__plato__get_grades_overview untrusted-input
- mcp__plato__list_quizzes untrusted-input
- mcp__plato__get_quiz_attempts untrusted-input
- mcp__plato__get_quiz_best_grade untrusted-input
- mcp__plato__get_quiz_access_information untrusted-input
- mcp__plato__get_quiz_required_qtypes untrusted-input
- mcp__plato__get_quiz_feedback_for_grade untrusted-input
- mcp__plato__get_quiz_combined_review_options untrusted-input
- mcp__plato__get_quiz_attempt_data untrusted-input
- mcp__plato__get_quiz_attempt_summary untrusted-input
- mcp__plato__get_quiz_attempt_review untrusted-input
- mcp__plato__list_forums untrusted-input
- mcp__plato__get_forum_discussions private-data, untrusted-input
- mcp__plato__get_discussion_posts private-data, untrusted-input
- mcp__plato__add_discussion outbound
- mcp__plato__add_discussion_post outbound
- mcp__plato__get_course_updates_since untrusted-input
- mcp__plato__get_course_module untrusted-input
- mcp__plato__search_courses untrusted-input
- mcp__plato__get_recent_courses untrusted-input
- mcp__plato__get_recent_items private-data, untrusted-input
- mcp__plato__get_starred_courses untrusted-input
- mcp__plato__list_video_conferences untrusted-input
- mcp__plato__list_lessons untrusted-input
- mcp__plato__list_workshops untrusted-input
- mcp__plato__list_feedbacks untrusted-input
- mcp__plato__list_choices untrusted-input
- mcp__plato__list_surveys untrusted-input
- mcp__plato__list_scorms untrusted-input
- mcp__plato__list_h5p_activities untrusted-input
- mcp__plato__list_glossaries untrusted-input
- mcp__plato__list_database_activities private-data, untrusted-input
- mcp__plato__list_wikis untrusted-input
- mcp__plato__list_chats private-data, untrusted-input
- mcp__plato__get_user_profile untrusted-input
- mcp__plato__get_private_files_info private-data, untrusted-input
- mcp__plato__get_user_preferences untrusted-input
- mcp__plato__get_my_course_groups untrusted-input
- mcp__plato__get_enrolled_users untrusted-input
Pin
Keep the decision: fail CI when the tools change, follow every change, or show a badge.
Pin in CI
Fail a build when the tools you reviewed are not the tools the server serves today.
curl -s "https://anlyon.dev/api/v1/servers/io.github.jin-1119/plato-mcp/verify?hash=ee4fe161b9701eff438a0924ef89a7ce1cfa934622f9cb902b5e1ca8fc5ad76c" | jq -e '.changed == false'Pinned hash ee4fe161b970, from Oct 28, 2026, 06:17 UTC.
Watch
Get told when its tools change: a new tool, a new description, a new class.
https://anlyon.dev/servers/io.github.jin-1119/plato-mcp/changes.xmlAn Atom feed. Works in any feed reader or Slack's RSS app.
Badge
[](https://anlyon.dev/servers/io.github.jin-1119/plato-mcp)Source: MCP Registry · repository. Synced Oct 28, 2026, 06:17 UTC.