Skip to main content
Glama

hse-ruz-mcp

CI npm License: MIT

English. A local (stdio) MCP server for the HSE University timetable (RUZ, ruz.hse.ru/api). It finds students, lecturers, groups and rooms (ruz_find_person) and returns their schedules (ruz_get_schedule, or ruz_get_my_schedule by a student's @edu.hse.ru email). No login needed, but RUZ only answers from inside the HSE network (campus Wi-Fi HSE.Student or staff VPN). Install for Claude Code: claude mcp add hse-ruz-mcp -- npx -y hse-ruz-mcp (Node.js 22+).

Локальный MCP-сервер (stdio) для расписания НИУ ВШЭ через API RUZ (ruz.hse.ru/api): ищет студентов, преподавателей, группы и аудитории и показывает их расписание (студента — в том числе по email). Логин, пароль и браузер не нужны.

Ограничение: только из сети ВШЭ

RUZ отвечает только из внутренней сети ВШЭ (Wi-Fi HSE.Student на кампусе или VPN сотрудника). Вне её API перенаправляет на HTML-заглушку, и tools возвращают ошибку с объяснением.

Related MCP server: hdu-ics-mcp-server

Установка

Нужен Node.js 22+.

Claude Code

claude mcp add hse-ruz-mcp -- npx -y hse-ruz-mcp

Claude Desktop, Cursor и другие клиенты

{
  "mcpServers": {
    "hse-ruz-mcp": {
      "command": "npx",
      "args": ["-y", "hse-ruz-mcp"]
    }
  }
}

Из исходников

git clone https://github.com/ihavealotofguap/hse-ruz-mcp.git
cd hse-ruz-mcp
npm install
npm run build
claude mcp add hse-ruz-mcp -- node <путь-к-проекту>/dist/index.js

Tools

Tool

Что делает

ruz_find_person

Ищет студента, преподавателя, группу или аудиторию по подстроке (от 2 символов) и возвращает до limit совпадений (по умолчанию 20) с id и общим числом совпадений с id total (type: student по умолчанию, lecturer, group, auditorium)

ruz_get_schedule

Возвращает расписание студента, преподавателя, группы или аудитории по RUZ id из ruz_find_person (с тем же type)

ruz_get_my_schedule

Возвращает расписание студента по корпоративному email (login@edu.hse.ru)

Параметры периода у всех тулов расписания:

  • startDate — первый день, ГГГГ-ММ-ДД (можно в прошлом), по умолчанию сегодня;

  • daysAhead — сколько дней, 1–60, по умолчанию 7;

  • language — язык названий дисциплин и аудиторий: ru (по умолчанию) или en.

Расписание возвращается как { from, to, lessons }, где from и to — фактические даты периода. Все тулы только читают данные (аннотация readOnlyHint) и описывают формат ответа в outputSchema.

Даты считаются по московскому времени при любой часовой зоне машины. Запрос к RUZ прерывается через 15 секунд или когда клиент отменяет вызов. Успешные ответы RUZ кэшируются в памяти на 5 минут, а одинаковые запросы, отправленные одновременно, уходят в RUZ один раз.

Примеры запросов

  • «Какие у меня пары завтра? Мой email login@edu.hse.ru»

  • «Найди группу БПИ231 и покажи её расписание на неделю»

  • «Какие пары у преподавателя Иванова на следующей неделе с понедельника?»

Разработка

  • npm run build собирает проект в dist/, npm run dev собирает в режиме watch.

  • npm run lint проверяет код линтером и форматтером Biome, npm run format исправляет то, что можно исправить автоматически.

  • npm test собирает проект и запускает тесты node:test (test/*.test.mjs, fetch подменён, сеть не нужна).

Участие в разработке и выпуск релизов описаны в CONTRIBUTING.md.

Лицензия

MIT

Available Tools

3 tools
ruz_find_personНайти в РУЗA
Read-onlyIdempotent

Поиск студента, преподавателя, группы или аудитории ВШЭ по подстроке (ФИО, номер группы) через API RUZ (ruz.hse.ru/api/search). ВАЖНО: RUZ отдаёт данные только из внутренней сети ВШЭ (Wi-Fi HSE.Student на кампусе или VPN сотрудника) — вне сети запрос вернёт ошибку. Возвращает до limit совпадений (id и подпись) и их общее число total — id с тем же type передаётся в ruz_get_schedule. Если total больше limit, уточните запрос.

NameRequiredDescriptionDefault
termYesСтрока поиска: часть ФИО, номер группы и т.п.
typeNostudent
limitNoСколько совпадений вернуть

Output Schema

NameRequiredDescription
totalYesСколько пригодных совпадений (с id) нашёл RUZ, до обрезки по limit
resultsYes

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/openWorld, but the description adds what annotations cannot: RUZ only serves data from the internal HSE network or staff VPN and otherwise returns an error. It also describes the response shape (up to limit matches with id+label plus total), far beyond the annotation set.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose, then the critical network warning, then return shape and follow-up. Dense but nearly every clause carries actionable information; slightly long for what is fundamentally a search tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers precondition (network), semantics of return (matches + total), truncation handling, and hand-off to the sibling tool. With an output schema present, nothing an agent needs before calling is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Adds meaning beyond the 67% schema coverage: term is a substring of ФИО or group number, limit caps returned matches, and type determines which id namespace the result belongs to for the follow-up schedule call. The type parameter itself has an enum without inline description, and the description only covers it indirectly.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (поиск по подстроке) and enumerates the exact resources found (студент, преподаватель, группа, аудитория) plus the backing endpoint (ruz.hse.ru/api/search). This is clearly distinct from ruz_get_schedule, which consumes the resulting id.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly routes the agent: the resulting id with the same type is passed to ruz_get_schedule, and if total exceeds limit the agent is told to refine the query. It also states the network precondition that determines whether the call can succeed at all.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ruz_get_my_scheduleРасписание студента по emailA
Read-onlyIdempotent

Расписание занятий студента ВШЭ по его корпоративному email (login@edu.hse.ru) на daysAhead дней начиная со startDate (по умолчанию с сегодня). Использует API RUZ, который отдаёт данные только из внутренней сети ВШЭ (Wi-Fi HSE.Student на кампусе или VPN) — вне сети запрос вернёт ошибку.

NameRequiredDescriptionDefault
emailYesКорпоративный email студента, напр. ivanov@edu.hse.ru
languageNoЯзык названий дисциплин, аудиторий и т.п.: ru или enru
daysAheadNoСколько календарных дней получить, начиная со startDate (по умолчанию с сегодня)
startDateNoПервый день периода, ГГГГ-ММ-ДД по московскому времени (можно в прошлом). По умолчанию сегодня

Output Schema

NameRequiredDescription
toYesПоследний день периода включительно, ГГГГ-ММ-ДД
fromYesПервый день периода, ГГГГ-ММ-ДД
lessonsYes
studentYesСтудент из RUZ studentinfo: id, ФИО (fio) и info

TDQS

A3.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations (readOnly, idempotent, openWorld, non-destructive), the description discloses a critical behavioral trait: the RUZ API is only reachable from the HSE internal network or VPN, and requests from outside will fail. This is exactly the kind of operational context an agent needs to avoid a failed call.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the purpose and followed by the crucial network constraint. Slight redundancy in restating the default start date that the schema already covers keeps it from a 5, but overall it is efficient and well-structured.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers purpose, date range behavior, and the decisive network prerequisite, and an output schema exists so return values need not be explained. It is missing explicit sibling differentiation, but otherwise complete for a read-only retrieval tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents every parameter, including email format, language enum, daysAhead range, and startDate default. The description mentions daysAhead and startDate but adds no semantics beyond what the schema provides; baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: retrieves a student's class schedule for HSE by corporate email over a date range. The scope is clear, but the description never distinguishes this tool from its sibling ruz_get_schedule, which an agent may confuse it with.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied by the tool name and the email parameter; the description gives no explicit guidance on when to use this tool versus ruz_find_person or ruz_get_schedule. The network prerequisite is useful but is a behavioral constraint, not usage guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ruz_get_scheduleРасписание по RUZ idA
Read-onlyIdempotent

Расписание студента, преподавателя, группы или аудитории ВШЭ по RUZ id (узнать id — ruz_find_person с тем же type) на daysAhead дней начиная со startDate (по умолчанию с сегодня).

NameRequiredDescriptionDefault
idYesRUZ id из ruz_find_person
typeYesТип объекта, как в ruz_find_person
languageNoЯзык названий дисциплин, аудиторий и т.п.: ru или enru
daysAheadNoСколько календарных дней получить, начиная со startDate (по умолчанию с сегодня)
startDateNoПервый день периода, ГГГГ-ММ-ДД по московскому времени (можно в прошлом). По умолчанию сегодня

Output Schema

NameRequiredDescription
toYesПоследний день периода включительно, ГГГГ-ММ-ДД
fromYesПервый день периода, ГГГГ-ММ-ДД
lessonsYes

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, non-destructive and open-world, so safety needs no restating. The description still adds workflow context the annotations cannot convey: the id must come from ruz_find_person and the period defaults to today's start, which is real value beyond the structured hints.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded sentence covering purpose, entities, the id prerequisite, and the date window, with no filler. Slight redundancy in restating 'daysAhead days starting from startDate' already defined by the schema keeps it from a 5.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists and the annotations are rich, so the description need not explain return values; it correctly focuses on the id prerequisite and default period. It leaves the relationship to ruz_get_my_schedule unstated, which is the one gap for a read tool with a sibling that overlaps in purpose.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and all five parameters are documented in the schema, so the baseline is 3. The description only echoes daysAhead/startDate semantics and the default start of today, adding little syntax or edge-case meaning on top of the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Names a specific verb (get schedule) and the exact resources (student, lecturer, group, auditorium at HSE) keyed by RUZ id. It explicitly routes the id lookup to the sibling ruz_find_person, so an agent can distinguish the two tools without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The prerequisite chain is spelled out: obtain the id via ruz_find_person with the same type, then call this tool. It does not say when to prefer the other sibling, ruz_get_my_schedule, over this id-based lookup, so the alternative-selection guidance is incomplete.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

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

  1. 4 tool updatesv0.2.3
    • Changedruz_find_person4 fields changed
      • removedInput schema / additionalProperties
        Removed value: -false
      • addedInput schema / properties / limit
        Added value: +{
        +  "default": 20,
        +  "description": "Сколько совпадений вернуть",
        +  "maximum": 100,
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • addedInput schema / properties / term / minLength
        Added value: +2
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "results": {
        +      "items": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "description": {
        +            "type": "string"
        +          },
        +          "id": {
        +            "type": "number"
        +          },
        +          "label": {
        +            "type": "string"
        +          },
        +          "type": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "id",
        +          "label",
        +          "type"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "total": {
        +      "description": "Сколько пригодных совпадений (с id) нашёл RUZ, до обрезки по limit",
        +      "type": "number"
        +    }
        +  },
        +  "required": [
        +    "results",
        +    "total"
        +  ],
        +  "type": "object"
        +}
    • Removedruz_get_group_schedule
    • Changedruz_get_my_schedule6 fields changed
      • removedInput schema / additionalProperties
        Removed value: -false
      • changedInput schema / properties / daysAhead / description
        Previous value: -"На сколько дней вперёд от сегодня получить расписание"New value: +"Сколько календарных дней получить, начиная со startDate (по умолчанию с сегодня)"
      • addedInput schema / properties / email / pattern
        Added value: +"^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
      • addedInput schema / properties / language
        Added value: +{
        +  "default": "ru",
        +  "description": "Язык названий дисциплин, аудиторий и т.п.: ru или en",
        +  "enum": [
        +    "ru",
        +    "en"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / startDate
        Added value: +{
        +  "description": "Первый день периода, ГГГГ-ММ-ДД по московскому времени (можно в прошлом). По умолчанию сегодня",
        +  "format": "date",
        +  "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +  "type": "string"
        +}
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "from": {
        +      "description": "Первый день периода, ГГГГ-ММ-ДД",
        +      "type": "string"
        +    },
        +    "lessons": {
        +      "items": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "auditorium": {
        +            "type": [
        +              "string",
        +              "number"
        +            ]
        +          },
        +          "beginLesson": {
        +            "type": [
        +              "string",
        +              "number"
        +            ]
        +          },
        +          "building": {
        +            "type": [
        +              "string",
        +              "number"
        +            ]
        +          },
        +          "date": {
        +            "type": [
        +              "string",
        +              "number"
        +            ]
        +          },
        +          "dayOfWeekString": {
        +            "type": [
        +              "string",
        +              "number"
        +            ]
        +          },
        +          "discipline": {
        +            "type": [
        +              "string",
        +              "number"
        +            ]
        +          },
        +          "endLesson": {
        +            "type": [
        +              "string",
        +              "number"
        +            ]
        +          },
        +          "group": {
        +            "type": [
        +              "string",
        +              "number"
        +            ]
        +          },
        +          "kindOfWork": {
        +            "type": [
        +              "string",
        +              "number"
        +            ]
        +          },
        +          "lecturer": {
        +            "type": [
        +              "string",
        +              "number"
        +            ]
        +          },
        +          "lecturer_rank": {
        +            "type": [
        +              "string",
        +              "number"
        +            ]
        +          },
        +          "lecturer_title": {
        +            "type": [
        +              "string",
        +              "number"
        +            ]
        +          },
        +          "note": {
        +            "type": [
        +              "string",
        +              "number"
        +            ]
        +          },
        +          "stream": {
        +            "type": [
        +              "string",
        +              "number"
        +            ]
        +          },
        +          "subGroup": {
        +            "type": [
        +              "string",
        +              "number"
        +            ]
        +          },
        +          "url1": {
        +            "type": [
        +              "string",
        +              "number"
        +            ]
        +          },
        +          "url1Description": {
        +            "type": [
        +              "string",
        +              "number"
        +            ]
        +          },
        +          "url2": {
        +            "type": [
        +              "string",
        +              "number"
        +            ]
        +          },
        +          "url2Description": {
        +            "type": [
        +              "string",
        +              "number"
        +            ]
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "student": {
        +      "additionalProperties": false,
        +      "description": "Студент из RUZ studentinfo: id, ФИО (fio) и info",
        +      "properties": {
        +        "fio": {
        +          "type": "string"
        +        },
        +        "id": {
        +          "type": "number"
        +        },
        +        "info": {
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "id"
        +      ],
        +      "type": "object"
        +    },
        +    "to": {
        +      "description": "Последний день периода включительно, ГГГГ-ММ-ДД",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "student",
        +    "from",
        +    "to",
        +    "lessons"
        +  ],
        +  "type": "object"
        +}
    • Addedruz_get_schedule
  2. 3 tool updatesv0.1.0
    • First observedruz_find_person
    • First observedruz_get_group_schedule
    • First observedruz_get_my_schedule

TDQS

A4.2/5.0

Scored across 3 tools

Disambiguation4/5

The search tool and schedule tools are clearly distinct: one resolves names to RUZ ids, the other fetches schedules. The only overlap is between ruz_get_schedule and ruz_get_my_schedule, both returning schedules, but the descriptions clarify that one works by RUZ id for any entity and the other by corporate email for the current student.

Naming Consistency5/5

All tools use the same ruz_ prefix and snake_case verb_noun pattern: ruz_find_person, ruz_get_schedule, ruz_get_my_schedule. The naming is predictable and readable.

Tool Count5/5

Three tools are well-scoped for a focused RUZ schedule lookup server: search, schedule by id, and schedule by email. Each tool has a clear role and there is no unnecessary surface area.

Completeness4/5

The core workflow is covered: find a person/group/room, then fetch its schedule, plus a shortcut for the current student's schedule by email. Minor gaps exist, such as no explicit tool for enumerating supported entity types or additional schedule metadata, but agents can work around this through search.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables querying University of Caen (Unicaen) schedule data to find next classes for professors, students, or rooms and check room availability. Integrates with ADE scheduling system to provide real-time schedule information through natural language queries.
    -
  • F
    license
    B
    quality
    C
    maintenance
    Enables querying of Hangzhou Dianzi University course schedules, exams, and campus events by accessing the HDUHelp ICS calendar subscription. Supports getting today's and upcoming events, as well as keyword search.
    3
    -
  • A
    license
    A
    quality
    B
    maintenance
    Provides LLM clients with real-time access to BSUIR class schedules, academic weeks, student groups, and teachers through a read-only MCP interface, enabling natural-language queries about lessons and timetable information.
    22
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables users to search for information about the Institute of Fundamental Medicine and Biology at KFU and retrieve academic group schedules. It uses OpenRouter to understand natural-language questions and automatically invoke MCP tools.
    1
    -