@whiteintel/mcp-server
Advanced tools
+13
-0
| # Changelog | ||
| ## 0.6.0 — 2026-07-21 | ||
| - **Agents can pay.** Three new tools drive a one-off dossier purchase end-to-end: | ||
| `get_pricing` (the honest static price list + the machine buy-flow), | ||
| `buy_dossier` (guest Stripe Checkout — Standard €39 / Premium €99, packs of | ||
| 5/25 — returns a `checkout_url` a human or payment-capable agent completes) | ||
| and `claim_dossier` (redeems the paid `session_id` for a 90-day entity-scoped | ||
| access token; idempotent, `402 not_paid` until payment lands). | ||
| - `get_dossier` accepts an optional `token`: a claimed Standard token unlocks | ||
| the full multi-hop UBO chain + year-over-year financial history for that | ||
| entity; a Premium token additionally unlocks itemised assets (vessels, | ||
| aircraft, securities, real estate). 13 → 16 tools. | ||
| ## 0.5.1 — 2026-07-16 | ||
@@ -4,0 +17,0 @@ |
+162
-4
@@ -16,3 +16,8 @@ #!/usr/bin/env node | ||
| * (a wi_… key from whiteintel.dev → Settings → API keys) to authenticate as your | ||
| * plan and lift free-tier limits — it's forwarded as a Bearer token. Stdio transport. | ||
| * plan and lift free-tier limits — it's forwarded as a Bearer token. | ||
| * | ||
| * Agents can pay: get_pricing → buy_dossier (guest Stripe Checkout, no account) → | ||
| * claim_dossier (mints a 90-day entity-scoped token) → get_dossier with `token` | ||
| * unlocks the paid depth (full UBO chain + financial history; premium adds | ||
| * itemised assets). Stdio transport. | ||
| * Add to an MCP client (Claude Desktop, Cursor) with: | ||
@@ -108,2 +113,89 @@ * { "command": "npx", "args": ["-y", "@whiteintel/mcp-server"], | ||
| // ── One-off dossier checkout (the agent-payment path) ───────────────────────── | ||
| // buy_dossier / claim_dossier talk straight to the public `dossier-checkout` | ||
| // Supabase Edge Function — guest checkout, no WhiteIntel account needed (Stripe | ||
| // collects an email for delivery). The apikey below is the same PUBLIC anon | ||
| // (publishable) key the whiteintel.dev web app ships to every browser; it grants | ||
| // nothing by itself — payment authenticity is Stripe-side, inside the function. | ||
| const CHECKOUT_URL = "https://azmnkvjnelbdjnmukxll.supabase.co/functions/v1/dossier-checkout"; | ||
| const SUPABASE_ANON_KEY = | ||
| "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImF6bW5rdmpuZWxiZGpubXVreGxsIiwicm9sZSI6ImFub24iLCJpYXQiOjE3ODE4NzQzNjcsImV4cCI6MjA5NzQ1MDM2N30.36Qo7y8BKY2WUk829eZUE9kS_1daaG8p-pDo8Q4kPtk"; | ||
| async function checkoutPost(payload) { | ||
| const ctrl = new AbortController(); | ||
| const timer = setTimeout(() => ctrl.abort(), REQUEST_TIMEOUT_MS); | ||
| const headers = { accept: "application/json", "content-type": "application/json", apikey: SUPABASE_ANON_KEY, "user-agent": "whiteintel-mcp-server" }; | ||
| let res; | ||
| try { | ||
| res = await fetch(CHECKOUT_URL, { method: "POST", headers, body: JSON.stringify(payload), signal: ctrl.signal }); | ||
| } catch (e) { | ||
| throw new Error(e?.name === "AbortError" ? `request timed out after ${REQUEST_TIMEOUT_MS}ms` : `network error: ${e?.message ?? e}`); | ||
| } finally { | ||
| clearTimeout(timer); | ||
| } | ||
| const text = await res.text(); | ||
| let body; | ||
| try { body = JSON.parse(text); } catch { body = text; } | ||
| if (!res.ok) { | ||
| const detail = body && typeof body === "object" ? (body.error || body.detail || body.message) : null; | ||
| if (res.status >= 500 || res.status === 429) { | ||
| const ra = res.headers.get("retry-after"); | ||
| throw new Error(`The WhiteIntel checkout service is temporarily unavailable (${res.status}${detail ? `: ${detail}` : ""}).` + (ra ? ` Retry after ${ra}s.` : " Please retry shortly.")); | ||
| } | ||
| // 402 not_paid is the expected pre-payment claim answer — surface it verbatim | ||
| // so the agent knows to wait for the human to finish Checkout, not to retry blindly. | ||
| throw new Error(`The WhiteIntel checkout service rejected the request (${res.status}${detail ? `: ${detail}` : ""}).`); | ||
| } | ||
| return body; | ||
| } | ||
| // Static, honest price list — mirrors whiteintel.dev/pricing (the single source of | ||
| // truth for advertised figures). No network call; safe to invoke any time. | ||
| const PRICING = { | ||
| currency: "EUR", | ||
| pricing_url: "https://whiteintel.dev/pricing", | ||
| one_off_dossiers: { | ||
| standard: { | ||
| price: "€39", | ||
| unlocks: | ||
| "Full multi-hop UBO chain + year-over-year financial history for ONE entity (the free tier shows the first ownership hop and the latest financial period only).", | ||
| }, | ||
| premium: { | ||
| price: "€99", | ||
| unlocks: | ||
| "Everything in Standard, plus the itemised asset layer held via the ownership graph — vessels, aircraft, securities, real estate.", | ||
| }, | ||
| packs: { | ||
| "standard × 5": "€159 total", | ||
| "standard × 25": "€599 total", | ||
| "premium × 5": "€399 total", | ||
| note: "A pack grants report credits redeemable on any entity; there is no premium 25-pack.", | ||
| }, | ||
| token_validity: "Each claimed access token is scoped to one entity and stays valid for 90 days.", | ||
| }, | ||
| subscriptions: { | ||
| investigator: { | ||
| price: "€149/seat·mo", | ||
| includes: | ||
| "Unlimited full-depth ownership graph, 10 Premium dossiers/mo included, risk scores + watchlists, metered API/MCP credit allowance.", | ||
| }, | ||
| business: { | ||
| price: "€1,900/mo", | ||
| includes: | ||
| "Everything in Investigator with 3 seats, 75 Premium dossiers/mo included, monitoring + webhooks, larger API/MCP credit allowance.", | ||
| }, | ||
| note: | ||
| "Subscriptions are bought at whiteintel.dev/pricing (account required); the wi_ API key from Settings then lifts this MCP server's limits via WHITEINTEL_API_KEY.", | ||
| }, | ||
| api: { | ||
| metered: "Pay-as-you-go API from €0.20/call, tapering to €0.12 and €0.08/call at volume.", | ||
| }, | ||
| how_an_agent_buys: [ | ||
| "1. Call buy_dossier { tier, pack?, entity_id?, entity_name? } → returns a Stripe checkout_url.", | ||
| "2. Open the checkout_url so a human (or a payment-capable agent) completes payment — no WhiteIntel account needed; Stripe collects an email for delivery.", | ||
| "3. After payment Stripe redirects to whiteintel.dev with ?session_id=cs_… — call claim_dossier { session_id } to mint the access token (idempotent, safe to retry).", | ||
| "4. Pass the token to get_dossier { id, token } for the unlocked dossier JSON.", | ||
| ], | ||
| }; | ||
| const TOOLS = [ | ||
@@ -170,3 +262,3 @@ { | ||
| description: | ||
| "Build a structured, fully-cited intelligence dossier for one entity by id: identity with cross-source linked records (the same real-world entity resolved across ICIJ leaks, GLEIF, registries), ownership/control (direct owners, holdings, and the UBO chain), risk signals, and provenance on every layer. Every claim traces to a source URL. Use this for 'tell me everything about X'. Get the id from search_entities.", | ||
| "Build a structured, fully-cited intelligence dossier for one entity by id: identity with cross-source linked records (the same real-world entity resolved across ICIJ leaks, GLEIF, registries), ownership/control (direct owners, holdings, and the UBO chain), risk signals, and provenance on every layer. Every claim traces to a source URL. Use this for 'tell me everything about X'. Get the id from search_entities. Free tier shows the first ownership hop + latest financials; pass a one-off purchase `token` (from claim_dossier, see get_pricing / buy_dossier) or set WHITEINTEL_API_KEY to unlock the full depth.", | ||
| inputSchema: { | ||
@@ -176,6 +268,7 @@ type: "object", | ||
| id: { type: "string", maxLength: 80, description: "Entity id (from search_entities)." }, | ||
| token: { type: "string", maxLength: 200, description: "Optional one-off dossier access token (from claim_dossier or the delivery email). A standard token unlocks the full UBO chain + financial history for this entity; a premium token additionally unlocks itemised assets." }, | ||
| }, | ||
| required: ["id"], | ||
| }, | ||
| handler: (a) => apiGet(`/api/public/dossier/${encodeURIComponent(String(a.id).trim())}`), | ||
| handler: (a) => apiGet(`/api/public/dossier/${encodeURIComponent(String(a.id).trim())}${qs({ token: a.token })}`), | ||
| }, | ||
@@ -294,2 +387,67 @@ { | ||
| }, | ||
| // ── The agent-payment path: get_pricing → buy_dossier → claim_dossier → get_dossier(token) ── | ||
| { | ||
| name: "get_pricing", | ||
| description: | ||
| "WhiteIntel's price list plus the exact machine flow for buying access. One-off cited dossiers (Standard €39: full UBO chain + financial history · Premium €99: additionally itemised assets), bulk packs (5× / 25× at a discount), subscriptions (Investigator €149/seat·mo, Business €1,900/mo) and the metered API. Returns how_an_agent_buys — buy_dossier opens a Stripe Checkout, a human (or payment-capable agent) pays, claim_dossier mints the access token, and get_dossier with that token returns the unlocked report. Static data, no network call — check it before recommending a purchase.", | ||
| inputSchema: { type: "object", properties: {} }, | ||
| handler: () => PRICING, | ||
| }, | ||
| { | ||
| name: "buy_dossier", | ||
| description: | ||
| "Start a one-off dossier purchase via guest Stripe Checkout — no WhiteIntel account needed (Stripe collects an email for delivery). Pick a tier ('standard' €39: full UBO chain + financial history · 'premium' €99: additionally itemised assets — vessels, aircraft, securities, real estate) and optionally a bulk pack ('5' or '25' report credits; standard 5×€159 / 25×€599, premium 5×€399 — no premium 25-pack) plus the entity_id (from search_entities) the report is for. Returns checkout_url + next_steps: open the URL so payment can be completed, then feed the session_id from the post-payment redirect to claim_dossier for the access token. See get_pricing for the full price list.", | ||
| inputSchema: { | ||
| type: "object", | ||
| properties: { | ||
| tier: { type: "string", enum: ["standard", "premium"], description: "Dossier tier: standard (€39) or premium (€99, adds itemised assets)." }, | ||
| pack: { type: "string", enum: ["single", "5", "25"], description: "Optional bulk pack (default single). standard: 5=€159 / 25=€599 · premium: 5=€399 (no 25-pack)." }, | ||
| entity_id: { type: "string", maxLength: 80, description: "Optional entity id (from search_entities) the dossier should unlock." }, | ||
| entity_name: { type: "string", maxLength: 200, description: "Optional entity display name (shown in Checkout and the delivery email)." }, | ||
| }, | ||
| required: ["tier"], | ||
| }, | ||
| handler: async (a) => { | ||
| const tier = String(a.tier).trim(); | ||
| const pack = String(a.pack ?? "single").trim(); | ||
| if (tier === "premium" && pack === "25") { | ||
| throw new Error("The premium tier has no 25-pack — choose pack 'single' or '5' (see get_pricing)."); | ||
| } | ||
| const body = await checkoutPost({ | ||
| action: "create", | ||
| tier, | ||
| pack, | ||
| ...(a.entity_id ? { entity_id: String(a.entity_id).trim() } : {}), | ||
| ...(a.entity_name ? { entity_name: String(a.entity_name).trim() } : {}), | ||
| }); | ||
| return { | ||
| checkout_url: body?.url ?? null, | ||
| next_steps: [ | ||
| "Open checkout_url and complete the Stripe payment (a human can do this — no WhiteIntel account is required).", | ||
| "After payment Stripe redirects to whiteintel.dev with ?session_id=cs_… in the URL.", | ||
| "Call claim_dossier with that session_id to mint the entity-scoped access token (idempotent — safe to call again).", | ||
| "Pass the token to get_dossier { id, token } for the unlocked dossier JSON. The token is also emailed as a magic link and stays valid for 90 days.", | ||
| ], | ||
| }; | ||
| }, | ||
| }, | ||
| { | ||
| name: "claim_dossier", | ||
| description: | ||
| "Redeem a paid Stripe Checkout session for a dossier access token. Pass the session_id (cs_…) from the post-payment redirect after buy_dossier. Returns { token, entity_id, tier } — pass the token to get_dossier as its `token` input for the unlocked report (standard: full UBO chain + financial history · premium: additionally itemised assets). Idempotent: claiming the same session again returns the same grant, so it is safe to retry. Fails with 402 not_paid until the payment has actually completed — wait for the human to finish Checkout, then call again.", | ||
| inputSchema: { | ||
| type: "object", | ||
| properties: { | ||
| session_id: { type: "string", maxLength: 200, description: "Stripe Checkout session id (cs_…) from the success redirect." }, | ||
| }, | ||
| required: ["session_id"], | ||
| }, | ||
| handler: async (a) => { | ||
| const body = await checkoutPost({ action: "claim", session_id: String(a.session_id).trim() }); | ||
| return { | ||
| ...body, | ||
| note: "Pass this token to get_dossier { id: entity_id, token } for the unlocked dossier JSON. Keep it private — it unlocks the paid report and stays valid for 90 days.", | ||
| }; | ||
| }, | ||
| }, | ||
| ]; | ||
@@ -300,3 +458,3 @@ | ||
| const server = new Server( | ||
| { name: "whiteintel-mcp-server", version: "0.5.1" }, | ||
| { name: "whiteintel-mcp-server", version: "0.6.0" }, | ||
| { capabilities: { tools: {} } }, | ||
@@ -303,0 +461,0 @@ ); |
+1
-1
| { | ||
| "name": "@whiteintel/mcp-server", | ||
| "version": "0.5.1", | ||
| "version": "0.6.0", | ||
| "description": "Model Context Protocol server for WhiteIntel — corporate & offshore ownership intelligence. Look up companies, search entities (companies + people), screen sanctions, and trace ownership chains to the ultimate beneficial owner. Freemium: anonymous free tier, or set WHITEINTEL_API_KEY for your plan.", | ||
@@ -5,0 +5,0 @@ "type": "module", |
+23
-2
@@ -5,3 +5,4 @@ # @whiteintel/mcp-server | ||
| [](https://github.com/Hei33enberg/whiteintel-mcp-server/actions/workflows/ci.yml) | ||
| [](LICENSE) | ||
| [](LICENSE) | ||
| [](https://modelcontextprotocol.io) | ||
@@ -53,3 +54,3 @@ **Trace ownership. Expose the network.** A [Model Context Protocol](https://modelcontextprotocol.io) | ||
| | `get_entity` | Full record for one entity + its direct relationships. | | ||
| | `get_dossier` | Structured, fully-cited dossier: cross-source identity, ownership/UBO chain, risk signals, provenance. | | ||
| | `get_dossier` | Structured, fully-cited dossier: cross-source identity, ownership/UBO chain, risk signals, provenance. Optional `token` (from `claim_dossier`) unlocks the paid depth. | | ||
| | `trace_ownership_path` | Walk ownership upward from a root entity to the ultimate beneficial owner. | | ||
@@ -59,3 +60,23 @@ | `lookup_by_identifier` | Resolve an entity by a strong id — LEI, OFAC/EU/UN/UK sanctions id, UEN, NIP, SEC CIK, KRS, GB-COH. | | ||
| | `check_offshore_exposure` | Walk the ownership chain and flag sanctioned + secrecy-jurisdiction hops (offshore-layering lead). | | ||
| | `get_company_details` | UK register detail: registered address, status, type, incorporation date, SIC codes + the filing/compliance layer (accounts, overdue flags, charges, former names). | | ||
| | `get_financials` | Filed UK financials year-over-year (turnover, profit, net assets, cash, employees) from Companies House iXBRL accounts. | | ||
| | `get_pulse` | The live corpus activity feed — recent ownership/control changes, newest first, each sourced; optional `since` cursor to stream only what's new. | | ||
| | `resolve` | Batch-resolve a list of names or `scheme:value` ids → canonical entity ids + confidence, in one call (enrich a whole supplier / portfolio list). | | ||
| | `get_pricing` | The honest price list (one-off dossiers, packs, subscriptions, metered API) + the exact machine flow for buying access. Static, no network call. | | ||
| | `buy_dossier` | Start a one-off dossier purchase via guest Stripe Checkout (Standard €39 / Premium €99, optional 5/25 packs) → returns a `checkout_url`. | | ||
| | `claim_dossier` | Redeem a paid Checkout session (`session_id`) for a 90-day entity-scoped access `token`. Idempotent. | | ||
| All lookup tools are **read-only**; the only side-effectful tools are `buy_dossier` (opens a Stripe Checkout — money moves only when a human completes it) and `claim_dossier` (redeems an already-paid session). Ids flow between tools: `search_entities` / `search_companies` / `resolve` / `lookup_by_identifier` return ids → feed them to `get_dossier` / `trace_ownership_path` / `get_sanctions`. | ||
| ## Agents can pay | ||
| An agent can buy the paid depth of a dossier end-to-end, no WhiteIntel account needed: | ||
| 1. **`buy_dossier`** `{ tier: "standard" | "premium", entity_id }` → returns a Stripe `checkout_url`. Standard (€39) unlocks the full multi-hop UBO chain + year-over-year financial history; Premium (€99) additionally unlocks itemised assets (vessels, aircraft, securities, real estate). Packs of 5/25 grant reusable report credits. | ||
| 2. A **human (or payment-capable agent) completes payment** at the `checkout_url` — Stripe collects an email and redirects back to whiteintel.dev with `?session_id=cs_…`. | ||
| 3. **`claim_dossier`** `{ session_id }` → `{ token, entity_id, tier }`. Idempotent; returns `402 not_paid` until payment completes. | ||
| 4. **`get_dossier`** `{ id, token }` → the unlocked, fully-cited dossier JSON. Tokens are entity-scoped and valid for 90 days. | ||
| Check **`get_pricing`** first — it returns the full price list plus this flow in machine-readable form. | ||
| ## Data & honesty | ||
@@ -62,0 +83,0 @@ |
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
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.
39932
51.99%524
44.35%100
26.58%5
25%3
50%