Skip to main content
Glama

medicover-mcp

An MCP server that lets an AI agent manage appointments on Medicover's Polish patient portal (https://online24.medicover.pl/). It talks directly to the portal's private JSON API (reverse-engineered from real traffic — see NOTES.md); it does not drive a browser at runtime.

It is built for an unattended daily routine: hunt for scarce slots and optionally rebook an existing appointment to an earlier one — including for linked dependents (e.g. children).

Tools

Tool

Purpose

list_patients

The account holder + linked dependents, each with a stable patient_id (MRN).

list_appointments

A patient's planned/past appointments (read-only).

search_slots

Available slots by region + specialty (optionally doctor/clinic/language, date range, and slot-search type e.g. DiagnosticProcedure). Each slot reports its visit_type (Center/Phone/PhoneAdvice).

book_appointment

Book a slot for a patient — patient_id required.

reschedule_appointment

Move an appointment to another slot; "earlier-only" by default.

list_appointment_filters

Resolve specialty/doctor/clinic/region names → IDs from history.

list_search_filters

Clinics/doctors/languages bookable for a region + specialty.

Patient-scoped read tools default to the account holder; the write tools require an explicit patient_id so a booking can never land on the wrong person. Nothing else (messaging, records, prescriptions, payments, cancel-without-rebook) is exposed.

Related MCP server: dental-calendar-mcp

Authentication (two-phase)

Login uses SMS 2FA, which can't be in an unattended hot path, so:

  1. One-time bootstrap (interactive CLI, not a tool):

    export MEDICOVER_USERNAME=<your-MRN-or-login>
    export MEDICOVER_PASSWORD=<your-password>   # or omit to be prompted
    uv run medicover-auth login                 # prompts for the SMS code

    This completes OAuth + 2FA and saves the refresh token to a 0600 file (default ~/.config/medicover-mcp/credentials.json; override with MEDICOVER_STORE_PATH). Username/password are never stored.

  2. Unattended runtime: the MCP server loads the refresh token and silently refreshes the short-lived (~3 min) access token on every run. No password or SMS is ever needed during tool calls.

  3. On expiry/revocation: tools fail with session expired — run medicover-auth login; they never prompt for an SMS through a tool call.

Token-lifetime decision: the in-MCP request_sms_code/submit_sms_code fallback is not shipped — see the reasoning in NOTES.md.

Helpers: uv run medicover-auth status (shows whether creds exist, no secrets) and uv run medicover-auth logout (deletes them).

Setup

uv sync                 # create the venv and install
uv run medicover-auth login
uv run pytest           # run the tests (no network — HTTP is mocked)

MCP client config

Add to your MCP client (e.g. Claude Desktop claude_desktop_config.json):

{
  "mcpServers": {
    "medicover": {
      "command": "uv",
      "args": ["--directory", "/abs/path/to/medicover", "run", "medicover-mcp"],
      "env": {
        "MEDICOVER_STORE_PATH": "/home/you/.config/medicover-mcp/credentials.json"
      }
    }
  }
}

(Run medicover-auth login once on the same machine first so the credential store exists.)

Environment variables

Var

Used by

Meaning

MEDICOVER_USERNAME / MEDICOVER_PASSWORD

bootstrap only

Login credentials (else prompted).

MEDICOVER_STORE_PATH

bootstrap + server

Credential file path (default ~/.config/medicover-mcp/credentials.json).

MEDICOVER_TIMEOUT

server

HTTP timeout seconds (default 30).

Example agent flow (earlier-slot hunt for a child)

  1. list_patients → find the child's patient_id.

  2. list_appointments(patient_id=child, state="Planned") → note the appointment to improve and its appointment_id/date.

  3. list_appointment_filters(patient_id=child) → get the region id and specialty id.

  4. search_slots(patient_id=child, region_ids=[...], specialty_ids=[...], start_date="today").

  5. If an earlier slot exists: reschedule_appointment(patient_id=child, appointment_id=..., booking_string=<slot>, new_slot_date=<slot date>) (refuses unless strictly earlier).

Safety

