{"name":"travlrid-vault","version":"1.0.0","protocol_version":"2024-11-05","description":"TravlrID Vault — zero-knowledge encrypted personal data vault","tools":[{"name":"update_traveler","description":"Update traveler identity fields — first name, last name, phone, date of birth, display name, or status.\n\n🤖 AGENT RULES — follow strictly:\n  • NEVER ask for user_aid, public_key, private_key — all auto-injected from OAuth2 token.\n  • NEVER assume or guess any field value — only send what the user explicitly confirms.\n  • NEVER call this tool without verbal confirmation from the user.\n  • Do NOT set a field the user did not mention — even if it seems obvious.\n\n📋 ALL FIELDS ARE OPTIONAL — ask the user which ones to update:\n  first_name    → string   e.g. \"Ayush\"\n  last_name     → string   e.g. \"Ishu\"\n  phone         → string   E.164 format, e.g. +919876543210\n  date_of_birth → string   YYYY-MM-DD format, e.g. 1995-08-15\n  display_name  → string   Name shown in the UI\n  status        → string   active | inactive | suspended\n\nThe traveler record is auto-created at sign-up — this tool only updates it.\nDo NOT use for profiles or travel preferences.","inputSchema":{"type":"object","properties":{"first_name":{"type":"string","description":"First name."},"last_name":{"type":"string","description":"Last name."},"phone":{"type":"string","description":"Phone in E.164 format, e.g. +919876543210."},"date_of_birth":{"type":"string","description":"Date of birth in YYYY-MM-DD format."},"display_name":{"type":"string","description":"Display name shown in the UI."},"status":{"type":"string","enum":["active","inactive","suspended"]},"user_aid":{"type":"string","description":"Auto-injected from OAuth2 token — omit."}}},"securitySchemes":[{"type":"oauth2","scopes":["mcp:write"]}],"_meta":{"securitySchemes":[{"type":"oauth2","scopes":["mcp:write"]}],"openai/toolInvocation/invoking":"Updating traveler identity…","openai/toolInvocation/invoked":"Traveler identity updated."}},{"name":"save_profile","description":"Create or update a travel profile.\n\nCREATE: Omit vault_record_id. profile_type is required.\nUPDATE: Pass vault_record_id — get it from a prior save_profile response (not from the user).\n\n🤖 AGENT RULES — follow strictly:\n  • NEVER ask for vault_record_id, user_aid, or public_key — auto-resolved.\n  • NEVER assume or guess any field value — only send what the user explicitly confirms.\n  • Infer profile_type from context (personal vs corporate) — but confirm with user if unclear.\n  • BEFORE CALLING: show ALL optional fields below and ask the user which to set.\n  • Once the user has answered (or declined), call immediately with only confirmed values.\n\n📋 REQUIRED: profile_type (personal | corporate | tmc)\n\n📋 OPTIONAL FIELDS — ask the user about these before calling:\n  tenant_id    → string   Organization tenant ID. REQUIRED if profile_type is corporate or tmc.\n  employee_id  → string   Employee ID within the organization.\n  department   → string   Department name, e.g. \"Engineering\", \"Sales\".\n  cost_center  → string   Cost center code, e.g. \"CC-4201\".\n  manager      → string   Manager name or ID.\n  workspace_id → string   Workspace ID.\n\nCreating a profile bootstraps 15 memory-layer nodes automatically.","inputSchema":{"type":"object","properties":{"vault_record_id":{"type":"string","description":"SAID of existing profile to update. Omit to create."},"profile_type":{"type":"string","description":"Required. \"personal\" | \"corporate\" | \"guest\" | \"corporate_guest\".","enum":["personal","corporate","guest","corporate_guest"]},"profile_email":{"type":"string","description":"Required. Email address for this profile — must be OTP-verified to link."},"org_id":{"type":"string","description":"AID of the linked organization. Required for corporate/corporate_guest."},"tenant_id":{"type":"string","description":"Organization tenant ID. Required for corporate/corporate_guest."},"employee_id":{"type":"string"},"department":{"type":"string"},"cost_center":{"type":"string"},"manager":{"type":"string"},"workspace_id":{"type":"string"},"allowed_mcp_scopes":{"type":"array","description":"MCP scopes this profile allows. Defaults to [\"public\"].","items":{"type":"string"}},"user_allows_on_orgs":{"type":"array","description":"Org AIDs the user has opted into for internal MCP access.","items":{"type":"string"}},"user_aid":{"type":"string","description":"Auto-injected from OAuth2 token — omit."}}},"securitySchemes":[{"type":"oauth2","scopes":["mcp:write"]}],"_meta":{"securitySchemes":[{"type":"oauth2","scopes":["mcp:write"]}],"openai/toolInvocation/invoking":"Saving profile…","openai/toolInvocation/invoked":"Profile saved."}},{"name":"save_preference","description":"Save (create OR update) travel preferences for a transport mode.\n\nOne preference record per transport mode per profile.\nCalling a second time for the same preference_type UPDATES silently — no vault_record_id needed.\n\n🏢 CORPORATE PROFILES — SCHEMA ENFORCEMENT:\n  The server enforces the corporate admin schema automatically.\n  If your fields do not match the admin-defined policy, the call will fail with:\n    \"Corporate travel policy violation\"\n  The error message will list:\n    • Which fields you sent that are NOT allowed.\n    • The COMPLETE list of allowed fields, their types, and permitted values.\n  WHEN THIS HAPPENS → Do NOT ask the user anything. Read the error, identify the\n    correct fields from the \"Correct schema\" section in the error, and retry immediately\n    using ONLY those fields. Move any disallowed fields to custom_fields if they are\n    corporate-specific, or drop them entirely.\n\n🏢 CORPORATE PROFILES — PRE-STEP (recommended):\n  Call get_preference_schema(preference_type) BEFORE collecting answers from the user.\n  This tells you which fields to ask about. Standard fields → named parameters.\n  Corporate-specific fields → custom_fields object.\n\n🤖 AGENT RULES — follow strictly:\n  • NEVER ask for vault_record_id, profile_id, user_aid, public_key — all auto-resolved.\n  • NEVER assume or guess any field value — only send what the user explicitly confirms.\n  • INFER preference_type from context.\n  • Do NOT ask \"do you want to create or update?\" — the server decides automatically.\n  • If a policy violation error is returned, fix the fields and retry — do not ask user.\n  • Ask about ONE field at a time.\n\npreference_type: flight | hotel | rail | bus | car","inputSchema":{"type":"object","properties":{"preference_type":{"type":"string","enum":["flight","hotel","rail","bus","car"],"description":"Transport mode. Required."},"profile_id":{"type":"string","description":"Profile ID. Optional — auto-resolved."},"preferred_cabin":{"type":"string","enum":["economy","premium_economy","business","first"]},"seat_preference":{"type":"string","enum":["window","aisle","front","back","no_preference"]},"meal_preference":{"type":"string","enum":["standard","vegetarian","vegan","kosher","halal","gluten_free"]},"frequent_flyer_programs":{"type":"array","description":"List of frequent flyer memberships.","items":{"type":"object","properties":{"airline":{"type":"string"},"program_name":{"type":"string"},"membership_number":{"type":"string"}}}},"room_type":{"type":"string","enum":["single","double","suite"]},"bed_preference":{"type":"string","enum":["single","double","twin","king"]},"smoking_preference":{"type":"string","enum":["non_smoking","smoking"]},"floor_preference":{"type":"string","enum":["low","high","no_preference"]},"amenities":{"type":"array","items":{"type":"string","enum":["wifi","gym","pool","spa","parking","breakfast"]}},"loyalty_programs":{"type":"array","items":{"type":"object"}},"preferred_class":{"type":"string","enum":["economy","first","business"]},"quiet_zone":{"type":"boolean","description":"Prefer quiet zone seating."},"preferred_bus_type":{"type":"string","enum":["standard","express","luxury","sleeper"]},"preferred_operators":{"type":"array","items":{"type":"string"}},"require_amenities":{"type":"array","items":{"type":"string","enum":["wifi","ac","restroom","charging","entertainment","meals","reclining_seats"]}},"max_duration":{"type":"string","description":"Max travel time in ISO 8601 duration format, e.g. PT8H."},"max_stops":{"type":"integer","description":"Maximum acceptable number of stops."},"transmission_type":{"type":"string","enum":["automatic","manual"]},"car_category":{"type":"string","enum":["economy","compact","midsize","fullsize","suv","luxury","van"]},"custom_fields":{"type":"object","description":"Corporate-specific fields returned by get_preference_schema. All key-value pairs here are merged into the saved record alongside the standard fields. Example: { \"cost_centre_code\": \"CC-4201\", \"require_work_wifi\": true }"},"user_aid":{"type":"string","description":"Auto-injected from OAuth2 token — omit."}},"required":["preference_type"]},"securitySchemes":[{"type":"oauth2","scopes":["mcp:write"]}],"_meta":{"securitySchemes":[{"type":"oauth2","scopes":["mcp:write"]}],"openai/toolInvocation/invoking":"Saving travel preference…","openai/toolInvocation/invoked":"Travel preference saved."}},{"name":"get_preference_schema","description":"Fetch the complete field definitions for a preference type in the current corporate context.\n\n🤖 AGENT RULES — call this:\n  • BEFORE save_preference when the active profile is corporate, to know which fields to collect.\n  • AFTER a \"Corporate travel policy violation\" error from save_preference, to see the\n    current schema and understand which fields are allowed before retrying.\n\n  Returns ALL fields — both standard Travlr ID fields AND any extra fields the\n  corporation has added (e.g. cost_centre_code, preferred_vendor, require_work_wifi).\n\n  Required fields (required: true) MUST be collected from the user.\n  Optional fields — skip if the user says \"no preference\".\n\n  Pass standard fields as named parameters in save_preference.\n  Pass corporate-specific extra fields in the custom_fields object.\n\npreference_type: flight | hotel | rail | bus | car","inputSchema":{"type":"object","properties":{"preference_type":{"type":"string","enum":["flight","hotel","rail","bus"],"description":"Transport mode to fetch the schema for."}},"required":["preference_type"]},"securitySchemes":[{"type":"oauth2","scopes":["mcp:write"]}],"_meta":{"securitySchemes":[{"type":"oauth2","scopes":["mcp:write"]}],"openai/toolInvocation/invoking":"Fetching preference schema…","openai/toolInvocation/invoked":"Preference schema loaded."}},{"name":"save_booking","description":"Save (create or update) a travel booking of any type.\n\nCREATE: Omit vault_record_id. booking_type and booking_reference are required.\nUPDATE: Pass vault_record_id — read it from the content_said field returned by get_analytics.\n        Only the fields you provide change; all others are preserved.\n\n🤖 AGENT RULES — follow strictly:\n  • NEVER ask the user for vault_record_id — get it from get_analytics (content_said).\n  • NEVER ask for profile_id, user_aid, public_key, session_token — all auto-resolved.\n  • INFER booking_type from context.\n  • NEVER assume or guess any field value — only send what the user explicitly confirms.\n\nbooking_type: flight | hotel | rail | car | bus | event","inputSchema":{"type":"object","properties":{"booking_type":{"type":"string","enum":["flight","hotel","rail","car","bus","event"],"description":"Booking transport type. Required."},"vault_record_id":{"type":"string","description":"SAID of existing booking to update. Omit to create a new booking."},"booking_reference":{"type":"string","description":"PNR / confirmation number. Required for create."},"status":{"type":"string","enum":["confirmed","pending","cancelled","completed"]},"profile_id":{"type":"string","description":"Profile this booking belongs to. Auto-resolved if omitted."},"trip_id":{"type":"string","description":"Trip this booking is part of. Optional."},"flight":{"type":"object","description":"{ airline (required), airlineCode (required), flightNumber (required), operatingAirline }"},"departure":{"type":"object","description":"{ airportCode (required), airport, terminal, gate, scheduledTime (required ISO 8601), actualTime }"},"arrival":{"type":"object","description":"{ airportCode (required), airport, terminal, scheduledTime (required ISO 8601) }"},"cabin_class":{"type":"string","enum":["economy","premium_economy","business","first"]},"seat_number":{"type":"string"},"fare":{"type":"object","description":"Bus/Rail/Flight total fare: { currency, totalAmount, baseAmount, taxes }"},"hotel":{"type":"object","description":"Hotel: { name (required), checkIn (required ISO 8601), checkOut (required ISO 8601), roomType, address }"},"number_of_guests":{"type":"integer","description":"Hotel: number of guests."},"special_requests":{"type":"string","description":"Hotel: special requests."},"operator":{"type":"string","description":"Rail/Bus: carrier operator name."},"train_number":{"type":"string","description":"Rail: train number."},"class":{"type":"string","description":"Rail: class (economy / first / business / sleeper)."},"car_rental_company":{"type":"string","description":"Car: rental company name."},"vehicle_type":{"type":"string","description":"Car: vehicle type, e.g. SUV, Compact."},"pickup_location":{"type":"string","description":"Car: pickup location."},"dropoff_location":{"type":"string","description":"Car: drop-off location."},"pickup_date":{"type":"string","description":"Car: ISO 8601 date-time."},"return_date":{"type":"string","description":"Car: ISO 8601 date-time."},"bus_type":{"type":"string","enum":["standard","express","luxury","sleeper","ac_seater","ac_sleeper","non_ac"],"description":"Bus: service type."},"origin":{"type":"string","description":"Bus/Rail: departure city or town name."},"destination":{"type":"string","description":"Bus/Rail: arrival city or location."},"boarding_point":{"type":"string","description":"Bus: exact boarding stop / address."},"drop_point":{"type":"string","description":"Bus: exact drop-off stop / address."},"departure_time":{"type":"string","description":"Bus: departure date-time ISO 8601."},"arrival_time":{"type":"string","description":"Bus: estimated arrival date-time ISO 8601."},"passengers":{"type":"array","description":"Bus: ALL passengers in this booking.","items":{"type":"object","properties":{"name":{"type":"string","description":"Passenger full name as on ticket."},"seatNumber":{"type":"string","description":"Assigned seat number."},"fare":{"type":"object","description":"{ currency, amount } — per-passenger fare."}},"required":["name"]}},"event_name":{"type":"string","description":"Event: event name."},"event_date":{"type":"string","description":"Event: ISO 8601 date-time."},"venue":{"type":"string","description":"Event: venue name or address."},"ticket_type":{"type":"string","description":"Event: ticket type, e.g. General, VIP."},"number_of_tickets":{"type":"integer","description":"Event: number of tickets."},"user_aid":{"type":"string","description":"Auto-injected from OAuth2 token — omit."}},"required":["booking_type"]},"securitySchemes":[{"type":"oauth2","scopes":["mcp:write"]}],"_meta":{"securitySchemes":[{"type":"oauth2","scopes":["mcp:write"]}],"openai/toolInvocation/invoking":"Saving booking…","openai/toolInvocation/invoked":"Booking saved."}},{"name":"save_document","description":"Save (create or update) a travel document (passport, visa, national ID, etc.).\n\nUpsert by document_number + issuing_country — same values on a later call update the document.\n\n🤖 AGENT RULES — follow strictly:\n  • NEVER ask for user_aid, public_key — auto-injected from OAuth2 token.\n  • ALWAYS read back document_number character by character for confirmation before saving.\n  • Do NOT ask \"is this a new document or update?\" — the server upserts automatically.\n\n📋 REQUIRED: document_type, document_number, issuing_country","inputSchema":{"type":"object","properties":{"document_type":{"type":"string","description":"Document type. Required.","enum":["passport","visa","national_id","driving_license","resident_permit","other"]},"document_number":{"type":"string","description":"Document number. Required."},"issuing_country":{"type":"string","description":"ISO 3166-1 alpha-2 country code. Required."},"holder_name":{"type":"string"},"date_of_birth":{"type":"string","description":"YYYY-MM-DD."},"issue_date":{"type":"string","description":"YYYY-MM-DD."},"expiry_date":{"type":"string","description":"YYYY-MM-DD."},"status":{"type":"string","enum":["valid","expired","cancelled","lost"]},"user_aid":{"type":"string","description":"Auto-injected from OAuth2 token — omit."}},"required":["document_type","document_number","issuing_country"]},"securitySchemes":[{"type":"oauth2","scopes":["mcp:write"]}],"_meta":{"securitySchemes":[{"type":"oauth2","scopes":["mcp:write"]}],"openai/toolInvocation/invoking":"Saving travel document…","openai/toolInvocation/invoked":"Travel document saved."}},{"name":"save_loyalty_account","description":"Save (create or update) a loyalty / rewards program membership.\n\nUpsert by program_name + account_number — same values on a later call update it.\n\n🤖 AGENT RULES — follow strictly:\n  • NEVER ask for user_aid, public_key — auto-injected from OAuth2 token.\n  • Do NOT ask \"create or update?\" — the server upserts automatically.\n\n📋 REQUIRED: program_name, programme_type, account_number","inputSchema":{"type":"object","properties":{"program_name":{"type":"string","description":"Program name, e.g. \"Air India Flying Returns\". Required."},"programme_type":{"type":"string","description":"Program category. Required.","enum":["airline","hotel","rail","car_rental"]},"account_number":{"type":"string","description":"Membership number. Required."},"tier":{"type":"string","description":"Tier level, e.g. Gold, Platinum."},"points":{"type":"number","description":"Current points balance."},"benefits":{"type":"array","items":{"type":"string"}},"user_aid":{"type":"string","description":"Auto-injected from OAuth2 token — omit."}},"required":["program_name","programme_type","account_number"]},"securitySchemes":[{"type":"oauth2","scopes":["mcp:write"]}],"_meta":{"securitySchemes":[{"type":"oauth2","scopes":["mcp:write"]}],"openai/toolInvocation/invoking":"Saving loyalty account…","openai/toolInvocation/invoked":"Loyalty account saved."}},{"name":"save_trip","description":"Save (create or update) a trip.\n\nCREATE: Omit trip_id. trip_name is required.\nUPDATE: Pass trip_id from a prior save_trip response (not from the user).\n\n📋 REQUIRED on create: trip_name (string)","inputSchema":{"type":"object","properties":{"trip_id":{"type":"string","description":"Omit to create a new trip. Provide to update an existing trip."},"trip_name":{"type":"string","description":"Trip name. Required for create."},"start_date":{"type":"string","description":"ISO 8601 date, e.g. 2026-04-01."},"end_date":{"type":"string","description":"ISO 8601 date."},"purpose":{"type":"string","description":"Trip purpose, e.g. \"Business\", \"Leisure\"."},"status":{"type":"string","enum":["planned","active","completed","cancelled"]},"budget":{"type":"object","description":"{ currency: \"INR\", amount: 50000 }"},"user_aid":{"type":"string","description":"Auto-injected from OAuth2 token — omit."}}},"securitySchemes":[{"type":"oauth2","scopes":["mcp:write"]}],"_meta":{"securitySchemes":[{"type":"oauth2","scopes":["mcp:write"]}],"openai/toolInvocation/invoking":"Saving trip…","openai/toolInvocation/invoked":"Trip saved."}},{"name":"save_itinerary","description":"Save (create or update) an itinerary linked to a trip.\n\nCREATE: Omit itinerary_id. trip_id is required.\nUPDATE: Pass itinerary_id from a prior save_itinerary response (not from the user).\n\n📋 REQUIRED on create: trip_id (string)","inputSchema":{"type":"object","properties":{"itinerary_id":{"type":"string","description":"Omit to create. Provide to update."},"trip_id":{"type":"string","description":"Trip this itinerary belongs to. Required for create."},"timeline":{"type":"array","description":"Ordered list of itinerary events.","items":{"type":"object"}},"schedule":{"type":"object","description":"Schedule summary object."},"participants":{"type":"array","description":"Participant names or AIDs.","items":{"type":"string"}},"budget":{"type":"object","description":"{ currency, amount }"},"user_aid":{"type":"string","description":"Auto-injected from OAuth2 token — omit."}}},"securitySchemes":[{"type":"oauth2","scopes":["mcp:write"]}],"_meta":{"securitySchemes":[{"type":"oauth2","scopes":["mcp:write"]}],"openai/toolInvocation/invoking":"Saving itinerary…","openai/toolInvocation/invoked":"Itinerary saved."}},{"name":"save_policy","description":"Save (create or update) a travel policy. CORPORATE ADMIN ONLY.\n\nCREATE: Omit policy_id. name and policy_type are required.\nUPDATE: Pass policy_id from a prior save_policy response (not from the user).\n\n📋 REQUIRED on create: name (string), policy_type\n  policy_type → corporate_travel | booking_rules | expense_limits | approval_workflow | compliance\n\nSimple users will receive a 403 Forbidden error.","inputSchema":{"type":"object","properties":{"policy_id":{"type":"string","description":"Omit to create. Provide to update."},"name":{"type":"string","description":"Policy name. Required for create."},"policy_type":{"type":"string","description":"Policy category. Required for create.","enum":["corporate_travel","booking_rules","expense_limits","approval_workflow","compliance"]},"rules":{"type":"object","description":"Rule definitions."},"constraints":{"type":"object","description":"Policy constraints."},"user_aid":{"type":"string","description":"Auto-injected from OAuth2 token — omit."}}},"securitySchemes":[{"type":"oauth2","scopes":["mcp:write"]}],"_meta":{"securitySchemes":[{"type":"oauth2","scopes":["mcp:write"]}],"openai/toolInvocation/invoking":"Saving policy…","openai/toolInvocation/invoked":"Policy saved."}},{"name":"list_vault_records","description":"List all vault records for the authenticated user. Returns metadata only (no decrypted content). Use to see what memories, preferences, profiles, or data exist in the vault. Use when user says \"what do you know about me\", \"show my preferences\", \"list my memories\", \"what have I saved\".","inputSchema":{"type":"object","properties":{"schema":{"type":"string","description":"Filter by schema (e.g., \"TravlrID:Profile@1.0.0\"). Optional — omit to list all."},"limit":{"type":"number","description":"Maximum number of records to return. Default: 50.","default":50},"user_aid":{"type":"string","description":"Your AID. Optional if set in environment variables."},"public_key":{"type":"string","description":"Base64-encoded public key. Optional if set in environment variables."}}}},{"name":"get_vault_record","description":"⚠️  THIS TOOL RETURNS ENCRYPTED CIPHERTEXT — NOT HUMAN-READABLE DATA.\n   The response contains a wrapped DEK + XChaCha20-Poly1305 encrypted blob.\n   You cannot read, display, or interpret the content from this tool.\n\nDO NOT call this tool when the user asks to \"show\", \"read\", or \"get\" bookings.\n   → Use get_analytics with query_type=\"details\" instead.\n\nONLY call this tool for:\n  - Sharing a record: you need the wrapped_dek to re-wrap for a recipient.\n  - Auditing: verifying a SAID exists in the vault.\n  - Syncing: a downstream system that handles decryption itself.\n\n⚠️  said must be a base64 vault SAID from `content_said` — NOT a UUID node_id.\nA valid SAID looks like: \"ejK0eNl9EeUBT5Fi3WY9kJYPTy/KmxuhY0HU0jC9ibU=\"","inputSchema":{"type":"object","properties":{"said":{"type":"string","description":"The vault SAID — use the `content_said` field from get_analytics rows. NOT the node_id (UUID). Required."},"user_aid":{"type":"string","description":"Your AID. Optional if set in environment variables."},"public_key":{"type":"string","description":"Base64-encoded public key. Optional if set in environment variables."}},"required":["said"]}},{"name":"grant_vault_access","description":"Grant access to a vault record for another user/entity. Server-side re-wraps the DEK with the recipient's public key. Requires the owner's private_key to unwrap the DEK before re-wrapping. Use when sharing profiles, bookings, or preferences with others.","inputSchema":{"type":"object","properties":{"said":{"type":"string","description":"SAID of the record to share. Required."},"recipient_aid":{"type":"string","description":"AID of the recipient who should get access. Required."},"recipient_public_key":{"type":"string","description":"Base64-encoded Ed25519/X25519 public key of the recipient. Required."},"purpose":{"type":"string","description":"Purpose of access grant (e.g., \"trip_planning\", \"booking_management\"). Optional."},"user_aid":{"type":"string","description":"Your AID. Optional if set via MCP_USER_AID environment variable."},"public_key":{"type":"string","description":"Base64-encoded owner public key. Optional if set via MCP_PUBLIC_KEY."},"private_key":{"type":"string","description":"Base64-encoded owner private key. Required for DEK re-wrapping."}},"required":["said","recipient_aid","recipient_public_key"]}},{"name":"revoke_vault_access","description":"Revoke access to a vault record from a specific user/entity. Removes their DEK wrap so they can no longer decrypt the data.","inputSchema":{"type":"object","properties":{"said":{"type":"string","description":"SAID of the record. Required."},"recipient_aid":{"type":"string","description":"AID of the recipient whose access should be revoked. Required."},"user_aid":{"type":"string","description":"Your AID. Optional if set via MCP_USER_AID environment variable."},"public_key":{"type":"string","description":"Base64-encoded public key. Optional if set via MCP_PUBLIC_KEY."}},"required":["said","recipient_aid"]}},{"name":"get_vault_audit_log","description":"Get the audit log for a specific vault record. Shows all operations (CREATE, UPDATE, GRANT, REVOKE) with timestamps and actor AIDs.","inputSchema":{"type":"object","properties":{"said":{"type":"string","description":"SAID of the record to get audit logs for. Required."},"user_aid":{"type":"string","description":"Your AID. Optional if set via MCP_USER_AID environment variable."},"public_key":{"type":"string","description":"Base64-encoded public key. Optional if set via MCP_PUBLIC_KEY."}},"required":["said"]}},{"name":"create_multiple_vault_records","description":"Create multiple vault records in batch. Useful for importing data or creating related records together (e.g., profile + preferences + bookings).","inputSchema":{"type":"object","properties":{"records":{"type":"array","description":"Array of records to create. Each must have schema and data.","items":{"type":"object","properties":{"schema":{"type":"string"},"data":{"type":"object"},"tenant_id":{"type":"string"},"workspace_id":{"type":"string"}},"required":["schema","data"]}},"user_aid":{"type":"string","description":"Your AID. Optional if set via MCP_USER_AID environment variable."},"public_key":{"type":"string","description":"Base64-encoded public key for encryption. Optional if set via MCP_PUBLIC_KEY."}},"required":["records"]}},{"name":"archive_vault_record","description":"Soft-delete (archive) a vault record. The record becomes invisible to list/read operations but is preserved and can be restored. Use when the user wants to hide or deactivate a record without permanently losing it.","inputSchema":{"type":"object","properties":{"said":{"type":"string","description":"SAID of the record to archive. Required."},"user_aid":{"type":"string","description":"Your AID. Optional if set via MCP_USER_AID."},"public_key":{"type":"string","description":"Base64-encoded public key. Optional if set via MCP_PUBLIC_KEY."}},"required":["said"]}},{"name":"delete_vault_record","description":"Permanently hard-delete a vault record. Removes the DB row, DEK wraps, and encrypted blob from storage. This is IRREVERSIBLE — the data cannot be recovered. Only use when the user explicitly requests permanent deletion.","inputSchema":{"type":"object","properties":{"said":{"type":"string","description":"SAID of the record to permanently delete. Required."},"user_aid":{"type":"string","description":"Your AID. Optional if set via MCP_USER_AID."},"public_key":{"type":"string","description":"Base64-encoded public key. Optional if set via MCP_PUBLIC_KEY."}},"required":["said"]}},{"name":"restore_vault_record","description":"Restore an archived vault record back to active status. Only works on archived records — permanently deleted records cannot be restored.","inputSchema":{"type":"object","properties":{"said":{"type":"string","description":"SAID of the archived record to restore. Required."},"user_aid":{"type":"string","description":"Your AID. Optional if set via MCP_USER_AID."},"public_key":{"type":"string","description":"Base64-encoded public key. Optional if set via MCP_PUBLIC_KEY."}},"required":["said"]}},{"name":"get_traveler_profile","description":"Get the traveler's base identity (name, email, phone) plus a lightweight index of profiles they hold.\n\nUSE WHEN user asks: \"who am I\", \"show my profile\", \"what is my name\", \"my email\", \"my phone\".\n\nDO NOT USE for:\n- Listing profiles only           → use list_profiles\n- Decrypted contents of a profile → use get_my_profile\n- Travel preferences              → use get_preferences\n- Bookings / trips                → use get_analytics\n- Documents / constraints         → use get_documents / get_constraints\n\nRETURNS:\n  data.identity.context = { first_name, last_name, email, phone, ... }\n  data.profiles[]       = brief { profile_id, tenant_id, profile_type, status }\n  data.profile_count    = number\n\nREAD-BACK: read identity.context fields naturally; skip null/empty fields.\n  e.g. \"Your name is {first_name} {last_name}, email {email}, phone {phone}.\"","inputSchema":{"type":"object","properties":{"user_aid":{"type":"string","description":"Auto-injected from OAuth2 token — omit."}}}},{"name":"get_my_profile","description":"Get the decrypted contents of the profile the user is currently logged in as.\n\nUSE WHEN user asks: \"show my profile\", \"my work profile\", \"my corporate details\",\n  \"what does my company know about me\", \"my profile data\".\n\nNo parameters. The active profile was chosen on the OAuth login screen and is bound\nto this session’s token — the LLM cannot (and need not) specify which profile.\n\nTo switch profiles the user must log out of the connector and reconnect.\nTo see ALL profiles (without decryption) call list_profiles instead.","inputSchema":{"type":"object","properties":{"user_aid":{"type":"string","description":"Auto-injected — omit."}}}},{"name":"get_preferences","description":"Get the travel preferences — flight seat, meal, cabin class, hotel room type, rail seat, etc. — for the user's active profile.\n\nUSE WHEN user asks: \"my preferences\", \"what seat do I prefer\", \"my meal preference\",\n  \"window or aisle\", \"my hotel preferences\".\n\nNo parameters. Preferences are scoped to the active profile bound to this session.\n\nREAD-BACK: group by mode.\n  e.g. \"For flights you prefer a {seat_preference} seat in {preferred_cabin}, meal: {meal_preference}.\"\n  If empty: \"You haven't saved any travel preferences yet.\"","inputSchema":{"type":"object","properties":{"user_aid":{"type":"string","description":"Auto-injected — omit."}}}},{"name":"get_complete_context","description":"Get the COMPLETE context for the user's active profile — identity + active profile + preferences in one call.\n\nUSE WHEN user asks: \"tell me everything about me\", \"all my data\", or BEFORE planning a trip\n  to load identity + preferences + policies in a single request.\n\nNo tenant or profile parameter — always scoped to the active profile bound to this session.\nSet include_preferences=false to skip preference decryption (faster).","inputSchema":{"type":"object","properties":{"include_preferences":{"type":"boolean","description":"Default: true."},"include_profiles":{"type":"boolean","description":"Default: true."},"user_aid":{"type":"string","description":"Auto-injected — omit."}}}},{"name":"get_analytics","description":"Get bookings, trips, or travel stats for the authenticated traveler.\n\nUSE WHEN user asks: \"show my bookings\", \"my travel history\", \"trips this year\", \"travel stats\".\n\nDEFAULTS: query_type=\"summary\", entity=\"bookings\".\n  Summary decrypts ONE index blob per booking type (O(1) at any scale) and returns\n  data.summaries[] with key fields: operator, route, date, fare, seat, reference.\n  Only switch to query_type=\"details\" when the user explicitly needs every field.\n\nDO NOT call get_vault_record on a SAID returned here — it returns ciphertext, not readable data.\n\nREAD-BACK: read bookings one at a time as natural sentences, never raw JSON.\n  e.g. \"You have a {airline} flight from {origin} to {destination} on {date} at {time},\n        booking reference {reference}, seat {seat} in {cabin_class}.\"\n  If empty: \"You don't have any bookings saved in your vault yet.\"","inputSchema":{"type":"object","properties":{"query_type":{"type":"string","description":"\"summary\" (default, O(1)) | \"details\" (O(N)) | \"list\" (metadata) | \"aggregation\" (counts).","enum":["summary","list","aggregation","details"],"default":"summary"},"entity":{"type":"string","description":"Entity to query. Default: \"bookings\".","enum":["bookings","flights","hotels","rail","car","bus","events","trips","travelers","profiles","preferences","loyalty"]},"tenant_id":{"type":"string","description":"Filter by organization. Optional."},"start_date":{"type":"string","description":"ISO 8601. Optional."},"end_date":{"type":"string","description":"ISO 8601. Optional."},"workspace_id":{"type":"string","description":"Filter by workspace. Optional."},"user_aid":{"type":"string","description":"Auto-injected — omit."}}}},{"name":"get_documents","description":"List every travel document (passport, visa, national_id, driving_license, resident_permit) attached to the traveler's identity. Server-decrypted.\n\nUSE WHEN user asks: \"what documents do I have\", \"show my passports\", \"list my visas\",\n  \"when does my passport expire\", \"my document numbers\", or BEFORE booking international travel.\n\nRETURNS:\n  data.documents[] = { document_type, document_number, issuing_country, holder_name,\n                       date_of_birth, issue_date, expiry_date, status,\n                       said, vault_id, document_id, created_at, updated_at, details{...} }\n  data.count       = number\n\nREAD-BACK: skip null fields. Flag expiry.\n  e.g. \"Your {document_type} #{document_number} ({issuing_country}) expires on {expiry_date}.\"\n  If expired: prepend \"Note — this document expired on {expiry_date}.\"\n\nDocuments are identity-level, not profile-scoped. Add new documents with save_document.","inputSchema":{"type":"object","properties":{"user_aid":{"type":"string","description":"Auto-injected — omit."}}}},{"name":"get_constraints","description":"List every constraint (dietary, accessibility, medical, religious, visa_restriction, travel_restriction) attached to the traveler's identity. Server-decrypted.\n\nUSE WHEN user asks: \"my dietary restrictions\", \"my accessibility needs\", \"my medical requirements\",\n  \"am I vegetarian\", \"do I need a wheelchair\", \"my religious restrictions\",\n  or BEFORE booking to flag mandatory accommodations.\n\nRETURNS:\n  data.constraints[] = { type, severity, category, description, applicable_to[],\n                         valid_from, valid_to, said, vault_id, constraint_id, details{...} }\n  data.count         = number\n\n  type:     \"accessibility\" | \"dietary\" | \"medical\" | \"religious\" | \"visa_restriction\" | \"travel_restriction\" | \"custom\"\n  severity: \"mandatory\" | \"important\" | \"preference\"\n\nREAD-BACK: group by type; mention severity for non-mandatory items.\n  e.g. \"You have a {type} constraint: {description}. Severity: {severity}.\"\n\nConstraints are identity-level, not profile-scoped.","inputSchema":{"type":"object","properties":{"user_aid":{"type":"string","description":"Auto-injected — omit."}}}},{"name":"list_profiles","description":"List all profiles linked to the authenticated traveler — both personal and corporate.\n\nUSE WHEN user asks: \"what profiles do I have\", \"show all my profiles\",\n  \"which companies am I linked to\".\n\nThis is a metadata-only listing — no decryption. To read the contents of the\ncurrently-active profile use get_my_profile (no parameters needed).\n\nRETURNS data.profiles[] = ProfileSummary {\n  profile_type    : \"personal\" | \"corporate\"\n  tenant_id       : \"default\" (personal) | org AID (corporate)\n  workspace_id    : Neo4j UUID  (corporate only)\n  organization_id : org AID     (corporate only)\n  label           : human-readable name if set\n}\n\nTo switch the active profile, the user must log out of the connector and reconnect —\nprofile selection happens only on the OAuth login screen.","inputSchema":{"type":"object","properties":{"user_aid":{"type":"string","description":"Auto-injected — omit."}}}},{"name":"routestack_hotel_search_destinations","description":"Search hotel destinations by name or code.","inputSchema":{"type":"object","properties":{"search_term":{"type":"string","description":"Search term (city, airport code, etc). Optional."}}}},{"name":"routestack_hotel_search","description":"Search available hotels with rooms and rates. Hotel preferences are auto-fetched (amenities, chain loyalty). Response contains preference_matched_offers (match saved amenity/chain prefs), other_offers, and all offers annotated with _prefMatch flags. ALWAYS present preference_matched_offers first. Then ask: \"Would you also like to see [N] other hotels that don't match your usual preferences?\" If preference_matched_offers is empty, say so and continue with other_offers. preferences_used.room_level_note tells you which room-level preferences (bed type, smoking) to check when the user selects a room via routestack_hotel_rooms. Read top results as: \"Option 1: [hotel name], [star rating] stars, from [fare] per night.\"","inputSchema":{"type":"object","properties":{"destination_id":{"type":"string"},"lat":{"type":"number"},"long":{"type":"number"},"check_in":{"type":"string"},"check_out":{"type":"string"},"rooms":{"type":"string","description":"JSON string of room specs."}},"required":["destination_id","lat","long","check_in","check_out","rooms"]}},{"name":"routestack_hotel_details","description":"Get full details of a specific hotel.","inputSchema":{"type":"object","properties":{"hotel_id":{"type":"string"}},"required":["hotel_id"]}},{"name":"routestack_hotel_rooms","description":"Get available rooms and rates for a hotel.","inputSchema":{"type":"object","properties":{"hotel_id":{"type":"string"},"check_in":{"type":"string"},"check_out":{"type":"string"},"rooms":{"type":"string"}},"required":["hotel_id","check_in","check_out","rooms"]}},{"name":"routestack_hotel_revalidate","description":"Revalidate hotel rates/availability.","inputSchema":{"type":"object","properties":{"hotel_id":{"type":"string"},"rate_key":{"type":"string"}},"required":["hotel_id","rate_key"]}},{"name":"routestack_hotel_get_payment_url","description":"Generate hotel booking payment link.","inputSchema":{"type":"object","properties":{"payload":{"type":"string","description":"JSON string of booking details."}},"required":["payload"]}},{"name":"routestack_hotel_booking_info","description":"Get details of a past hotel booking.","inputSchema":{"type":"object","properties":{"booking_reference":{"type":"string"}},"required":["booking_reference"]}},{"name":"routestack_hotel_cancel_booking","description":"Cancel an active hotel booking.","inputSchema":{"type":"object","properties":{"booking_reference":{"type":"string"}},"required":["booking_reference"]}},{"name":"routestack_flight_session","description":"Create a new flight search session.","inputSchema":{"type":"object","properties":{"trip_type":{"type":"string","enum":["one_way","round_trip","multi_city"]}},"required":["trip_type"]}},{"name":"routestack_flight_locations","description":"Resolve a city or airport name to an IATA code. Call this BEFORE routestack_flight_search whenever the user provides a city name instead of an IATA code (e.g. \"Dubai\" → \"DXB\", \"Delhi\" → \"DEL\").","inputSchema":{"type":"object","properties":{"search_term":{"type":"string","description":"Airport name or IATA code."}},"required":["search_term"]}},{"name":"routestack_flight_search","description":"Search available flights and fares. IMPORTANT: origin and destination MUST be IATA codes (e.g. DXB, DEL). If the user gives a city name, call routestack_flight_locations first to resolve it. Preferences are auto-fetched and applied server-side — cabin_class defaults to the saved preference if omitted, so you rarely need to ask for it. The response has THREE arrays: preference_matched_offers (match saved cabin/airline prefs), other_offers (do not match), and offers (all, annotated with _prefMatch). ALWAYS present preference_matched_offers first. Then ask: \"Would you also like to see [N] other options that don't match your usual preferences?\" If preference_matched_offers is empty, say so then read other_offers. Read results as: \"Option 1: [airline], departs [time], arrives [time], [cabin], [fare] [currency].\"","inputSchema":{"type":"object","properties":{"origin":{"type":"string"},"destination":{"type":"string"},"depart_date":{"type":"string"},"return_date":{"type":"string"},"cabin_class":{"type":"string","enum":["economy","business","first_class"]},"passengers":{"type":"string","description":"JSON string."}},"required":["origin","destination","depart_date","passengers"]}},{"name":"routestack_flight_revalidate","description":"Revalidate / reprice a selected flight to confirm fare is still available before booking. Call this BEFORE routestack_flight_get_payment_url. Returns updated pricing and booking data.","inputSchema":{"type":"object","properties":{"fare_source_code":{"type":"string","description":"From offer.raw.fareSourceCode of the chosen search result."},"search_filter_obj":{"type":"object","description":"Optional: from offer.raw.searchFilterObj if present."},"search_list_price":{"type":"object","description":"Optional: from offer.raw.searchListPrice if present."}},"required":["fare_source_code"]}},{"name":"routestack_flight_get_payment_url","description":"Generate the external payment URL for a selected flight. RECOMMENDED FLOW: search → revalidate → get_payment_url. Returns { url } — show this URL to the user to complete payment.\n\nHow to pass the flight data: after calling routestack_flight_search, the user picks an offer. Pass offer_raw = offer.raw from that offer. This auto-extracts fareSourceCode and flight internally. Alternatively pass fare_source_code = offer.raw.fareSourceCode and flight = offer.raw.flights[0] manually.","inputSchema":{"type":"object","properties":{"origin":{"type":"string","description":"Origin IATA code (e.g. DXB)."},"destination":{"type":"string","description":"Destination IATA code (e.g. DEL)."},"departure_date":{"type":"string","description":"Departure date YYYY-MM-DD."},"return_date":{"type":"string","description":"Return date YYYY-MM-DD for round trips."},"adults":{"type":"number","description":"Number of adult passengers."},"children":{"type":"number","description":"Number of child passengers."},"fare_source_code":{"type":"string","description":"From offer.raw.fareSourceCode of the selected search result."},"flight":{"type":"object","description":"Flight leg data. Pass offer.raw.flights[0] from the chosen search result."},"offer_raw":{"type":"object","description":"SHORTCUT: pass the entire offer.raw object from the chosen search result. fare_source_code and flight are auto-extracted from it. Use this instead of passing fare_source_code and flight separately."}},"required":["origin","destination","departure_date","adults"]}},{"name":"routestack_flight_search_and_book","description":"One-shot: searches flights, auto-picks the best offer, and returns a payment URL — all in a single call. Use this when the user says something like \"book me a flight\" without wanting to browse results first. Automatically fetches the traveler's email and phone from their vault profile to pre-fill the payment form. Picks the best offer by: fewest stops first, then lowest price. Optionally filter by max_price. Returns: offers_found (total), selected_offer (the chosen flight), payment_url (direct link to complete payment). After calling this tool, show the user the selected flight details and the payment URL.","inputSchema":{"type":"object","properties":{"origin":{"type":"string","description":"Origin airport IATA code (e.g. DXB). Resolve with routestack_flight_locations if unsure."},"destination":{"type":"string","description":"Destination airport IATA code (e.g. DEL)."},"depart_date":{"type":"string","description":"Departure date YYYY-MM-DD."},"return_date":{"type":"string","description":"Return date YYYY-MM-DD for round trips. Omit for one-way."},"passengers":{"type":"string","description":"JSON string with passenger counts, e.g. {\"adults\":1} or {\"ADT\":1,\"CHD\":1}."},"cabin_class":{"type":"string","enum":["economy","business","first_class"],"description":"Cabin class. Defaults to economy."},"max_price":{"type":"number","description":"Maximum total price in USD. Omit for no price filter."},"direct_only":{"type":"boolean","description":"If true, only consider non-stop flights."}},"required":["origin","destination","depart_date","passengers"]}},{"name":"routestack_car_locations","description":"Search car rental locations.","inputSchema":{"type":"object","properties":{"search_term":{"type":"string","description":"Location name/code. Optional."}}}},{"name":"routestack_car_search","description":"Search available car rentals and rates.","inputSchema":{"type":"object","properties":{"pickup_code":{"type":"string"},"dropoff_code":{"type":"string"},"pickup_date":{"type":"string"},"dropoff_date":{"type":"string"},"driver_age":{"type":"number","description":"Default: 30."},"currency":{"type":"string","description":"Default: USD."}},"required":["pickup_code","dropoff_code","pickup_date","dropoff_date"]}},{"name":"routestack_car_get_payment_url","description":"Generate car rental booking payment link.","inputSchema":{"type":"object","properties":{"payload":{"type":"string","description":"JSON string of booking details."}},"required":["payload"]}}],"auth":{"type":"bearer","description":"Obtain a Bearer token via the OAuth2 PKCE flow","token_url":"https://vault.staging.travlr.network/oauth/token","authorize_url":"https://vault.staging.travlr.network/oauth/authorize"},"endpoints":{"mcp":"https://vault.staging.travlr.network/mcp"}}