Visa MCP LIVE

Book an India visa from your own agent

A remote MCP server that exposes Naytive's Visit India / Edge City visa flow — search visas, upload a passport & photo, file the application, and take payment — as tools any MCP-compatible AI agent can call on a user's behalf.

MCP https://visa-mcp.naytive.com/mcp
Download docs (.md) Hand it to your coding agent

Overview

The server speaks the Model Context Protocol over Streamable HTTP. Point any MCP client at the endpoint above; the client discovers the tools and drives them. Every call acts on behalf of a signed-in Naytive user, so the visa is filed against a real account with a real document vault.

Transport

Streamable HTTP (JSON-RPC 2.0). One endpoint: POST /mcp.

Auth

Two keys: a Naytive partner API key (X-API-Key, issued to you) identifies your integration; the traveller signs in with Privy (OAuth 2.1 + PKCE) in the browser.

Billing

You charge your own users through your own Stripe. Naytive's per-application fee is drawn from a prepaid wallet you top up.

Staging. This deployment runs against Naytive's staging environment and Stripe test mode. Use it to build and validate; a production endpoint is issued separately.

Get an API key

Every call carries a Naytive partner API key in the X-API-Key header, so all usage is attributed to your integration and billed to your wallet. Keys are issued by Naytive — request one below and we'll approve it and send your key (shown once).

1 · Request

Send your organisation and a contact email. We review and approve.

2 · Receive your key

On approval you get an oc_live_… / oc_test_… key. Store it as a secret.

3 · Top up & build

Add funds to your wallet, then point your MCP client at the endpoint with your key set.

Connect a client

The endpoint is a standard remote MCP server, so anything that speaks MCP works. On first use the client opens a browser window for the user to sign in, then remembers the session.

Claude Desktop / Claude Code

Add the server to your MCP config (Claude Code: run the CLI command; Desktop: edit claude_desktop_config.json). Set your partner key as the X-API-Key header. Optionally add X-Stripe-Key (a restricted Stripe key) to collect end-user payments on your own Stripe — see Wallet & billing.

claude_desktop_config.json
// mcpServers entry
{
  "mcpServers": {
    "naytive-visa": {
      "type": "http",
      "url": "https://visa-mcp.naytive.com/mcp",
      "headers": {
        "X-API-Key": "oc_test_your_key_here",
        // optional — collect on your own Stripe:
        "X-Stripe-Key": "rk_test_your_restricted_key"
      }
    }
  }
}
Claude Code — terminal
claude mcp add --transport http naytive-visa https://visa-mcp.naytive.com/mcp \
  --header "X-API-Key: oc_test_your_key_here"

Cursor

