Skip to main content
Glama
Smartschool MCP Server

Smartschool MCP Server

by MauroDruwel

Smartschool MCP Server

CI Mauro Quality Gate codecov PyPI version License: MIT Python 3.10+

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

get_courses

List enrolled courses with teacher info

get_results

Grades with optional filtering, pagination, and statistics

get_future_tasks

Upcoming assignments organised by date

get_messages

Inbox/sent/trash with search, sender filter, and body retrieval

get_schedule

Day schedule by offset (0 = today, 1 = tomorrow, …)

get_periods

Academic terms for the current school year

get_reports

Available report cards

get_planned_elements

Planner items for the next N days

get_student_support_links

School support resources and links

get_student_notes

Student file notes (Leerlingvolgsysteem), without confidential notes; details on request (text, fields, date, choice, attachments as name + mime)

get_student_absences

Absences recorded in the Leerlingvolgsysteem (date, code, description, part of day)

get_attachments

List attachments for a specific message

download_attachment

Download a specific attachment by message and file ID

get_homepage_blocks

"In de kijker" blocks pinned to the homepage (e.g. monthly menu, calendar)

download_homepage_image

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 8000

Add to claude.ai → Settings → Integrations:

  • URL: https://your-domain.example.com/mcp

  • Authorization 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 8000

In claude.ai → Settings → Integrations → Add custom integration:

  • URL: https://your-domain.example.com/mcp

How it works:

  1. Claude.ai discovers OAuth endpoints at https://your-domain.example.com/.well-known/oauth-authorization-server

  2. Claude.ai registers a client dynamically via /register

  3. Claude.ai directs the user to /authorize?... (OAuth authorization endpoint)

  4. User is redirected to a login form at /smartschool-login

  5. User enters: School URL, Username, Password, and optional MFA (date of birth)

  6. On successful login, the server generates an authorization code

  7. Claude.ai exchanges the code for an access token (via /token with PKCE)

  8. Claude.ai uses the Bearer token on all subsequent /mcp requests

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

cloudflared tunnel --url http://localhost:8000

ngrok

ngrok http 8000

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

MCP_TRANSPORT

--transport

stdio

stdio or streamable-http

MCP_HOST

--host

0.0.0.0

Bind address (HTTP only)

MCP_PORT

--port

8000

Port (HTTP only)

MCP_API_KEY

—

—

Static Bearer token (single-user mode only)

MCP_UNIVERSAL

--universal

off

Enable universal mode (set to 1, true, or yes)

MCP_ISSUER_URL

--issuer-url

—

Required in universal mode. Public URL of the server, e.g. https://mcp.example.com

SESSION_TTL_SECONDS

—

3600

How long to cache Smartschool sessions (universal mode)

SMARTSCHOOL_USERNAME

—

—

Your Smartschool username (single-user mode only)

SMARTSCHOOL_PASSWORD

—

—

Your Smartschool password (single-user mode only)

SMARTSCHOOL_MAIN_URL

—

—

School hostname, e.g. school.smartschool.be (single-user mode only)

SMARTSCHOOL_MFA

—

—

Date of birth YYYY-MM-DD if required (single-user mode only)

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 tools
download_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

Tool Schema Changelog

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

Loading tool schema changelog…

    TDQS

    A3.9/5.0

    Scored across 13 tools

    Disambiguation4/5

    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.

    Naming Consistency5/5

    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.

    Tool Count5/5

    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.

    Completeness4/5

    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

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers