Edupage Mcp Full
FreeNot checkedFull-feature EduPage MCP server: timetables, grades, homework, meals (ordering), messages, role-aware student switching, 2FA, multi-school with automatic studen
About
Full-feature EduPage MCP server: timetables, grades, homework, meals (ordering), messages, role-aware student switching, 2FA, multi-school with automatic student discovery, tiered name matching, and student cache.
README
GitHub release Quality gates Security Container security Coverage drift
Project
A Model Context Protocol (MCP) server that exposes the full functionality of the edupage-api Python library to AI agents such as opencode, Claude, Cursor and any other MCP client.
EduPage is a school information system used across Europe. This server lets you query and operate a student / teacher / parent EduPage account directly from your agent: timetables, grades, homework, substitutions, meals (including ordering), messages, rosters, parent child-switching and more — including multiple schools (e.g. two children attending different schools).
⚠️ Unofficial API. Like all EduPage MCP servers, this relies on the community-maintained edupage-api library, which talks to EduPage's undocumented endpoints. Use read-only features freely; use the write features (
send_message, meal ordering, child switching) carefully.
Table of Contents
- Why another EduPage MCP server?
- What it provides
- Getting started
- Prompt examples
- Multiple schools (subdomains)
- Tool reference
- Data & safety notes
- Contributing
- Limitations
- Support
- License
Why another EduPage MCP server?
Two other EduPage MCP servers already exist:
- mrtineu/edupage-mcp — also published on PyPI as edupage-mcp
- mhlavac/edupage-mcp
Both are good and I have no affiliation with them — they are simply referenced here for honest comparison. They primarily focus on the read-only surface of the API.
This project deliberately goes further:
| Capability | mhlavac | mrtineu (PyPI) | this project |
|---|---|---|---|
Advanced login — portal auto-detect, 2FA, session id (PHPSESSID) |
partial (portal) | basic only | ✅ |
| Timetables (own + any teacher/class/room) | ✅ | ✅ | ✅ |
| Grades (all / by term & year) | ✅ | ✅ | ✅ |
| Substitutions / timetable changes | ✅ | ✅ | ✅ |
| Meals — read menu | ✅ | ✅ | ✅ |
| Meals — choose / sign-off / rate | ❌ | ❌ | ✅ |
Send messages (send_message) |
✅ | ❌ | ✅ |
| Parent student switching (switch to/from student) | partial (list) | ❌ | ✅ |
| Next ringing time / bell schedule | ❌ | ❌ | ✅ |
| Raw session custom request | ❌ | ❌ | ✅ |
| Multiple schools (auto-login + discovery) | ❌ | ❌ | ✅ |
| Role-aware (parent / student / teacher) | ❌ | ❌ | ✅ |
| Day summaries (one-call daily report) | ❌ | ❌ | ✅ |
Key differentiators:
- Multi-school automatic discovery. Set
EDUPAGE_SUBDOMAINSwith one shared login and the server auto-discovers students across all schools — no need to maintain a manual "Student → school1, Student → school2" mapping. A student at two schools (e.g. Student atschool1+school2) is found automatically with separate per-school results. - Role-aware tools. The server detects whether you're a parent, student, or
teacher at each school and behaves accordingly —
get_student_timetableswitches to the student account for parents, returns direct timetables for students. No tool duplication. - Full write surface. Meal ordering/rating, message sending, student switching — the other servers don't cover these.
What it provides
A single stdio MCP server exposing 29 tools (published on PyPI as edupage-mcp-full):
- Authentication —
login(by credentials, portal auto-detect, or aPHPSESSIDcookie viamethod=),login_all(multi-school, one call),two_factor_finish(complete a pending 2FA),get_subdomains(schools available to the account with role/user id per school + env config, live subdomain discovery for parents). The formerauth_status,user_id,login_auto,login_from_session, andtwo_factor_check_confirmedtools are folded into these. - Timetables —
get_my_timetable,get_timetable(teacher/student/class/ classroom;end_datefor a range, formerlyget_timetable_range),get_student_timetable(student by name, cross-school),get_next_week_timetable,get_next_ringing_time,get_periods,get_school_year - Students —
find_student(name → person_id, cross-school),get_student_timetable(cross-school, role-aware),scan_students(auto-discover all students across schools),get_my_students(classmates or school-wide for parents),switch_to_student(by id or name, parent only),switch_to_parent,clear_student_cache(force refresh cached student lists) - Schools —
get_subdomains(subdomains available to the account — live-discovered for parents, limited byEDUPAGE_SUBDOMAINSwhen set — plus session state per school) - Grades —
get_grades - Timeline / notifications —
get_timeline(category=for homework, assignments, absences, events, news, or full history since a date) - Substitutions —
get_timetable_changes,get_missing_teachers - Meals —
get_meals,choose_meal,sign_off_meal,rate_meal - Day summaries —
get_day_summary(one call: timetable, substitutions, missing teachers, grades, meals, homework, assignments, absences, news, events, notifications for a date — "what happened yesterday at school" in a single round trip; each section is isolated so one failure doesn't kill the report). Includes an OpenCode skill (school-day-summary) for human-readable formatting in OpenCode; other clients use the raw JSON directly. - Rosters —
get_roster(roster_type=for students, all students, teachers, classes, classrooms, or subjects),get_my_students - Actions —
send_message,switch_to_student,switch_to_parent,custom_request
Getting started
You need an MCP-capable client (opencode, Claude Desktop, Cursor, etc.).
1. Install
If you are using an AI coding client, a simple prompt is often enough to get started, for example: "Install the EduPage MCP as described in this GitHub repository oliverhruby/edupage-mcp". Most MCP-capable clients can then guide you through the available setup options.
Option A — from MCP Registry (recommended, one-click in VS Code / GitHub Copilot)
The server is listed in the MCP Registry.
In VS Code or GitHub Copilot, search for "EduPage MCP" and install with one click.
Or use the direct deeplink: mcp://install/io.github.oliverhruby/edupage-mcp
Option B — from PyPI
Use this for normal usage with a released version.
Requirements: uv for uvx, or Python 3.10+ for pip.
uvx edupage-mcp-full
# or, if you prefer pip (into whatever environment your MCP client uses):
pip install edupage-mcp-full
uvx runs the package without a persistent install. If uvx is unavailable,
install uv first (pip install uv or winget install astral-sh.uv).
Option C — from GitHub (latest source)
Use this if you want the latest changes before a PyPI release.
Requirements: uv for uvx, or Python 3.10+ for pip.
uvx --from "git+https://github.com/oliverhruby/edupage-mcp.git" edupage-mcp-full
# or
pip install "git+https://github.com/oliverhruby/edupage-mcp.git"
Option D — Docker
Use this for an isolated container runtime.
Requirements: Docker.
Pull a prebuilt image (recommended):
docker pull ghcr.io/oliverhruby/edupage-mcp:latest
docker run --rm -i \
-e EDUPAGE_USERNAME=your_username \
-e EDUPAGE_PASSWORD=your_password \
ghcr.io/oliverhruby/edupage-mcp:latest
Version tags are also available (for example v0.4.0) if you prefer pinned
images.
Build locally from source (fallback):
docker build -t edupage-mcp-full .
docker run --rm -i \
-e EDUPAGE_USERNAME=your_username \
-e EDUPAGE_PASSWORD=your_password \
edupage-mcp-full
The container uses the same environment variables described in
Configure credentials. It also includes a
HEALTHCHECK (stdio process liveness by default; local TCP check in HTTP
transport modes).
For HTTP transports, set optional runtime vars:
MCP_TRANSPORT:stdio(default),sse, orstreamable-httpMCP_HOST: bind host (default127.0.0.1)MCP_PORT: bind port (default8000)MCP_API_KEY: optional bearer token for HTTP auth
When MCP_API_KEY is set, HTTP requests must include Authorization: Bearer <key>.
If MCP_API_KEY is not set, HTTP endpoints are unauthenticated. For production,
prefer proper authentication and TLS via a reverse proxy or API gateway.
pyproject.tomlpinsmcp<2(the stable FastMCP v1 API).mcp 2.xrenamedFastMCPtoMCPServerand changed the API surface; this server targets the FastMCP v1 API for simplicity and stability.
Option C — development from source
Use this if you are contributing or debugging locally.
Requirements: Python 3.10+.
git clone https://github.com/oliverhruby/edupage-mcp.git
cd edupage-mcp
uv sync # or: python -m venv .venv && .venv/bin/python -m pip install -e .
uv run edupage-mcp-full
Option D — Docker
Use this for an isolated container runtime.
Requirements: Docker.
Pull a prebuilt image (recommended):
docker pull ghcr.io/oliverhruby/edupage-mcp:latest
docker run --rm -i \
-e EDUPAGE_USERNAME=your_username \
-e EDUPAGE_PASSWORD=your_password \
ghcr.io/oliverhruby/edupage-mcp:latest
Version tags are also available (for example v0.4.0) if you prefer pinned
images.
Build locally from source (fallback):
docker build -t edupage-mcp-full .
docker run --rm -i \
-e EDUPAGE_USERNAME=your_username \
-e EDUPAGE_PASSWORD=your_password \
edupage-mcp-full
The container uses the same environment variables described in
Configure credentials. It also includes a
HEALTHCHECK (stdio process liveness by default; local TCP check in HTTP
transport modes).
For HTTP transports, set optional runtime vars:
MCP_TRANSPORT:stdio(default),sse, orstreamable-httpMCP_HOST: bind host (default127.0.0.1)MCP_PORT: bind port (default8000)MCP_API_KEY: optional bearer token for HTTP auth
When MCP_API_KEY is set, HTTP requests must include Authorization: Bearer <key>.
If MCP_API_KEY is not set, HTTP endpoints are unauthenticated. For production,
prefer proper authentication and TLS via a reverse proxy or API gateway.
pyproject.tomlpinsmcp<2(the stable FastMCP v1 API).mcp 2.xrenamedFastMCPtoMCPServerand changed the API surface; this server targets the FastMCP v1 API for simplicity and stability.
2. Configure credentials
Either set environment variables or pass credentials to login (see
Prompt examples).
# Windows (persistent, per-user)
setx EDUPAGE_USERNAME "your_username"
setx EDUPAGE_PASSWORD "your_password"
setx EDUPAGE_SUBDOMAINS "s1,s2,s3" # optional: multiple schools (auto-login + discovery)
# macOS / Linux
export EDUPAGE_USERNAME="your_username"
export EDUPAGE_PASSWORD="your_password"
export EDUPAGE_SUBDOMAINS="s1,s2,s3" # optional
Single school? Just set EDUPAGE_USERNAME + EDUPAGE_PASSWORD. The server
auto-discovers your school via the EduPage portal on startup — no subdomain needed.
Multiple schools? Add EDUPAGE_SUBDOMAINS (comma-separated). The server
logs into all of them on startup with your shared credentials.
3. Register with your MCP client
opencode — add to ~/.config/opencode/opencode.json (or opencode.jsonc):
{
"mcp": {
"edupage": {
"type": "local",
"enabled": true,
"command": ["uvx", "edupage-mcp-full"],
"env": {
"EDUPAGE_USERNAME": "{env:EDUPAGE_USERNAME}",
"EDUPAGE_PASSWORD": "{env:EDUPAGE_PASSWORD}",
"EDUPAGE_SUBDOMAINS": "{env:EDUPAGE_SUBDOMAINS}"
}
}
}
}
Put credentials in your shell/environment (or a
.env) and reference them with{env:VAR}, or hardcode them underenv:directly.uvxwill auto-provision the package the first time; it must be on yourPATH.
Claude Desktop / Cursor — use claude_desktop_config.json /
.mcp.json with a mcpServers entry in the standard shape, pointing
command/args at the venv python and the edupage_mcp.py path, plus an
env block with your credentials.
After editing client config, restart the client so the MCP server is loaded.
Prompt examples
| User prompt | Likely tool call(s) | Expected response |
|---|---|---|
| "Are we connected and logged in?" | get_subdomains |
Available school subdomains (live-discovered for parents), active school/subdomain, env config, and login state per school. |
| "What classes do I have today?" | get_my_timetable |
A short timetable summary for today. |
| "Show me the 9.A schedule for 2026-09-10" | get_timetable target_type="class" target_id="9.A" date_str="2026-09-10" |
Class timetable for that date. |
| "What grades do I have this term?" | get_grades term="FIRST" year=2026 |
Subject-by-subject grade overview for the selected term/year. |
| "Any substitutions today?" | get_timetable_changes |
Changes, cancellations, and replacements for today. |
| "What is for lunch and order option 2 for tomorrow" | get_meals → choose_meal date_str="2026-09-10" meal_type="lunch" number=2 |
Meal menu and order confirmation (or a clear error if unavailable). |
| "Find Student A's timetable for tomorrow" | get_student_timetable name="Student A" date_str="2026-09-10" |
Student A's timetable; if found in multiple schools, one result per school. |
| "List teachers and send a hello to Teacher456" | get_roster roster_type="teachers" → send_message recipient_id="Teacher456" body="Hello!" |
Teacher list plus message sent confirmation. |
| "What happened at school yesterday for my kids?" | get_day_summary date_str="2026-09-09" (discovery index) → get_day_summary date_str="2026-09-09" name="Student A" subdomain="school-a" → ... name="Student B" subdomain="school-b" |
Discovery-first: the no-name call lists each child per school; then one complete daily report call per child (timetable, substitutions, missing teachers, grades, meals, homework, assignments, absences, news, events, notifications). Keeps each response small and avoids mixing schools/students. |
| "How was school today for Student A?" | get_day_summary name="Student A" (defaults to today) |
Human-readable summary via the bundled OpenCode skill school-day-summary. |
Multiple schools & automatic student discovery
Each subdomain (school) keeps its own logged-in session. There are two ways to log in to several schools at once:
A) Automatic on startup (recommended). Set EDUPAGE_SUBDOMAINS (a
comma-separated list) plus the shared EDUPAGE_USERNAME / EDUPAGE_PASSWORD —
the server logs into all of them when it launches, so every tool is immediately
ready and students are discoverable across all schools with no login call and
no student→school mapping:
setx EDUPAGE_SUBDOMAINS "school1,school2,school3" # Windows
export EDUPAGE_SUBDOMAINS="school1,school2,school3" # macOS / Linux
get_subdomains # lists school1, school2, school3 (logged in, with role)
scan_students # discovers Student A and Student B across those schools
get_student_timetable name="Student A" # is found at school1 AND school2
B) On demand with login_all. Authenticate several schools at once, then pass
subdomain to any data tool (it defaults to the last active subdomain when
omitted):
login_all subdomains="school1,school2" usernames="u1,u2" passwords="p1,p2"
get_my_timetable subdomain="school1"
get_my_timetable subdomain="school2"
get_subdomains # shows all logged-in subdomains + which is active
You can also call login once per school to add/lookup sessions incrementally.
Single school? No
EDUPAGE_SUBDOMAINSneeded — the server auto-discovers your school via the portal on startup. For two or more schools, setEDUPAGE_SUBDOMAINS(auto-login) or uselogin_all/ repeatedlogincalls.
Students by name (e.g. "timetable for Student A")
Because the server auto-discovers students across the configured
EDUPAGE_SUBDOMAINS (or every logged-in school when the variable is unset),
you don't need to know or state which school a student is in. Just ask for the
timetable by name and the server searches every school in scope:
"timetable for Student A" -> get_student_timetable name="Student A"
get_student_timetable (with no subdomain):
- searches every school in the discovery scope — the configured
EDUPAGE_SUBDOMAINS, or all logged-in schools when unset — for a student whose first/last/full name matches (scan_studentsdoes just the discovery step), - for each school where the student is found, switches to the student account if you're logged in as a parent, returns that student's timetable for the date, and switches back to the parent account afterwards,
- returns one result per school.
A student attending more than one school (e.g. Student at school1 +
school2) therefore yields a list of two per-school timetables — separate
results, never merged. This is the built-in replacement for maintaining a
manual "Student → school1" mapping: with EDUPAGE_SUBDOMAINS set, discovery is
fully automatic.
Tool reference
| Tool | Description | Writes? |
|---|---|---|
login |
Log in with username/password; method="credentials" (default), method="auto" (portal auto-detect, formerly login_auto), or method="session" with a PHPSESSID cookie (formerly login_from_session). Env vars supported. |
✅ session |
login_all |
Log in to multiple schools in one call | ✅ session |
two_factor_finish |
Finish a pending 2FA login (email/app code or poll_seconds device confirmation; formerly two_factor_check_confirmed + two_factor_finish) |
✅ session |
get_subdomains |
Subdomains available to the account (live-discovered for parents; limited to EDUPAGE_SUBDOMAINS when set) + role/user id per school, active subdomain, failed logins, env config (formerly auth_status, user_id) |
|
get_school_year |
Current school year | |
get_my_timetable |
Logged-in user's timetable for a date | |
get_timetable |
Timetable of a teacher/student/class/classroom; end_date for a daily range (formerly get_timetable_range) |
|
get_student_timetable |
Student's timetable by name or id (role-aware, cross-school) | ✅ session |
get_next_week_timetable |
Mon–Fri timetable for next week | |
get_next_ringing_time |
Next bell (break/lesson) at a given time | |
get_periods |
Bell schedule (period start/end times) | |
get_grades |
Grades, optionally by year & term | |
get_timeline |
Timeline notifications, one category= at a time: recent, history (since date_from), homework, assignments, absences, events, news (formerly get_notifications, get_notification_history, get_homework, get_assignments, get_absences, get_upcoming_events, get_news) |
|
get_timetable_changes |
Substitutions / timetable changes for a date | |
get_missing_teachers |
Teachers missing on a date | |
get_day_summary |
One-call daily report (timetable, substitutions, teachers, grades, meals incl. breakfast/dinner when published, homework, assignments, absences, news, events, notifications) for a date; student by name/id (role-aware). Discovery-first: parent without name/student_id returns a lightweight per-school student index (mode:"discovery"); pass full=True to build full reports for every child. Bundles OpenCode skill school-day-summary for human-readable output. |
|
get_meals |
Meal menu (all 5 slots: breakfast, snack, lunch, afternoon snack, dinner) | |
choose_meal |
Order a meal | ✅ |
sign_off_meal |
Cancel an ordered meal | ✅ |
rate_meal |
Rate a meal (quality/quantity) | ✅ |
get_roster |
One roster_type= at a time: students (logged-in user's class), all_students (whole school, short list), teachers, classes, classrooms, subjects (formerly get_students, get_all_students, get_teachers, get_classes, get_classrooms, get_subjects) |
|
get_my_students |
Students visible to the logged-in account (one school) | |
find_student |
Look up a student's person_id by name (cross-school) | |
scan_students |
Auto-discover students across the configured EDUPAGE_SUBDOMAINS (or all logged-in schools when unset) |
|
clear_student_cache |
Clear cached student rosters (one school or all schools) | ✅ cache |
get_subdomains |
Available school subdomains + role/session per school | |
send_message |
Send a message to a user | ✅ |
switch_to_student |
Switch to a student account by id or name (parent only) | ✅ session |
switch_to_parent |
Switch back to the parent account | ✅ session |
custom_request |
Raw request through the active session (GET/POST) | ✅ |
Data & safety notes
- Most tools are read-only. The ones marked Writes? ✅ mutate EduPage state (sent messages, ordered meals, switched accounts). Use them with care.
get_timelinecategorieshomework,assignments,absences,eventsandnewsderive their data from the timeline notifications — if the school doesn't push certain event types, those categories may return empty lists.get_missing_teachersis marked experimental upstream (parses HTML from the substitution page) and can raise if a teacher's name no longer matches.- Meal
rate_mealand ordering depend on the school publishing menus with the matching identifiers; not all schools expose ratings. get_mealsfirst tries the per-student meal-ordering endpoint (needed for ordering/ratings). When a school doesn't enable that, it falls back to the school's public canteen menu widget (/menu/?wid=menu_CanteenMenu_1). All five slots (breakfast/snack/lunch/afternoon_snack/dinner) are always returned; slots the school doesn't publish areNone.
Skills
The package includes an OpenCode skill (school-day-summary) at
<site-packages>/edupage_mcp/skills/school-day-summary/SKILL.md. It teaches
OpenCode agents how to turn get_day_summary JSON into a human-readable daily
school report.
OpenCode only: To register it:
mkdir -p ~/.config/opencode/skills/school-day-summary
cp <site-packages>/edupage_mcp/skills/school-day-summary/SKILL.md \
~/.config/opencode/skills/school-day-summary/SKILL.md
Restart OpenCode; the agent can then answer "what happened at school yesterday
for my kids?" by calling get_day_summary per child.
Other MCP clients (Copilot, Claude, Cursor, etc.) — call get_day_summary
directly; they receive the full structured JSON. Formatting is client-specific
(no skill system in the MCP protocol).
Contributing
Contributor and maintainer guidance is in CONTRIBUTING.md.
- Contribution workflow and local setup
- Architecture and implementation details
- Release process (PyPI, GitHub Releases, GHCR)
- CI quality gates and upstream coverage drift checks
Limitations
- Unofficial/read-mostly by design. EduPage can change its endpoints at any
time; reliability ultimately depends on
edupage-api, not this wrapper. - No CAPTCHA bypass. If EduPage presents a CAPTCHA during login, log in via
browser first, then use
login method="session"with the resultingPHPSESSID. - 2FA requires human interaction (approve on device or provide a code).
- Parent/teacher accounts are only partially verified upstream; some parent methods are best-effort.
- The auth session lives for the lifetime of the MCP server process; restarting the client means logging in again.
- Cross-school student discovery depends on being logged into all relevant
schools (via
EDUPAGE_SUBDOMAINS,login_all, or repeatedlogincalls). If a school is not logged in, that student's results from that school cannot be discovered.
Support
If you like this project and want to support or request a feature, send me a beer, it keeps my mind relaxed and ideas will come :-)
License
MIT © Oliver Hrubý
This project is not affiliated with or endorsed by Ascora (EduPage) or by
the authors of edupage-api. EduPage is a registered trademark of its
respective owner(s).
Install Edupage Mcp Full in Claude Desktop, Claude Code & Cursor
unyly install edupage-mcp-fullInstalls into Claude Desktop, Claude Code, Cursor & VS Code — handles npx, uvx and build-from-source repos for you.
First time? Get the CLI: curl -fsSL https://unyly.org/install | sh
Or configure manually
Run in your terminal:
claude mcp add edupage-mcp-full -- uvx edupage-mcp-fullStep-by-step: how to install Edupage Mcp Full
FAQ
Is Edupage Mcp Full MCP free?
Yes, Edupage Mcp Full MCP is free — one-click install via Unyly at no cost.
Does Edupage Mcp Full need an API key?
No, Edupage Mcp Full runs without API keys or environment variables.
Is Edupage Mcp Full hosted or self-hosted?
Self-hosted: the server runs locally on your machine via the install command above.
How do I install Edupage Mcp Full in Claude Desktop, Claude Code or Cursor?
Open Edupage Mcp Full on unyly.org, pick your client tab (Claude Desktop, Claude Code, Cursor) and press Install — the config is generated automatically, no JSON editing.
Related MCPs
Fetch
Web content fetching and conversion for efficient LLM usage.
Roblox Studio
Enables AI coding tools to control Roblox Studio for workspace exploration, instance manipulation, and script management. It provides tools for playtesting, sce
by paralovOpencode Omniroute Plugin
OpenCode plugin for the OmniRoute AI Gateway. Drives dynamic model discovery, /connect auth flow, and multi-instance OmniRoute providers via the official @openc
by GitHub ActionsAWS KB Retrieval
Retrieval from AWS Knowledge Base using Bedrock Agent Runtime.
by modelcontextprotocolSpring AI MCP Server
Provides auto-configuration for setting up an MCP server in Spring Boot applications.
llm-analysis-assistant
A very streamlined mcp client that supports calling and monitoring stdio/sse/streamableHttp, and can also view request responses through the /logs page. It also
by xuzexin-hzMCP-Agent
A simple, composable framework to build agents using Model Context Protocol by [LastMile AI](https://www.lastmileai.dev)
by lastmile-aiSpring AI MCP Client
Provides auto-configuration for MCP client functionality in Spring Boot applications.
mcp.natoma.ai
A Hosted MCP Platform to discover, install, manage and deploy MCP servers by [Natoma Labs](https://www.natoma.ai)
MCPHub
Website to list high quality MCP servers and reviews by real users. Also provide online chatbot for popular LLM models with MCP server support.
Compare Edupage Mcp Full with
Not sure what to pick?
Find your stack in 60 seconds
Author?
Embed badge for your README
Browse similar
All ai MCPs
