jcs-mcp
An MCP server that exposes the Joaquim Chaves Saúde (JCS) patient portal (webapp.jcs.pt) as tools for Claude and other MCP clients.
It lets you ask Claude things like:
- "Show me my upcoming appointments"
- "What prescriptions do I have active?"
- "Download my latest exam result and summarise it"
- "List my invoices from the past 6 months"
Features
11 MCP tools covering the full JCS portal:
| Tool | Description | |------|-------------| | jcs_login(password) | Authenticate; session saved to ~/.jcs_session.json (auto-renewed) | | get_patient_info() | Name, email, patient ID | | list_timeline(rows_to_skip?, archived?) | Main health feed — exam results, appointment confirmations, documents | | list_notifications(rows_to_skip?, archived?) | Notifications and messages | | get_message(id) | Full message detail; body contains signed document URIs | | list_appointments() | Upcoming and recent appointments from the calendar | | list_prescriptions(include_expired?) | Active (and optionally expired) prescriptions | | list_invoices() | Invoices (Faturas/Recibos) from the patient profile | | get_document_content(uri) | Fetch HTML exam result content from a signed URI | | download_document(uri, filename?) | Download a PDF document, saved to ./downloads/jcs/documentos/ | | parse_prescription(file_path, model?) | Parse a prescription PDF with a local Ollama model |
Session management
Authentication uses OAuth2 Resource Owner Password Grant against the GatewayBox platform. After the first jcs_login() call the session is persisted to ~/.jcs_session.json and reloaded automatically on subsequent calls. If JCS_PASSWORD is set in .env, the server will auto-login when the session expires — no manual intervention needed.
Prescription parsing
parse_prescription extracts structured data from a downloaded prescription PDF using a local Ollama model:
{
"patient": "...",
"date": "YYYY-MM-DD",
"doctor": "...",
"specialty": "...",
"medications": [
{
"name": "...", "dci": "...", "strength": "...",
"form": "...", "quantity": "...", "posology": "...", "duration": "..."
}
],
"prescription_number": "...",
"notes": "..."
}
For image-based PDFs it falls back to vision mode automatically (use a vision-capable model like llava).
Requirements
- Python 3.10+
- uv
- A JCS account at webapp.jcs.pt
- Your device UUID and device token key (see Auth setup below)
- Ollama (optional, only needed for
parse_prescription)
Installation
git clone https://github.com/nathanfolkman/jcs-mcp.git
cd jcs-mcp
uv sync
Configuration
Copy .env.example to .env and fill in your credentials:
cp .env.example .env
# Required
JCS_PHONE_NUMBER=+351912345678
# Optional — if set, the server will auto-login when the session expires
JCS_PASSWORD=your_password
# Required for first login (see Auth setup below)
JCS_DEVICE_UUID=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
JCS_DEVICE_DTK=your_device_token_key
# Optional — where to save downloaded documents (default: ./downloads)
OUTPUT_DIR=./downloads
Auth setup
The JCS API uses a GatewayBox device registration system. Your script must present a device UUID and device token key (dtk) that are already registered with the server — unrecognised devices are rejected.
The easiest way to obtain these is from your browser session on webapp.jcs.pt:
- Open Chrome DevTools → Application → Local Storage →
https://webapp.jcs.pt - Find the key that contains your
appUuid— this is yourJCS_DEVICE_UUID - Open DevTools → Network, log in normally, and look for the
POST /api/device/tokenresponse — thedeviceTokenfield is yourJCS_DEVICE_DTK
Set both values in .env. After the first successful jcs_login() call they are also persisted to ~/.jcs_session.json.
Usage
With Claude Code
Add to your MCP settings (e.g. ~/.claude.json):
{
"mcpServers": {
"jcs-health": {
"command": "uv",
"args": ["run", "--directory", "/path/to/jcs-mcp", "python", "mcp_server.py"]
}
}
}
MCP Inspector (development)
uv run mcp dev mcp_server.py
Standalone
uv run python mcp_server.py
First-time login
If JCS_PASSWORD is not set in .env, call the login tool explicitly once:
jcs_login(password="your_password")
The session is saved and reused automatically until it expires (~24 hours).
Project structure
jcs-mcp/
├── jcs_client.py # Async HTTP client (GatewayBox OAuth2 + all API methods)
├── mcp_server.py # FastMCP server — 11 tools
├── pyproject.toml # Dependencies
└── .env # Credentials (not committed)
API notes
The JCS webapp is a single-page application built on the GatewayBox platform by Seamlink. All API endpoints were reverse-engineered from network traffic. Key facts:
- Base URL:
https://webapp.jcs.pt - Auth: OAuth2 password grant via
POST /Tokenwithuid,AppUuid, anddtkcustom headers - All data endpoints use
POSTwith a JSON body containingdevice(the appUuid) - Document URIs are signed, time-limited tokens embedded in message body HTML as
data-attach-htmlattributes - HTML exam results:
GET /api/attachdata/getcontent?uri=... - PDF documents:
GET /api/attachdata/getfile?uri=...
License
MIT











