The mental model
MCP returns to context. CLI returns to disk.When you call MCP
get_note_transcript, the entire transcript text — typically 5–50 KB per note — is injected into your conversation context window. Every subsequent turn carries that weight until compaction or summarization.
When you call tiro notes transcript --output transcript.md, the same content lands on disk. stdout returns a single metadata line:
Tool selection cheatsheet
| You need to… | Use | Notes |
|---|---|---|
| Find notes by topic | MCP search_notes | hydrated with primary documents; lives in context |
| Pull 50+ notes to disk | CLI tiro notes search "…" --json > meetings.jsonl | NDJSON pipe; trivial to slice with jq |
| Read a verbatim quote | MCP get_note_transcript | small subset only — token-heavy |
| Save a full transcript for later | CLI tiro notes transcript <guid> --output <path> | content on disk; metadata in stdout |
| Browse meetings by date | CLI tiro notes list --since 7d --json | lightweight — metadata only |
| Read MCP-shape JSON without an MCP host | CLI tiro notes transcript <guid> --format json | byte-for-byte match with MCP get_note_transcript |
When to call MCP vs CLI
Worked example — 30 days of “Acme Corp” meetings
You want to draft a client-specific quarterly summary. You need every meeting where Acme came up in the last 30 days, with full transcripts../out/ — read them with the Read tool one at a time, only when you need exact wording.
Compare to MCP-only: get_note_transcript × 12 calls would inject 60–600 KB into context (12 transcripts × 5–50 KB each). Most of that is dead weight — you only need 2–3 of the transcripts in detail.
Reading errors as JSON
Every error from the CLI follows a stable envelope:| Field | Use |
|---|---|
error.code | machine-readable identifier — branch on this |
error.errorType | coarse-grained category (unauthorized, not_found, bad_request, …) |
error.suggestion | the exact next command to run for auto-recovery |
error.httpStatus | the upstream HTTP status (when applicable) |
error.requestId | upstream x-request-id for support escalation |
error.message is human-readable and may change wording across releases — don’t pattern-match against it.
Exit codes
| Code | Meaning | Agent action |
|---|---|---|
0 | success | continue |
1 | generic error | inspect error.code |
2 | usage error (bad flag, invalid date, missing required arg) | fix the call; do not retry blindly |
4 | auth required | run tiro auth login, then retry |
64 | EX_USAGE | same as 2 |
65 | EX_DATAERR | response failed schema validation; surface to user |
78 | EX_CONFIG | no token in env or keychain; ask the user to authenticate or supply TIRO_TOKEN |
Output guarantees
--jsonis NDJSON for streams — list and search emit one JSON object per line. Pagination cursors arrive as a final{"_cursor": "…"}line.--output <path>writes atomically — temp file + rename, never partial.- TTY auto-detection — pretty in interactive shells, JSON when piped or redirected. Force either with
--pretty/--json. tiro notes transcript --format jsonmatches MCPget_note_transcript— same field names, same nesting, same speaker-segment structure. Reuse your existing parser.- Tokens are never echoed —
auth statusonly shows the first 4 chars; logs even at--verboseredact the rest.
Stable contract — what won’t break across patch releases
error.codevalueserror.errorTypevalues- Exit codes
- NDJSON line shape for list/search
- The MCP-shape JSON returned by
tiro notes transcript --format json - The metadata-line shape returned by
--outputoperations
Links
- Quickstart — five hands-on scenarios.
- Setup — install + auth + headless/CI configuration.
- CLI on npm
- tiro-cli on GitHub
- CHANGELOG