@voyagier/cli
Advanced tools
@@ -34,3 +34,3 @@ import { readFileSync } from "fs"; | ||
| for (const tool of TOOLS) { | ||
| server.registerTool(tool.name, { description: tool.description, inputSchema: tool.inputSchema }, async (input) => { | ||
| server.registerTool(tool.name, { title: tool.title, description: tool.description, inputSchema: tool.inputSchema, annotations: tool.annotations }, async (input) => { | ||
| const args = tool.buildArgs(input ?? {}); | ||
@@ -37,0 +37,0 @@ const result = await run(args, tool.timeoutMs); |
+44
-0
@@ -181,5 +181,7 @@ import { z } from "zod"; | ||
| name: "doctor", | ||
| title: "Check connectivity", | ||
| description: "Self-check the CLI environment (auth, schema reachability, local state, version) before doing real work. Run this first when you hit an unfamiliar error.", | ||
| timeoutMs: T.short, | ||
| inputSchema: {}, | ||
| annotations: { readOnlyHint: true }, | ||
| buildArgs: () => buildDoctorArgs(), | ||
@@ -189,2 +191,3 @@ }), | ||
| name: "create_client", | ||
| title: "Create client", | ||
| description: "Create or return an existing advisor CRM client by email (idempotent upsert). A trip plan requires a clientId. Returns { client, ok, created }.", | ||
@@ -197,2 +200,3 @@ timeoutMs: T.short, | ||
| }, | ||
| annotations: { readOnlyHint: false, destructiveHint: false }, | ||
| buildArgs: (i) => buildCreateClientArgs(i), | ||
@@ -202,2 +206,3 @@ }), | ||
| name: "plan_trip", | ||
| title: "Plan trip", | ||
| description: "Scaffold a trip plan: creates the plan + a default goal graph (a round-trip + hotel TEMPLATE) and returns { tripPlanId, travellerIds, nextSteps }. It does NOT search or select — follow nextSteps to compose. Prune goals the brief doesn't need with the shape flags: one_way (drops the Return Flights goal), flight_only (drops the hotel goal), hotel_only (drops ALL flight goals). Omitting return alone does NOT make a plan one-way. Pass travellers as a comma-separated names string to add them inline.", | ||
@@ -222,2 +227,3 @@ timeoutMs: T.medium, | ||
| }, | ||
| annotations: { readOnlyHint: false, destructiveHint: false }, | ||
| buildArgs: (i) => buildPlanTripArgs(i), | ||
@@ -227,2 +233,3 @@ }), | ||
| name: "add_traveller", | ||
| title: "Add traveller", | ||
| description: "Add a traveller to a trip plan. Travellers are required before search. Gender and date of birth are required at flight checkout and passport data hard-gates international reservations — set them with the travellers_update tool (or pass gender/dob here) once you have them. Loyalty programs are applied at checkout best-effort — a booking never fails because of them.", | ||
@@ -241,2 +248,3 @@ timeoutMs: T.short, | ||
| }, | ||
| annotations: { readOnlyHint: false, destructiveHint: false }, | ||
| buildArgs: (i) => buildAddTravellerArgs(i), | ||
@@ -246,2 +254,3 @@ }), | ||
| name: "travellers_update", | ||
| title: "Update traveller", | ||
| description: "Update an existing traveller's record on a plan. Use to correct names or to fill the fields checkout requires: gender and date of birth (required at flight checkout) and passport data (hard-gates international reservations). Loyalty programs: passing frequent_flyer/hotel_loyalty REPLACES the existing list; clear_frequent_flyer/clear_hotel_loyalty remove all. At least one field must be provided.", | ||
@@ -267,2 +276,3 @@ timeoutMs: T.short, | ||
| }, | ||
| annotations: { readOnlyHint: false, destructiveHint: false }, | ||
| buildArgs: (i) => buildUpdateTravellerArgs(i), | ||
@@ -272,2 +282,3 @@ }), | ||
| name: "travellers_list", | ||
| title: "List travellers", | ||
| description: "List the travellers on a plan. Use to discover traveller ids and to see which checkout-required fields are still missing (gender, date of birth, passport) — travellers may have been created outside this session, so never assume the roster. Pair with travellers_update to fill any gaps.", | ||
@@ -278,2 +289,3 @@ timeoutMs: T.short, | ||
| }, | ||
| annotations: { readOnlyHint: true }, | ||
| buildArgs: (i) => buildTravellersListArgs(i), | ||
@@ -283,2 +295,3 @@ }), | ||
| name: "goal_add", | ||
| title: "Add goal", | ||
| description: "Add a goal to a trip plan (no item/selection). A goal defines a slot the plan needs decided — e.g. an Activity goal is required before search_activities has anything to search against. type is a SelectionType (Activity, Flight, Hotel, HotelRoom, …), validated by the CLI. Returns the created goal; traveller assignment (if requested) is best-effort and surfaced in the result.", | ||
@@ -297,2 +310,3 @@ timeoutMs: T.short, | ||
| }, | ||
| annotations: { readOnlyHint: false, destructiveHint: false }, | ||
| buildArgs: (i) => buildGoalAddArgs(i), | ||
@@ -302,2 +316,3 @@ }), | ||
| name: "search_flights", | ||
| title: "Search flights", | ||
| description: "Search flights against the plan's Flight goal (REUSES the goal's selection — does not create a new one). Returns a compact envelope { selectionId, optionCount, topOptions[≤10], requestedParams } (round trips also return returnSelectionId). Because the selection is reused (not refetched), the envelope also echoes effectiveParams (the params the reused inventory was originally searched with) and a warnings[] entry starting SELECTION_REUSED_PARAMS_MISMATCH when the requested params differ — treat the results as reflecting effectiveParams in that case. If optionCount is 0 the async fetch is still running — poll get_selection_options with wait. Round trip: pick BOTH legs; the SAME optionId appears in both legs' lists (leg-mirrored) — picking the identical id on outbound and return is intended. A topOption MAY also carry rankScore (typically 0-1, higher is better): the platform's value score, surfaced verbatim and informational only; server order remains the default and the CLI never re-sorts by it." + | ||
@@ -317,2 +332,3 @@ INJECTION_NOTE, | ||
| }, | ||
| annotations: { readOnlyHint: true }, | ||
| buildArgs: (i) => buildSearchFlightsArgs(i), | ||
@@ -322,2 +338,3 @@ }), | ||
| name: "search_hotels", | ||
| title: "Search hotels", | ||
| description: "Search hotels against the plan's Hotel goal (REUSES the goal's selection). Returns a compact envelope { selectionId, optionCount, topOptions[≤10], requestedParams }. IMPORTANT: topOptions is a CURATED SEED shortlist (typically 5), NOT the full market. When the market holds more than the shortlist, the envelope includes a seededFrom block whose totalAvailable reports the real inventory count (best-effort: omitted when the count is unavailable or nothing beyond the shortlist exists — do NOT rely on it being present). To consider more options, either refine the search (narrower location/dates, sort/rating/price filters) to re-shop, or use the listings_list and listings_add_to_selection tools to browse the full set and promote specific properties into the decision. Because the selection is reused (not refetched), the envelope also echoes effectiveParams (the params the reused inventory was originally searched with) and a warnings[] entry starting SELECTION_REUSED_PARAMS_MISMATCH when the requested params differ — treat the results as reflecting effectiveParams in that case. Prices are STAY TOTALS, not nightly. If optionCount is 0 the async fetch is still running — poll get_selection_options with wait, then select." + | ||
@@ -336,2 +353,3 @@ INJECTION_NOTE, | ||
| }, | ||
| annotations: { readOnlyHint: true }, | ||
| buildArgs: (i) => buildSearchHotelsArgs(i), | ||
@@ -341,2 +359,3 @@ }), | ||
| name: "listings_list", | ||
| title: "List listings", | ||
| description: "Browse the FULL set of available hotel/inventory listings on a selection's monitor (beyond the seeded shortlist). Returns id, name, price, rating, bookability for each. Use after search_hotels when you need more than the seeded options; then promote a listing with listings_add_to_selection." + | ||
@@ -349,2 +368,3 @@ INJECTION_NOTE, | ||
| }, | ||
| annotations: { readOnlyHint: true }, | ||
| buildArgs: (i) => buildListingsListArgs(i), | ||
@@ -354,2 +374,3 @@ }), | ||
| name: "listings_add_to_selection", | ||
| title: "Add listing to selection", | ||
| description: "Promote a specific listing (from listings_list) into a selection as a pickable option, so it can be selected/booked. Use to consider hotels beyond the seeded shortlist.", | ||
@@ -361,2 +382,3 @@ timeoutMs: T.short, | ||
| }, | ||
| annotations: { readOnlyHint: false, destructiveHint: false }, | ||
| buildArgs: (i) => buildListingsAddToSelectionArgs(i), | ||
@@ -366,2 +388,3 @@ }), | ||
| name: "search_activities", | ||
| title: "Search activities", | ||
| description: "Search bookable activities/experiences against the plan's Activity goal. Returns a compact envelope { selectionId, optionCount, topOptions[≤10] }. If optionCount is 0 the async fetch is still running — poll get_selection_options with wait, then select." + | ||
@@ -376,2 +399,3 @@ INJECTION_NOTE, | ||
| }, | ||
| annotations: { readOnlyHint: true }, | ||
| buildArgs: (i) => buildSearchActivitiesArgs(i), | ||
@@ -381,2 +405,3 @@ }), | ||
| name: "get_selection_options", | ||
| title: "Get selection options", | ||
| description: "Read a selection's options. Search is ASYNC: when a search returns optionCount 0 the inventory fetch is still running — with wait=true (default) this polls with backoff until the status is terminal (READY / NO_RESULTS / AWAITING_INPUT / FETCH_ERROR), then returns the options to select from." + | ||
@@ -389,2 +414,3 @@ INJECTION_NOTE, | ||
| }, | ||
| annotations: { readOnlyHint: true }, | ||
| buildArgs: (i) => buildGetSelectionOptionsArgs(i), | ||
@@ -394,2 +420,3 @@ }), | ||
| name: "select_option", | ||
| title: "Select option", | ||
| description: "Choose an option on a selection by explicit selection + option id (defaults to choosing for all travellers). With wait=true (default), after the pick succeeds it polls until the pick is reflected server-side AND readiness settles, then returns a plan-status snapshot. A timed-out wait never means the pick failed. Round trip: call once per leg — the identical optionId on both legs is intended.", | ||
@@ -402,2 +429,3 @@ timeoutMs: T.search, | ||
| }, | ||
| annotations: { readOnlyHint: false, destructiveHint: false }, | ||
| buildArgs: (i) => buildSelectOptionArgs(i), | ||
@@ -407,2 +435,3 @@ }), | ||
| name: "itinerary", | ||
| title: "Trip itinerary", | ||
| description: "Show the computed itinerary for a plan (the actual composed trip, sourced from the platform's tripPlanEvents): time-sorted events with per-leg routing, times, and locations. Use this after selecting flights or hotels to verify the real composed trip — per-leg routing (layovers/stops), times, and hotel check-in/out — before describing the trip to a user or booking. A compact option summary can hide connections; the itinerary is the ground truth. Returns the standard envelope: events are under data.events (with data.total and data.dayRange), alongside planContext." + | ||
@@ -414,2 +443,3 @@ INJECTION_NOTE, | ||
| }, | ||
| annotations: { readOnlyHint: true }, | ||
| buildArgs: (i) => buildItineraryArgs(i), | ||
@@ -419,2 +449,3 @@ }), | ||
| name: "plan_status", | ||
| title: "Plan status", | ||
| description: "ONE call answering 'what's left before this plan can book?'. Switch on data.readiness: BOOKED | READY_TO_BOOK | BLOCKED (act on data.blockers[]/nextSteps[]) | IN_PROGRESS (system is working — poll, don't act). book_dry_run is the checkout truth on any contradiction.", | ||
@@ -425,2 +456,3 @@ timeoutMs: T.short, | ||
| }, | ||
| annotations: { readOnlyHint: true }, | ||
| buildArgs: (i) => buildPlanStatusArgs(i), | ||
@@ -430,2 +462,3 @@ }), | ||
| name: "quote", | ||
| title: "Quote trip", | ||
| description: "Produce the advisor offer snapshot for a plan: items, chargeableTotal, and a machine-readable acceptance block { command, itemIds, expectedTotal }. quote's chargeableTotal equals the book price gate, so the acceptance total can never fail its own gate on an unchanged cart.", | ||
@@ -436,2 +469,3 @@ timeoutMs: T.medium, | ||
| }, | ||
| annotations: { readOnlyHint: true }, | ||
| buildArgs: (i) => buildQuoteArgs(i), | ||
@@ -441,2 +475,3 @@ }), | ||
| name: "book_dry_run", | ||
| title: "Preview checkout", | ||
| description: "Preview a checkout WITHOUT creating one and WITHOUT needing a price gate: returns the chargeable subtotal, blockers, existing checkouts, and the next step. Optionally pass expect_total to also get a gate verdict (data.gate.{wouldPass,failReason}) — pre-verify without risking PRICE_CHANGED. This is the checkout truth; run it before book.", | ||
@@ -448,2 +483,3 @@ timeoutMs: T.medium, | ||
| }, | ||
| annotations: { readOnlyHint: true }, | ||
| buildArgs: (i) => buildBookDryRunArgs(i), | ||
@@ -453,2 +489,3 @@ }), | ||
| name: "book", | ||
| title: "Book the trip", | ||
| description: "Create a real Stripe checkout for the bookable items. REQUIRES expect_total — this is the price hard-gate: the checkout is created only if the chargeable subtotal equals expect_total exactly (cents-compared), else it fails closed with PRICE_CHANGED and NO checkout is created. Get the current subtotal from book_dry_run first. Never retry a successful book (unpaid sessions are invisible and a retry mints a duplicate link).", | ||
@@ -466,2 +503,3 @@ timeoutMs: T.medium, | ||
| }, | ||
| annotations: { readOnlyHint: false, destructiveHint: true }, | ||
| buildArgs: (i) => buildBookArgs(i), | ||
@@ -471,2 +509,3 @@ }), | ||
| name: "booking_status", | ||
| title: "Booking status", | ||
| description: "Show payment + booking status for past checkouts on a plan (post-payment confirmation lookup). Booking-record amounts are raw CENTS.", | ||
@@ -477,2 +516,3 @@ timeoutMs: T.short, | ||
| }, | ||
| annotations: { readOnlyHint: true }, | ||
| buildArgs: (i) => buildBookingStatusArgs(i), | ||
@@ -482,2 +522,3 @@ }), | ||
| name: "bookings_list", | ||
| title: "List bookings", | ||
| description: "List booking records for a plan with their status (Pending/Confirmed/Failed/Cancelled). Check it after any book call and before telling a user their trip is secured — a created checkout is not yet a confirmed booking. Booking-record amounts are raw CENTS (amountCents)." + | ||
@@ -489,2 +530,3 @@ INJECTION_NOTE, | ||
| }, | ||
| annotations: { readOnlyHint: true }, | ||
| buildArgs: (i) => buildBookingsListArgs(i), | ||
@@ -494,7 +536,9 @@ }), | ||
| name: "agent_docs", | ||
| title: "Voyagier agent guide", | ||
| description: "Print the full Voyagier agent reference (AGENT.md) as markdown — the canonical integration guide for the compose/close loop, error codes, and quirks.", | ||
| timeoutMs: T.quick, | ||
| inputSchema: {}, | ||
| annotations: { readOnlyHint: true }, | ||
| buildArgs: () => buildAgentDocsArgs(), | ||
| }), | ||
| ]; |
+1
-1
| { | ||
| "name": "@voyagier/cli", | ||
| "version": "2.20.0", | ||
| "version": "2.21.0", | ||
| "mcpName": "com.voyagier/cli", | ||
@@ -5,0 +5,0 @@ "description": "Agent-ready travel CLI — search, plan, quote, and book real trips (flights, hotels, activities) against the Voyagier platform. Built for AI agents: --json everywhere, uniform error codes, price-gated checkout, printable agent reference (voyagier agent-docs).", |
+8
-0
@@ -201,4 +201,12 @@ # @voyagier/cli | ||
| ## Claude Desktop Extension (MCPB) | ||
| The MCP server is also packaged as a Claude Desktop extension bundle (MCPB). Build it from the repo with `scripts/build-mcpb.sh`, which produces `dist-mcpb/voyagier-<version>.mcpb`. To install, drag the `.mcpb` file into Claude Desktop → Settings → Extensions, then enter your Personal Access Token when prompted. | ||
| ## Privacy Policy | ||
| Data processed through the CLI and Voyagier services is handled per the [Voyagier privacy policy](https://www.voyagier.com/privacy-policy). | ||
| ## License | ||
| [Apache-2.0](LICENSE) — Copyright 2026 Voyagier, Inc. Use of Voyagier services through the CLI is subject to the [Voyagier Terms of Service](https://voyagier.com/terms). "Voyagier" and the Voyagier logo are trademarks of Voyagier, Inc.; the Apache-2.0 license does not grant trademark rights. |
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
1295932
0.19%20586
0.21%212
3.92%