Smartschool MCP Server
Connect Claude or other MCP clients to your Smartschool account to query school data and download files.
Get courses and teacher info
Get grades/results with filters, pagination, and statistics
Get upcoming assignments and planned planner items
Read messages (inbox/sent/trash/drafts/scheduled) with search and sender filters
Get daily lesson schedules by day offset
Get academic periods and available report cards
Get student support links and resources
List and download message attachments
Get homepage blocks (e.g., monthly menu/calendar) and download embedded images
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., "@Smartschool MCP Server show my grades for this term"
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.
Smartschool MCP Server
Connect Claude (and other MCP clients) to your Smartschool account — ask about grades, assignments, messages, and your schedule in plain language.
Tools
Tool | What it does |
| List enrolled courses with teacher info |
| Grades with optional filtering, pagination, and statistics |
| Upcoming assignments organised by date |
| Inbox/sent/trash with search, sender filter, and body retrieval |
| Day schedule by offset (0 = today, 1 = tomorrow, …) |
| Academic terms for the current school year |
| Available report cards |
| Planner items for the next N days |
| School support resources and links |
| Student file notes (Leerlingvolgsysteem), without confidential notes; details on request ( |
| Absences recorded in the Leerlingvolgsysteem (date, code, description, part of day) |
| List attachments for a specific message |
| Download a specific attachment by message and file ID |
| "In de kijker" blocks pinned to the homepage (e.g. monthly menu, calendar) |
| Download an image embedded in a homepage block |
Related MCP server: studieplus-mcp
Quick start — Claude Desktop
uvx mcp install smartschool-mcp \
-e SMARTSCHOOL_USERNAME="you" \
-e SMARTSCHOOL_PASSWORD="secret" \
-e SMARTSCHOOL_MAIN_URL="school.smartschool.be" \
-e SMARTSCHOOL_MFA="YYYY-MM-DD"Or add it manually to claude_desktop_config.json:
{
"mcpServers": {
"smartschool": {
"command": "uvx",
"args": ["smartschool-mcp"],
"env": {
"SMARTSCHOOL_USERNAME": "you",
"SMARTSCHOOL_PASSWORD": "secret",
"SMARTSCHOOL_MAIN_URL": "school.smartschool.be",
"SMARTSCHOOL_MFA": "YYYY-MM-DD"
}
}
}
}Config file locations: %APPDATA%\Claude\claude_desktop_config.json (Windows) · ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) · ~/.config/Claude/claude_desktop_config.json (Linux)
Remote / claude.ai
The server supports Streamable HTTP transport for use as a remote integration on claude.ai.
Comparing modes
Mode | Best for | Setup | Credentials | Auth method |
Single-user | Personal use or one household | Simple, local | In env vars | Optional static Bearer token |
Universal | Hosting for multiple users | Requires public URL + HTTPS | Via login form | OAuth 2.1 with login form |
Single-user mode
One server instance, your credentials in environment variables:
export SMARTSCHOOL_USERNAME="..."
export SMARTSCHOOL_PASSWORD="..."
export SMARTSCHOOL_MAIN_URL="school.smartschool.be"
export SMARTSCHOOL_MFA="YYYY-MM-DD"
export MCP_API_KEY="a-long-random-secret" # optional but recommended
smartschool-mcp --transport streamable-http --host 0.0.0.0 --port 8000Add to claude.ai → Settings → Integrations:
URL:
https://your-domain.example.com/mcpAuthorization header:
Bearer <your MCP_API_KEY>(if set)
Universal mode — OAuth 2.1 login flow
One hosted server instance serves any Smartschool user via OAuth 2.1. Users authenticate through a browser-based login form during the authorization flow.
export MCP_ISSUER_URL="https://your-domain.example.com" # public server URL
smartschool-mcp --transport streamable-http --universal \
--issuer-url "$MCP_ISSUER_URL" \
--host 0.0.0.0 --port 8000In claude.ai → Settings → Integrations → Add custom integration:
URL:
https://your-domain.example.com/mcp
How it works:
Claude.ai discovers OAuth endpoints at
https://your-domain.example.com/.well-known/oauth-authorization-serverClaude.ai registers a client dynamically via
/registerClaude.ai directs the user to
/authorize?...(OAuth authorization endpoint)User is redirected to a login form at
/smartschool-loginUser enters: School URL, Username, Password, and optional MFA (date of birth)
On successful login, the server generates an authorization code
Claude.ai exchanges the code for an access token (via
/tokenwith PKCE)Claude.ai uses the Bearer token on all subsequent
/mcprequests
Security: Credentials are never stored in URLs or environment variables. They're collected via HTTPS form submission and validated against Smartschool. Only access tokens are sent with API requests.
Making the server publicly accessible
Required for universal mode. Claude.ai requires HTTPS and must be able to reach your server to redirect users to the login form and receive authorization callbacks.
Some options:
Option | Command |
Cloudflare Tunnel |
|
ngrok |
|
VPS | nginx / Caddy with a Let's Encrypt cert |
After setting up the tunnel/proxy, your server will be reachable at https://your-domain.example.com. Use this as MCP_ISSUER_URL.
Environment variables
Variable | CLI flag | Default | Description |
|
|
|
|
|
|
| Bind address (HTTP only) |
|
|
| Port (HTTP only) |
| — | — | Static Bearer token (single-user mode only) |
|
| off | Enable universal mode (set to |
|
| — | Required in universal mode. Public URL of the server, e.g. |
| — |
| How long to cache Smartschool sessions (universal mode) |
| — | — | Your Smartschool username (single-user mode only) |
| — | — | Your Smartschool password (single-user mode only) |
| — | — | School hostname, e.g. |
| — | — | Date of birth |
Contributing
PRs are welcome. Run uv sync --extra dev to install dev dependencies, then uv run pytest / uv run ruff check . / uv run mypy smartschool_mcp/ before submitting.
Disclaimer
Unofficial tool, not affiliated with Smartschool. Use in accordance with your school's terms of service.
Available Tools
13 toolsdownload_attachmentA
Download a specific attachment from a message.
Files are saved to save_path when provided, otherwise to
~/Downloads/smartschool/. The directory is created automatically.
Existing files are never overwritten — a counter suffix is appended
instead (e.g. report (1).pdf).
Args: message_id: The ID of the message containing the attachment. file_id: The file ID of the attachment to download (from get_attachments). save_path: Optional directory to save the file into.
Returns: Dictionary with the saved file path, filename, mime type, and bytes written.
Examples: - download_attachment(249184, 12345) -> Download to ~/Downloads/smartschool/ - download_attachment(249184, 12345, "/tmp") -> Download to /tmp/
Inputs: file_id (required), message_id (required), save_path. Returns: object
download_homepage_imageA
Download an image embedded in a homepage block.
Use the URLs returned in get_homepage_blocks()["blocks"][*]["images"].
Only assets on the configured Smartschool host are accepted.
Args: image_url: Image URL from get_homepage_blocks. save_path: Optional directory to save into (default: ~/Downloads/smartschool/).
Returns: Dictionary with the saved file path and bytes written.
Inputs: image_url (required), save_path. Returns: object
get_attachmentsA
List all attachments for a specific message.
Args: message_id: The ID of the message to get attachments for (from get_messages results).
Returns: Dictionary with attachment list including file names, sizes, and IDs for downloading.
Examples: - get_attachments(249184) -> List attachments for message 249184
Inputs: message_id (required). Returns: object
get_coursesA
Retrieve all available courses with their teachers.
Returns: List of courses with name and teacher information.
Inputs: no named parameters. Returns: result
get_future_tasksB
Retrieve upcoming assignments and tasks.
Returns: Dictionary with future tasks organized by date and course.
Inputs: no named parameters. Returns: object
get_homepage_blocksA
Retrieve the "in de kijker" blocks pinned to the Smartschool homepage.
Schools use these blocks for recurring content that is never sent as a
message and never lands in a document module — a monthly lunch menu
("Maandmenu"), a monthly calendar ("Maandkalender"), announcements. The
content is frequently an embedded image rather than text, so images
is usually where the information actually lives.
Args: include_html: Also return each block's raw inner HTML (default: False).
Returns: Dictionary with the list of blocks. Each block has a title, its news_id, plain text, and absolute URLs for any embedded images and links.
Examples: - get_homepage_blocks() -> [{"title": "Maandmenu", "images": [...]}, ...]
Inputs: include_html. Returns: object
get_messagesA
Retrieve messages from the specified mailbox with filtering options.
Args: limit: Maximum number of messages to return (default: 15) offset: Number of messages to skip from the beginning (default: 0) box_type: Type of mailbox - "INBOX", "SENT", "DRAFT", "SCHEDULED", "TRASH" (default: "INBOX") search_query: Search in subject and body content (case-insensitive) sender_filter: Filter messages by sender name (partial match, case-insensitive) include_body: Whether to include full message body (default: False for performance)
Returns: Dictionary with messages list and pagination info.
Examples: - get_messages() -> First 15 inbox messages (headers only) - get_messages(search_query="homework") -> Messages containing "homework" - get_messages(sender_filter="teacher") -> Messages from senders containing "teacher" - get_messages(include_body=True) -> Full messages with body content
Inputs: limit, offset, box_type, include_body, +2 more. Returns: object
get_periodsA
Retrieve academic periods/terms for the current school year.
Returns: List of academic periods with name, dates, and active status.
Inputs: no named parameters. Returns: result
get_planned_elementsB
Retrieve planned assignments and to-dos from the Smartschool planner.
Args: days_ahead: Number of days ahead to fetch (default: 34)
Returns: Dictionary with planned elements including dates, courses, and assignment types.
Inputs: days_ahead. Returns: object
get_reportsA
Retrieve available academic report cards.
Returns: List of report cards with name, date, class, and school year label.
Inputs: no named parameters. Returns: result
get_resultsA
Retrieve student results/grades with detailed information.
Args: limit: Maximum number of results to return (default: 15) offset: Number of results to skip from the beginning (default: 0) course_filter: Filter results by course name (partial match, case-insensitive) include_details: Whether to fetch detailed info (teacher, average, median) - saves API calls if False
Returns: Dictionary with results list and pagination info.
Examples: - get_results() -> First 15 results with details - get_results(course_filter="Math") -> Results from courses containing "Math" - get_results(include_details=False) -> Basic info only, faster response
Inputs: limit, offset, course_filter, include_details. Returns: object
get_scheduleA
Retrieve the lesson schedule for a given day.
Args: date_offset: Days from today (0=today, 1=tomorrow, -1=yesterday, default: 0)
Returns: Dictionary with the lessons scheduled for the given date.
Inputs: date_offset. Returns: object
get_student_support_linksA
Retrieve student support links and resources.
Returns: List of visible support links with name, description, and URL.
Inputs: no named parameters. Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 13 tools
Most tools target clearly distinct resources (courses, results, messages, schedule, reports, etc.). However, get_future_tasks and get_planned_elements both describe retrieval of upcoming assignments/tasks, creating potential ambiguity.
All tools follow a consistent lowercase snake_case verb_noun pattern: get_* for retrieval and download_* for file downloads. No mixed conventions or unpredictable naming styles.
13 tools is well within the typical 3-15 range and each tool serves a distinct read-only purpose within the Smartschool domain. The count feels complete without being bloated.
The server covers a broad read-only surface for Smartschool: courses, results, schedules, messages, attachments, reports, planner, homepage blocks, and support links. Minor gaps exist, such as no ability to fetch detailed course content or timeline events, but core workflows are covered.
Maintenance
Related MCP Connectors
Connect Claude, Cursor, or any MCP client to your FlowContent account
Let Claude or ChatGPT search, read and send your WhatsApp messages over MCP. OAuth sign-in.
Connect ChatGPT and Claude to your Mac, Windows or Linux with secure MCP remote access.
Your Telegram, WhatsApp, Instagram, mail and calendar in Claude or ChatGPT. Never sends messages.
Related MCP Servers
- AlicenseAqualityDmaintenanceAn MCP server for accessing Dutch school schedules from Magister. Enables Claude and other MCP-compatible AI assistants to query school schedules, drop-off times, and pick-up times.44 npm4MIT
- AlicenseNot gradedqualityCmaintenanceMCP server that gives Claude Desktop access to school data from Studie+ (Danish school platform), enabling queries about schedules, homework, assignments, and files directly in chat.MIT
- AlicenseAqualityCmaintenanceMCP server that connects Claude to Edupage, a school information system used across Europe. Provides access to timetables, grades, homework, messages, students, teachers, and more.251GPL 3.0
- AlicenseBqualityBmaintenanceEnables Claude to query your KRÉTA student data locally and read-only, including timetables, homework, grades, tests, and absences, using your own credentials via OAuth/PKCE.203Apache 2.0