tourclaim (Python CLI, SDK and MCP server)
Python SDK and command-line client for TourClaim by Copernican. Give your app, assistant, or terminal a travel-claim workflow: save a traveler’s answers, collect the evidence they choose to share, hand them the authorization to sign, and follow their claim. Works with any assistant that can run shell commands or call the API; no enrolled tour operator or booking-platform integration is required.
Review mode. The TourClaim connector API currently runs in review mode: it creates synthetic claims and files nothing with an insurer. Use fictional booking and medical data only.
tourclaim status(orClient().connector_info()["mode"]) shows the current mode, and every draft and claim the API returns says which mode it came from.
This is the Python edition of tourclaim. It has the same commands, flags, output, exit codes and credentials file as the Node edition (npx tourclaim), so a key saved by one works in the other. It adds a typed library, tourclaim.Client, and an optional MCP server.
For developers, agents, and platforms
TourClaim’s service reviews credit-card travel benefits, organizes receipts and cancellation evidence, coordinates medical-provider evaluation when needed, and handles claim preparation, filing, and follow-up. A traveler can bring a flight, hotel, or tour booking directly. Coverage, reimbursement, and clinical documentation depend on the relevant benefit administrator or provider.
The package exposes saved intake, selected email and file evidence, traveler authorization, submission to Copernican, and status. The API and both CLI editions currently use synthetic review mode: no insurer filing, payment, or clinical service is triggered. To start a real claim today, the traveler uses the online claim form, where they supply their documents and payment details securely.
- Terminal agents: use either CLI with
--json; the traveler approves sign-in and signs in their own browser. - Python applications: use
tourclaim.Clientfrom the Python edition. - Platforms and tool-calling assistants: use the developer guide and OpenAPI schema.
Muse is one integration of these capabilities and is under review; it is not required to use this package. Existing /muse URLs and key formats are compatibility details and continue to work. Each connection acts for one traveler, not an operator or a platform-wide account.
What it does
- Sign in. The traveler opens the sign-in page in their own browser, types the code shown in the terminal, and approves. The tool saves a key that belongs to that traveler.
- Start a draft with whatever the traveler has said, then answer the questions the API says are still open.
- Add evidence the traveler chooses to share: receipts, itineraries, a doctor's note they already have, and booking or cancellation emails.
- The traveler signs. They review the draft and sign an authorization in their own browser. This package cannot sign for them.
- Submit the signed draft, then check the claim's status.
Nothing here decides whether a loss is covered, or promises reimbursement or a medical note. Copernican charges a 10% fee only when a claim is reimbursed; no payment is taken through this package. Only bookings charged in US dollars are supported.
AI agents: read AGENTS.md before driving the command line. The rules there apply to the library too.
Install
The CLI and SDK require Python 3.9 or newer and have no runtime dependencies. The optional MCP extra requires Python 3.10 or newer and installs the MCP SDK.
pip install tourclaim
or run it without installing, or install it as an isolated command:
uvx tourclaim --help
pipx install tourclaim
python -m tourclaim works too.
MCP server for AI assistants
With uv installed, add this to an MCP client's configuration (Claude Desktop, Cursor, and clients using mcpServers):
{
"mcpServers": {
"tourclaim": {
"command": "uvx",
"args": ["--python", "3.12", "--from", "tourclaim[mcp]==0.2.0", "tourclaim", "mcp"]
}
}
}
Or install pip install 'tourclaim[mcp]==0.2.0' in a Python 3.10+ environment and configure that environment's tourclaim executable with args: ["mcp"]. MCP uses stdio; it waits for a client, and does not print a welcome message to stdout. The server exposes 17 tools with input schemas and read/write annotations. No API key is required to start: the assistant can begin a browser sign-in at the traveler's request. The credential stays in the local credentials store and is never returned to the model.
The current service is in review mode. Use fictional data only. The traveler must approve evidence sharing and sign the authorization in their own browser. See MCP.md for the tool list, VS Code and GitHub configurations, troubleshooting, and transport limitations.
Command line quickstart
# 1. Connect to the traveler's account. Opens a page; the traveler enters the code shown.
tourclaim login
# 2. Find the card the booking was paid with (by product name, never a card number).
tourclaim cards search sapphire
# 3. Start a draft with what the traveler has said so far (check `tourclaim intake list` first).
tourclaim intake start --set merchant_name="Example Air" --set booking_ref=EXA-482913 \
--set reason_category=airline_cancellation
# 4. Answer what is missing. The draft id comes from step 3.
tourclaim intake set <id> trip_date=2026-03-04 booking_amount=250.00 refunded_amount=50.00 \
currency=USD card_product_id=412 other_insurance=no \
narrative="Example Air cancelled flight EX 204 the night before departure."
# 5. Add the evidence the traveler agreed to share.
tourclaim intake attach <id> receipt.pdf --type receipt
tourclaim intake add-email <id> --eml cancellation.eml
# 6. The traveler reviews and signs in their browser. --wait returns once they have.
tourclaim intake sign <id> --wait
# 7. Submit, then follow the claim.
tourclaim intake submit <id>
tourclaim claims list
Every ordinary CLI command takes --json (one JSON value per line on stdout, errors as one JSON line on stderr), --api-url <url>, -h/--help and --version. The full command reference, the field table and the JSON output contract are in the main README; they apply unchanged.
| Command | What it does |
|---|---|
tourclaim login |
Sign in: the traveler opens the sign-in page and types the code shown in the terminal (--no-browser, --scope, --force). Or --with-token to save an existing key read from stdin or a hidden prompt; such a key does not say whose account it is. |
tourclaim logout |
Revoke the key on the server and remove the stored copy. |
tourclaim status (whoami) |
The API mode, whether the connector is enabled, the signed-in account and key expiry. |
tourclaim cards search <name> |
Find a card product id. |
tourclaim intake start|list|show|set|attach|add-email|sign|submit|delete |
The whole draft lifecycle. |
tourclaim claims list|show |
Submitted claims and their status. |
tourclaim mcp |
Optional MCP stdio server; install the mcp extra. It uses the MCP protocol, not the CLI JSON format. |
tourclaim schema |
The live OpenAPI document with every operation the CLI uses (openapi-cli.json; openapi.json on older servers). |
Exit codes
| Code | Meaning |
|---|---|
| 0 | Success. |
| 1 | Error: invalid values (422), unreadable or unsupported file, network failure, timeout, declined prompt. |
| 2 | Usage: bad flags or arguments, or a confirmation was needed and there was no terminal. |
| 3 | Not signed in, or the key was rejected (401) or lacks permission (403). Also a declined or expired sign-in. |
| 4 | Conflict (409). The JSON error code names the cause: stale_revision, approval_required, approval_outdated, intake_incomplete, intake_submitted, duplicate_booking, evidence_conflict, idempotency_key_reused, idempotency_key_other_connection or concurrent_request. |
| 5 | Rate limited (429) after one automatic retry. |
| 6 | Not found (404). |
| 7 | The connector is disabled or unavailable (503). |
Library quickstart
from tourclaim import Client
# Uses TOURCLAIM_API_KEY, else the key `tourclaim login` saved. Or pass api_key=...
client = Client()
if not client.has_api_key:
# The traveler opens the page and types the code in their own browser; never put
# the code in a link. save=True stores the key where `tourclaim login` keeps it.
client.device_login(
on_code=lambda code: print(f"Open {code['verification_uri']}\nEnter this code on that page: {code['user_code']}"),
save=True,
)
# account_email is present only for keys from `tourclaim login` (device_login).
print(client.get_connection().get("account_email"), client.connector_info()["mode"])
drafts = client.list_drafts() # offer to continue one before starting another
draft = client.start_intake({"merchant_name": "Example Air", "reason_category": "AIRLINE_CANCELLATION"})
print(draft["missing_fields"], draft["next_questions"])
draft = client.update_intake(
draft["id"],
{
"booking_ref": "EXA-482913",
"trip_date": "2026-03-04",
"booking_amount": "250.00",
"refunded_amount": "50.00",
"currency": "USD",
"card_product_id": client.search_cards("sapphire preferred")[0]["id"],
"narrative": "Example Air cancelled flight EX 204 the night before departure.",
"other_insurance": "NO",
},
expected_revision=draft["revision"],
)
# Only after the traveler agreed to share this exact file:
with open("receipt.pdf", "rb") as f:
draft = client.add_attachment(
draft["id"], expected_revision=draft["revision"], filename="receipt.pdf",
content=f.read(), doc_type="receipt", user_authorized_sharing=True,
)
# The traveler signs at draft["review_url"] in their own browser.
print("Review and sign:", draft["review_url"])
signed = client.wait_for_signature(draft["id"], timeout=900)
claim = client.submit(draft["id"], expected_revision=signed["revision"])
print(claim["status"], claim["next_action"])
Client(api_key=None, api_url=None) has one method per API operation:
| Method | Operation |
|---|---|
connector_info(), schema() |
Discovery and the OpenAPI document (no key needed). |
get_connection(), disconnect() |
get_connection, disconnect: the key's account, expiry and scopes; revoke it. |
search_cards(query) |
search_credit_cards |
start_intake(fields=None, *, idempotency_key=None) |
start_travel_claim |
list_drafts(offset=0) |
list_claim_drafts |
get_intake(id), update_intake(id, fields, *, expected_revision), delete_draft(id) |
Read, change and delete a draft. |
add_email(id, *, expected_revision, subject, sender, text, user_authorized_sharing, ...) |
import_selected_email |
add_attachment(id, *, expected_revision, filename, content, doc_type, user_authorized_sharing) |
import_claim_attachment |
submit(id, *, expected_revision) |
submit_authorized_travel_claim (safe to retry) |
list_claims(offset=0), get_claim(id) |
list_my_claims, get_my_claim_status |
device_login(scopes=None, *, on_code=None, save=False) |
Sign in with a device code (also request_device_code, poll_device_token, wait_for_device_token). |
wait_for_signature(id, *, timeout=900) |
Poll until the traveler has signed. |
Responses are plain dict objects described by typed dictionaries (IntakeResponse, ClaimResponse, CardResponse, KeyInfo, ...). After each call, client.mode holds the API's mode (review or live).
Errors
Every exception derives from tourclaim.TourClaimError and carries message, code (stable, machine-readable), status (the HTTP status, or None), exit_code (what the command line would exit with) and extra. API errors (APIError) also carry detail and headers.
| Exception | When |
|---|---|
AuthenticationError (401), PermissionDeniedError (403), NotSignedInError |
The key is missing, expired, revoked or lacks the permission. |
NotFoundError (404) |
No such draft or claim for this key. |
ConflictError (409) |
code is the API's cause from X-TourClaim-Error, such as stale_revision or approval_required. |
ValidationError (422) |
detail lists each invalid field as {loc, type, msg}, or explains in a sentence. |
RateLimitError (429) |
retry_after seconds. The client retries once by itself when that is at most 60. |
UnavailableError (503) |
The connector is disabled or temporarily unavailable. |
NetworkError, RequestTimeoutError |
The API could not be reached, or did not answer in 90 seconds. |
AccessDeniedError, ExpiredTokenError |
The traveler declined the sign-in, or its code expired. |
ConsentRequiredError, UnsupportedFileError, FileTooLargeError, UsageError |
Checked before anything is sent. |
Configuration
| Variable | Meaning |
|---|---|
TOURCLAIM_API_URL |
API base URL (default https://app.getcopernican.com). --api-url overrides it. Plain http:// is accepted only for localhost. |
TOURCLAIM_API_KEY |
A key to use instead of the stored one. It takes precedence over the stored key. |
XDG_CONFIG_HOME |
Credentials are stored in $XDG_CONFIG_HOME/tourclaim/credentials.json (default ~/.config/tourclaim/credentials.json; %APPDATA%\tourclaim\credentials.json on Windows). |
The credentials file maps each API base URL to {"api_key","expires_at","grant_id","scopes"} and is shared with the Node edition.
Security
- Keys belong to one traveler. A key lasts 30 days and cannot be refreshed; a traveler can have at most 5 connections, and a new
tourclaim loginpast that retires the account's oldesttourclaim loginkey (never another app's). Keys fromtourclaim loginreach the drafts started by anytourclaim loginon the same account, so signing in again does not lose a draft. The traveler can revoke keys athttps://app.getcopernican.com/connect/muse, andtourclaim logoutrevokes the one in use. - Stored with tight permissions. The credentials file is written with mode 0600 inside a 0700 directory, and the tool warns if it is readable by others. On Windows it lives in your user profile and relies on its permissions.
- The code is typed, never linked. The traveler types the code shown in the terminal (or relayed by an assistant they are using right now) on the sign-in page; there is no link with the code in it. A sign-in that replaces a stored key sends that key along, and the server retires it as it issues the new one.
- Never on the command line, never printed. Keys are not accepted as arguments, and anything shaped like a key is redacted from output.
repr(Client(...))does not show the key. - Only https. Keys are only sent over https, except to localhost for testing. Redirects are not followed.
- A person signs. Only the traveler can sign the claim authorization, in their own browser at the review link. Neither the command line nor the library can sign.
- Sharing needs consent. Files and emails are uploaded only after the traveler agrees: at a prompt or with
--yeson the command line, and withuser_authorized_sharing=Truein the library. There is no default that shares. - Evidence is not instructions. Email and file contents are stored as evidence. Neither the API nor this package follows instructions found in them.
To report a vulnerability, see SECURITY.md.
Development
cd python
python -m venv .venv && .venv/bin/pip install -e ".[dev]"
.venv/bin/python -m pytest
.venv/bin/python tests/mock_server.py # a mock API on http://127.0.0.1:4010 for trying the tool by hand
The tests run the command line in-process and as a child process against a mock of the API built on http.server. Releases are described in RELEASING.md.
License
Metadata
Release files for tourclaim 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| tourclaim-0.2.0.tar.gz | 115.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tourclaim-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 193.3 kB
Release files / tourclaim-0.2.0.tar.gz
| Download URL | tourclaim-0.2.0.tar.gz |
|---|---|
| Size | 115.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7b948b36649eea6af95a2923ea63453f2df514e0003f3202d1393f69b137dcc6
|
|
BLAKE2b-256 checksum How to use checksums |
9f3888f2267269a883b2cecc68c5cf70c6e47a2a487270f8bea62da9e0048ea8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.
Transparency logRelease files / tourclaim-0.2.0-py3-none-any.whl
| Download URL | tourclaim-0.2.0-py3-none-any.whl |
|---|---|
| Size | 77.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8c85aab6d981f2eb495fe3fffb5f2cf1943566149ee73789d376c5e708274635
|
|
BLAKE2b-256 checksum How to use checksums |
4f960d2889eef3331d5b4e865a8ed00ffe5ef034aeb79e707b48e07f0cf5960b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.
Transparency log