TUM MCP
Provides tools for interacting with TUM Moodle, including courses and contents, file downloads, forums and announcements, assignments and submissions, quizzes, grades, calendar events and deadlines, conversations, notifications, and Moodle iCal/RSS feeds.
Provides tools for interacting with Zulip at zulip.cit.tum.de, including reading messages, listing channels and topics, sending channel messages and direct messages, managing reactions, uploading files, and subscribing to channels.
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., "@TUM MCPwhat's new since my last check across mail, Zulip and Moodle?"
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.
TUM MCP
A remote MCP server on Cloudflare Workers. It connects Claude (claude.ai custom connector) to TUM platforms.
It gives Claude tools for TUM mail, Zulip, TUMonline, Moodle, Artemis, TUM-Live and the ITS scoreboard. A collector reads these sources every 30 minutes and returns what is new, changed or removed since the last call.
Quick start
npm install
cp .env.example .env # fill in your own values, never commit this file
npm test
npm run dev # http://localhost:8788/mcpAll credentials come from environment variables (.env or .dev.vars locally, Worker secrets in production). .env.example lists every name. The full setup is in Cloudflare setup.
This version (0.10.0) has these tool groups:
Prefix | Platform | Login |
| TUM mail through LRZ: IMAP | LRZ ID and password |
| Zulip | Zulip API key |
| Public TUMonline course data ( | none |
| TUMonline web service | TUMonline token (KV or |
| TUM Moodle | TUM SSO session with LRZ ID and password (TUM issues no web service tokens) |
| Moodle iCal export and forum RSS feeds | export link and RSS key, no login |
| Artemis | LRZ ID and password (LDAP), JWT cached in KV |
| TUM-Live | TUM SSO with LRZ ID and password, session cached in KV |
| ITS scoreboard | TUM SSO (the scoreboard is not public) |
| Pure collector. It reads every source, stores the last state per item in D1 and R2, returns the exact delta since the last call. No interpretation (docs/REQUIREMENTS.md, docs/TECH.md) | uses the above |
| Connection check for every platform; server version and registered tools | uses the above |
The owner's rules (what to do with new items) are not in this repository. A separate Claude chat (the watcher) applies them to the output of collector_run. The technical requirements are in docs/REQUIREMENTS.md, the setup in docs/TECH.md.
Related MCP server: Canvas LMS MCP Server
Tools
Tool | What it does | Writes |
| Tests each platform. Result per platform: OK, not configured, login error, token not activated, error, not implemented. | no |
| Lists folders with special use (Sent, Trash) and optional counts. | no |
| Searches a folder (from, to, subject, text, date range, unread, flagged). Newest first. | no |
| Reads one message: headers, text body, attachment list. | only with |
| Gets one attachment. Images as image, text as text, other files as base64 resource. | no |
| Sends a new mail, with attachments. Saves a copy in Sent. | yes, needs a yes |
| Replies (optionally to all) with threading headers and quote. Flags the original as answered. | yes, needs a yes |
| Forwards inline with the original attachments. | yes, needs a yes |
| Moves messages to another folder. | yes |
| Sets or removes seen, flagged, answered, draft or keywords. | yes |
| Moves messages to Trash. Nothing is deleted permanently. | yes, needs a yes |
| Gets messages with narrow filters (channel, topic, sender, DM, search, is). | no |
| Gets one message by ID. | no |
| Lists subscribed or all channels. | no |
| Lists the topics of a channel. | no |
| Posts to a channel topic. | yes, needs a yes |
| Sends a direct message. | yes, needs a yes |
| Adds or removes an emoji reaction. | yes, needs a yes |
| Uploads a file and returns its URL. | yes, needs a yes |
| Subscribes to channels. | yes, needs a yes |
| Lists semesters (ID and key, for example 26W). | no |
| Searches the course catalogue by title or number. | no |
| Gets course details: lecturers, SWS, language, description, links. | no |
| Gets the course groups with weekly series. | no |
| Gets the single dates with time and room. | no |
| Requests a TUMonline token for | yes, needs a yes |
| Checks if the token is activated. | no |
| Name, TUM ID, obfuscated IDs. | no |
| Exam results. | no |
| Raw data of one read-only token function (allowlist: kalender, noten, pruefungenEigene, veranstaltungenEigene, veranstaltungenDetails, veranstaltungenTermine, absNoten, id, studienbeitragsstatus). | no |
| Personal calendar in a date range. | no |
| Own registered courses. | no |
| Details and dates of a course by LV number. | no |
| Find TUM persons, get contact details. | no |
| Tuition fee status. | no |
| Public TUMonline exam dates, no login: exam date and time, registration start and end, deregistration end, raw entries. Optional course numbers (module number or course id); the tool reads all pages and filters. | no |
| Session mode: user ID and the probe result. Token mode: the allowed web service functions. | no |
| Any Moodle page through the session as text with links, or raw HTML. Fallback for everything else. | no |
| Calls the Moodle function behind each tool once and reports allowed or not allowed. Write functions get empty arguments, which Moodle rejects before it does anything. | no |
| Events and deadlines from the iCal export ( | no |
| Finds the forum RSS feeds of the current courses through the SSO session once and stores them in KV. | stores feed list |
| Latest forum and announcement posts from the stored feeds ( | no |
| Courses, sections, activities, file URLs. | no |
| Downloads a Moodle file (only from www.moodle.tum.de). | no |
| Read forums and announcements. | no |
| New discussion, reply. | yes, needs a yes |
| Assignments with due dates, submission and grading status, feedback. | no |
| Save a text or file submission, optionally submit for grading. File upload needs | yes, needs a yes |
| Quizzes, my attempts, attempt results. | no |
| Grades overview and grade items per course. | no |
| Calendar in a range, deadlines in the next N days. | no |
| Read messages, find users. | no |
| Sends a private message. | yes, needs a yes |
| Latest notifications. | no |
| Courses with my total score and active exams. | no |
| Exercises with due dates, my submission and result, problem statement. | no |
| Test cases and feedback of a result. | no |
| Lectures, units, lecture files. | no |
| Exams of a course. | no |
| Channels and messages (reading marks the channel as read). | no |
| Posts a message or a thread reply. | yes, needs a yes |
| Course notifications. | no |
| My courses, streams and recordings of a course. | no |
| New recordings since a date. | no |
| Watch link, HLS playlists, download links, attachments. Signed URLs expire after about 7 hours. | no |
| Courses that stream live now. | no |
| All teams with their columns and | no |
| My team's entry and rank ( | no |
| One scoreboard page as shown when logged in: title, text, links, dates, tables. Action links (logout, join, register, submit, book, delete) are refused. | no |
| One task page, by path or by a text of its link on | no |
| My team page ( | no |
| Server version, deployed Worker version, all tools of this session, and per platform what works and what is blocked (and why). | no |
| Create, rename or move a folder (special folders are refused). | yes |
| Delete a folder, only if it is empty and has no subfolders. | yes, needs a yes |
| Save a mail in Drafts (nothing is sent). | yes |
| Edit or delete one of my own messages. | yes, needs a yes |
| Mark messages, a topic or a channel as read. | yes |
| Find users, user details. | no |
| My subscriptions; mute, unmute, pin. |
|
| Unsubscribe from channels. | yes, needs a yes |
| Start an exercise (creates the participation and, for programming, the repository). | yes, needs a yes |
| Read and save my text. Every save before the due date counts as submitted. | submit needs a yes |
| Read and save my model (Apollon JSON). | submit needs a yes |
| Files of my programming repository. | no |
| Write files, commit (starts a build, counts as submission), build again. | yes, needs a yes |
| Latest build and test result, build logs. | no |
| Course quizzes: questions, submit live or practice. No exam quizzes. | submit needs a yes |
| Reads all sources (or the ones named), stores the last state per item, and returns the deltas after the delivered pointer: new items with complete content, changed items with complete new content and each changed field (old and new value), removed items with their last known content. Pages with | stores the state in D1 and R2 (no platform writes) |
| Confirms the deltas up to | moves the pointer |
| Full stored content of an item or of one delta, the stored HTML of a web page, or a stored file ( | no |
"Needs a yes" means that the tool description contains the sentence "Call only after the user said yes." This applies to every tool that sends, posts, submits, uploads, subscribes, reacts or moves mail to Trash. mail_move and mail_flags change only your own mailbox and are reversible, so they do not have the sentence.
Security
Login to the MCP server is OAuth 2.1 through
@cloudflare/workers-oauth-providerwith GitHub as the identity provider.Only the GitHub account in the secret
ALLOWED_GITHUB_LOGINcan log in. Without this secret nobody can log in. The check is insrc/auth/github.ts. The MCP agent checks it again before it registers tools.The server does not keep the GitHub token.
All credentials are Worker secrets. No credential is in the code or in git.
.env,.dev.varsand key files are in.gitignore..env.examplelists every name.
Cloudflare setup
You need a Cloudflare account and admin access to this GitHub repository.
1. Connect the repository to Workers Builds
Open the Cloudflare dashboard. Go to Workers & Pages > Create application.
Select GitHub (in some dashboards: Import a repository). Authorize the Cloudflare GitHub app if Cloudflare asks for it.
Select your copy of this repository.
Set these values:
Project name:
tum-mcp. It must be the same asnameinwrangler.jsonc, or the build fails.Production branch:
main.Build command: empty.
Deploy command:
npx wrangler deploy(default).Root directory:
/(default).
Select Save and Deploy.
The first deploy creates these resources automatically, because wrangler.jsonc has the bindings without IDs (automatic provisioning):
KV namespace for binding
OAUTH_KV(OAuth clients, grants, tokens).KV namespace for binding
CACHE(TUMonline token, Artemis JWT, Moodle and TUM-Live sessions). Values are encrypted with AES-GCM whenCOOKIE_ENCRYPTION_KEYis set.D1 database
tum-mcpfor bindingDB(collector state and delta log, tables created in code).Durable Object class
TumMCP(one MCP session per connection).Cron trigger
*/30 * * * *(runs the collector).R2 bucket
tum-filesfor bindingFILES(collector HTML, files and large contents).
Every push to main deploys again.
Note your Worker URL. It looks like https://tum-mcp.<your-subdomain>.workers.dev. The examples below use https://tum-mcp.example.workers.dev.
Set PUBLIC_ORIGIN in wrangler.jsonc (vars) to this URL. Replace the placeholder YOUR_SUBDOMAIN. The signed download links of collector_item use it.
Set the scope of the collector in config/moodle-courses.json (Moodle course ids or name texts) and config/external-sites.json (external course websites). Both lists are empty in this repository.
2. D1 and R2
No migrations. The collector creates its tables (items, deltas, state, unit_runs) on first use. Version 0.7.0 wiped D1 tum-mcp and R2 tum-files once. Version 0.7.1 removed the wipe code, so the worker never drops or deletes stored data.
If the automatic provisioning did not create the database, create it and bind it in the dashboard: Storage & Databases > D1 > Create with the name tum-mcp. Then go to the Worker > Settings > Bindings > Add > D1 database, variable name DB.
3. GitHub OAuth app
On GitHub, go to Settings > Developer settings > OAuth Apps > New OAuth App.
Set these values:
Application name:
TUM MCP.Homepage URL:
https://tum-mcp.example.workers.dev.Authorization callback URL:
https://tum-mcp.example.workers.dev/callback.
Select Register application.
Copy the Client ID. Select Generate a new client secret and copy the secret.
4. Secrets
Go to the Worker > Settings > Variables and Secrets > Add. Select type Secret for each value. Then select Deploy.
Alternative on your computer: npx wrangler secret put <NAME>.
Secret | Required | Value |
| yes | Client ID of the GitHub OAuth app |
| yes | Client secret of the GitHub OAuth app |
| yes | Your GitHub user name. Only this account can log in. |
| recommended | Random string, minimum 32 characters, for example from |
| for mail | LRZ ID (TUM ID), for example |
| for mail | Password of the LRZ ID |
| for sending mail | Your sender address, for example |
| optional | Sender name, for example |
| for Zulip | The email of your Zulip account (Zulip > Personal settings > Account & privacy) |
| for Zulip | Zulip > Personal settings > Account & privacy > API key > Manage your API key |
| not available at TUM | TUM issues no Moodle web service tokens. Leave it empty. The code still supports a token if TUM ever offers one. |
| recommended for Moodle | Moodle > Kalender > Exportieren: select all courses, events and deadlines, a long time range, then copy the calendar URL. |
| not useful | RSS is off on TUM Moodle. |
| optional | Your team name exactly as the ITS scoreboard shows it (the scoreboard lists teams, not persons). |
| optional | TUMonline web service token. Overrides the token that |
Artemis and TUM-Live use TUM_USER and TUM_PASSWORD. They need no new secret.
A platform without its secrets shows "not configured" in status. The other platforms still work.
Secrets stay when Workers Builds deploys again. wrangler deploy does not delete secrets.
5. Platform tokens
TUMonline personal data:
In a chat, ask Claude to run
tumonline_request_token. The server requests a token forTUM_USERand stores it in KV.TUMonline sends an email. Open TUMonline (campus.tum.de) > Visitenkarte > Token-Management, or use the link in the email.
Activate the token "tum-mcp" and grant all rights.
Run
tumonline_token_statusorstatus.
Moodle access: TUM Moodle has the mobile web service turned off (enablemobilewebservice = 0), and the "Sicherheitsschlüssel" page shows only the RSS key. So there is no MOODLE_TOKEN. The tools use these sources:
TUM SSO session (login.tum.de with
TUM_USERandTUM_PASSWORD). The tools use a Moodle AJAX function where TUM allows it (courses, deadlines, discussion posts, replies, messages, notifications, course index). For everything TUM blocks, they read the normal Moodle web pages: course contents, forums and discussions, announcements, assignments and their status, quizzes and attempts, grades, file downloads. New forum posts and assignment submissions use the normal Moodle web forms. Tools that work on one activity take itscmid(course module ID) frommoodle_course_contents,moodle_assignments,moodle_quizzesormoodle_forums.iCal export (
MOODLE_CALENDAR_URL): deadlines and events without login.moodle_upcoming_deadlinesfalls back to it when the session fails.RSS (
MOODLE_RSS_TOKEN): tested on 2026-10-17 with 10 forums. Every feed answered "Fehler beim Lesen der RSS-Daten", and no forum page showed an RSS link. RSS is switched off for these forums on TUM Moodle.moodle_forum_rsssays so in its result. Usemoodle_announcements(SSO session) for forum posts.moodle_upcoming_deadlinesnever used RSS.
The SSO login fails if your account needs a second factor at login.tum.de.
6. Collector
Nothing to set up. The cron */30 * * * * and the tool collector_run read every source, store the last state per item in D1 tum-mcp and R2 tum-files, and write one delta row per new, changed or removed item. Details are in docs/TECH.md.
Workers Free plan. Each unit (one source, or one Moodle or Artemis course) runs in its own invocation through the service binding COLLECTOR (entrypoint CollectorRunner), so each unit has its own budget of 50 external subrequests and 10 ms CPU. A first read that does not fit (a large mailbox, the Zulip history, a big course) goes on run by run. collector_run lists what is not read yet.
7. Add the connector in claude.ai
Open claude.ai. Go to Settings > Connectors.
Select Add custom connector.
Name:
TUM. URL:https://tum-mcp.example.workers.dev/mcp.Leave the advanced OAuth fields (client ID, client secret) empty. Claude registers itself through the server (dynamic client registration or client ID metadata document).
Select Add, then Connect. A consent page from the Worker opens. Select Allow. Log in to GitHub with the account in
ALLOWED_GITHUB_LOGIN.In a chat, enable the connector and ask Claude to run the
statustool.
After a deploy that adds tools: claude.ai keeps the tool list it loaded when it connected. In Settings > Connectors, disconnect the connector and connect it again (or remove and add it), then start a new chat. server_info lists every tool the server registers in the current session. If claude.ai shows fewer, its list is stale.
Local development
npm install
cp .env.example .env # fill in values, never commit this file
npm run dev # http://localhost:8788, MCP endpoint /mcp
npm test # unit tests (IMAP, SMTP, MIME, collector)
npm run type-checkFor a local GitHub login, create a second GitHub OAuth app with the callback http://localhost:8788/callback. To test with the MCP Inspector, run npx @modelcontextprotocol/inspector and connect to http://localhost:8788/mcp.
After a change to wrangler.jsonc or to the secret names, run npm run cf-typegen with a .env that has all secret names. This updates worker-configuration.d.ts.
Project layout
src/index.ts OAuth provider, MCP agent (Durable Object), cron, collector entrypoint
src/auth/github.ts consent page, GitHub login, account check
src/platforms/mail.ts mail_ tools
src/platforms/zulip.ts zulip_ tools
src/platforms/tumonline.ts tumonline_ tools (public)
src/platforms/tumonline-personal.ts tumonline_ tools (token, wbservicesbasic)
src/platforms/moodle.ts moodle_ tools
src/platforms/artemis.ts artemis_ tools
src/platforms/tumlive.ts tumlive_ tools
src/platforms/status.ts status tool
src/lib/tum-sso.ts login through login.tum.de (SAML)
src/lib/http.ts cookie jar, redirects, form parsing
src/lib/store.ts encrypted state in the CACHE KV namespace
src/lib/xml.ts minimal XML parser for TUMonline
src/lib/imap.ts minimal IMAP client (RFC 3501)
src/lib/smtp.ts minimal SMTP client with STARTTLS and AUTH PLAIN
src/lib/mime-build.ts MIME message builder
src/lib/net.ts cloudflare:sockets connect()
src/collector/ collector: model and change computation, web page text, files, store, runner, tools
src/collector/units/ collector units per source
test/ unit tests (fake IMAP and SMTP servers, collector store on node:sqlite)
docs/REQUIREMENTS.md what the collector must do technically
docs/TECH.md setup, storage, secrets, limits
config/moodle-courses.json the Moodle courses the collector reads
config/external-sites.json the external course websites the collector readsThe IMAP and SMTP clients are written for this project because the common Node libraries need net and tls APIs. MIME parsing uses postal-mime, which runs on Workers.
Test status
0.10.0: npm test (82 tests) and npm run type-check pass. The collector tests cover the change computation, the web page text and the D1 apply and wipe logic on an in-memory SQLite. The collector units were not run against the live platforms before the deploy.
Deployed and reported OK by the user: mail (IMAP, SMTP), Zulip, TUMonline public and personal (token active, 5 of 5 rights), Artemis, TUM-Live (SSO login works).
Tested in this build environment (0.3):
Unit tests (
npm test, 22 tests): iCal parser (folding, escapes, UTC and Europe/Berlin times, deadline detection), RSS parser and the Moodle error feed, forum ID detection, Moodle user ID detection, scoreboard table parsing and rank lookup, plus the earlier tests.The real
TumMCPDurable Object inwrangler dev: a session created on the phase 1 code (26 tools) lists all 87 tools after the switch to the new code, and so does a new session. The server keeps no stale tool list.In
wrangler devagainst the live services with fake credentials:statusreports every platform; the ITS scoreboard SSO login runs to "Username or password was incorrect"; the Moodle calendar export answers "Invalid authentication";moodle_upcoming_deadlinesreports both the session and the iCal error.Live checks without login: the scoreboard redirects to its TUM-ID login; the Moodle RSS URL format
rss/file.php/{contextid}/{token}/mod_forum/{forumid}/rss.xmlanswers with an RSS error document for a wrong token.
Not tested (no valid credentials here):
moodle_probeand everymoodle_session tool with real data. Which functions TUM Moodle allows through AJAX.The Moodle user ID detection from the real pages, and the new status check (
core_course_get_enrolled_courses_by_timeline_classification).moodle_calendar_icswith a real export link (the real event titles that mark deadlines).moodle_rss_discover(course page and forum page markup) andmoodle_forum_rsswith real feeds.Both ITS scoreboard tools: the page after login and its table layout were not visible. If the scoreboard is not an HTML table, the tool returns the page text in its error.
That claude.ai shows all tools after a disconnect and connect.
Run status and server_info first after the deploy.
Known limits
One IMAP connection per tool call. Each call logs in again.
Mail calls stop after 50 seconds, and the connect and login step after 15 seconds, because MCP clients stop waiting after about 60 seconds.
Messages larger than 25 MB are not read. Attachments larger than 10 MB are not downloaded.
mail_forwardforwards inline. It does not attach the original asmessage/rfc822.The TUMonline endpoints are the REST API of the TUMonline web app. They are not officially documented and can change.
Every Artemis password login sends a "new login" email. The JWT is cached for 6 days to avoid this.
Moodle and TUM-Live logins through TUM SSO fail for accounts that must use a second factor or a passkey.
License
MIT. See LICENSE.
This server cannot be deployed
Maintenance
Related MCP Connectors
- platform7nOAuthtech.p7n
Connect Claude to your Platform7n workspaces: chat, links, work and decks. One-click OAuth.
Multiple Google accounts (Gmail, Calendar, Drive, Contacts, Tasks) in one Claude connector.
Multiple Google accounts (Gmail, Calendar, Drive, Contacts, Tasks) in one Claude connector.
tri-train is a training platform for triathletes that syncs activities from Strava and Garmin and exposes them to Claude through a remote MCP server. Ask Claude how your last block went, why your run pace dropped, or whether you are fresh enough for Sunday's race, and it answers from your real data: activities with laps and grade-adjusted pace, weekly load and the performance management chart (CTL/ATL/TSB), sleep, HRV and resting heart rate, and your race calendar with predictions. Claude can also act: create and adjust planned workouts with structured intervals, push them to your Garmin watch, add races and write notes. Every change is journaled and can be undone. Read and write access are separate OAuth scopes, and the server enforces them on every call. Built and hosted in Switzerland by a triathlete; data stays on our own servers (Swiss revDSG / GDPR).
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceConnects Claude to Canvas LMS, enabling students to query their coursework, assignments, grades, deadlines, announcements, and calendar events through natural conversation instead of navigating the Canvas interface.8-
- AlicenseNot gradedqualityDmaintenanceEnables Claude to interact with Canvas LMS to manage coursework, track assignments, and view grades through natural language. It supports comprehensive academic tasks including checking rubrics, participating in discussion boards, and submitting assignments.10 npmMIT
- AlicenseNot gradedqualityDmaintenanceConnects Claude to Canvas LMS accounts, enabling natural language queries about courses, assignments, grades, and files. Supports content search, file downloads, syllabus retrieval, and bulk course exports via 13 integrated tools.10 npmMIT
- AlicenseBqualityCmaintenanceEnables Claude to interact with Canvas LMS, allowing natural language queries about courses, deadlines, grades, and feedback.29MIT