Add to ~/.cursor/mcp.json (or the project's .cursor/mcp.json) with the same shape — "url" pointing at the endpoint and an X-API-Key header.

MCP Inspector

The quickest way to click through the tools. Use v2+, which supports the OAuth sign-in:

terminal
npx @modelcontextprotocol/inspector@latest

In the UI: Add Server → Transport Streamable HTTP → URL the endpoint → toggle it on → complete the Naytive sign-in.

Custom client (TypeScript SDK)

client.ts
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";

const transport = new StreamableHTTPClientTransport(
  new URL("https://visa-mcp.naytive.com/mcp"),
  { authProvider }  // your OAuthClientProvider — SDK runs the PKCE flow
);
const client = new Client({ name: "my-agent", version: "1.0.0" }, { capabilities: {} });
await client.connect(transport);

const { tools } = await client.listTools();
const res = await client.callTool({ name: "list_india_events", arguments: {} });

Try it

Run any tool live, right here. Every call needs your X-API-Key. Wallet & catalog tools run with just the key; traveller tools also need a Bearer access token.

Ready
// the response will appear here

Tip: run list_india_events first to get a visaConfigId, then paste it into get_visa_details.

Authentication

Two layers. Your partner API key (X-API-Key) identifies your integration on every request and is what your wallet is billed against. On top of that, user-scoped tools need the traveller's Privy sign-in (OAuth 2.1). A request with no key returns 401; a user tool with no sign-in returns 401 + WWW-Authenticate, which a compliant client uses to run the browser sign-in automatically.

  1. Set your Naytive-issued key as the X-API-Key header (see Get an API key). It never expires unless revoked.
  2. For a user-scoped tool, the client opens the authorize URL; the server redirects to Naytive's hosted sign-in, where the traveller logs in with email or wallet (Privy).
  3. Naytive verifies the identity and the server issues a short-lived access token bound to that user. The client sends it as Authorization: Bearer … alongside your X-API-Key.
Two identities, two jobs. The X-API-Key = your integration (billing + attribution); the Privy sign-in = the traveller the visa is filed under, using that user's stored documents. Access tokens are short-lived and refresh automatically.
GET /.well-known/oauth-authorization-server
{
  "issuer": "https://visa-mcp.naytive.com/",
  "authorization_endpoint": ".../authorize",
  "token_endpoint": ".../token",
  "registration_endpoint": ".../register",
  "code_challenge_methods_supported": ["S256"],
  "grant_types_supported": ["authorization_code", "refresh_token"]
}

Wallet & billing

Two ways to collect payment from your end-user — you choose per connection with the optional X-Stripe-Key header:

Your own Stripe

Set an X-Stripe-Key header (a restricted Stripe key). The end-user's checkout is created on your Stripe — they pay you. Naytive's fee is drawn from your prepaid wallet and the visa is filed immediately; submit_application returns a paymentUrl for your end-user.

Naytive collects (default)

No X-Stripe-Key → the end-user pays Naytive. submit_application creates a pending_payment; call create_payment_link for a Naytive checkout. No wallet is used.

Top up & rate

Own-Stripe mode debits fee × traveller count per filing. Check balance + rate with get_wallet_balance; add funds with create_wallet_topup_link. Low balance → the application is not created (402).

Your key is never stored. X-Stripe-Key travels as a request header (not a tool argument, so it never enters the model's context), is used just-in-time to create the checkout on your account, and is never logged or persisted. Use a restricted key. Wallet debits are atomic and idempotent — a retried submit is charged at most once and the balance can never go negative.

Tools

Twelve tools, grouped by what they touch. Read tools return catalog, account, or wallet data; write tools mutate the user's vault, applications, or your wallet. Every tool returns a JSON payload as text content. All tools require your X-API-Key; user-scoped tools also need the traveller's sign-in.

You never hardcode identifiers. A visaConfigId comes from list_india_events; an applicationId / applicationNumber comes from submit_application or list_applications; document and photo ids come from the upload tools. Treat them as opaque handles.

Catalog

list_india_events

Read

The India builder events you can get a visa for (Edge City India, India Blockchain Week, Devcon Mumbai) and the available India visa options. No arguments.

get_visa_details

Read

Full detail for one visa: validity, max stay, entries, processing time, nationality-aware pricing, and the required documents.

FieldTypeNotes
visaConfigIdintegerrequiredFrom list_india_events.
nationalitystringoptionalISO code (US, GB, IN) for accurate pricing/docs.

get_required_documents

Read

Required documents for a visa, merged with what the signed-in user already has stored — so the agent only asks for what's missing.

FieldTypeNotes
visaConfigIdintegerrequiredThe handle returned by list_india_events.
nationalitystringoptionalISO code.

Applications

list_applications

Read

The signed-in user's filed visa applications with current status, travel dates, and amount. No arguments.

check_application_status

Read

Status and detail for one application by its number.

FieldTypeNotes
applicationNumberstringrequirede.g. NV…

Documents

upload_passport

Write

Upload a passport image or PDF. It's read, the identity fields extracted, and stored in the traveller's vault. Returns a documentId to pass to submit_application.

FieldTypeNotes
fileBase64stringrequiredRaw base64 (no data: prefix), ≤ 6 MB.
fileNamestringrequired
fileMimestringrequiredimage/png, image/jpeg, or application/pdf.

upload_photo

Write

Upload the traveller's passport-size photo. Returns a photoId for submit_application.

FieldTypeNotes
imageBase64stringrequiredBase64 JPEG/PNG.
countryCodestringoptionalDestination code, default IN.
formatstringoptionaljpeg / png.

Submit & pay

submit_application

Write

File the application. Every traveller must already have a passport documentId and a photoId, or the call is rejected. Naytive's fee (rate × travellers) is debited from your wallet and the application is filed immediately (submitted). If the balance is too low nothing is created — top up and retry. You collect payment from your own end-user separately.

FieldTypeNotes
visaConfigIdintegerrequiredThe handle returned by list_india_events.
nationalitystringoptionalISO code.
arrivalDate / departureDatestringoptionalYYYY-MM-DD.
eventName / visitTypestringoptionale.g. "Edge City India".
documentIdsinteger[]singlePassport doc id(s) for a solo applicant.
processedPhotoIdintegersinglePhoto id for a solo applicant.
travelersobject[]groupOne per traveller: { fullName?, relationship?, documentIds, processedPhotoId }.

create_payment_link

Write

Alternate flow. Have Naytive collect from the traveller directly (Stripe/Helio) instead of your wallet. Not needed for the wallet model above — a wallet-billed application is already submitted.

FieldTypeNotes
applicationIdintegerrequiredFrom submit_application.
paymentModestringoptionalcard (default) or crypto.
returnUrlstringoptionalWhere to send the browser after payment. Pass your own app URL (e.g. your success page) — if omitted it defaults to naytive.com.

Wallet & billing

get_wallet_balance

Read

Your prepaid wallet balance (USD cents), currency, and the per-application wholesale fee. No arguments.

list_wallet_transactions

Read

Recent ledger entries — top-ups, per-application debits, and refunds — each with the running balance.

FieldTypeNotes
limitintegeroptional1–100, default 20.

create_wallet_topup_link

Write

A Stripe checkout url to add funds to your wallet. Open it in a browser to pay; the balance updates automatically once the charge settles.

FieldTypeNotes
amountUsdnumberrequiredAmount to add in USD (e.g. 100 = $100). Minimum $1.
returnUrlstringoptionalWhere to send the browser after payment. Pass your own app URL (e.g. your success page) — if omitted it defaults to naytive.com.

Filing a visa, end to end

A typical agent conversation walks the user from "what can I get" to a filed, paid application. The server owns the rules; the agent just calls tools in order.

  1. Discover

    list_india_events → pick a visa and event. get_visa_details for pricing and the document checklist.

  2. Check the vault

    get_required_documents shows what the user already has stored versus what's still needed.

  3. Collect documents

    upload_passport and upload_photo for anything missing. Keep the returned documentId and photoId.

  4. Fund your wallet

    Once, up front: get_wallet_balance to check funds; create_wallet_topup_link if you need more. Your end-user pays you separately, through your own Stripe.

  5. File

    submit_application with the ids, dates, and event. Naytive's fee is debited from your wallet and the application is filed — it returns an applicationNumber already submitted.

  6. Track

    list_applications / check_application_status — the application reads submitted and moves through review.

Errors & limits

Tool errors come back as text content with isError: true and a plain message. A few things worth knowing before you build against it.

SituationWhat you get
Missing / invalid API key401 — set your Naytive X-API-Key header.
No / expired user token401 + WWW-Authenticate — the client re-runs sign-in.
Wallet balance too low on submit402 insufficient_wallet_balance with the fee and current balance — no application is created. Top up and retry.
Missing passport or photo on submitError: "Passport and photo are required for every traveller before filing."
File over 6 MBError: file too large.
  • Wallet debits are atomic & idempotent. A submitted application is charged once; a retry is never double-charged and the balance can't go negative. Top-ups are credited by the Stripe webhook, not from the client claiming success.
  • Documents belong to the signed-in user. A tool can only reference documents and applications owned by the authenticated account.
  • Staging Stripe is in test mode — use a test card at checkout.
Need production access, a rate-limit bump, or a new destination? Contact the Naytive team — production issues a separate endpoint and credentials.