L'API e l'MCP di Magica sono già disponibili per tutti?

API Mode e MCP sono in early access e disponibili agli utenti premium. La funzionalità è ancora in fase di rifinitura e il comportamento può cambiare nelle versioni future.

Cos'è API Mode e l'integrazione MCP di Magica?

Magica integra un piccolo server HTTP che permette di leggere o scrivere i tuoi dati (veicoli, viaggi, rifornimenti, manutenzioni, statistiche, costi) da qualsiasi dispositivo sulla stessa Wi-Fi. Lo stesso server espone tool MCP (Model Context Protocol) per assistenti AI come Claude o Codex. Tutto resta in rete locale, niente cloud.

Caratteristiche principali:

  • Solo rete locale — i tuoi dati non escono mai dal telefono
  • A comando — il server gira solo quando lo accendi
  • Auto-stop — si spegne da solo dopo un periodo di inattivita configurabile
  • Sicuro — ogni client si autentica con un token Bearer JWT
  • Granulare — scegli solo lettura o lettura e scrittura per ciascun client

Come si accende il server API di Magica?

Apri Magica e vai su Account > API Mode, poi tappa il toggle in alto a destra. La URL del server (es. http://192.168.1.42:8080) appare sotto "Listening on", con un countdown per l'auto-stop. Il server è raggiungibile solo dalla Wi-Fi locale.

I passi:

  1. Apri Magica e vai su Account > API Mode
  2. Tocca il toggle in alto a destra per avviare il server
  3. Leggi la URL mostrata sotto "Listening on" (esempio http://192.168.1.42:8080)
  4. Sotto la URL trovi un countdown che indica quando il server si spegnera se inattivo
ℹ️Il server si binda solo sulla tua Wi-Fi locale. Non e mai raggiungibile da internet.

Quanto resta acceso il server API senza richieste?

Puoi scegliere quanto tempo il server resta attivo senza richieste autenticate: 5 minuti (default, per polling occasionale), 10/20/30 minuti (sviluppo e debug), 1 ora (live coding con un'AI via MCP) oppure "Mai" (demo, attenzione alla batteria). L'impostazione è persistente.

Le opzioni disponibili:

  • 5 minuti (default) — Polling occasionale, automazioni in stile cron
  • 10 / 20 / 30 minuti — Sessioni di sviluppo o debug
  • 1 ora — Live coding con un assistente AI via MCP
  • Mai — Demo o troubleshooting prolungato (attenzione alla batteria)

Come si autorizza un nuovo client API con il pairing?

In API Mode tappa "Pair a new client": l'app mostra un codice a 6 cifre con 60 secondi di countdown. Inseriscilo nel client (o chiama POST /auth/pair) e poi tappa Approve, Read only o Reject. Il token così generato è valido per 30 giorni.

Il flow di pairing:

  1. In API Mode tocca "Pair a new client"
  2. Si apre una sheet con un codice a 6 cifre e un countdown di 60 secondi
  3. Inserisci il codice nel client (oppure chiama POST /auth/pair con il codice)
  4. Nella sheet appare una card con i bottoni Approve / Read only / Reject
  5. Tocca uno dei bottoni per concedere al client l'accesso richiesto
💡Un token paired e valido 30 giorni. Dopo serve rifare il pairing.

Come si genera un token API a lunga scadenza?

In API Mode tappa "Generate manual token", scegli nome, etichetta dispositivo, mode (lettura o lettura+scrittura) e durata (da 1 giorno a 1 anno). Magica genera il token e lo mostra una sola volta — copialo subito perché non verrà più mostrato.

I passi:

  1. In API Mode tocca "Generate manual token"
  2. Scegli un nome, un'etichetta dispositivo, il mode (lettura o lettura e scrittura) e la durata (da 1 giorno a 1 anno)
  3. Tocca Generate
  4. Copia subito il token — viene mostrato una sola volta
ℹ️Magica non conserva una copia del bearer token in chiaro. Se lo perdi, revoca quello vecchio e generane uno nuovo.

Qual è la differenza tra token API in Lettura e Lettura+Scrittura?

Un token di Lettura può solo consultare veicoli, viaggi, rifornimenti, manutenzioni, statistiche e dati finanziari. Un token Lettura+Scrittura aggiunge la creazione, modifica ed eliminazione di viaggi, rifornimenti, servizi e tag. Un token Read che chiama un endpoint write riceve HTTP 403.

I due livelli di permesso:

  • Lettura — Puo consultare veicoli, viaggi, rifornimenti, manutenzioni, statistiche e dati finanziari
  • Lettura + Scrittura — Lettura, piu creazione, modifica ed eliminazione di viaggi, rifornimenti, servizi e tag
ℹ️Un token di sola lettura che chiama un endpoint write riceve HTTP 403. Concedi sempre il minimo necessario.

Come si revoca l'accesso a un client API?

La sezione "Active sessions" in API Mode mostra ogni token valido con nome, dispositivo, mode e scadenza. Per revocare un client, tappa la X rossa accanto alla sessione e conferma: la revoca è immediata e persistente, anche dopo riavvio dell'app.

I passi:

  1. Tocca la X rossa accanto alla sessione
  2. Conferma nell'alert
ℹ️La revoca e immediata e persistente — il token non e piu utilizzabile nemmeno dopo il restart dell'app.

Come si usa Magica con Claude o altri assistenti AI via MCP?

Magica parla MCP, il Model Context Protocol di Anthropic. Assistenti compatibili (Claude, Codex e altri) possono leggere i tuoi dati o registrare nuove voci con linguaggio naturale: "quanto ho speso di carburante il mese scorso?", "aggiungi un rifornimento di 35 litri", "quali manutenzioni scadono nei prossimi 30 giorni?".

Esempi di cosa puoi chiedere:

  • "Quanto ho speso di carburante il mese scorso?"
  • "Aggiungi un rifornimento di 35 litri a 60,50 euro, pieno"
  • "Quali manutenzioni scadono nei prossimi 30 giorni?"
  • "Mostrami sulla mappa gli ultimi 5 viaggi"
💡Abbina il client AI con un token di sola lettura se vuoi solo che risponda alle domande. Usa lettura e scrittura solo se vuoi che registri dati per te.

Posso accedere ai dati di Magica fuori dalla rete di casa?

Sì, ma il ponte verso l'esterno lo costruisci tu. Magica resta solo-locale di design: il suo server non è mai esposto su internet da solo. Per raggiungerlo da fuori usi uno strumento di terze parti — una VPN come Tailscale o un tunnel come Cloudflare — che porti il traffico fino al telefono in modo cifrato. È uno scenario fai-da-te, non supportato ufficialmente.

Due cose da sapere prima di iniziare:

  • Il server gira sull'iPhone, e l'iPhone va in standby — non esiste un accesso remoto sempre attivo. Funziona bene a sessioni: accendi API Mode, interroghi da fuori, spegni. Per una sessione lunga imposta Auto-stop su "Mai" (ma tieni d'occhio la batteria)
  • Magica parla in chiaro (HTTP) — quindi è il ponte a dover fornire la cifratura. Tailscale e Cloudflare lo fanno entrambi. Non aprire mai la porta 8080 sul router con un semplice port forwarding: esporresti token e dati in chiaro su internet
ℹ️Tutto questo si configura fuori da Magica, con strumenti di terze parti. L'app non cambia: continua a esporre lo stesso indirizzo locale, sei tu a renderlo raggiungibile da fuori.

Come accedo a Magica da remoto con Tailscale?

Tailscale crea una rete privata cifrata tra i tuoi dispositivi senza toccare il router. Installalo su iPhone e sul computer da cui ti colleghi, con lo stesso account: il telefono riceve un indirizzo stabile (100.x.y.z) che usi al posto dell'IP locale, raggiungibile da qualsiasi rete, anche in 4G/5G. È la via più semplice per uso personale.

I passi:

  1. Installa l'app Tailscale sull'iPhone e sul dispositivo da cui vuoi collegarti (Mac, PC), accedendo con lo stesso account su entrambi
  2. Nell'app Tailscale sull'iPhone leggi l'indirizzo assegnato, tipo 100.101.102.103
  3. Accendi API Mode in Magica come al solito
  4. Dal client, usa quell'indirizzo al posto dell'IP locale
Dal terminale del client
export MAGICA="http://100.101.102.103:8080"
curl $MAGICA/health     # funziona da qualsiasi rete, anche in 4G/5G
💡Per Magica sei "in rete locale" anche se sei dall'altra parte del mondo: tutto il resto della guida funziona identico, e il traffico è cifrato dal tunnel di Tailscale.

Come espongo Magica con un URL pubblico HTTPS?

Cloudflare Tunnel ti dà un indirizzo https:// pubblico, utile per collegare un Custom Connector di Claude Desktop o condividere l'accesso. Richiede un computer sempre acceso sulla stessa Wi-Fi del telefono (un Mac o un Raspberry Pi) che faccia da ponte, perché cloudflared non gira su iPhone: quel computer inoltra le richieste all'indirizzo locale dell'iPhone.

Installa cloudflared sul computer-ponte e avvia un tunnel veloce verso l'IP locale dell'iPhone (lo leggi in API Mode sotto "Listening on"):

1. Installa cloudflared (macOS)
brew install cloudflared
2. Tunnel veloce verso l'iPhone (URL provvisorio, nessun account)
cloudflared tunnel --url http://192.168.1.45:8080
3. Prova l'URL pubblico stampato a schermo
curl https://<nome-casuale>.trycloudflare.com/health
# {"status":"ok"}
💡Da remoto tieni l'igiene minima: token di sola lettura quando puoi, scadenze brevi, revoca appena finito e spegni il server. Controlla ogni tanto le sessioni attive per accorgerti di accessi che non riconosci.
ℹ️L'URL trycloudflare.com è provvisorio e cambia a ogni avvio: va benissimo per le prove. Per un indirizzo fisso (es. magica.tuodominio.com) serve un account Cloudflare gratuito e un dominio, con cloudflared tunnel login / create / route dns / run. Sia REST sia MCP passano interi attraverso il tunnel, incluso l'HTTPS che sblocca il Custom Connector di Claude Desktop.

Quali sono le garanzie di sicurezza dell'API di Magica?

L'API è solo locale — i dati non escono mai dal telefono. Ogni richiesta richiede un Bearer JWT; ogni client deve essere approvato esplicitamente via pairing o token manuale; la revoca è immediata e persistente; l'auto-stop spegne il server quando non viene usato.

Le garanzie di sicurezza:

  • Solo rete locale — i tuoi dati non escono mai dal telefono
  • Bearer JWT obbligatorio su ogni richiesta
  • Ogni client deve essere approvato esplicitamente via pairing o token manuale
  • La revoca e immediata e persistente
  • L'auto-stop spegne il server in automatico quando non viene usato

Developer reference — REST & MCP

The rest of this page is a self-contained technical reference for integrating Magica into external systems (scripts, dashboards, CRMs, AI assistants). Magica embeds an HTTP server in the iOS app that exposes your vehicle data as a REST API and, over the same process, an MCP (Model Context Protocol) server. This reference is written in English regardless of the page language.

  • Base URL — http://<iphone-ip>:8080, shown under "Listening on" in API Mode (e.g. http://192.168.1.42:8080)
  • Base path — every REST route lives under /api/v1; the MCP endpoint is /api/v1/mcp
  • Encoding — JSON request/response, snake_case keys, dates as ISO 8601 in UTC
  • Authentication — every /api/v1 route requires the header Authorization: Bearer <jwt>
  • Transport — LAN-only, plain HTTP (no TLS), never exposed to the internet
Health check — no auth required
$ curl http://192.168.1.42:8080/health
{"status":"ok"}
ℹ️The server is offline-first and runs on the device. It auto-stops after an idle period (default 5 minutes, configurable up to 1 hour or Never in API Mode). Reinstalling Magica rotates the signing key and invalidates every previously issued token.

Authentication & authorization

Every route under /api/v1 requires a JWT bearer token. There are two ways to obtain one: interactive pairing (a 6-digit code shown in the app; yields a 30-day token) or a manual token generated in API Mode (duration 1 day to 1 year). Tokens are scoped to a mode chosen at issue time.

ModeAllowed
readAll GET routes (vehicles, trips, refills, services, stats, finance) + MCP read tools
readwriteread + POST/PATCH/DELETE on trips, refills, services and tags + MCP write tools
Interactive pairing — request a token (POST /auth/pair)
curl -X POST http://192.168.1.42:8080/auth/pair \
  -H "Content-Type: application/json" \
  -d '{
    "code": "932103",
    "client_id": "my.script",
    "client_name": "Backup Script",
    "device_label": "MacBook",
    "requested_mode": "read"
  }'

# 200 OK
{"pairing_id":"pair_xxx","status":"pending_approval","expires_in":58}
Poll for approval (GET /auth/pair/{pairing_id})
curl http://192.168.1.42:8080/auth/pair/pair_xxx

# 202 -> still pending      403 -> rejected      408 -> code expired (60s)
# 200 -> approved:
{"access_token":"eyJhbGciOiJI...","mode":"read","expires_in":2592000}
401 — missing / expired / revoked token (RFC 7807)
{
  "type": "about:blank",
  "title": "Authentication required",
  "status": 401,
  "detail": "Token has expired"
}
ℹ️A read token calling a write route returns HTTP 403. Paired tokens last 30 days; manual tokens last for the chosen duration. Revoking a session in API Mode invalidates its token immediately and permanently (a persistent blocklist that survives app restarts).

Vehicles

Query params: updated_since=<ISO8601> returns only vehicles changed after the given instant.

MethodPathModeDescription
GET/vehiclesreadList vehicles + metadata (brand, model, fuel, odometer, tank capacity)
GET /api/v1/vehicles
curl -H "Authorization: Bearer $TOKEN" \
  http://192.168.1.42:8080/api/v1/vehicles

{
  "items": [
    {
      "id": "veh_9462755a",
      "brand": "Nissan",
      "model": "Juke N-Connecta Hybrid",
      "fuel_type": "hybrid",
      "current_odometer": {"value": 10950.33, "unit": "km"},
      "fuel_capacity": {"value": 46, "unit": "L"}
    }
  ]
}
ℹ️Take the id (e.g. veh_9462755a) and reuse it as {id} in all per-vehicle routes below.

Trips

List query params: from, to, tag (repeatable, AND), analysis_state, min_distance_km, max_distance_km, updated_since, cursor, limit (1–200, default 50). Route params: cursor, limit (max 2000, default 500), simplify=<meters> for server-side Douglas–Peucker simplification.

MethodPathModeDescription
GET/vehicles/{id}/tripsreadList trips
GET/vehicles/{id}/trips/{trip_id}readTrip detail
GET/vehicles/{id}/trips/{trip_id}/routereadTrip GPS points
POST/vehicles/{id}/tripsreadwriteCreate a manual trip
PATCH/vehicles/{id}/trips/{trip_id}readwriteUpdate safe fields
DELETE/vehicles/{id}/trips/{trip_id}readwriteDelete a trip
POST /vehicles/{id}/trips — ManualTripInput
{
  "started_at": "2026-05-20T08:00:00Z",
  "start_location": {"latitude": 43.7228, "longitude": 10.4017, "label": "Home"},
  "end_location": {"latitude": 43.7711, "longitude": 11.2486, "label": "Florence office"},
  "odometer": {"value": 11020, "unit": "km"},
  "notes": "Client visit",
  "tags": ["work"]
}
PATCH /vehicles/{id}/trips/{trip_id} — editable fields (flat)
{
  "notes": "New note",
  "tags": ["work", "business-trip"],
  "toll_cost": 12.50,
  "parking_cost": 5.00,
  "driving_score": 87
}
ℹ️POST /trips only works when {id} is the app's active vehicle; other vehicles return HTTP 503. PATCH updates only safe fields (notes, tags, toll_cost, parking_cost, driving_score) — distance, speed and route are GPS-derived and immutable.

Refills

type is full or partial; a partial requires parent_refill_id (an existing full). amount.unit is "L" for liquid fuels or "kWh" for electric. cost.currency must match the vehicle base currency (EUR on iOS in v1). PATCH accepts a flat shape: amount_value, cost_value, notes, tags, is_excluded_from_stats, is_primary_fuel.

MethodPathModeDescription
GET/vehicles/{id}/refillsreadList refills
GET/vehicles/{id}/refills/{refill_id}readRefill detail
POST/vehicles/{id}/refillsreadwriteCreate a refill
PATCH/vehicles/{id}/refills/{refill_id}readwriteUpdate a refill
DELETE/vehicles/{id}/refills/{refill_id}readwriteDelete (cascade on partial children of a full)
POST /vehicles/{id}/refills
{
  "date": "2026-05-20T08:30:00Z",
  "type": "full",
  "amount": {"value": 35, "unit": "L"},
  "cost": {"value": 60.50, "currency": "EUR"},
  "odometer": {"value": 11020, "unit": "km"},
  "fuel_type": "gasoline",
  "is_excluded_from_stats": false,
  "notes": "Q8 motorway",
  "tags": ["motorway"]
}
ℹ️DELETE on a full refill cascades to its partial children. A refill created without a location is marked source: "manual"; with a location, "gps".

Services, deadlines & maintenance

List filters: category (cost | maintenance | extraordinary_maintenance, repeatable AND), done, from, to, has_expiration, cursor, limit. Deadlines params: within_days (default 30), include_expired (default true), urgency (low | medium | high | critical, repeatable).

  • category — cost | maintenance | extraordinary_maintenance
  • subtype — oil_change, tires_replacement, insurance, tax, revision, regular_check, traffic_fine, air_filter, cabin_air_filter, oil_filter, fuel_filter, brake_pads, coolant, battery, timing_belt, wheel_alignment, or other (with subtype_custom for iOS-only categories)
  • expiration.type — none | distance_single | distance_recursive | date_single | date_recursive_day | date_recursive_week | date_recursive_month | date_recursive_year
MethodPathModeDescription
GET/vehicles/{id}/servicesreadList events
GET/vehicles/{id}/services/{service_id}readEvent detail
GET/vehicles/{id}/deadlinesreadDeadlines (future projection + overdue)
POST/vehicles/{id}/servicesreadwriteCreate an event
PATCH/vehicles/{id}/services/{service_id}readwriteUpdate an event
DELETE/vehicles/{id}/services/{service_id}readwriteDelete an event
POST/vehicles/{id}/services/{service_id}/completereadwriteMark done + advance recurring deadline
POST /vehicles/{id}/services
{
  "name": "Road tax 2026",
  "category": "cost",
  "subtype": "tax",
  "cost": {"value": 120, "currency": "EUR"},
  "done": false,
  "expiration": {
    "enabled": true,
    "type": "date_recursive_year",
    "next_date": "2026-09-13T00:00:00Z"
  },
  "notes": "Annual road tax"
}
POST /vehicles/{id}/services/{service_id}/complete
{
  "execution_date": "2026-09-12T15:00:00Z",
  "execution_odometer": {"value": 12500, "unit": "km"},
  "cost": {"value": 120, "currency": "EUR"},
  "notes": "Paid at the office"
}
ℹ️complete advances expiration.next_date by one unit only for date_recursive_* / distance_recursive; for *_single types it only sets done=true. /deadlines hides done date_single records (they are history) and returns only events that still need attention.

Tags

  • color — red | blue | green | yellow | orange | purple
  • days_of_week — ISO weekday (1 = Monday … 7 = Sunday)
  • auto_apply — every property is optional; together they form an AND condition
MethodPathModeDescription
GET/vehicles/{id}/tagsreadList tags
GET/vehicles/{id}/tags/{tag_id}readDetail + auto-apply rules + usage
POST/vehicles/{id}/tagsreadwriteCreate a tag
PATCH/vehicles/{id}/tags/{tag_id}readwriteUpdate a tag
DELETE/vehicles/{id}/tags/{tag_id}readwriteDelete (auto-cleared on trips/refills/services)
POST /vehicles/{id}/tags
{
  "title": "Work",
  "color": "blue",
  "auto_apply": {
    "enabled": true,
    "days_of_week": [1, 2, 3, 4, 5],
    "time_range": {"start": "08:00", "end": "19:00"},
    "location": {
      "center": {"latitude": 43.77, "longitude": 11.25},
      "radius_meters": 500
    }
  }
}

Statistics & finance

Choose the period one way at a time: ?period=<key> where key is current_month, current_year, previous_month, previous_year, YYYY-MM, YYYY-Q1…YYYY-Q4, YYYY, last_30d, last_90d, last_365d or all. Alternatively pass an explicit range ?from=<ISO8601>&to=<ISO8601> (wins over period).

MethodPathModeDescription
GET/vehicles/{id}/stats/summaryreadDistance, trips, fuel consumed, CO₂, avg/max speed, driving score
GET/vehicles/{id}/finance/summaryreadTotal spend + 4-category breakdown (fuel/services/tolls/parking) + cost_per_km
GET/vehicles/{id}/finance/breakdownreadDetailed 8-category breakdown (sorted DESC)
GET stats summary for April 2026
curl -H "Authorization: Bearer $TOKEN" \
  "http://192.168.1.42:8080/api/v1/vehicles/$VEH/stats/summary?period=2026-04"

Error model (RFC 7807)

All error responses use Content-Type: application/problem+json with a consistent shape.

StatusWhen
400Malformed body or query (e.g. negative cost.value, type=partial without parent_refill_id)
401Missing / expired / wrongly signed / revoked token
403Valid token but insufficient scope (read token on a write route)
404Resource not found, or scoped to the wrong vehicle
503App in a state that cannot serve the request (e.g. POST /trips on a non-active vehicle)
Example — 400 Invalid request
{
  "type": "about:blank",
  "title": "Invalid request",
  "status": 400,
  "detail": "`amount.value` must be > 0"
}

MCP transport (Streamable HTTP)

The MCP server speaks JSON-RPC 2.0 over POST /api/v1/mcp and implements the MCP Streamable HTTP spec. It uses the same JWT as REST. Supported protocol versions (preferred → oldest): 2025-06-18 (default), 2025-03-26, 2024-11-05 — the server echoes the client's requested version when supported, otherwise falls back to the default. JSON-RPC errors return HTTP 200 with an error envelope; only transport/parse errors return HTTP 400.

  • Mcp-Session-Id — minted on initialize (response header) and echoed by the client on later requests; absent → accepted (curl/script friendly), present-but-unknown → HTTP 404 (signal to re-initialize)
  • OPTIONS /api/v1/mcp — CORS preflight, public (no auth), returns 204 + Access-Control-Allow-Origin: *
  • DELETE /api/v1/mcp — terminates the session (auth required, 204)
  • GET /api/v1/mcp — returns 405 (no server-initiated SSE stream in v1)
  • Notifications (no id field, e.g. notifications/initialized) — return HTTP 202 with an empty body
  • JSON-RPC error codes — -32602 invalid params, -32001 unauthorized, -32003 forbidden, -32004 resource not found, -32603 internal error

Verify the MCP handshake

Before configuring a client, confirm the full handshake works end to end:

OPTIONS → initialize → tools/list
# 1. CORS preflight (what a browser-based client does first)
curl -i -X OPTIONS http://192.168.1.42:8080/api/v1/mcp \
  -H "Origin: https://claude.ai" \
  -H "Access-Control-Request-Method: POST"
# -> HTTP/1.1 204 No Content + Access-Control-Allow-Origin: *

# 2. initialize — opens the session, returns an Mcp-Session-Id header
curl -i -X POST http://192.168.1.42:8080/api/v1/mcp \
  -H "Authorization: Bearer eyJ..." -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"1"}}}'
# -> 200 OK + Mcp-Session-Id: <uuid> + JSON with serverInfo.name="Magica"

# 3. tools/list — verify the 11 tools
curl -X POST http://192.168.1.42:8080/api/v1/mcp \
  -H "Authorization: Bearer eyJ..." -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'
ℹ️HTTP 401 → check the token. If OPTIONS returns 404, the installed app predates the Streamable HTTP conformance build — update Magica.

MCP tool catalog (11 tools)

8 read tools + 3 write tools. Write tools require a readwrite token and are declared destructive=false, idempotent=false. Tool names are semantic snake_case (not REST mirrors); currency on write tools is implicit (EUR on iOS).

ToolModeDescription
list_vehiclesreadList configured vehicles — call first to discover ids
get_vehicle_healthreadDaily-checkup snapshot: odometer, current month, top deadlines, overdue count
get_monthly_summaryreadMonthly summary + delta vs previous month
get_fuel_analysisreadRefill stats: min/max/avg unit cost, real vs official consumption
get_expenses_breakdownreadDetailed expenses by category, sorted by amount
find_tripsreadSearch trips by address/notes/tags (max 1000 scanned)
get_upcoming_deadlinesreadDeadlines projected forward (default 30 days)
compare_periodsreadA/B comparison with percentage delta
log_refillreadwriteRecord a refill (liters or kWh)
log_servicereadwriteRecord a service / maintenance / cost
update_trip_notesreadwriteUpdate a trip's notes and tags
Tool signatures (? = optional)
list_vehicles()
get_vehicle_health(vehicle)
get_monthly_summary(vehicle, month?)
get_fuel_analysis(vehicle, period?)
get_expenses_breakdown(vehicle, period?)
find_trips(vehicle, query, period?, limit?)
get_upcoming_deadlines(vehicle, days_ahead?, urgency?, include_expired?)
compare_periods(vehicle, period_a, period_b, metric?)

# readwrite
log_refill(vehicle, amount_liters|amount_kwh, total_cost, date?, type?,
           odometer_km?, notes?, tags?, parent_refill_id?)
log_service(vehicle, name, category, cost, subtype?, done?,
            execution_date?, notes?, tags?, expiration?)
update_trip_notes(vehicle, trip_id, notes?, tags?)

MCP resources (3)

Resources are static snapshots the assistant can read without a tool call. resources/list fans out per vehicle: N vehicles → 1 + 2N URIs. All require read mode.

URIContents
magica://vehiclesCompact vehicle list (same payload as list_vehicles)
magica://vehicles/{vehicle_id}/stats/current-monthMonth-to-date: km, trips, fuel cost, total cost, CO₂
magica://vehicles/{vehicle_id}/deadlines/upcomingTop 5 deadlines within 60 days + overdue count

Configure Claude Desktop

Claude Desktop talks MCP only over stdio, so a LAN HTTP server like Magica needs a stdio→HTTP bridge — the Custom Connector UI rejects http:// URLs (it requires HTTPS). Edit the config file at ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows), then fully restart Claude (⌘Q).

Variant A (recommended) — mcp-remote (npm, needs Node)
{
  "mcpServers": {
    "magica": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "http://192.168.1.42:8080/api/v1/mcp",
        "--allow-http",
        "--header",
        "Authorization: Bearer eyJhbGciOiJI..."
      ]
    }
  }
}
Variant B — mcp-proxy (Python: pipx install mcp-proxy)
{
  "mcpServers": {
    "magica": {
      "command": "mcp-proxy",
      "args": [
        "--transport=streamablehttp",
        "http://192.168.1.42:8080/api/v1/mcp"
      ],
      "env": {
        "API_ACCESS_TOKEN": "eyJhbGciOiJI..."
      }
    }
  }
}
ℹ️The --allow-http flag is mandatory: mcp-remote refuses non-HTTPS non-localhost URLs without it. If you see an OAuth 404 / "Unexpected end of JSON input" error, the bearer is almost always expired or signed with an old key (reinstalling Magica rotates the HMAC key) — regenerate a manual token and restart Claude.

Configure Codex, Cursor, Continue & generic clients

Clients with native Streamable HTTP support connect directly with a URL + Authorization header. If your client version only supports stdio, reuse the mcp-remote / mcp-proxy bridge shown for Claude Desktop.

  • URL — http://<iphone-ip>:8080/api/v1/mcp
  • Required headers — Authorization: Bearer <token>, Content-Type: application/json
  • Optional headers — Mcp-Session-Id (echo the value returned by initialize), Accept: application/json, text/event-stream
  • Least privilege — issue a separate manual token per client; use a read token for query-only assistants
Codex CLI — ~/.codex/config.json
{
  "mcpServers": {
    "magica": {
      "url": "http://192.168.1.42:8080/api/v1/mcp",
      "headers": { "Authorization": "Bearer eyJhbGciOiJI..." }
    }
  }
}
Cursor (≥ 0.40) — ~/.cursor/mcp.json
{
  "mcpServers": {
    "magica": {
      "url": "http://192.168.1.42:8080/api/v1/mcp",
      "headers": { "Authorization": "Bearer eyJhbGciOiJI..." }
    }
  }
}
Continue (VS Code) — ~/.continue/config.json
{
  "experimental": {
    "modelContextProtocolServers": [
      {
        "transport": {
          "type": "streamable-http",
          "url": "http://192.168.1.42:8080/api/v1/mcp",
          "requestOptions": {
            "headers": { "Authorization": "Bearer eyJhbGciOiJI..." }
          }
        }
      }
    ]
  }
}