Skip to main content
Glama

ntnu-api

Async Python client for NTNU course data. Wraps the three public, no-auth data sources for course information at the Norwegian University of Science and Technology behind one typed interface — built as a stepping stone toward an MCP server exposing course data to LLM agents.

Namespace

Data

Backing source

client.courses

catalog search, per-course schedules & weekly timetables

ntnu.no course-page JSON (Liferay)

client.grades

grade distributions per course/year/semester

HK-dir DBH statistics API

client.semesters

term ids (26h/26v), teaching weeks, exam periods

NTNU's TP timetable system

See docs/api-research.md for the full survey of NTNU data sources (including the dead and auth-gated ones) and the exact upstream request shapes.

Usage

import asyncio
from ntnu_api import NTNUClient


async def main() -> None:
    async with NTNUClient() as client:
        # Server-side course search (one 500-course page)
        page = await client.courses.search(2026, "objektorientert")
        for hit in page.courses[:3]:
            print(hit.course_code, hit.course_name)

        # Full catalog iteration
        async for result_page in client.courses.search_all(2026):
            ...

        # Dated teaching activities and the summarized weekly grid
        activities = await client.courses.schedules("TDT4100", 2026)
        grid = await client.courses.timetable("TDT4100", 2026)

        # Grade distribution (accepts bare or DBH-versioned codes)
        for row in await client.grades.distribution("TDT4100", years=[2023]):
            print(row.year, row.semester_name, row.grade, row.total)

        # Terms as known by NTNU's timetable system
        current = await client.semesters.current()


asyncio.run(main())

CLI

A small ntnu command wraps every client method for quick terminal poking:

uv run ntnu search 2026 maskinlæring        # catalog search (--all, --page, --sort)
uv run ntnu schedules TDT4100 2026          # dated activities, Oslo-local times
uv run ntnu timetable TDT4100 2026          # weekly grid
uv run ntnu grades TDT4100 --years 2023     # grade distribution table
uv run ntnu versions TDT4100                # DBH course-code versions
uv run ntnu semesters --current             # terms known by TP
uv run ntnu search 2026 ai --json | jq ...  # every subcommand takes --json

All models are pydantic v2; all errors derive from ntnu_api.NTNUAPIError (with NotFoundError, RateLimitError, APITimeoutError, ... subclasses). Transient failures (429, 502–504, connection errors) are retried with exponential backoff, honoring Retry-After.

A word of caution: the ntnu.no endpoints are NTNU's own internal AJAX surface, not a documented API — treat results accordingly and be polite (the client ships a descriptive User-Agent by default).

MCP server

The mcp extra ships an MCP server exposing the client as six tools (search_courses, get_course_schedule, get_weekly_timetable, get_grade_distribution, get_course_versions, get_semesters) with LLM-shaped responses: English names with Norwegian fallback, Oslo-local times, grade rows collapsed into per-term distribution tables with percentages, and an in-process TTL cache for the catalog and semester data.

uv sync --extra mcp                       # or: pip install 'ntnu-api[mcp]'
claude mcp add ntnu -- uv run ntnu-mcp    # register with Claude Code (stdio)
uv run ntnu-mcp --transport streamable-http --port 8000   # hostable HTTP service
npx @modelcontextprotocol/inspector uv run ntnu-mcp       # interactive testing UI

For Claude Desktop, add to claude_desktop_config.json:

{"mcpServers": {"ntnu": {"command": "uv", "args": ["run", "--directory", "/path/to/NTNU_python_api", "ntnu-mcp"]}}}

Stack

  • uv — dependency & virtualenv management

  • httpx + pydantic v2 — transport and models

  • ruff — linting + formatting

  • ty — static type checking

  • pytest + pytest-asyncio + respx — testing

  • mise — pins Python/uv and exposes task shortcuts

  • Dev Container — reproducible environment

Development

Inside the Dev Container (or after uv sync on the host):

Task

Command

mise test

uv run pytest

mise lint

uv run ruff check . && uv run ruff format --check .

mise fmt

uv run ruff format . && uv run ruff check --fix .

mise typecheck

uv run ty check

mise check

lint + typecheck + test

The default test run is fully mocked (respx) against real captured payloads in tests/fixtures/. To also verify against the live endpoints:

NTNU_API_LIVE=1 uv run pytest tests/test_live.py

Roadmap

  • MCP server exposing the client as tools (ntnu-mcp)

  • Expose the remaining catalog search facets (campus, level, faculty/institute)

  • Course detail scraping (description, credits, prerequisites — HTML-only upstream)

  • TP emner.php semester catalog (English names, campus ids — see docs/api-research.md)

  • TP iCal export as a secondary timetable source once semesters publish

-
license - not tested
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/MartinSA04/ntnu-api'

If you have feedback or need assistance with the MCP directory API, please join our Discord server