Read-before-write on booking/reschedule (the portal validates the slot at action time); reschedule never cancels without rebooking and defaults to earlier-only; polite request pacing with backoff; tokens/credentials are never logged or returned; request/response bodies (which carry medical data) are not logged.

Disclaimer

Unofficial, built against an undocumented private API that may change without notice. Use with your own account and within Medicover's terms. Not affiliated with Medicover.

Available Tools

7 tools
book_appointmentA

Book an available slot for a specific patient.

patient_id is mandatory so a booking can never land on the wrong person's record. The portal validates the slot at booking time (read-before-write); if the slot is gone you get a clear error and nothing is booked. Returns the new appointment id on success.

Note: reporting_id defaults to empty. It's unverified whether the API requires it (the captured bookings carried one from the out-of-scope triage flow); if booking fails citing it, that's the likely cause.

Inputs: patient_id (required), booking_string (required), reporting_id. Returns: booked, clinic, doctor, message, +2 more

list_appointment_filtersA

Resolve names → IDs from a patient's own visit history.

Returns the specialties, doctors, clinics and regions seen in this patient's appointments, each as {id, name}. Use this to discover the opaque IDs that search_slots needs (e.g. the region id and a specialty id), then narrow further with list_search_filters. Read-only.

Inputs: patient_id. Returns: Reference data for building a slot search (resolve names → opaque IDs).

list_appointmentsA

List a patient's appointments (upcoming by default).

Each appointment includes an opaque appointment_id (pass it to reschedule_appointment) and a can_reschedule flag. Read-only.

Inputs: state, patient_id. Returns: result

list_patientsA

List every patient the logged-in account can act on.

Returns the account holder plus any linked dependents (e.g. children). Each entry has a stable patient_id (MRN) used by all other tools, and is_account_holder marks the logged-in user. Use these IDs — never names — for the patient-scoped tools.

Inputs: no named parameters. Returns: result

list_search_filtersA

List the clinics, doctors and languages bookable for a region + specialty selection.

Use this after picking a region and specialty to enumerate valid clinic and doctor IDs before calling search_slots. Read-only.

Inputs: region_ids (required), specialty_ids (required), doctor_ids, patient_id, +1 more. Returns: Reference data for building a slot search (resolve names → opaque IDs).

reschedule_appointmentA

Move an existing appointment to a different slot (atomic; never cancels without rebooking).

Only moves to the slot you explicitly pass. With require_earlier (default), it first confirms the new slot is strictly earlier than the current appointment and otherwise refuses — so an unattended 'earlier slot' routine can't accidentally move an appointment later. The portal re-validates the slot at reschedule time.

Inputs: patient_id (required), new_slot_date (required), appointment_id (required), booking_string (required), +1 more. Returns: status, message, new_date, old_date, +1 more

search_slotsA

Find available appointment slots for a specialty/region (optionally doctor/clinic).

Each returned slot carries a booking_string — the single-use handle you pass to book_appointment or reschedule_appointment, and a visit_type (Center | Phone | PhoneAdvice). The portal has no visit-type search filter, so to get in-person ("Center") visits, choose an in-person specialty and/or filter the returned slots by visit_type. next_search_date hints the StartTime to use to page further into the future. Re-run this immediately before booking, because a booking_string can expire. Read-only.

Inputs: region_ids (required), start_date (required), specialty_ids (required), end_date, +5 more. Returns: count, slots, next_search_date

Tool Schema Changelog

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

Loading tool schema changelog…

    TDQS

    A4.4/5.0

    Scored across 7 tools

    Disambiguation5/5

    Each tool targets a distinct action (booking, listing, searching, rescheduling) on different entities (appointments, patients, filters). There is no ambiguity between them.

    Naming Consistency5/5

    All tool names follow the consistent verb_noun pattern in snake_case (e.g., book_appointment, list_patients, search_slots). No mixing of styles or unconventional names.

    Tool Count5/5

    With 7 tools, the set is well-scoped for an appointment booking domain. Each tool has a clear role, and the count is neither too thin nor too heavy.

    Completeness4/5

    The set covers the main lifecycle: search, filter, book, list, and reschedule. However, a cancellation tool is missing, which is a minor gap for a complete appointment management workflow.

    Maintenance

    ActivityInactive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers