¿La API y MCP de Magica están disponibles para todos?

API Mode y MCP están en acceso anticipado y disponibles para usuarios premium. La funcionalidad sigue en desarrollo y su comportamiento puede cambiar en versiones futuras.

¿Qué es el API Mode y la integración MCP de Magica?

Magica integra un pequeño servidor HTTP que te permite leer o escribir tus datos (vehículos, viajes, repostajes, mantenimientos, estadísticas, costos) desde cualquier dispositivo en la misma Wi-Fi. El mismo servidor expone herramientas MCP (Model Context Protocol) para asistentes de IA como Claude o Codex. Todo se queda en la red local, sin nube.

Características principales:

  • Solo red local — tus datos nunca salen del telefono
  • Bajo demanda — el servidor se ejecuta solo cuando lo enciendes
  • Auto-apagado — se apaga solo despues de un periodo de inactividad configurable
  • Seguro — cada cliente se autentica con un token Bearer JWT
  • Granular — elige solo lectura o lectura y escritura por cada cliente

¿Cómo se enciende el servidor API de Magica?

Abre Magica y ve a Cuenta > API Mode, luego toca el switch en la esquina superior derecha. La URL del servidor (ej. http://192.168.1.42:8080) aparece bajo "Listening on", con un contador para el auto-apagado. El servidor solo es accesible desde la Wi-Fi local.

Los pasos:

  1. Abre Magica y ve a Cuenta > API Mode
  2. Toca el switch en la esquina superior derecha para iniciar el servidor
  3. Lee la URL mostrada bajo "Listening on" (por ejemplo http://192.168.1.42:8080)
  4. Debajo de la URL veras un contador que indica cuando el servidor se apagara si esta inactivo
ℹ️El servidor se vincula solo a tu Wi-Fi local. Nunca es accesible desde internet.

¿Cuánto tiempo permanece encendido el servidor API sin peticiones?

Puedes elegir cuánto tiempo permanece encendido el servidor sin peticiones autenticadas: 5 minutos (por defecto, polling ocasional), 10/20/30 minutos (desarrollo y depuración), 1 hora (live coding con una IA via MCP) o "Nunca" (demos, cuidado con la batería). El ajuste es persistente.

Opciones disponibles:

  • 5 minutos (por defecto) — Polling ocasional, automatizaciones tipo cron
  • 10 / 20 / 30 minutos — Sesiones de desarrollo o depuracion
  • 1 hora — Live coding con un asistente de IA via MCP
  • Nunca — Demos o resolucion de problemas prolongada (cuidado con la bateria)

¿Cómo se autoriza un nuevo cliente API con el emparejamiento?

En API Mode toca "Pair a new client": la app muestra un código de 6 dígitos con 60 segundos de cuenta atrás. Introdúcelo en el cliente (o llama a POST /auth/pair) y luego toca Approve, Read only o Reject. El token resultante es válido durante 30 días.

El flujo de emparejamiento:

  1. En API Mode toca "Pair a new client"
  2. Aparece una hoja con un codigo de 6 digitos y un contador de 60 segundos
  3. Introduce el codigo en el cliente (o llama a POST /auth/pair con el codigo)
  4. En la hoja aparece una tarjeta con los botones Approve / Read only / Reject
  5. Toca uno de los botones para conceder al cliente el acceso solicitado
💡Un token emparejado es valido durante 30 dias. Despues hay que emparejar de nuevo.

¿Cómo se genera un token API de larga duración?

En API Mode toca "Generate manual token", elige nombre, etiqueta de dispositivo, modo (lectura o lectura+escritura) y validez (de 1 día a 1 año). Magica genera el token y lo muestra una sola vez — cópialo de inmediato porque no se mostrará de nuevo.

Los pasos:

  1. En API Mode toca "Generate manual token"
  2. Elige un nombre, una etiqueta de dispositivo, el modo (lectura o lectura + escritura) y la validez (de 1 dia a 1 ano)
  3. Toca Generate
  4. Copia el token de inmediato — solo se muestra una vez
ℹ️Magica nunca guarda una copia del bearer token en claro. Si lo pierdes, revoca el viejo y genera uno nuevo.

¿Cuál es la diferencia entre tokens API de Lectura y Lectura+Escritura?

Un token de Lectura solo puede consultar vehículos, viajes, repostajes, mantenimientos, estadísticas y datos financieros. Un token Lectura+Escritura añade creación, modificación y borrado de viajes, repostajes, servicios y etiquetas. Un token Read que llama a un endpoint write recibe HTTP 403.

Los dos niveles de permiso:

  • Lectura — Puede consultar vehiculos, viajes, repostajes, mantenimientos, estadisticas y datos financieros
  • Lectura + Escritura — Lectura, mas creacion, actualizacion y borrado de viajes, repostajes, servicios y etiquetas
ℹ️Un token de solo lectura que llama a un endpoint de escritura recibe HTTP 403. Concede siempre lo minimo necesario.

¿Cómo se revoca el acceso de un cliente API?

La sección "Active sessions" en API Mode lista cada token válido con nombre, dispositivo, modo y caducidad. Para revocar un cliente, toca la X roja junto a la sesión y confirma: la revocación es inmediata y persistente, incluso después de reiniciar la app.

Los pasos:

  1. Toca la X roja junto a la sesion
  2. Confirma en el aviso
ℹ️La revocacion es inmediata y persistente — el token no puede reutilizarse ni despues de reiniciar la app.

¿Cómo se usa Magica con Claude u otros asistentes de IA mediante MCP?

Magica habla MCP, el Model Context Protocol de Anthropic. Asistentes compatibles (Claude, Codex y otros) pueden leer tus datos o registrar nuevas entradas con lenguaje natural: "¿cuánto gasté en combustible el mes pasado?", "añade un repostaje de 35 litros", "¿qué mantenimientos vencen en los próximos 30 días?".

Ejemplos de lo que puedes pedir:

  • "Cuanto gaste en combustible el mes pasado?"
  • "Anade un repostaje de 35 litros a 60,50 euros, lleno"
  • "Que mantenimientos vencen en los proximos 30 dias?"
  • "Muestrame los ultimos 5 viajes en un mapa"
💡Empareja el cliente de IA con un token de solo lectura si solo quieres que responda preguntas. Usa lectura + escritura solo si quieres que registre datos por ti.

¿Puedo acceder a mis datos de Magica desde fuera de mi red de casa?

Sí, pero el puente hacia el exterior lo construyes tú. Magica sigue siendo solo local por diseño: su servidor nunca queda expuesto a internet por sí mismo. Para alcanzarlo desde fuera usas una herramienta de terceros — una VPN como Tailscale o un túnel como Cloudflare — que lleva el tráfico hasta el teléfono cifrado. Es un escenario hazlo-tú-mismo, no soportado oficialmente.

Dos cosas que conviene saber antes de empezar:

  • El servidor corre en el iPhone, y el iPhone entra en reposo — no existe un acceso remoto siempre activo. Funciona bien por sesiones: enciende API Mode, consultas desde fuera, lo apagas. Para una sesión larga pon Auto-stop en "Nunca" (pero vigila la batería)
  • Magica habla en claro (HTTP) — así que el puente debe aportar el cifrado. Tailscale y Cloudflare lo hacen ambos. Nunca abras el puerto 8080 en el router con un simple port forwarding: expondrías tokens y datos en texto claro en internet
ℹ️Todo esto se configura fuera de Magica, con herramientas de terceros. La app no cambia: sigue exponiendo la misma dirección local — eres tú quien la hace accesible desde fuera.

¿Cómo accedo a Magica de forma remota con Tailscale?

Tailscale crea una red privada cifrada entre tus dispositivos sin tocar el router. Instálalo en el iPhone y en el ordenador desde el que te conectas, con la misma cuenta: el teléfono recibe una dirección estable (100.x.y.z) que usas en lugar de la IP local, accesible desde cualquier red, incluso en 4G/5G. Es la vía más sencilla para uso personal.

Los pasos:

  1. Instala la app Tailscale en el iPhone y en el dispositivo desde el que quieres conectarte (Mac, PC), con la misma cuenta en ambos
  2. En la app Tailscale del iPhone lee la dirección asignada, tipo 100.101.102.103
  3. Enciende API Mode en Magica como de costumbre
  4. Desde el cliente, usa esa dirección en lugar de la IP local
Desde el terminal del cliente
export MAGICA="http://100.101.102.103:8080"
curl $MAGICA/health     # funciona desde cualquier red, incluso en 4G/5G
💡Para Magica estás "en la red local" aunque estés al otro lado del mundo: todo lo demás de esta guía funciona igual, y el tráfico va cifrado por el túnel de Tailscale.

¿Cómo expongo Magica con una URL pública HTTPS?

Cloudflare Tunnel te da una dirección https:// pública, útil para conectar un Custom Connector de Claude Desktop o compartir el acceso. Necesita un ordenador siempre encendido en la misma Wi-Fi que el teléfono (un Mac o una Raspberry Pi) que haga de puente, porque cloudflared no corre en iPhone: ese ordenador reenvía las peticiones a la dirección local del iPhone.

Instala cloudflared en el ordenador-puente y arranca un túnel rápido hacia la IP local del iPhone (la lees en API Mode bajo "Listening on"):

1. Instala cloudflared (macOS)
brew install cloudflared
2. Túnel rápido hacia el iPhone (URL temporal, sin cuenta)
cloudflared tunnel --url http://192.168.1.45:8080
3. Prueba la URL pública impresa en pantalla
curl https://<nombre-aleatorio>.trycloudflare.com/health
# {"status":"ok"}
💡En remoto, mantén la higiene mínima: tokens de solo lectura cuando puedas, caducidades cortas, revoca en cuanto termines y apaga el servidor. Revisa de vez en cuando las sesiones activas para detectar accesos que no reconozcas.
ℹ️La URL trycloudflare.com es temporal y cambia en cada arranque: vale para pruebas. Para una dirección fija (p. ej. magica.tudominio.com) necesitas una cuenta gratuita de Cloudflare y un dominio, con cloudflared tunnel login / create / route dns / run. Tanto REST como MCP pasan intactos por el túnel, incluido el HTTPS que desbloquea el Custom Connector de Claude Desktop.

¿Cuáles son las garantías de seguridad de la API de Magica?

La API es solo local — tus datos nunca salen del teléfono. Cada petición requiere un Bearer JWT; cada cliente debe ser aprobado explícitamente vía emparejamiento o token manual; la revocación es inmediata y persistente; el auto-apagado por inactividad apaga el servidor cuando no se usa.

Las garantías de seguridad:

  • Solo red local — tus datos nunca salen del telefono
  • Bearer JWT obligatorio en cada peticion
  • Cada cliente debe ser aprobado explicitamente via emparejamiento o token manual
  • La revocacion es inmediata y persistente
  • El auto-apagado por inactividad apaga el servidor cuando no se usa

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..." }
          }
        }
      }
    ]
  }
}