Skip to content
verify mcp Beta VerifyMCP is currently in beta. If you notice any issues, get in touch and we’ll put it right.

İTÜ MCP

PYPI · ITU-MCP

İTÜ Ninova, OBS, Portal, kampüs servisleri ve kütüphane için MCP sunucusu

Available components

−2 this week 76 Trust /100

Last scanned (26 minutes ago)

Scores higher than 73% of PyPI servers

Category Education and Research

Trust breakdown (7 categories)

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. How we score → Why this is hard to score →

Supply Chain Security50
  • Malware scan not yet available for this package.Unverified
  • No known CVEs affecting this package version or its production dependencies.Pass
  • Runs setuptools.build_meta at install time, a recognised build step with no custom scripting around it. View diagnostics → Pass
  • 0 of 37 dependencies flagged as unhealthy. View diagnostics → Pass
Provenance & Transparency100
  • Source repository is publicly reachable at the declared URL. View diagnostics → Pass
  • Cryptographically verified build provenance (signed, bound to yatuk/itu-mcp). View diagnostics → Pass
  • Clear OSI-approved license (MIT).Pass
  • Actively maintained (last published 8 days ago).Pass
  • Publishes a security disclosure policy (SECURITY.md).Pass
Schema Quality & AI Usability75
  • 100% of prompts and resources have a non-trivial description (not blank, and not just the item's name).Pass
  • AI-judged instruction clarity (good).Pass
  • Context-footprint check failed: tool/resource definitions use about 16781 tokens (~132/item across 127 items; 122 tools + 5 resources), over budget; trim descriptions and params. See how to fix → Fail
  • Usage-examples check failed: none of the tools include examples. See how to fix → Fail
Stability & Change Management80
  • Stability observed for 24 of 30 days with no destabilising changes; credit accrues until the full window elapses.Partial
Tool Coverage75
  • 100% of tools have a non-trivial description (not blank, and not just the tool's name).Pass
  • 12% of tool parameters carry a description.Partial
  • Structured output schemas are declared (99% of tools); any adoption earns full credit.Pass
Tool Safety100
  • No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.Pass
  • All 1 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation.Pass
  • An AI judge read all 124 captured unit(s) of tool text and found none that tries to manipulate the model reading it.Pass
Capabilities100
  • Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.Pass
Changelog

Every change we have recorded for this component, newest first. Security-relevant changes are always shown. ▲ marks a change for the better, ▼ a change for the worse; unmarked changes are neutral.

  • 5 Nov 26 −17
    • Malware scan: pass → unverified ▼ security
    • Stability: fail → 0.80 functional
  • 31 Oct 26 +15
    • Malware scan: unverified → pass ▲ security
  • 27 Oct 26 0
    • Package version: 1.3.0 → 1.4.0 functional
  • 23 Oct 26 0
    • Package version: 1.2.1 → 1.3.0 functional
  • 19 Oct 26 0
    • Security disclosure: unverified → pass ▲ functional
  • 18 Oct 26 0
    • Security disclosure: pass → unverified ▼ functional
  • 15 Oct 26 +1

    No change was recorded against any check on this day. Stability & Change Management went from 92 to 95.

  • 13 Oct 26 −14
    • Malware scan: pass → unverified ▼ security
Diagnostics

Diagnostic detail from the automated scan of this channel: what the scanner observed at each step, so you can see exactly where a check passed or failed. It is informational only and never changes the trust score.

Captured 5 Nov 2026 · Analysed pypi/itu-mcp@1.4.0

Provenance Verified

A signed build attestation was found and verified, binding this exact artifact to the source repository it claims to come from.

Result Verified
Ecosystem pypi
Reason Verified
Discovered via Registry attestation endpoint
Source repo yatuk/itu-mcp
Certificate issuer https://token.actions.githubusercontent.com
Certificate SAN https://github.com/yatuk/itu-mcp/.github/workflows/publish.yml@refs/tags/v1.4.0
Rekor log index 3523641015
Predicate type PyPI publish attestation https://docs.pypi.org/attestations/publish/v1
Subject digest sha256:04cee16eb32a3e997830b216bb54586d4ff8d94c76efdcc515f4312fcc92a6fb

Background: How many MCP packages publish verified provenance →

Install scripts 1 script
Hook Tier Command
build_backend allowlisted setuptools.build_meta

Background: Why install scripts are a supply-chain risk →

Dependencies 37 packages
Packages resolved 37
Tree resolution Complete

Background: SBOMs and build attestations, explained →

MCP tools · 122 exposed · ~15,757 tokens

The tools this component advertises to a client, with an estimated token cost for each. Expand a tool to see its parameters and schema. The per-tool counts are indicative and are not scored directly; the schema's total context footprint is one signal in Schema Quality & AI Usability. A tool's description is untrusted text the model reads on every call, which is what makes this list a security surface and not just an inventory: how tool poisoning works →

Tool Tokens
archive_compare_terms ~227

Diff one course's sections between two archived terms: instructor turnover, section-count delta, and capacity/fill movement, named explicitly rather than left for two separate archive_term_sections calls to be compared by eye. Read four flags before quoting a number: 'comparable'; 'coverage_differs' (the two dumps hold different study levels, listed under 'levels'; only the shared levels are compared); 'enrolment_comparison' (a side marked enrolment_not_captured has 0 enrolled in every section of the whole term: no enrolled count or fill ratio, and not a term with zero students); and 'capacity_comparison' (a side marked capacity_not_captured has 0 capacity in every section of the whole term: total_capacity and capacity_delta are null). Each block gives 'comparable', 'not_captured_terms' and a 'reason'; a side's 'data_quality' names what is missing in one line. Section counts and instructors are compared either way.

NameTypeReqDescription
course_codestringyes–
term_a–yes–
term_b–yes–
NameTypeReqDescription
resultobjectyes–

No examples provided.

archive_course_catalog ~108

Catalog entry for a course from the archive: Turkish and English name, language, credits (theory/practice/lab/local/ECTS), description, learning outcomes, weekly topics, textbooks, and the OBS source URL. Fields the catalog does not hold are named in 'missing_fields' rather than filled in. 'coverage' separates 'course_absent_from_catalog' from 'branch_catalog_missing' (no catalog file was ever recorded for the branch).

NameTypeReqDescription
course_codestringyes–
NameTypeReqDescription
resultobjectyes–

No examples provided.

archive_course_history ~301

Term-by-term offering history for a course from the archive: which terms it ran, how many sections, which instructors, and which season it opens in. Answers 'is this course ever offered in the spring?', which OBS cannot. Read seasonality.pattern before claiming a season: insufficient_data (fewer than 3 term records) means the archive cannot tell, not that the course runs in one term; summer school is counted apart from Güz and Bahar. Placeholder counts: a term in enrolment_not_captured_terms has 0 enrolled in every section of the whole term (dump taken before registration opened), so its enrolled and fill_ratio are null: unknown, not zero. A term in capacity_not_captured_terms also has 0 capacity everywhere: its capacity is null too. Such terms are left out of every average and carry a one-line data_quality. A single 0 in a captured term is real. capture_basis is 'term' when the decision rests on term-wide totals, 'branch' when the totals of the terms in capture_basis_branch_terms could not be read and only the course's branch file decided. A course whose department code changed keeps its earlier terms under the old code (CEN 411E ran as BLG 411E): same_course_other_codes lists such codes, never merged; call again with that code for the earlier history.

NameTypeReqDescription
course_codestringyes–
limit_termsinteger––
NameTypeReqDescription
resultobjectyes–

No examples provided.

archive_course_unlocks ~141

Which courses list the given course as a prerequisite, from the archive's reverse prerequisite index. This is the direct next level only ('depth' is 'direct'), not the whole chain. Prerequisite rules have AND/OR (Ve/Veya) alternatives and minimum letter grades that this flat list does not express, so passing the course does not by itself make the listed courses takeable: call the tool named in 'rule_tool' (explain_course_eligibility) on a listed course for the real rule. 'coverage' is 'not_listed_as_prerequisite' when no course names it.

NameTypeReqDescription
course_codestringyes–
NameTypeReqDescription
resultobjectyes–

No examples provided.

archive_exam_schedule ~107

Final exam schedule the archive recorded for a term (date, day, time, place, exam type), optionally filtered by branch or exact course code. Most terms have no recorded schedule: 'coverage' is then 'exam_schedule_not_recorded', which means the schedule was never captured, not that there are no exams. For the live current schedule use get_public_exam_schedule.

NameTypeReqDescription
branch–––
course_code–––
limitinteger––
term–yes–
NameTypeReqDescription
resultobjectyes–

No examples provided.

archive_fill_rate ~320

How full a section got. With a CRN, reads that term's quota time series. With a course code, reports capacity vs enrolment across every past section so you can judge whether the course reliably fills up; add a term to narrow the course answer to that one term (term_filter says which). average_fill_ratio, max_fill_ratio and always_fills are null when no section has a usable ratio. Placeholder counts: a term in enrolment_not_captured_terms has 0 enrolled in every section of the whole term (dump taken before registration opened), so its enrolled and fill_ratio are null: unknown, not zero. A term in capacity_not_captured_terms also has 0 capacity everywhere: its capacity is null too. Such terms are left out of every average and carry a one-line data_quality. A single 0 in a captured term is real. capture_basis is 'term' when the decision rests on term-wide totals, 'branch' when the totals of the terms in capture_basis_branch_terms could not be read and only the course's branch file decided. The CRN note states how old the last snapshot is and whether the archive is scanning now (scan_active); the numbers are never live. A course whose department code changed keeps its earlier terms under the old code (CEN 411E ran as BLG 411E): same_course_other_codes lists such codes, never merged; call again with that code for the earlier history.

NameTypeReqDescription
course_code–––
crn–––
term–––
NameTypeReqDescription
resultobjectyes–

No examples provided.

archive_grade_distribution ~310

Letter grade counts for a course across the terms the archive has (from 2023-2024 on): per term the counts ('grades'), the published total, and the OBS source URL. Returns the most recent 6 terms by default: 'total_term_count' says how many exist, 'available_terms' names them, 'truncated' says some were left out; raise 'limit_terms' or pass 'term' for the rest. Percentages are not returned unless 'include_percentages' is true; they are shares of the counted grades ('counted_total'), so they add up to 100 even when the published total disagrees. Only the exact code is used; a Turkish/English sibling such as 'BLG 212' vs 'BLG 212E' is listed under 'related_codes', kept apart and never merged into this result, and 'same_counts_as' marks terms where the archive stores identical numbers under both codes (do not add them up). Grade labels are passed through as published, including the '+' grades; a label absent from a term was not published and is not zero. 'total_mismatch' flags terms where the published total differs from the sum of the counts; both numbers are kept. Check 'coverage': 'branch_grades_missing' means no grades file was ever recorded for the branch.

NameTypeReqDescription
course_codestringyes–
include_percentagesboolean––
limit_termsinteger––
term–––
NameTypeReqDescription
resultobjectyes–

No examples provided.

archive_instructor_courses ~47

List the courses one instructor has taught across archived terms, newest first. Returns candidate matches when the name is ambiguous.

NameTypeReqDescription
instructorstringyes–
limitinteger––
NameTypeReqDescription
resultobjectyes–

No examples provided.

archive_list_branches ~77

List every branch present in one term's archive dump, with section and course counts and the study levels the dump holds ('levels', e.g. LS undergraduate, LU graduate). Answers 'does this branch even have a döküm for this term?' directly, instead of probing archive_term_sections branch by branch.

NameTypeReqDescription
term–yes–
NameTypeReqDescription
resultobjectyes–

No examples provided.

archive_list_terms ~195

List every term held in the İTÜ ders arşivi (2016-2017 onward), including terms OBS no longer publishes and terms not yet active. Every archive tool that takes a term accepts the slug ('2025-2026-guz'), the OBS term id (202610) or the label printed here ('2025-2026 Güz Dönemi'). The archive exists because OBS publishes only the active term: the active term comes from OBS, past terms from historical dumps. Section counts of two terms are not comparable when 'coverage_may_differ' names one of them: the live term holds graduate sections that older dumps may lack. A term carries 'enrolment_not_captured' / 'capacity_not_captured' only when the index itself holds that term's totals (today the live term); for another term call a term tool such as archive_term_sections, which reports both flags.

Input schema present but exposes no named parameters.

NameTypeReqDescription
resultobjectyes–

No examples provided.

archive_search_courses ~136

Search the archive's full course index by code or name fragment, across every term it has ever seen — not just the active one. Use this to find the exact code archive_course_history needs when only a name fragment is known. Matching ignores case, accents and spacing ('cen411e', 'yazilim'). The index holds one name per course, in its language of instruction: a course taught in English (code ending in E) is found by its English name or its code, not by a Turkish name. An empty result carries a hint saying so.

NameTypeReqDescription
limitinteger––
querystringyes–
NameTypeReqDescription
resultobjectyes–

No examples provided.

archive_search_sections ~234

Search one whole term across all branches at once by course code fragment, course name fragment, instructor, and/or day; every filter given must match. Matching is case-insensitive and Turkish-aware ('sahin' finds 'Şahin'). Defaults to the archive's current term. Use this when the branch is unknown or the question spans branches; archive_term_sections reads a single branch in more detail. Returns 'match_count' and 'truncated' alongside 'coverage'. 'enrolment_not_captured' means no section of the whole term has an enrolled student in the dump (taken before registration opened): 'enrolled' and 'fill_ratio' are then null, unknown and not zero. 'capacity_not_captured' means no section of the term has a capacity either: 'capacity' is null too. 'data_quality' names what is missing in one line. A single 0 in a term that was captured is a real 0.

NameTypeReqDescription
course_code–––
course_name–––
day–––
instructor–––
limitinteger––
term–––
NameTypeReqDescription
resultobjectyes–

No examples provided.

archive_status ~81

When the archive scraper last ran and last succeeded, its section count, whether the last run was partial, which branches failed, and the data age in days ('data_age_days'). Informational only: the archive deliberately stops scraping outside registration and add/drop weeks, so an old date or a large data_age_days is expected and is not an error or a fault.

Input schema present but exposes no named parameters.

NameTypeReqDescription
resultobjectyes–

No examples provided.

archive_term_sections ~167

List archived sections for a term, filtered by branch, course code, or instructor. Critically, the archive holds terms OBS has not published yet, so upcoming-term offerings can be checked instead of guessed. A null instructor means none was announced. enrolment_not_captured means no section of the whole term has an enrolled student in the dump (taken before registration opened): enrolled and fill_ratio are null, unknown and not zero. capacity_not_captured means no section of the term has a capacity either: capacity is null too. data_quality names what is missing in one line. A single 0 in a captured term is a real 0.

NameTypeReqDescription
branch–––
course_code–––
instructor–––
limitinteger––
term–yes–
NameTypeReqDescription
resultobjectyes–

No examples provided.

archive_who_taught ~284

List every instructor who has taught a course across archived terms, ranked by how many terms they taught it, with their most recent term and average section fill rate. Sections with no announced instructor are counted in unannounced_section_count, never listed as a person. fill_ratio_section_count says how many sections an average rests on; average_fill_ratio is null when it rests on none. Placeholder counts: a term in enrolment_not_captured_terms has 0 enrolled in every section of the whole term (dump taken before registration opened), so its enrolled and fill_ratio are null: unknown, not zero. A term in capacity_not_captured_terms also has 0 capacity everywhere: its capacity is null too. Such terms are left out of every average and carry a one-line data_quality. A single 0 in a captured term is real. capture_basis is 'term' when the decision rests on term-wide totals, 'branch' when the totals of the terms in capture_basis_branch_terms could not be read and only the course's branch file decided. A course whose department code changed keeps its earlier terms under the old code (CEN 411E ran as BLG 411E): same_course_other_codes lists such codes, never merged; call again with that code for the earlier history.

NameTypeReqDescription
course_codestringyes–
limit_terms–––
NameTypeReqDescription
resultobjectyes–

No examples provided.

auth_status ~24

Check whether Ninova credentials are configured and whether a fresh session can be created.

Input schema present but exposes no named parameters.

NameTypeReqDescription
resultobjectyes–

No examples provided.

build_degree_plan ~115

Read an official semester-by-semester OBS curriculum; latest plan is selected by default. Courses are listed once, under plan.semesters[].courses. 'ects' is a number; when the plan gives a range such as '4 / 5' it is null and ects_min, ects_max and ects_raw carry the range.

NameTypeReqDescription
faculty_idintegeryes–
latestboolean––
plan_id–––
plan_typestring––
program_codestringyes–
NameTypeReqDescription
resultobjectyes–

No examples provided.

calculate_target_gpa ~296

Quick arithmetic without the student's record and without login: the average needed over future credits to reach a target cumulative GPA, from four numbers the caller supplies. It cannot see retakes; a retake replaces its old grade and adds no credit, so state them in retakes or the result understates what is reachable (see the assumption field). When the student is logged in, prefer obs_simulate_cumulative_gpa(target_gpa=...), which works from the record and handles retakes.

NameTypeReqDescription
current_creditsnumberyesCredits that count in the current GPA, e.g. 101. Not ECTS and not the credits completed.
current_gpanumberyesCurrent cumulative GPA (GANO) on the 4.00 scale, e.g. 2.35.
future_creditsnumberyesTotal credits of the courses still to be taken, retakes included, e.g. 18.
retakes––The part of future_credits that repeats a course already counted in the current GPA, e.g. [{"credit": 3, "old_grade": "FF"}, {"credit": 4, "old_grade": "DD"}]. A retake replaces its old grade and add…
target_gpanumberyesCumulative GPA to reach, e.g. 2.5.
NameTypeReqDescription
resultobjectyes–

No examples provided.

check_course_conflicts ~126

Check for schedule time conflicts between courses by CRN. Uses the public course schedule to look up session day/time/room. Give only the CRNs: the department of each CRN is found from the course archive (no login) and, for what is left, from the student's registered courses when logged in. Read status: ok, partial (missing_crns were not checked), not_found, or departments_required (pass department_codes).

NameTypeReqDescription
crnsarrayyes–
department_code–––
department_codes–––
program_typestring––
NameTypeReqDescription
resultobjectyes–

No examples provided.

check_watched_course_sections ~225

Read the public OBS schedule now for the watched sections (one request per branch, no login) and report per section: capacity, enrolled, seats free, and what changed since the previous check ('opened', 'filled', 'capacity_raised', 'delisted', ...). The first check of a section only sets a baseline. Status 'unknown' means OBS gave no usable numbers (missing values, or the enrolled column not populated yet) and is never a free seat; 'not_listed' means the CRN is absent from the schedule, which is not the same as full. Entries from a past term are reported as 'stale_term' and not compared. This is a one-shot check: the server cannot run in the background and sends no notifications, so a periodic check must be driven by the user or by a scheduled task on the client. Schedule reads are cached for a short time; when 'freshness.all_from_cache' is true the numbers were not re-read, so wait 'retry_after_seconds' instead of calling again in a loop.

Input schema present but exposes no named parameters.

NameTypeReqDescription
resultobjectyes–

No examples provided.

crawl_course ~72

Inventory pages and downloadable resources inside a Ninova course tree. A link that is refused or fails is listed in skipped with its reason and the crawl continues.

NameTypeReqDescription
course_urlstringyes–
include_downloadsboolean––
max_depthinteger––
max_pagesinteger––
NameTypeReqDescription
resultobjectyes–

No examples provided.

diff_snapshot ~41

Compare the current state of a Ninova page against a previously stored snapshot.

NameTypeReqDescription
label–––
snapshot_path–––
urlstringyes–
NameTypeReqDescription
resultobjectyes–

No examples provided.

download_resource ~64

Download a Ninova file or other authenticated resource to disk. The text of a saved PDF/DOCX/PPTX/TXT is also added to the local index that search_content searches.

NameTypeReqDescription
filename–––
output_dir–––
urlstringyes–
NameTypeReqDescription
resultobjectyes–

No examples provided.

estimate_relative_grade ~257

Estimate a likely letter grade from raw class scores under İTÜ's relative-grading (bağıl değerlendirme) rules, using both official methods: Method 1 (T-score against Table 1, an EXAMPLE class-level table from the regulation — the actual instructor may use different T-score cutoffs) and Method 2 (mean ± standard-deviation multiples, Table 2, a fixed formula with no table lookup). This is an estimate for planning purposes only, not the official grade. Scores must be finite numbers from 0 to 100; anything else is rejected with the offending value. No letter is estimated when fewer than 10 scores are counted or when all scores are equal: estimate_available is false, no_estimate_reason says why, and the mean and standard deviation are still returned. my_score is added to the list unless the same value is already in it (reported as my_score_included). class_scores must be every student's raw 0-100 score who counts toward the relative-grading average (VF students are excluded from that average per the regulation and must not be included here).

NameTypeReqDescription
class_scoresarrayyes–
my_scorenumberyes–
my_score_included–––
NameTypeReqDescription
resultobjectyes–

No examples provided.

explain_course_eligibility ~402

Explain whether a course's prerequisites are satisfied, using the official OBS branch prerequisite table (full Ve/Veya expression, per-course minimum grades, and credit requirement). Supports 3- and 4-digit codes including capstone courses like CEN 4901E. 'prerequisite_status' distinguishes 'no_prerequisites' (proven absent from the official table) from 'unknown' (table unreadable) — never read an empty result as 'no prerequisites'. 'cross_check' additionally diffs the result against an independent community dataset (third-party, not official); OBS stays authoritative and a disagreement is reported, never silently resolved either way. 'archive_seasonality', when the archive has the course, flags courses that only open in one term of the year (e.g. eligible now, but only ever offered in Güz) — check it even when eligibility alone looks fine. With use_obs_history=true, prerequisites the student is taking this term are listed in in_progress_prerequisites and eligible_if_in_progress_passed says what the answer becomes once they are passed; report that instead of a bare 'not eligible'. In missing_courses the alternatives of one OR group are a single entry ('A VEYA B'): one of them is enough. requirement is the whole rule as text with its minimum grades, and prerequisite_grades holds the student's grade in each prerequisite course already completed. The full completed-course history and the rule tree are returned only with include_raw=true.

NameTypeReqDescription
class_year–––
completed_courses–––
completed_credits–––
course_codestringyes–
include_rawboolean–Also return the whole completed-course history (completed_courses, completed_grades), requirement_tree, minimum_grades and explanation_parts. Default false: the verdict, the requirement as text and t…
program_typestring––
use_obs_historyboolean––
NameTypeReqDescription
resultobjectyes–

No examples provided.

export_course_schedule_ics ~239

Build an iCalendar (.ics) document from the weekly meetings of the given CRNs, read from the public OBS course schedule (no login). Each meeting becomes a weekly recurring event in Europe/Istanbul time between the first and last day of classes. Those two dates are taken from term_start/term_end; when omitted they are read from the official academic calendar ("Beginning/End of Fall Term" for that academic year and level) and 'term_date_sources' says where each came from. If the calendar does not state one, the result is status='term_dates_required' with no calendar: ask the user for the dates instead of guessing. Meetings whose day or time is a placeholder ('-', '--') are listed in 'skipped' and never given a time; CRNs not found in the scanned departments are in 'missing_crns'. Holidays are not excluded from the recurrence. Returns the text in 'ics'; it does not write a file.

NameTypeReqDescription
crnsarrayyes–
department_codesarrayyes–
program_typestring––
term_end–––
term_start–––
NameTypeReqDescription
resultobjectyes–

No examples provided.

export_exam_schedule_ics ~148

Build an iCalendar (.ics) document from the current public OBS final exam schedule (no login), filtered to the given course codes. Each exam is a single dated event in Europe/Istanbul time. An exam whose date or time is missing or unreadable is listed in 'skipped'; a code with no row is in 'not_found'; a branch whose schedule is not published yet is skipped with 'exam_schedule_not_published', which is not the same as having no exam. When only a start time is published the event has no end time ('end_time_unknown'). Returns the text in 'ics'; it does not write a file.

NameTypeReqDescription
course_codesarrayyes–
NameTypeReqDescription
resultobjectyes–

No examples provided.

export_table ~461

Export one of the student's own tables as a CSV that opens correctly in a Turkish Excel: UTF-8 with a byte order mark, ';' as the delimiter, decimal comma, Turkish column headers. Use it when the user wants their grades, weekly schedule or assignment deadlines as a spreadsheet or a file. Returns 'columns', 'row_count' and the text in 'csv' (or 'path' with save=true). A text of more than about 200 KB is cut at a row boundary with 'truncated' and 'total_row_count'. Cells that a spreadsheet would run as a formula are prefixed with a single quote. term_grades also reports the term average; deadlines is read from the stored snapshot without a sync and reports 'stale' and 'snapshot_age_hours', so call sync_all_courses first when it is stale. Reads only; nothing is changed at the university.

NameTypeReqDescription
datasetstringyesWhich table to export. term_grades: the courses of one term (Ders Kodu, Ders Adı, Kredi, Harf Notu). all_grades: every graded attempt of every term (Dönem, Ders Kodu, Ders Adı, Kredi, Harf Notu, Duru…
saveboolean–false (default): return the CSV text in 'csv'. true: write the file into the exports folder of the server's downloads directory and return its path instead of the text. An existing file is never repl…
semester––Term for term_grades and weekly_schedule: term code, OBS term id or name, e.g. "202610", 202610 or "2025-2026 Bahar". Default: the latest term. Ignored for all_grades and deadlines.

Structured output declared, but exposes no named fields.

No examples provided.

find_empty_classrooms ~77

Estimate empty rooms at a weekday/time from selected public department schedules. Only rooms that appear in the scanned schedules are known; sessions without an announced building or room are ignored.

NameTypeReqDescription
building–––
daystringyes–
department_codesarrayyes–
program_typestring––
time–yes–
NameTypeReqDescription
resultobjectyes–

No examples provided.

find_open_course_sections ~188

Find sections with seats a student can actually take, across selected public OBS department schedules. Part of a section's capacity can be reserved for named programmes, so 'available_seats' counts only the general pool; pass program_code to add your own programme's remaining quota. 'total_free_seats' is capacity minus enrolled and 'reserved_free_seats' lists free seats held for other programmes. Sections without a day and time (project and graduation work) are listed last with unscheduled=true; 'Ek Sınav' rows are left out. An empty result carries 'no_result_reason': the query matched no section, the matching sections are full, or their free seats are reserved for other programmes.

NameTypeReqDescription
department_codesarrayyes–
min_available_seatsinteger––
program_code–––
program_typestring––
query–––
NameTypeReqDescription
resultobjectyes–

No examples provided.

get_academic_calendar ~308

Read the official İTÜ academic calendar (public, no login): term start and end, course registration, add-drop and withdrawal periods, final and make-up exams, breaks. Covers the whole current academic year, not only this month; with date_from/date_to the academic years those dates fall in are read (at most 2 per call, and only years the site still lists). Each event has an English 'description' and a Turkish 'description_tr'; query matches either language, ignoring case and Turkish accents (e.g. 'dersten çekilme', 'ekle bırak', 'final'). 'terms' gives the first and last day of classes per term. With no argument only recent and upcoming events are listed (see 'default_window'). Check 'coverage' and 'coverage_warning' before concluding that nothing is scheduled. Official public holidays are not on this calendar. An event carries only what is its own: an empty field is left out (no start_at means the source gives no time of day), and timezone, source_url and academic_year are on an event only when they differ from the result's own timezone, url and academic_year.

NameTypeReqDescription
category–––
date_from–––
date_to–––
include_rawboolean–Return every event with all its fields, including empty ones, the site's row id (uid) and the timezone, source_url and academic_year repeated on each event. Default false.
query–––
NameTypeReqDescription
resultobjectyes–

No examples provided.

get_assignment_upload_slots ~59

List the file slots on an assignment's 'Ödevi Yükle / OdevGonder' page, including which slots are already filled and allowed extensions.

NameTypeReqDescription
assignment–––
course–––
upload_url–––
NameTypeReqDescription
resultobjectyes–

No examples provided.

get_cafeteria_menu ~53

Read a dated lunch/dinner or vegan menu from the İTÜ Portal (requires login), including calories and allergens.

NameTypeReqDescription
date–––
meal–––
veganboolean––
NameTypeReqDescription
resultobjectyes–

No examples provided.

get_course_announcements ~47

Return announcements for a specific Ninova course.

NameTypeReqDescription
compactboolean––
course–yes–
include_full_textboolean––
limitinteger––
NameTypeReqDescription
resultobjectyes–

No examples provided.

get_course_assignments ~66

Return a course's assignment list. By default also fetches each assignment detail/upload page; set include_details=false for a faster list-only read.

NameTypeReqDescription
compactboolean––
course–yes–
include_detailsboolean––
limitinteger––
NameTypeReqDescription
resultobjectyes–

No examples provided.

get_course_attendance ~146

Read the Ninova 'Yoklama' page for a course — attendance as the instructor recorded it in the LMS, not the official OBS record. The grid shows 0 both for an absence and for a session not entered yet, so only zeros in weeks that also hold a recorded 1 are counted as absences (total_absent_marks); the rest are total_unmarked_or_absent_marks, and weeks after today are total_future_marks. Never report unmarked or future marks as absences; when absence_counts_reliable is false, say the count is uncertain. For official attendance with an absence-risk summary, use obs_get_attendance instead.

NameTypeReqDescription
course–yes–
NameTypeReqDescription
resultobjectyes–

No examples provided.

get_course_class_files ~58

List files and folders under the Ninova 'Sınıf Dosyaları' section for a course.

NameTypeReqDescription
compactboolean––
course–yes–
max_depthinteger––
recursiveboolean––
NameTypeReqDescription
resultobjectyes–

No examples provided.

get_course_grades ~61

Read the Ninova 'Notlar' page for a course — grades as the instructor entered them in the LMS, not the official transcript record. For the official letter/midterm grade, use obs_get_course_grades instead.

NameTypeReqDescription
course–yes–
NameTypeReqDescription
resultobjectyes–

No examples provided.

get_course_info ~31

Return structured information from a course's 'Sınıf Bilgileri' page.

NameTypeReqDescription
course–yes–
NameTypeReqDescription
resultobjectyes–

No examples provided.

get_course_lesson_files ~58

List files and folders under the Ninova 'Ders Dosyaları' section for a course.

NameTypeReqDescription
compactboolean––
course–yes–
max_depthinteger––
recursiveboolean––
NameTypeReqDescription
resultobjectyes–

No examples provided.

get_course_message_board ~46

Read the Ninova 'Mesaj Panosu' page for a course.

NameTypeReqDescription
course–yes–
include_thread_detailsboolean––
limitinteger––
NameTypeReqDescription
resultobjectyes–

No examples provided.

get_course_overview ~151

Return a combined view of a course's sections, announcements, assignments, files, grades, message board, attendance, and remote learning routes. Without refresh=true a course that was synced before is answered from the stored snapshot (source: tracked_state). The result carries snapshot_age_hours and stale: stale=true means the stored data is older than the limit (12 hours by default, NINOVA_TRACKING_MAX_AGE_SECONDS) and must not be presented as the current state. Call again with refresh=true for live data.

NameTypeReqDescription
compactboolean––
course–yes–
file_max_depthinteger––
include_assignment_detailsboolean––
refreshboolean––
NameTypeReqDescription
resultobjectyes–

No examples provided.

get_course_remote_learning ~29

Read the Ninova 'Uzaktan Eğitim' page for a course.

NameTypeReqDescription
course–yes–
NameTypeReqDescription
resultobjectyes–

No examples provided.

get_course_sections ~28

List the direct course routes exposed on the Ninova course home page.

NameTypeReqDescription
course–yes–
NameTypeReqDescription
resultobjectyes–

No examples provided.

get_dashboard ~175

Read the Ninova dashboard and summarize courses, recent announcements, assignments, and messages. Each course row is one enrolled section: section and crn tell two sections of one course apart, and code_uncertain marks a code that could not be read reliably. Dashboard dates have no year: date_iso is inferred from today's date (date_year_inferred). A start/end window is split in date_ranges (start, end, raw) without ISO values. The page's link list and headings are left out by default (link_count says how many links there are); include_raw=true adds them.

NameTypeReqDescription
compactboolean––
include_rawboolean–Also return links (every link of the page, mostly site navigation) and page.headings. Default false: link_count only. With compact=true the list is still shortened.
NameTypeReqDescription
resultobjectyes–

No examples provided.

get_dashboard_announcements ~40

Return the announcements listed under the Ninova dashboard's aggregated announcements page.

NameTypeReqDescription
include_full_textboolean––
limitinteger––
NameTypeReqDescription
resultobjectyes–

No examples provided.

get_dashboard_assignments ~50

Return the assignments listed under the Ninova dashboard's aggregated assignments page. Set include_details=false for a faster list-only read.

NameTypeReqDescription
include_detailsboolean––
limitinteger––
NameTypeReqDescription
resultobjectyes–

No examples provided.

get_help_ticket ~90

Read one help ticket by numeric ID: title, description, unit, category, subcategory, status, dates, messages, institutional replies and attachment links. Does not download attachments. Reply detection compares history authors with the original requester. Missing fields are null. Dates are local to the source with no assumed timezone. Requires login.

NameTypeReqDescription
include_sensitiveboolean––
ticket_idstringyes–
NameTypeReqDescription
resultobjectyes–

No examples provided.

get_itu_announcements ~157

Aggregate official announcements from İTÜ (www.itu.edu.tr), ÖDEK, İKM, SKS and Erasmus sources, newest first across sources. 'published_at' is the source's own text and 'published_at_iso' the same date in ISO form; undated items come last. When limit is smaller than what the sources offer, every source first gets an equal share (see selection_note); ask for one source to read it in full. 'empty_sources' names sources that answered with no items, 'source_errors' those that failed. A summary cut short ends with '…' and has summary_truncated=true.

NameTypeReqDescription
limitinteger––
query–––
sources–––
NameTypeReqDescription
resultobjectyes–

No examples provided.

get_personal_exam_calendar ~99

Read the signed-in student's official OBS final calendar. matched_courses names the registered courses the calendar was read for (all of them, or the ones matching course) by code, CRN and title.

NameTypeReqDescription
course–––
include_rawboolean–Return matched_courses as full OBS rows and the final calendar unreduced. Default false: a matched course is named by code, CRN and title only.
semester–––
NameTypeReqDescription
resultobjectyes–

No examples provided.

Install

How do I install the İTÜ MCP server?

İTÜ MCP runs locally as a PyPI package, launched with uvx itu-mcp. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

pypi · itu-mcp

# add to Claude Code
claude mcp add yatuk-itu-mcp -- uvx itu-mcp
Common questions

What is the İTÜ MCP server?

İTÜ MCP is listed in the public MCP registry as io.github.yatuk/itu-mcp. İTÜ Ninova, OBS, Portal, kampüs servisleri ve kütüphane için MCP sunucusu. This page covers its PyPI package (itu-mcp).

Is the İTÜ MCP server safe to use?

İTÜ MCP scores 76 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 5 November 2026. Its build provenance is signed and verified. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

What tools does the İTÜ MCP server expose?

İTÜ MCP exposes 122 tools: auth_status, mail_status, mail_list_inbox, mail_list_sent, mail_get_message, and 117 more. Their descriptions and schemas cost roughly 15,757 tokens of context every time the server is loaded.

Is the İTÜ MCP server still maintained?

İTÜ MCP is still listed as active in the MCP registry. We last reached this channel on 5 November 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.

What licence is the İTÜ MCP server under?

İTÜ MCP declares the MIT licence, which is OSI-approved. That covers the source only, and says nothing about the cost of any service it calls.