# MiTour MCP Runtime

Current runtime version: `0.2.9`.

This package owns the MiTour CLI, stdio MCP entry point, and closed tool
registry. It consumes the generated MiTour AI schemas and canonicalization
module rather than maintaining a mirrored command vocabulary. The currently
released product path is iPhone MiTour plus bounded file handoff; connected
CloudKit transport remains unavailable and fails closed. Tests inject bounded
in-memory adapters and never contain real tokens, personal records, or
sensitive values.

```sh
npm install
npm run check:ai-mcp
npm run test:ai-mcp
node Packages/MiTourMCPRuntime/src/cli.mjs doctor
node Packages/MiTourMCPRuntime/src/cli.mjs install-host --host claude-desktop --dry-run
node Packages/MiTourMCPRuntime/src/cli.mjs stdio
node Packages/MiTourMCPRuntime/src/cli.mjs inspect-ai-source --source /absolute/trip.mitour
node Packages/MiTourMCPRuntime/src/cli.mjs generate-ai --source /absolute/trip.mitour --proposal /absolute/proposal.json --output /absolute/change.mitourai --host codex
```

`generate-ai` is the single generator used by Codex and Claude Desktop. A
proposal contains `operation`, the generated-contract `commands` array,
optional `attachments`, `createdAt`, and `expiresAt`. The runtime derives stable
IDs, binds an exact App authority capsule for modifications, canonicalizes the
formal command envelope, and writes a stored ZIP package. Host adapters supply
provenance and installation only; they do not own a command or package schema.
The same generator is exposed to MCP hosts as `generate_mitourai_package`, so
an agent does not need to discover or invoke this CLI directly. The MCP tool
requires an explicit absolute output path and preserves the generator's
create-only/no-overwrite behavior.

For a source-free Trip create proposal only, reviewed person-reference fields
(`bookedByPersonID`, `payerPersonID`, `transferOutPersonID`,
`transferInPersonID`, `occupantPersonIDs`, `participantPersonIDs`, and
`travelerPersonIDs`) may use the exact token `"$currentUser"`. The generator
materializes it to an App-owned deterministic identity. The package does not
contain the current user's name, avatar, contact information, or document
fields; iPhone MiTour resolves the identity from its local profile while
applying the draft. Never create or patch that person with
`trip.person.upsert`. Source-backed Trip modification does not accept this
token.

Every source-free Trip command list must begin with exactly one `trip.create`.
All later upserts create new stable objects; they cannot target an object that
does not exist yet. Create people and checklist categories before commands that
reference them, use `"$currentUser"` instead of inventing an `owner`, and link
attachments only to objects already created by the same proposal. The
generator rejects graphs that cannot be applied sequentially by iPhone MiTour
instead of emitting an importable-looking package that will later roll back.
For App-derived fields, omit `timeBand`, `autoSettlementKey`, and the three
`linked*ID` Expense references. An Accommodation payer, when present, must
equal its booking person, and `guestCount` must equal the complete occupant
list. Every standalone Expense must use the Trip settlement currency; a
private Expense may reference only `"$currentUser"`. Checklist-category names
must be unique within their packing or preparation domain.

Attachment formats come from the same generated contract used by the App:
`MiTourAIAttachmentContractV2.json`. There is no separate product attachment
count cap. The complete `.mitourai` archive, each entry, and the aggregate
uncompressed payload are bounded by the generated 64 MiB budget. Attachments
may be linked to the trip, an accommodation, transport, activity, or expense;
POIs do not own attachments.

The tool surface has no raw CloudKit record/zone operation, `forceUpdate`,
formal commit, permission, invitation acceptance, or Pro entitlement API.
Attachment bytes may only enter the hash-bound draft package path. All
modifications remain previewable drafts until the user confirms them in MiTour.

The current release supports two fail-closed paths. MiTour Mac exposes a signed
local Helper that publishes a redacted snapshot and accepts review-required
drafts after the user pairs an Agent. iPhone MiTour continues to use bounded
file handoff. CloudKit Web auth remains frozen, and neither path lets the Agent
write formal App data without review:

- on Mac, enable **Settings > Data > Connect AI Agent**, generate a six-digit
  connection code, and authorize the installed runtime's `connect-agent`
  subcommand to read that code from standard input;
- after pairing, restart or reconnect the MCP server and require
  `get_icloud_login_status` to report `connected` before reading snapshots or
  submitting drafts;
- the code is short-lived and single-use. Never pass it as a command-line
  argument, store it in configuration, files, or logs, or echo it in chat;
- if the code expires or has already been consumed, ask the user to generate a
  new one in MiTour Mac;

- creating a new trip or POI needs no exported source;
- editing an existing trip requires an App-exported `.mitour`;
- editing an existing POI requires an App-exported `.mitourpoi`.

`generate-ai` binds modifications to the exact authority target and baseline
from that source. It never guesses an existing POI identity from a name,
address, or coordinates. When the signed Mac Helper is connected, its redacted,
version-anchored snapshot is the authoritative local read path; otherwise the
runtime fails closed or uses an explicit App-exported source file.

The Helper's `trips.json` snapshot schema v3 carries one bounded `people` array
and one nullable App-produced authority capsule per trip, with at most 10,000
people across the snapshot. For a non-null, valid capsule, the runtime exposes
people as `people[]` read-model entities with only `id`, display `name`,
`isSelf`, and `role`; it never admits avatars,
contact details, document identifiers, custom fields, or custom-field values.
Use `get_trip_bundle` with `sections: ["people[]"]` when a proposal needs an
existing `personID`. The formal target and baseline are copied exactly from the
capsule; the runtime never synthesizes a `snapshot-*` change tag or content
hash. Snapshot schemas v1/v2 and v3 trips with null authority remain visible as
summary-only legacy entries, without `target` or `base`, and cannot serve
`get_trip_bundle` or authorize mutation. Mixed version shapes, malformed or
mismatched authority, unknown keys, duplicate IDs, invalid UUIDs, and over-limit
values fail closed.

The public MCP tool surface intentionally does not advertise `search_poi`.
The reviewed POI service requires an external authenticated adapter that the
portable local runtime does not possess. Agents may collect POI candidates
through their ordinary reviewed web capabilities and pass the resulting
untrusted fields to `generate_mitourai_package`; MiTour still previews and
validates every field before the user can apply it. See `AGENT-GUIDE.md` for
the concise host-facing contract.
