hse-ruz-mcp
A local stdio MCP server for the HSE University timetable (RUZ API) that looks up people/groups/rooms and returns their class schedules — no login, but only reachable from the HSE network.
ruz_find_person— search students (default), lecturers, groups or auditoriums by substring (min 2 chars), returning up tolimit(default 20, max 100) matches withid/labelplustotalcount.ruz_get_schedule— fetch the schedule for a student, lecturer, group or auditorium by RUZid(sametype), for a date range.ruz_get_my_schedule— fetch a student's own schedule from their@edu.hse.rucorporate email.Period controls on every schedule tool:
startDate(YYYY-MM-DD, MSK, past allowed, default today) anddaysAhead(1–60, default 7).languageoption (rudefault /en) for discipline and room names.Results come back as
{ from, to, lessons }(my-schedule also includesstudent), with read-only, cached (5 min) and 15-second-timeout behavior.Requires campus Wi-Fi
HSE.Studentor staff VPN; outside the HSE network calls return an explanatory error.
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., "@hse-ruz-mcpshow my schedule for the next 7 days, my HSE email is i.petrov@edu.hse.ru"
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.
hse-ruz-mcp
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, orruz_get_my_scheduleby a student's@edu.hse.ruemail). No login needed, but RUZ only answers from inside the HSE network (campus Wi-FiHSE.Studentor 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-mcpClaude 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.jsTools
Tool | Что делает |
| Ищет студента, преподавателя, группу или аудиторию по подстроке (от 2 символов) и возвращает до |
| Возвращает расписание студента, преподавателя, группы или аудитории по RUZ id из |
| Возвращает расписание студента по корпоративному email ( |
Параметры периода у всех тулов расписания:
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.
Лицензия
Available Tools
3 toolsruz_find_personНайти в РУЗARead-onlyIdempotent
Поиск студента, преподавателя, группы или аудитории ВШЭ по подстроке (ФИО, номер группы) через API RUZ (ruz.hse.ru/api/search). ВАЖНО: RUZ отдаёт данные только из внутренней сети ВШЭ (Wi-Fi HSE.Student на кампусе или VPN сотрудника) — вне сети запрос вернёт ошибку. Возвращает до limit совпадений (id и подпись) и их общее число total — id с тем же type передаётся в ruz_get_schedule. Если total больше limit, уточните запрос.
| Name | Required | Description | Default |
|---|---|---|---|
| term | Yes | Строка поиска: часть ФИО, номер группы и т.п. | |
| type | No | student | |
| limit | No | Сколько совпадений вернуть |
Output Schema
| Name | Required | Description |
|---|---|---|
| total | Yes | Сколько пригодных совпадений (с id) нашёл RUZ, до обрезки по limit |
| results | Yes |
TDQS
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.
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.
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.
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.
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.
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Расписание студента по emailARead-onlyIdempotent
Расписание занятий студента ВШЭ по его корпоративному email (login@edu.hse.ru) на daysAhead дней начиная со startDate (по умолчанию с сегодня). Использует API RUZ, который отдаёт данные только из внутренней сети ВШЭ (Wi-Fi HSE.Student на кампусе или VPN) — вне сети запрос вернёт ошибку.
| Name | Required | Description | Default |
|---|---|---|---|
| Yes | Корпоративный email студента, напр. ivanov@edu.hse.ru | ||
| language | No | Язык названий дисциплин, аудиторий и т.п.: ru или en | ru |
| daysAhead | No | Сколько календарных дней получить, начиная со startDate (по умолчанию с сегодня) | |
| startDate | No | Первый день периода, ГГГГ-ММ-ДД по московскому времени (можно в прошлом). По умолчанию сегодня |
Output Schema
| Name | Required | Description |
|---|---|---|
| to | Yes | Последний день периода включительно, ГГГГ-ММ-ДД |
| from | Yes | Первый день периода, ГГГГ-ММ-ДД |
| lessons | Yes | |
| student | Yes | Студент из RUZ studentinfo: id, ФИО (fio) и info |
TDQS
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.
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.
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.
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.
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.
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 idARead-onlyIdempotent
Расписание студента, преподавателя, группы или аудитории ВШЭ по RUZ id (узнать id — ruz_find_person с тем же type) на daysAhead дней начиная со startDate (по умолчанию с сегодня).
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | RUZ id из ruz_find_person | |
| type | Yes | Тип объекта, как в ruz_find_person | |
| language | No | Язык названий дисциплин, аудиторий и т.п.: ru или en | ru |
| daysAhead | No | Сколько календарных дней получить, начиная со startDate (по умолчанию с сегодня) | |
| startDate | No | Первый день периода, ГГГГ-ММ-ДД по московскому времени (можно в прошлом). По умолчанию сегодня |
Output Schema
| Name | Required | Description |
|---|---|---|
| to | Yes | Последний день периода включительно, ГГГГ-ММ-ДД |
| from | Yes | Первый день периода, ГГГГ-ММ-ДД |
| lessons | Yes |
TDQS
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.
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.
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.
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.
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.
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.
4 tool updates
v0.2.3- Changed
ruz_find_person4 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / limitAdded value: +{ + "default": 20, + "description": "Сколько совпадений вернуть", + "maximum": 100, + "minimum": 1, + "type": "integer" +} - added
Input schema / properties / term / minLengthAdded value: +2 - changed
Output 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" +}
- Removed
ruz_get_group_schedule - Changed
ruz_get_my_schedule6 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Input schema / properties / daysAhead / descriptionPrevious value: -"На сколько дней вперёд от сегодня получить расписание"New value: +"Сколько календарных дней получить, начиная со startDate (по умолчанию с сегодня)" - added
Input schema / properties / email / patternAdded 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,}$" - added
Input schema / properties / languageAdded value: +{ + "default": "ru", + "description": "Язык названий дисциплин, аудиторий и т.п.: ru или en", + "enum": [ + "ru", + "en" + ], + "type": "string" +} - added
Input schema / properties / startDateAdded 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" +} - changed
Output 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" +}
- Added
ruz_get_schedule
3 tool updates
v0.1.0- First observed
ruz_find_person - First observed
ruz_get_group_schedule - First observed
ruz_get_my_schedule
TDQS
Scored across 3 tools
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.
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.
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.
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
Related MCP Connectors
Enables AI assistants to retrieve event data and execute event management operations in Nunify.
Connects AI assistants to TrackingTime for querying time entries, projects, tasks, customers, and team data using natural language.
Calendar API for AI agents: events, availability, Google/Microsoft setup, scheduling, and iCal.
Read Schedule it events, resources, groups and labels; create and update events and resources.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables 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.-
- FlicenseBqualityCmaintenanceEnables 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-
- AlicenseAqualityBmaintenanceProvides 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.22MIT
- FlicenseNot gradedqualityCmaintenanceEnables 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-