Skip to main content
Glama
NCCU-AI-SYSTEM

NCCU Moodle MCP

NCCU Moodle MCP

An MCP server that accesses NCCU Moodle (moodle.nccu.edu.tw) on behalf of a student. It logs in through the NCCU single-sign-on portal (i.nccu.edu.tw) and exposes Moodle data as MCP tools.

It runs as a hosted HTTP server: you (the operator) run one instance, and everyone else just adds its URL to their MCP client config — no install on their side.

  • Multi-tenant & stateless — each call authenticates with the credentials passed to it, uses that session for the one call, and discards it. Nothing is cached to disk or shared between calls, so concurrent users never interfere.

Tools

Tool

Description

WS function

list_courses

Enrolled courses by semester, each with the user's role (student/teacher/…). No sem → latest; sem="1142" → that term; sem="all" → every course.

core_enrol_get_users_courses + core_enrol_get_enrolled_users (role, ≤5 parallel)

search_courses

Filter enrolled courses by a keyword (the app's "filter my courses" box) — case-insensitive substring of the name (code / 中文 / English). Searches every term by default; sem scopes it.

core_enrol_get_users_courses + core_enrol_get_enrolled_users (role on matches)

get_course_role

The user's role in one course (course_id): student / teacher / editingteacher / teachingassistant / manager.

core_enrol_get_enrolled_users

list_assignments

Assignments with due dates, submission status, and your role per course. Only your student courses by default (include_all_role to add TA/teacher ones). Scope by sem, course_ids, and/or due (due_from/due_to) or open (opens_from/opens_to) date ranges.

mod_assign_get_assignments + mod_assign_get_submission_status + core_enrol_get_enrolled_users (≤5 parallel)

upcoming_deadlines

Upcoming due dates/quiz closings within days (default 14), each with your role; student courses only unless include_all_role.

core_calendar_get_action_events_by_timesort + core_enrol_get_enrolled_users

get_grades

Your grade items for one course (course_id).

gradereport_user_get_grade_items

get_course_contents

Everything the teacher posted in a course (course_id), grouped by week/section; empty weeks hidden unless include_empty.

core_course_get_contents

get_module

Open one posted item by cmid (the id in a mod/.../view.php?id= link; course_id optional — resolved from the cmid). Returns content by type — file links (browser-openable), page html, label/forum intro, forum discussions, rich assignment detail (instructions, attachments, submission, grade & feedback), quiz attempts.

core_course_get_course_module + core_course_get_contents (+ mod_assign/mod_page/mod_forum/mod_quiz by type)

list_announcements

Announcement tiles (headers only) for one course or all current-semester courses; paginated.

mod_forum_get_forums_by_courses + mod_forum_get_forum_discussions

get_announcement

Read one announcement's thread (posts + replies) by discussion_id; paginated.

mod_forum_get_discussion_posts

get_notifications

The notification bell (due reminders, grading, forum posts); reports unread count.

message_popup_get_popup_notifications

Course data comes from Moodle's mobile Web Services API, not HTML scraping: after SSO login, the server obtains a Web Services token the way the Moodle app does (admin/tool/mobile/launch.phpmoodlemobile://token=…) and calls the REST API. Semester is the NCCU term code encoded in each course's short name (e.g. 1151).

Nothing about the Moodle instance is hardcoded. On startup the server fetches Moodle's login page (via the stable entry moodle.nccu.edu.tw) and discovers both the current backend host (e.g. moodle45.nccu.edu.tw) and the NCCU SSO login URL (which encodes the MoodleSSOxx.aspx path) — so if the school moves to a different instance number, it keeps working. The discovered values are cached in memory for the process (site-wide config, not per-user state).


Part A — For users (setup guide)

You do not clone or install anything. You just add one block to your MCP client's config: the central server's address plus your own NCCU credentials as headers. The server reads those headers on each request, so every user connects as themselves.

Before you start, get these three things:

  1. The server address from the operator — e.g. http://140.119.x.x:3033/mcp or https://moodle-mcp.example.com/mcp.

  2. Your NCCU student ID (e.g. 112703016).

  3. Your NCCU portal password (the one you use at https://i.nccu.edu.tw).

In every snippet below, replace SERVER_ADDRESS, YOUR_STUDENT_ID, and YOUR_PASSWORD.


Claude Code

Option 1 — CLI (easiest). Run this once; the flag -s user makes it available in every project:

claude mcp add -s user --transport http nccu-moodle SERVER_ADDRESS \
  -H "X-Moodle-Username: YOUR_STUDENT_ID" \
  -H "X-Moodle-Password: YOUR_PASSWORD"

Option 2 — edit the config file directly. Create/edit .mcp.json in your project folder (or add this mcpServers block to your existing config):

{
  "mcpServers": {
    "nccu-moodle": {
      "type": "http",
      "url": "SERVER_ADDRESS",
      "headers": {
        "X-Moodle-Username": "YOUR_STUDENT_ID",
        "X-Moodle-Password": "YOUR_PASSWORD"
      }
    }
  }
}

Verify:

claude mcp list                 # nccu-moodle should be listed

Then start Claude Code and run /mcp — you should see nccu-moodle connected with the list_courses tool.


opencode

opencode is configured by a JSON file (there's no add command for MCP). Edit one of:

  • Global (recommended, works everywhere): ~/.config/opencode/opencode.json

  • Per project: opencode.json in the project root

Add the mcp block (merge into the file if it already exists):

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "nccu-moodle": {
      "type": "remote",
      "url": "SERVER_ADDRESS",
      "enabled": true,
      "headers": {
        "X-Moodle-Username": "YOUR_STUDENT_ID",
        "X-Moodle-Password": "YOUR_PASSWORD"
      }
    }
  }
}

Verify: restart opencode; the list_courses tool from nccu-moodle should be available to the assistant.


Try it

Ask the assistant, for example:

List my Moodle courses this semester. · List all my Moodle courses. What's due this week — and have I submitted it? · What was due last week? Which assignments haven't I submitted yet? · Any assignments in 1142? What are the latest announcements? · Open that announcement and read it. What are my grades in course 18284? · Do I have any notifications?

The assistant picks the right tool and reads your credentials from the headers you set — so you never type your password into the chat, and the assistant never sees or handles your password (the tool has no username/password parameters).


Notes & safety

⚠️ Lockout: NCCU suspends an account for 15 minutes after 5 failed login attempts. Make sure the password in your config is correct.

🔒 Your password is stored in a local config file and sent to the server on each call. Keep that file private, and don't commit a personal .mcp.json / opencode.json containing your password to a shared repository. The operator should serve the endpoint over HTTPS (see Part B).

Troubleshooting:

Symptom

Fix

Tool errors with "Missing credentials…"

The headers block is missing or misspelled. Header names must be exactly X-Moodle-Username and X-Moodle-Password.

"Moodle login failed…"

Wrong student ID or password. Fix it in the config (mind the 5-attempt lockout).

list_courses not showing up

Config not loaded — re-check the file location, valid JSON, and restart the client. For Claude Code, confirm with claude mcp list.

Connection/timeout errors

Server address wrong or server not reachable. Confirm SERVER_ADDRESS with the operator.


Related MCP server: MCP Student Assistant

Part B — For the operator (run the server)

This project uses uv to manage Python and dependencies.

1. Install

cd /path/to/moodle_mcp
uv sync          # creates .venv and installs from uv.lock

(Install uv first if needed: curl -LsSf https://astral.sh/uv/install.sh | sh.)

2. Run as an HTTP server

MCP_HOST=0.0.0.0 uv run nccu-moodle-mcp http

Endpoint: http://<host>:3033/mcp (Streamable HTTP, stateless, JSON responses). On startup it discovers + caches the Moodle backend and SSO URL, then serves.

Environment variables:

Var

Default

Purpose

MCP_HOST

127.0.0.1

Bind address. Set 0.0.0.0 to accept remote connections.

MCP_PORT

3033

Port.

MCP_ALLOWED_HOSTS

* (any host)

Hostnames allowed in the Host header (DNS-rebinding guard). Default * accepts any host. To lock down, set specific hostnames (comma-separated) — include the port if clients send one (e.g. 1.2.3.4:3033).

MOODLE_SSO_URL

(auto-discovered)

The NCCU SSO login URL (i.nccu.edu.tw/Login.aspx?...). Normally found automatically from Moodle's login page; set this to skip discovery or pin it.

The host check defaults to allowing any host. If you set MCP_ALLOWED_HOSTS to specific names, a request whose Host isn't listed is rejected with HTTP 421 — the value must match the Host header exactly, including the port when one is present.

Terminate TLS with a reverse proxy and forward to the app on localhost. Example Caddy config:

moodle-mcp.example.com {
    reverse_proxy 127.0.0.1:3033
}

Run the app bound to localhost, optionally locking the host to your domain:

MCP_ALLOWED_HOSTS="moodle-mcp.example.com" uv run nccu-moodle-mcp http

(You can also leave MCP_ALLOWED_HOSTS at its default * when the app port is only reachable through the proxy.)

4. Keep it running

Docker Compose (recommended). The repo ships a Dockerfile (multi-stage, uv-based) and docker-compose.yml (service nccucourse, bind 0.0.0.0:3033, MCP_ALLOWED_HOSTS=*, restart policy, healthcheck):

docker compose up -d --build     # build and start
docker compose logs -f           # watch
docker compose down              # stop

Override settings via a local .env or the shell, e.g. to lock the host down:

MCP_ALLOWED_HOSTS=moodle-mcp.example.com docker compose up -d

systemd (bare-metal alternative):

[Unit]
Description=NCCU Moodle MCP
After=network.target

[Service]
WorkingDirectory=/path/to/moodle_mcp
Environment=MCP_HOST=0.0.0.0
Environment=MCP_PORT=3033
ExecStart=/usr/local/bin/uv run nccu-moodle-mcp http
Restart=always

[Install]
WantedBy=multi-user.target

Smoke test

curl -s https://moodle-mcp.example.com/mcp -X POST \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Layout

src/nccu_moodle_mcp/        the package
├── __init__.py
├── __main__.py             `python -m nccu_moodle_mcp [http]`
├── app.py                  the MCPServer instance, credential handling, tool runner, param types
├── server.py               entry point: imports tools (registers them) and runs the transport
├── moodle_client.py        MoodleClient: SSO login, site discovery, ws() core
├── helpers.py              shared helpers (time / HTML / term-code / semester filter)
└── tools/                  one module per tool — logic + its own @mcp.tool (+ tool-specific helpers)
    ├── courses.py          list_courses, search_courses, get_course_role
    ├── assignments.py      list_assignments
    ├── deadlines.py        upcoming_deadlines
    ├── grades.py           get_grades
    ├── contents.py         get_course_contents
    ├── module.py           get_module (open one item, dispatch by type)
    ├── announcements.py    list_announcements, get_announcement
    └── notifications.py    get_notifications
scripts/
└── http_client.py          minimal plain-requests client for testing
pyproject.toml              metadata, deps, `nccu-moodle-mcp` entry point
uv.lock                     pinned lockfile (committed)
Dockerfile                  multi-stage uv build; `prod` target runs the server
docker-compose.yml          service `nccucourse` — build + run on port 3033
.dockerignore               keeps .venv, secrets, caches out of the build context

Available Tools

11 tools
get_announcementRead an announcementA

Open ONE announcement and read its thread — the original post plus any replies — given a discussion_id from list_announcements.

Posts are oldest-first; limit/offset paginate long threads.

Returns {discussion_id, total, posts:[{post_id, parent_id, subject, author, posted, message}]}. posted is Taipei time 'YYYY-MM-DD HH:MM'.

Credentials come from the MCP settings headers, not from you.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMax posts to return.
offsetNoSkip this many posts (for paging).
discussion_idYesDiscussion id from list_announcements.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are present, so the description carries the full burden. It discloses post ordering, pagination behavior via limit/offset, the exact return shape, the Taipei time format, and the fact that credentials come from MCP settings headers. That is a thorough behavioral profile for a read-only resource.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with purpose, then efficiently covers ordering/pagination, return format, and credential handling. Every sentence contributes operational information and there is no filler or redundant restatement of the tool name.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Without an output schema, the description carefully documents the returned JSON and the timestamp format. It also states the dependency on list_announcements. Given only three parameters and a straightforward read operation, this is complete enough for an agent to select and call the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so baseline is 3. The description adds useful value by noting that limit/offset paginate long threads. It also reinforces the relationship between discussion_id and list_announcements, though that is already in the schema. Just enough added meaning to go above baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a clear action and resource: 'Open ONE announcement and read its thread — the original post plus any replies — given a discussion_id from list_announcements.' This distinguishes it from siblings like list_announcements and get_notifications by specifying it retrieves one conversation thread, not a list.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear usage context by tying the input to a discussion_id from list_announcements. It tells the agent when the flow is list first then read, but it does not explicitly list alternatives or say 'when not to use this tool.' Clear context, no exclusion statement.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_course_contentsGet course contentsA

Get everything the teacher posted in one course (by Moodle course id, from list_courses), grouped by section — NCCU names sections by week, so this is the week-by-week list of materials, links, forums and assignments.

The summary is the teacher's text for that section/week (readings, plan, notes) — many NCCU weeks have only a summary and no attached items. By default a section is shown if it has items OR a summary; only truly blank sections are dropped. Set include_empty true for the full week skeleton including blank weeks.

Each section: {section_id, section, summary, modules:[{id, instance, name, type, url}]}. type is the Moodle module (assign, resource, url, forum, quiz, page, folder, label, …); id is the course-module id (cmid) and instance the activity id — use them to open an item with other tools (e.g. an assign instance is the course_id-independent assignment id, a forum instance feeds get_announcement's forum).

Credentials come from the MCP settings headers, not from you.

ParametersJSON Schema
NameRequiredDescriptionDefault
course_idYesMoodle course id (from list_courses).
include_emptyNoInclude truly blank sections (no items and no summary).

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden, and it is highly transparent: it explains default section filtering, the effect of include_empty, the meaning of module fields, and that credentials come from MCP headers rather than the caller. It does not claim a read-only flag, but 'Get' plus the absence of any mutation language aligns with a retrieval operation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Although long, every sentence earns its place: purpose, filtering behavior, output structure, cross-tool routing, and authentication. The main purpose is front-loaded, and the later paragraphs provide necessary detail for a tool with no output schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description completely compensates for the missing output schema by specifying the section and module object shapes, default behavior, and how ids connect to other tools. There are no obvious gaps in what the agent needs to call or interpret the result.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds meaningful context: course_id is tied to list_courses, and include_empty is explained as showing the 'full week skeleton including blank weeks.' This enriches the schema's terse descriptions without being redundant.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Get everything the teacher posted in one course', and adds that results are grouped by section/week. It distinguishes itself from sibling tools by asserting a comprehensive week-by-week list of materials, links, forums and assignments, unlike narrower tools like list_assignments or get_announcement.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It clearly states the input comes from a Moodle course id obtained from list_courses, and it shows how the output ties to other tools (e.g., a forum instance feeds get_announcement). However, it never explicitly states when not to use this tool or names alternative tools for narrower cases.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_course_roleGet my role in a courseA

Get the user's role in one course (by Moodle course id, from list_courses): 'student', 'teacher' (often the TA/助教), 'editingteacher' (instructor), 'teachingassistant', 'manager', etc.

Returns {course_id, role, roles}: role is the primary role shortname, roles all of them (a user can hold more than one).

Credentials come from the MCP settings headers, not from you.

ParametersJSON Schema
NameRequiredDescriptionDefault
course_idYesMoodle course id (from list_courses).

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the behavioral disclosure burden. It explains the exact return structure ({course_id, role, roles}), clarifies that a user can hold multiple roles, and explicitly states that credentials come from MCP settings headers rather than from the agent. This is strong transparency for a simple read-only lookup.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and front-loaded: it states the purpose first, then role values, then return format, then credential handling. Every sentence adds distinct value with no filler or repetition of schema fields.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter tool with no output schema, the description is complete: it identifies the input source, enumerates expected role values, explains the return fields and their meaning, and clarifies authentication. An agent has enough information to call this tool correctly and interpret the result.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, and the schema already documents course_id as a Moodle course id. The description adds useful provenance (from list_courses) and role-value context, but it does not need to compensate for schema gaps. This meets the baseline for a well-covered single parameter.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific verb ('Get'), a concrete resource ('the user's role in one course'), and identifies the required input (Moodle course id). It also distinguishes itself from course listing tools by scoping to a single course and returning role data, not course metadata.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly indicates that course_id comes from list_courses, giving an agent a concrete prerequisite and source. It does not explicitly state when not to use the tool or name alternatives, but the narrow scope and role-specific output make the usage context clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_gradesGet course gradesA

Get the student's own grade items for one course (by Moodle course id, from list_courses).

Each item: {item, grade, percentage, range, feedback, type}. A '-' grade means not yet graded.

Credentials come from the MCP settings headers, not from you.

ParametersJSON Schema
NameRequiredDescriptionDefault
course_idYesMoodle course id (from list_courses).

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden of behavioral disclosure. It specifies the output format (each item fields), explains the meaning of a '-' grade, and clarifies that credentials are taken from MCP settings headers rather than the agent. This gives the agent necessary operational details without stating explicit read-only status, though 'get' implies it.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise and efficiently structured: the first sentence states the purpose, the second explains the output format, and the third addresses credentials. Every sentence earns its place with no fluff, and the main purpose is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple tool with one parameter and no output schema, the description is complete: it provides the return structure, the meaning of a special grade value, and the credential source. It doesn't mention error cases or pagination, but these are minor for this scope. The agent has everything needed to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema already describes course_id fully with 100% coverage, including the note 'from list_courses.' The description repeats this same information without adding new semantic meaning about the parameter. Since the schema covers it, the baseline is 3; the description adds no additional parameter-specific insight.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a clear verb and resource: 'Get the student's own grade items for one course.' It distinguishes itself from siblings by focusing on grades specifically, and it clarifies the input is a Moodle course id from list_courses. This unambiguously differentiates it from course listing, announcements, and assignment tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides a clear prerequisite: the course id must come from list_courses. It implies the tool is for retrieving grades for a single course, but does not explicitly state when not to use it or name alternatives. The context is clear enough for an agent to know this is the go-to for grades, but it lacks explicit exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_moduleOpen a course itemA

Open ONE item a teacher posted and return its content, given its cmid (course-module id — the id in a /mod//view.php?id= link, or from get_course_contents). course_id is OPTIONAL — omit it and it's resolved from the cmid, so a bare cmid/link is enough. It detects the item type and returns:

  • resource/folder -> files:[{filename, mimetype, size, url}] (open the url/view_url in a browser to download; no direct download here yet)

  • url -> external_url

  • page -> html (plain text)

  • label -> text

  • forum -> forum_id + intro + discussions[] (read one with get_announcement)

  • assign -> description (instructions), attachments, due/opens/cutoff, grade_max, status, submission{submitted_at,files,text}, feedback{grade,grade_display,graded_at,comment,files}

  • quiz -> metadata + attempts · otherwise -> description

Always includes {course_id, cmid, instance, type, name, view_url}.

Credentials come from the MCP settings headers, not from you.

ParametersJSON Schema
NameRequiredDescriptionDefault
cmidYesCourse-module id (the id in a view.php?id= link).
course_idNoMoodle course id. Optional — resolved from cmid if omitted.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full disclosure burden and does so thoroughly. It reveals the exact type-dependent return shapes, the always-included common fields, that file downloads must be done via browser, and that credentials come from MCP settings headers rather than from the agent. This goes well beyond a generic 'open an item' statement.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long due to necessary type-specific detail, but it is tightly structured with a clear opening sentence, parameter guidance, and a bullet-like breakdown of return shapes. Every sentence adds value, and the most important usage constraint is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema and no annotations, yet the description covers the full item-type matrix, common response fields, optional parameter resolution, download limitations, and authentication source. For an agent selecting and invoking this tool, the available context is sufficient to proceed correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds useful meaning: `cmid` is the id from `/mod/<type>/view.php?id=<cmid>` or `get_course_contents`, and `course_id` can be omitted entirely because it is resolved from `cmid`. This helps an agent construct a valid call with minimal inputs.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Open ONE item a teacher posted and return its content, given its `cmid`'. It also differentiates itself by explaining the item-type-specific behavior and explicitly routes forum reading to `get_announcement`, so an agent can distinguish it from siblings like `list_courses` or `get_course_contents`.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context: use this tool to open a single course item from a `cmid`, optionally omitting `course_id` because it is resolved from the `cmid`. It points to `get_course_contents` as the source for `cmid` values and suggests `get_announcement` for reading individual forum posts, but it does not explicitly state exhaustive when-not-to-use conditions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_notificationsGet notificationsA

Get the student's Moodle notifications (the notification bell): assignment due reminders, grading, forum posts, etc.

Each notification: {subject, message, posted, read, url}, newest first. limit caps the count. The result also reports how many are unread.

Credentials come from the MCP settings headers, not from you.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMax notifications to return.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full behavioral burden. It discloses the return structure (subject, message, posted, read, url), ordering (newest first), the effect of limit, the unread count, and the authentication source (MCP settings headers). This is strong transparency, though it omits edge cases like empty results.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and front-loaded. It opens with the purpose, then packs essential behavioral details into a few sentences without fluff. Every sentence contributes value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple one-parameter getter with no output schema, the description covers output structure, ordering, limit behavior, unread count, and authentication. Nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema covers the only parameter (limit) with a description ('Max notifications to return.'). The tool description adds 'caps the count,' which is essentially a restatement. With 100% schema coverage, the baseline is 3; no significant additional semantics are provided.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool 'Get the student's Moodle notifications' and gives concrete examples (assignment due reminders, grading, forum posts). It distinguishes from siblings like list_announcements and get_grades by referencing the notification bell, making the purpose unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context for when to use the tool (to fetch the notification bell) but does not explicitly name alternatives or state when not to use it. The scope is clear, but there's no explicit routing guidance beyond the implied distinctness from siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_announcementsList announcementsA

List announcement TILES (headers only, no message body) from a course's "Announcements" forum — like scanning the forum page. To read one, take its discussion_id and call get_announcement.

If course_id is given, lists that course's announcements; otherwise aggregates across the current (latest) semester's courses. limit/offset paginate the newest-first list.

Each tile: {discussion_id, course_id, course, subject, author, posted, replies, pinned, url}. posted is Taipei time 'YYYY-MM-DD HH:MM'.

Credentials come from the MCP settings headers, not from you.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMax tiles to return.
offsetNoSkip this many (for paging).
course_idNoMoodle course id (from list_courses). Omit to cover all current-semester courses.

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full behavioral burden, and it delivers: it discloses that only headers are returned, that results are newest-first, that course_id scopes vs. aggregates, the exact tile shape, the Taipei timezone format, and that credentials come from MCP settings rather than the agent. This gives the agent a clear model of what the tool does and what it returns.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and well-organized: it leads with the core purpose and distinction from get_announcement, then covers parameter behavior, return shape, timezone, and authentication. Every sentence adds value with no redundancy or filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite having no output schema and no annotations, the description is self-sufficient: it explains what is returned, how pagination works, how course_id scopes the result, what each tile contains, and where credentials come from. An agent can invoke this tool correctly without needing additional context.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Although the schema already covers 100% of parameters, the description adds meaningful semantics beyond the schema: course_id is said to come from list_courses and omitting it aggregates across current-semester courses, and limit/offset are tied to the newest-first pagination behavior. This enriches the agent's understanding of how to invoke the tool correctly.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool lists announcement tiles (headers only, no message body) from a course's Announcements forum, using the specific verb 'List' and a well-defined resource. It also distinguishes itself from get_announcement by explicitly directing the agent to call that sibling to read a full announcement, making the purpose unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit guidance on when to use this tool: it is for scanning announcement tiles, and reading a full announcement requires get_announcement using the discussion_id. It also explains the course_id behavior (specific course vs. aggregate across current-semester courses), which tells the agent exactly how to choose parameters.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_assignmentsList assignmentsA

List assignments (with due dates and submission status) for the student's courses.

Scope, in priority order:

  • course_ids: if given, list assignments for exactly those Moodle course ids (from list_courses); sem is ignored.

  • sem: otherwise filter all enrolled courses by NCCU term code. Default (neither given) = latest semester; "1142" = that term; "all" = every course.

Filter by date (ISO dates in Taipei time, e.g. "2026-09-08"): due_from/due_to bound the DUE date, opens_from/opens_to bound the OPEN (submissions-from) date. Give any subset; compute ranges from today for 'due this week', 'opened last week', etc. This is the best way to answer 'what's due/opened in some period', since it also carries submission status.

By default only courses where you are a STUDENT are included (your own homework); set include_all_role true to also include courses where you are a teacher/TA.

Each assignment: {id, course_id, course, role, name, due, opens, cutoff, status, url}, where role is the user's role in that course (student/teacher/…) and status is 'graded' / 'submitted' / 'not submitted'. Times are Taipei time 'YYYY-MM-DD HH:MM'; null means unset. Sorted by due date.

Credentials come from the MCP settings headers, not from you.

ParametersJSON Schema
NameRequiredDescriptionDefault
semNoNCCU term code, e.g. "1142". Omit for the latest semester; "all" for every semester.
due_toNoOnly assignments due on/before this ISO date (Taipei tz).
due_fromNoOnly assignments due on/after this ISO date (Taipei tz).
opens_toNoOnly assignments opening on/before this ISO date (Taipei tz).
course_idsNoSpecific Moodle course ids (from list_courses). When given, overrides `sem`.
opens_fromNoOnly assignments opening on/after this ISO date (Taipei tz).
include_all_roleNoInclude courses where you are not a student (teacher/TA). Default false = only your student courses.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and discloses substantial behavior: scope precedence rules, defaults (latest semester, student-only), the semantic distinction between DUE and OPEN dates, Taipei timezone handling, exact return fields with status values, sort order, null semantics, and that credentials come from MCP headers. Only pagination/limits and error behavior are unmentioned, which is minor for a read-only list tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is longer than average but every block earns its place: summary line, scope precedence, date semantics, role filtering, output shape, and credential source are all scannable sections. It is front-loaded with the core purpose and would only be trimmed by removing minor redundancy with the schema's own descriptions of sem.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 7 parameters with no annotations and no output schema, the description is well-near complete: it defines every parameter's semantics, the return shape, timezone and date format, defaults, sort order, and credential source. The notable gap is no mention of result limits or pagination, and no explicit contrast with upcoming_deadlines, but for a list-query tool the coverage is strong.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds real meaning beyond the schema: it explains the due-vs-open semantic split, gives use-case guidance ('compute ranges from today for 'due this week''), clarifies that course_ids come from list_courses and override sem, and explains the rationale behind include_all_role. This elevates it above baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening line names a specific verb and resource ('List assignments') and immediately adds the distinguishing payload: due dates and submission status. It differentiates from siblings by scope ('student's courses'), data carried (status), and the closing claim that it is the best way to answer period-based 'due/opened' questions, which separates it from upcoming_deadlines.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit when-to-use context: scope precedence for course_ids vs sem, a clear 'best way to answer' date-range questions claim, and default student-only behavior with an override flag. It does not explicitly name sibling tools to use instead for other cases, so it falls short of a 5, but the guidance is concrete and actionable.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_coursesList Moodle coursesA

List the student's enrolled Moodle courses (with the user's role in each), filtered by semester.

By default (no sem), returns ONLY the latest semester's courses (the current term). Pass sem as an NCCU term code (e.g. "1142") to get that semester; pass "all" to return every enrolled course.

Each course is returned as an object with:

  • id (int) Moodle course id, usable in other course tools

  • name (str) full course title

  • url (str) direct link to the course

  • semester (str) NCCU term code the course belongs to (e.g. "1151")

  • current (bool) true if it is in the current (latest) semester

  • role (str) the user's role: 'student', 'teacher', 'editingteacher', 'teachingassistant', … (null if unknown)

Credentials come from the MCP settings headers, not from you.

ParametersJSON Schema
NameRequiredDescriptionDefault
semNoNCCU term code, e.g. "1142". Omit for the latest semester; "all" for every semester.

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations are absent, so the description carries the full burden. It discloses the non-obvious default (latest semester only), the output fields and their types, possible role values, and that credentials are injected from MCP settings. This is rich behavioral context beyond the schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-organized: a one-sentence purpose, a compact behavior paragraph, a bulleted output definition, and a short credential note. No sentence is redundant or wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter list tool with no output schema, the description fully covers return values, default semantics, parameter usage, and authentication behavior. Potential gaps like pagination or error handling are minor and do not prevent correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Although schema description coverage is 100%, the description adds meaning beyond the schema by explaining the default behavior when sem is omitted, the semantic value 'all', and providing example term codes. This gives an agent everything needed to use the parameter correctly.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('List'), a precise resource ('the student's enrolled Moodle courses'), and the scope (with role, filtered by semester). It clearly distinguishes this from sibling search_courses by limiting to enrolled courses.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly explains the default behavior (latest semester only) and how to use the sem parameter for a specific term or 'all'. It does not name alternative tools directly, but the enrollment scope and parameter guidance give a clear usage context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_coursesSearch my coursesA

Search the user's enrolled courses by keyword — the Moodle app's "filter my courses" box. query is matched as a case-insensitive substring of each course name, which contains the NCCU term code, the Chinese title and the English title — so a course code, a Chinese word or an English word all work (e.g. "物件導向", "Object-oriented", "703009").

Searches ALL enrolled courses across every term by default, so a keyword finds the course whatever semester it is in. Pass sem as a term code (e.g. "1142") to scope the search to one semester, or "latest" for the current term only.

Returns the same fields as list_courses: {id, name, url, semester, current, role}, newest term first. An empty query returns everything in scope (same as list_courses).

Credentials come from the MCP settings headers, not from you.

ParametersJSON Schema
NameRequiredDescriptionDefault
semNoTerm to search: 'all' (default, every enrolled course), a term code like '1142', or 'latest' for the current term.all
queryYesKeyword to match against the course name (code / 中文 / English).

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden — and it delivers. It discloses case-insensitive substring matching, the matchable name fields with examples, the default all-terms scope, sem scoping semantics, return field list, newest-term-first ordering, empty-query behavior, and the fact that credentials come from MCP settings headers rather than the agent. This is unusually complete behavioral disclosure for a tool with zero annotation coverage.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is slightly longer than the calibration ideal, but every sentence earns its place — purpose, matching details, scope behavior, return format, and credential note are each useful. It is front-loaded with the core purpose. A minor deduction for some redundancy between the schema and description (sem values are restated), though the description does add interpretive context.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 2-parameter search tool with no output schema, this is near-complete: it covers what is matched, how it is matched, default and scoped behavior, return fields, and ordering. The only gap is the absence of explicit pagination or result-limit information, which is minor given the tool mirrors list_courses behavior. An agent has everything it needs to invoke this correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, yet the description still adds substantial meaning beyond the schema. It explains what 'all' means as a default scope, how sem values map to behavior (term code vs 'latest'), and gives concrete example queries ('物件導向', 'Object-oriented', '703009'). The schema only labels parameters; the description supplies the matching and scoping semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb-resource pair (search enrolled courses by keyword) and anchors it to a concrete analog (the Moodle app's filter box). It explicitly names the matching semantics and the three name components (NCCU term code, Chinese title, English title), which makes the tool's purpose unmistakable. It also differentiates from the sibling list_courses by describing the empty-query equivalence.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Clearly describes when this tool is appropriate: keyword search across all enrolled courses or scoped to a term via the sem parameter. It references list_courses twice ('same fields as', 'same as list_courses'), which implicitly routes the agent to the list-all alternative, and explains the default all-terms behavior. It stops short of an explicit 'use list_courses when you want everything unfiltered' exclusion, hence 4 rather than 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

upcoming_deadlinesUpcoming deadlinesA

List the student's upcoming action events (assignment due dates, quiz closings, etc.) across courses within the next days (default 14). This is the best 'what's due soon' overview.

By default only events from courses where you are a STUDENT are included; set include_all_role true to also include courses where you are a teacher/TA. (Personal/site events are always kept.)

Each event: {name, course_id, course, role, due, overdue, module, url}. due is Taipei time 'YYYY-MM-DD HH:MM'. Sorted soonest first.

Credentials come from the MCP settings headers, not from you.

ParametersJSON Schema
NameRequiredDescriptionDefault
daysNoHow many days ahead to look (1-365).
include_all_roleNoInclude courses where you are not a student (teacher/TA). Default false = only your student courses.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full burden and it does a thorough job: it discloses the default 14-day window, the role-filter semantics, that personal/site events are always kept, the exact return fields, the timezone (Taipei time), the sort order (soonest first), and that credentials come from MCP settings rather than from the agent. This level of behavioral detail is rare and clearly exceeds what a simple 'list' description would provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core purpose in the first sentence, then layers role-filtering, output format, and credentials in a logical sequence. Every sentence contributes a distinct fact; there is no filler or repetition. It is longer than a typical tool description but justified by the density of useful information (timezone, sort, fields).

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, so the description must explain the return format itself—it does, listing all fields and their meaning (due in Taipei time). It also covers sorting, default filtering, and authentication source. For a read-only 'list' tool this is complete; an agent could call it correctly without needing to guess any behavior.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% (both parameters are described), so the baseline is 3. The description adds value beyond the schema by explaining the semantic difference of include_all_role (including teacher/TA courses) and reiterating the default for days. It also mentions the role field in the output, which indirectly clarifies what the parameter means for the response. This moves it above the schema-only baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb-resource pair ('List the student's upcoming action events') and scopes it precisely (across courses, within a time window). It also asserts 'This is the best what's due soon overview,' which signals its intended niche relative to the sibling tools (list_assignments, get_notifications, etc.), so an agent can distinguish it without opening their schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It clearly explains when to use it ('best what's due soon overview') and how the role filter changes the result set ('By default only events from courses where you are a STUDENT... set include_all_role true to also include teacher/TA courses'). It does not explicitly name alternatives or state when NOT to use it, but the purpose is clear enough that an agent can reasonably choose it over siblings that list specific resource types.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 11 tool updatesv0.1.0
    • First observedget_announcement
    • First observedget_course_contents
    • First observedget_course_role
    • First observedget_grades
    • First observedget_module
    • First observedget_notifications
    • First observedlist_announcements
    • First observedlist_assignments
    • First observedlist_courses
    • First observedsearch_courses
    • First observedupcoming_deadlines

TDQS

A4.4/5.0

Scored across 11 tools

Disambiguation4/5

Most tools target distinct resources (courses, announcements, assignments, grades, modules, notifications). However, list_courses/search_courses overlap as both enumerate courses with different filters, and list_assignments/upcoming_deadlines both surface due-date information, creating minor ambiguity.

Naming Consistency4/5

Tool names consistently use snake_case with a clear verb_noun pattern (list_*, get_*, search_courses). The only deviation is upcoming_deadlines, which is a noun phrase rather than verb_noun, but it remains predictable and readable.

Tool Count5/5

11 tools is well-scoped for a student-facing Moodle assistant. Each tool has a clear, useful purpose, and the set is neither bloated nor too thin.

Completeness4/5

The set covers core read-only student workflows: courses, announcements, assignments, deadlines, grades, and course content. Write operations like submitting assignments are missing, but these appear outside the server's apparent purpose, so the gap is minor.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers