POLITEMall MCP Server
The exposed schema provides a small, read-only POLITEMall toolset for courses and your own academic data.
List your enrolled POLITEMall courses.
Get a course’s module/topic table of contents.
Get your grade items and scores for a course.
Get a course’s announcements/news.
Get a course’s calendar events.
Get a course’s assignment/dropbox folders and due dates.
Check the currently authenticated POLITEMall user’s identity.
Course-specific tools take a numeric courseId (orgUnitId) from list_courses; this schema exposes no write, instructor, quiz-authoring, discussion, survey, or catalog tools.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@POLITEMall MCP Serverwhat are my current grades?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
politemall-mcp
MCP server for the Singapore polytechnic/ITE learning systems on POLITEMall: the two D2L Brightspace tenants POLITEMall and NYP. Talks directly to each tenant's own REST API as the signed-in person — no institutional API key or app registration involved.
Live server: https://<your-server-host> — one shared server; each person signs in once with
their own Microsoft account. The exact same server (same tools, same code) can also
run on your own machine with npx -y @qiaoguanming/politemall-mcp@latest, signing in in
your own browser and keeping your sign-in data on your own disk.
The two tenants
One sign-in covers both:
POLITEMall (
lms.polite.edu.sg) — shared D2L Brightspace instance across polytechnics.NYP (
nyplms.polite.edu.sg) — NYP's own dedicated D2L Brightspace instance.
Related MCP server: moodle-utn-mcp
Tools
D2L (POLITEMall and NYP) — courseId is an opaque string like politemall:6606
or nyp:12345 returned by list_courses; it encodes which of the two schools the
course belongs to, so just pass it through as-is to the other tools.
Tool | What it does |
| Your enrolled courses, merged across POLITEMall and/or NYP |
| Content items with due dates across every course and connected school in one call — completed and pending |
| D2L-computed overdue items across every course and connected school — a filtered view distinct from |
| Counts of unread/pending activity (discussions, feedback, quizzes) across every course and connected school — a "what's new" feed |
| Your calendar events across every course and connected school in one call, within a date window (default: 7 days ago to 60 days ahead) |
| The course's module/topic tree — one call — with |
| A single content topic — a drill-down from |
| The course description/overview content (the "Class Overview"/syllabus) |
| Grade items and your scores |
| Your calculated/adjusted final grade for a course |
| Latest announcements, newest first, plain text, drafts excluded — for one course or (no |
| Course calendar events |
| Assignments and quizzes, soonest due first — instructions, rubric, whether you've submitted, your files and feedback, quiz attempts, plus scored items that have no assignment behind them. One course, or all active courses |
| Read the files an instructor attached to an assignment (PDF, DOCX, XLSX, PPTX, text): list which assignments have attachments, then read one and get its text |
| Your own submission (files, dates, score, feedback) for an assignment folder |
| Quiz list, then your attempt scores/status for one |
| Questions defined for a quiz |
| Drill down forums → topics → actual post content and authors |
| Who is in a course: headcount per role, plus the staff by default (students only with |
| Rubric criteria/levels — by |
| Survey list, then your attempt history for one |
| Questions defined for a survey |
| Group categories and groups, with member counts |
| Your identity on each connected school |
POLITEMall/NYP (D2L), instructor/TA only — same courseIds as above, but
these call grading-permission-gated endpoints. A student's session gets a clear
permission error, not their own data, if they call one of these by mistake.
Tool | What it does |
| Every grade item and score for every student — the gradebook view |
| Every student's calculated/adjusted final grade — the gradebook's final-grade column |
| Every student's attempts for a quiz (or one student's, by classlist Identifier) |
| Every student's attempts for a survey (or one student's, by classlist Identifier) |
| Every student's submission for an assignment folder — files, dates, score, grading status |
POLITEMall/NYP (D2L), quiz authoring (instructor/TA only, writes to the school) — the only tools that change anything in D2L. Every other tool is read-only. Your MCP client should ask before running them. The agent turns your question list (Excel, CSV, a document) into structured data; these tools never read files.
Tool | What it does |
| Create an empty quiz — hidden from students unless |
| Change those settings on an existing quiz; settings you leave out keep their value |
| Add questions to a quiz (up to 100 per call), or update existing ones by |
All three take dryRun: true to preview the request without changing anything. There is no tool to delete
a quiz or a question. Example question list for save_quiz_questions:
[
{ "type": "multiple_choice", "text": "Capital of France?", "answers": [
{ "text": "Paris", "correct": true }, { "text": "Rome", "correct": false } ] },
{ "type": "true_false", "text": "Water boils at 100 °C at sea level.", "answer": true, "points": 2 },
{ "type": "matching", "text": "Match the symbol", "pairs": [
{ "prompt": "H2O", "match": "Water" }, { "prompt": "NaCl", "match": "Salt" } ] }
]POLITEMall/NYP (D2L), long-tail escape hatch — the tools above are a curated slice of the
~190 read (GET) routes Valence exposes under Learning Environment; the rest are reachable
without a dedicated tool for each one. Start with the curated tools above — they're
response-shaped and better-documented. Reach for these only when nothing above covers what you
need.
Tool | What it does |
| Search/browse the full route catalog by category or keyword, to find an operation's key and required parameters |
| Invoke any cataloged operation by key — returns D2L's raw JSON response, unshaped. Course-scoped operations take |
POLITEMall public catalog — a third, separate system again: the marketing
site at politemall.polite.edu.sg, not Brightspace. No login required.
Tool | What it does |
| Search/browse all ~300 modules in the public marketing catalog across every poly/ITE — not your enrollments |
Valence (the actual Brightspace/D2L API) has no endpoint for browsing courses
you're not enrolled in, for any non-admin role — confirmed by testing directly,
not just reading docs: even GET /d2l/api/lp/(version)/courses/(orgUnitId) for a
course we are enrolled in returns 403 Forbidden, since it needs a
course-management permission regular students/staff don't have. The public
catalog above is the closest available substitute for "what modules exist" —
but note its catalogCode values (e.g. D-NP-06030001) are a completely
different ID space from Brightspace courseIds and can't be passed to
get_grades/get_course_content/etc.
Evidence links
Tool results let you check what you were told. Where a result has a page on the school's site, it carries the link next to the data:
sourceUrlon an item (an announcement, quiz, assignment, content topic, discussion topic, calendar event, ...) opens that item.pageUrlon a result opens the page that shows the whole result (the classlist, "my grades", a course's quiz list). An item with no verified page has no link at all, not a guessed one.provenance(or, for results that are plain lists, a second text block) says which system the data came from (NYP Brightspace, POLITEMall Brightspace) and when it was read....Sgtfields (dueDateSgt,dateSgt, ...) give the same instant as the original UTC value in Singapore time (+08:00), which is what the sites display. The original value is never changed.Links inside announcement, discussion or description text were written by other people; results flag them (
untrustedLinksInText) and they are never used as evidence.
The server also sends citation rules to the connecting agent (cite the sourceUrl, never build or
edit a link, say when there is none). A link opens only for someone signed in to that school in
their browser, and it can show only what that person is already allowed to see. Every
pattern is opened in a real session before it is emitted, and test-oracle/verify-links.js
re-checks them.
Two environment switches (see deploy/README.md): SOURCE_LINKS=off removes all
of the above and returns the previous result shapes; SOURCE_RESOURCE_LINKS=on additionally
returns MCP resource_link blocks for clients that display them.
Connecting
You connect with only the server URL. The first time, your MCP client opens a sign-in page in your browser; you type your own Microsoft account and approve MFA there, and you're connected. Nothing to install, no cookies or tokens to copy.
How the sign-in works. The page shows a live view of a browser running on the server, at the real Microsoft sign-in page. What you type goes only to Microsoft's page: it isn't stored or logged. When you reach POLITEMall (and NYP, which signs in automatically from the same Microsoft session), the server keeps your D2L session, exchanges it for an access token, and renews that token itself. If the session ever lapses it first tries to renew it silently from your saved Microsoft sign-in; only if Microsoft asks for something again will a tool reply with a fresh one-time sign-in link.
What the server keeps about you (all encrypted at rest): your D2L session for each tenant, your current access token, and your Microsoft sign-in state, which is deleted after 30 days without use. By connecting you trust this server with that state, so only connect to a server you trust. To delete everything and revoke every token your MCP clients hold:
curl -X POST https://<your-server-host>/signout -H "Authorization: Bearer <your MCP access token>"Sign-ins are limited to a few at a time; if the server is busy, try again in a minute.
Connecting your MCP client
Claude Code
claude mcp add --transport http politemall https://<your-server-host>/mcpAdd --scope user to make it available in every project, not just the current one. Then run
/mcp in Claude Code, choose politemall and Authenticate; your browser opens the sign-in page.
Claude Desktop
Settings → Connectors → Add custom connector, name it, and enter
https://<your-server-host>/mcp. Claude Desktop opens the sign-in page in your browser.
Microsoft Copilot Studio
Your agent → Tools → Add a tool → New tool → Model Context Protocol, server URL
https://<your-server-host>/mcp, authentication OAuth 2.0 with dynamic discovery (the
server publishes its OAuth metadata and supports dynamic client registration and PKCE).
Security notes
There is no signup and no shared secret: an MCP access token is only issued after a completed Microsoft sign-in, and it identifies a person, nothing more.
Sign-in links are unguessable, single-use and short-lived; each runs in its own isolated browser that is closed as soon as the sign-in ends, fails, times out or you leave the page.
D2L sessions, access tokens and Microsoft sign-in state are encrypted at rest (AES-256-GCM) and used only server-side to call D2L on your behalf. Typed credentials, cookies and tokens are never logged;
/mcpand/signinrequests are rate-limited and audit-logged with a short one-way hash of your id, a timestamp and IP.OAuth endpoints enforce PKCE and exact redirect-URI matching; authorization codes work once.
Architecture
server/
control-plane/ the MCP server (Streamable HTTP) — the only server in this repo
src/
index.ts hosted entry point; app.ts builds the HTTP app
local/ npx entry point: stdio server, local-browser sign-in, key storage, CLI
server.ts builds the MCP server for one caller
api/ D2L client: version discovery, routes, pagination, errors
auth/ OAuth server, streamed sign-in, session vault, token mint/renewal, encryption, rate limiting
tools/ one file per tool (+ shared helpers and schemas)
utils/ config, audit log, HTML→Markdown, PDF/Office text extraction, deep links
types/ shared types, incl. ToolContext
tests/ mirrors src/ (api/, auth/, tools/, utils/); run with `npm test`
docker-compose.yml, Caddyfile
deploy/ AWS provisioning notes/scripts for the hosted serverTools never know where a caller's sessions live: they receive a ToolContext
(types/tool-context.ts), so the hosted server and a local run expose the identical
tool set. See deploy/README.md for how the server is provisioned
and operated on AWS.
Running it locally
The same tools, D2L client and session handling run on your own computer, started by your MCP
client with npx. Only two things differ from the hosted server: you sign in in a browser window
on your own computer, and your sign-in data stays on your own disk.
Add this to your MCP client's servers (or run npx -y @qiaoguanming/politemall-mcp@latest setup and answer yes
for the clients it finds):
{ "mcpServers": { "politemall": { "command": "npx", "args": ["-y", "@qiaoguanming/politemall-mcp@latest"] } } }Needs Node.js 22 or newer and Google Chrome or Microsoft Edge (or set CHROMIUM_PATH to a Chrome,
Edge or Chromium executable). Nothing is downloaded. The first time you ask for something, a
browser window opens on the school's Microsoft sign-in; type your own credentials and approve MFA
there. The window closes by itself and you ask again. On macOS run npx from your home folder, not
Documents, Desktop or Downloads.
Command | What it does |
| Runs the MCP server over stdio (what your client launches) |
| Checks Node and the browser, offers to add the server to your MCP clients, offers to sign in. Never asks for a password |
| Opens the sign-in window now (also retries a stuck sign-in) |
| Deletes the sign-in data stored on this computer (does not sign you out of Microsoft or the school elsewhere) |
| Checks Node, browser, key storage, data directory, connectivity and who is signed in; prints no secrets |
Where your data lives. Encrypted sessions are in sessions.json under %APPDATA%\politemall-mcp
(Windows), ~/Library/Application Support/politemall-mcp (macOS) or ~/.local/share/politemall-mcp
(Linux); set POLITEMALL_DATA_DIR to move it. The encryption key is kept in the operating
system's credential store (Keychain, Credential Manager, Secret Service) and, only when none is
available, in an owner-only master.key beside it. doctor tells you which. Your Microsoft
password is never stored or seen by this program.
npx -y @qiaoguanming/politemall-mcp@latest always runs the newest release (npx may reuse a cached copy for a
short while). To pin one, use @qiaoguanming/politemall-mcp@X.Y.Z; releases are listed on the
releases page.
Developing it: from server/control-plane, npm ci && npm run build, then
node dist/local/cli.js is the same command. Tests: npm test (compiles src/ and tests/, then
runs everything with Node's test runner).
Contributing and releases
Changes go through pull requests with a Conventional Commit title (feat: ..., fix: ...); CI must pass. Versions, tags and CHANGELOG.md are produced by release-please: merge the Release PR to cut a release. A release does not deploy; see deploy/README.md for deploying. Full rules for people and agents: .claude/rules/cicd.md.
License
MIT. Third-party notices are in THIRD_PARTY_NOTICES.md.
Available Tools
7 toolsget_announcementsGet announcementsA
Get news/announcements posted in a course.
| Name | Required | Description | Default |
|---|---|---|---|
| courseId | Yes | The course's orgUnitId, from list_courses |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries full behavioral disclosure burden, but it only says 'Get', implying a read-only operation. It does not mention whether only published announcements are returned, ordering, pagination, permission requirements, or the shape of the result, leaving meaningful gaps for the agent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single compact sentence with no fluff. The phrase 'news/announcements' clarifies synonyms without adding unnecessary length, and the core resource is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple one-parameter read tool, the description is adequate but not complete: it omits what the response contains and whether the tool requires any special context. Given no output schema and no annotations, a bit more detail about returned data would make it fully self-sufficient.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and the single courseId param already documents its meaning and source via list_courses. The description adds no parameter-level nuance beyond the schema; baseline 3 is warranted because the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Get') and resource ('news/announcements posted in a course'), which clearly distinguishes it from siblings like get_grades or get_assignments. It also aligns with the tool name and title without being tautological.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage: call this tool when you need course announcements. However, it provides no explicit when-to-use guidance or exclusion versus alternatives such as get_course_content, which could also conceivably surface announcements. The interaction with siblings is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_assignmentsGet assignmentsB
Get dropbox/assignment folders and due dates for a course.
| Name | Required | Description | Default |
|---|---|---|---|
| courseId | Yes | The course's orgUnitId, from list_courses |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description must carry the behavioral disclosure burden. It implies a read operation but does not mention what the returned data looks like, whether it can be empty, authentication expectations, or any side effects. This is a meaningful gap for a tool with no output schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single concise sentence with no filler. Every word contributes to identifying the resource and scope, and the core purpose is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is simple with one well-documented parameter, so the description covers the basic call context. However, since there is no output schema, the description could usefully clarify the expected return shape beyond 'folders and due dates', and it does not.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and the sole parameter courseId is already documented as the orgUnitId from list_courses. The description does not add further parameter-level meaning, but it also does not need to because the schema already provides adequate semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a clear verb ('Get'), a specific resource ('dropbox/assignment folders and due dates'), and a scope ('for a course'). This distinguishes it from sibling tools like get_grades and get_announcements without needing to open the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no guidance on when to use this tool versus alternatives such as get_course_content or get_calendar_events. The phrase 'for a course' implies context, but the description does not state when this tool is the right choice or when it is not.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_calendar_eventsGet calendar eventsB
Get calendar events for a course.
| Name | Required | Description | Default |
|---|---|---|---|
| courseId | Yes | The course's orgUnitId, from list_courses |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description itself must signal behavior; 'Get' clearly implies a read-only retrieval within the course scope. However, it does not disclose what the returned events look like, whether date-range filtering is available, pagination, or authentication expectations, so transparency is partial.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single front-loaded sentence with no filler words. Every word carries meaning, and it is easy to scan quickly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter read-only tool with no output schema, the description provides the essential what and scope, and the schema covers the parameter. It is less complete than ideal because it offers no usage guidance or return-value context and has no annotations to fall back on.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the courseId property already explains that it is the course's orgUnitId from list_courses. The description's 'for a course' reinforces that single parameter but adds no new semantic information beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Get'), a specific resource ('calendar events'), and a scope ('for a course'), so an agent can tell it retrieves course-calendar data rather than content, grades, or announcements. It doesn't explicitly contrast it with sibling tools, so it misses the top score.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance is given about when to call this tool instead of a sibling such as get_course_content or get_assignments. The phrase 'for a course' indicates a required parameter but provides no selection heuristics or exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_course_contentGet course contentA
Get the module/topic table of contents for a course.
| Name | Required | Description | Default |
|---|---|---|---|
| courseId | Yes | The course's orgUnitId, from list_courses |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden of behavioral disclosure. 'Get' implies read-only, and 'module/topic table of contents' indicates the response is a structural outline, but the description does not disclose side effects, permission requirements, or nesting/pagination behavior. This is acceptable for a simple get but leaves some traits unstated.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One compact sentence with a clear verb and object, no filler or redundant phrasing. It front-loads the action and resource effectively.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is simple with one required parameter, the schema is complete, and the description states the nature of the output as a module/topic table of contents. Without an output schema, the description does not detail the exact return structure, but for a basic read-only content outline this is sufficient for an agent to invoke it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and the schema already fully describes courseId, including its source from list_courses. The description's phrase 'for a course' merely echoes the schema without adding new parameter semantics, so the baseline score of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Get') and a concrete resource ('module/topic table of contents for a course'), making it immediately distinguishable from siblings like get_grades and get_assignments. The phrase 'table of contents' clearly narrows the scope to a structural overview, not the course content itself.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies the tool is for retrieving course structure but gives no explicit guidance on when to use it versus alternatives. It also doesn't mention in the description that courseId comes from list_courses, though that is documented in the schema. Usage is inferable rather than explicitly stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_gradesGet gradesB
Get your grade items and scores for a course.
| Name | Required | Description | Default |
|---|---|---|---|
| courseId | Yes | The course's orgUnitId, from list_courses |
TDQS
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 only says the tool fetches grade data; it does not disclose response shape, pagination behavior, error cases, authorization needs, or explicitly affirm that it is read-only beyond the word 'Get'.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence states the action, object, and scope with no filler. It avoids repeating the tool name and earns every word.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple one-parameter getter, the description names the returned concept (grade items and scores), and the schema fully documents the parameter. It does not describe edge cases or output formatting, but nothing critical is missing for a tool of this complexity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the input schema already explains courseId as the orgUnitId from list_courses. The description adds no parameter-level meaning, so it meets the baseline but does not go beyond it.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Get') and resource ('grade items and scores') scoped to a course, which distinguishes it from siblings like get_assignments and get_course_content. 'Your' also clarifies that this returns the calling user's own grade data.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance is given on when to use this tool versus alternatives. The schema mentions that courseId comes from list_courses, but the description itself provides no prerequisites, exclusions, or alternative tool routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_coursesList coursesA
List the courses you are enrolled in on POLITEMall.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
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 merely states the action without mentioning whether it is read-only, what the return format is, or any side effects. For a listing operation, read-only is implied, but the description does not confirm it or describe the output shape, which is a gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, concise sentence that front-loads the action and scope. There is no fluff, and it is appropriately sized for a simple tool with no parameters or complex behavior.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a straightforward list tool with no parameters and no output schema, the description is minimal but functional. It tells the agent what it lists, but does not specify what a course entry includes or whether the list is sorted, which could be relevant. Given the simplicity, this is acceptable but not exhaustive.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters and the schema coverage is 100% (empty properties). Baseline for 0 parameters is 4, and the description adds nothing about parameters because there are none, which is appropriate. No compensation is needed.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb 'List' and clearly identifies the resource: courses the user is enrolled in on POLITEMall. This distinguishes it from sibling tools that focus on content, grades, announcements, etc., so an agent can infer its role without additional detail.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance is provided on when to use this tool versus alternatives. The description only states what it does, leaving the agent to infer context from the tool name and siblings. There is no mention of scenarios like 'use this to get an overview of your courses' or any exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
whoamiWhoamiA
Get the currently authenticated POLITEMall user's identity.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the burden. It clearly states this is a read-only identity lookup, which implies no side effects. However, it doesn't disclose details like whether the identity includes roles, email, or other attributes, or whether authentication is required. For a simple identity tool, this is adequate but not rich.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single, clear sentence that front-loads the verb and resource. No wasted words, no repetition of the title. It earns its place entirely.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter, no-output-schema tool, the description is nearly complete. It tells the agent what the tool returns (the identity of the authenticated user). The only minor gap is not specifying the shape of the identity object, but without an output schema, a bit more detail could help. Still, for such a simple tool, this is strong.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so the description doesn't need to explain parameter semantics. The baseline for 0 params is 4, and the description correctly focuses on the output concept (the user's identity) rather than inputs. No deduction needed.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Get') and a clear resource ('the currently authenticated POLITEMall user's identity'). It clearly distinguishes itself from sibling tools that fetch courses, grades, announcements, etc., by focusing on the authenticated user's identity rather than any domain data.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage context: call it when you need the current user's identity, which is a common prerequisite for personalization or authorization. It doesn't explicitly state when not to use it or name alternatives, but the sibling list makes the distinction clear enough. A small deduction for not explicitly stating exclusions.
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.
7 tool updates
v0.1.0- First observed
get_announcements - First observed
get_assignments - First observed
get_calendar_events - First observed
get_course_content - First observed
get_grades - First observed
list_courses - First observed
whoami
TDQS
Scored across 7 tools
Each tool targets a distinct resource type: courses, content, grades, announcements, calendar events, assignments, and user identity. There is no overlap or ambiguity between them.
All tools follow a consistent verb_noun snake_case pattern (list_courses, get_course_content, get_grades), with 'whoami' being a standard exception. The naming is predictable and readable.
Seven tools is well within the ideal 3-15 range and appropriately covers the core student-facing features of an LMS without unnecessary bulk.
The surface covers the main read-only information needs: enrollment, content, grades, announcements, calendar, and assignments. Missing discussion forums or quizzes are minor gaps for a read-only student portal.
Maintenance
Related MCP Connectors
PLATO (Pusan National University LMS) MCP server via Moodle Web Service API + ubboard scraping
Read Lessonspace sessions, recordings, transcripts, spaces and users; launch spaces, edit sessions.
Read and author HiveLearn courses, events, quizzes, certificates, resources, leaderboards, tracks.
Unofficial NTNU course data: search, timetables, grades, course info, and exam logistics.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables reading and writing Canvas LMS course content using browser session cookies, without needing an API key.MIT
- FlicenseNot gradedqualityBmaintenanceEnables browser-based login to approved UTN Moodle sites and read-only access to the user's profile, course list, and course activities via local Chromium automation.2-
- FlicenseAqualityBmaintenanceEnables local, read-only access to SMU's D2L Brightspace eLearn, allowing users to list courses, browse weekly modules and documents, search content, retrieve metadata, and download files after authenticating through Chrome.111-
- AlicenseAqualityBmaintenanceGives Claude, Codex, Cursor and any other MCP client read access to your courses, content, files, grades, deadlines, announcements and discussions, using your own browser session.3136 npm2MIT