Skip to main content
20% off 3 months · code LAUNCH20 · until 31 October

Look up your contacts from Claude Code

A contact is one person across everything Launch knows about them. With the MCP server connected, the agent can answer questions that otherwise mean exporting three CSV files and matching emails by hand.

Claude Code connects to remote MCP servers over HTTP directly. One command registers the server under the name nordva.

Setup

You need a secret key (nv_live_…) from Dashboard → API keys.

01Register the server

claude mcp add --transport http nordva https://mcp.nordva.dev \
  --header "Authorization: Bearer nv_live_..."

Run it in your project's folder. The name comes before the URL. By default the server is added for that folder only and stored outside the repository; add --scope user to make it available in every project. Claude Code loads servers when it starts, so quit and start it again in that folder; /mcp lists the Nordva tools.

02Or share it with the team without sharing the key

.mcp.json

{
  "mcpServers": {
    "nordva": {
      "type": "http",
      "url": "https://mcp.nordva.dev",
      "headers": {
        "Authorization": "Bearer ${NORDVA_API_KEY}"
      }
    }
  }
}

Claude Code expands ${NORDVA_API_KEY} from the environment, so the file can be committed while each developer keeps their own key in their shell profile.

03Check the connection

Run claude mcp list, or type /mcp inside a session. nordva should show as connected. Then ask Claude to run setup_check: it reports the project, the plan and which features are unlocked.

Then ask Claude Code

  • Which of my waitlist signups are paying customers now?
  • What has jane@example.com asked for, and is she paying?
  • List paying customers who came from Product Hunt.
  • Mark ada@example.com as in talks and note that she wants SSO.
  • Export everyone who agreed to marketing email as a CSV.

For “Which paying customers left feedback?” Claude Code calls list_contacts with:

{
  "paying": true,
  "has_feedback": true,
  "limit": 10
}

Returned: Contacts with id, email, source, waitlist status, subscriber flag, feedback count, Stripe status, plan, MRR, stage, details and consents, plus a cursor when there are more.

Contacts tools and arguments

list_contacts

Read-only

List people across waitlist, feedback, subscribers and payments

payingoptionalboolean
has_feedbackoptionalboolean
statusoptional"waiting" | "invited" | "unsubscribed"
sourceoptionalstring, max 255
stageoptional"potential" | "in_talks" | "customer" | "recurring" | "not_a_fit" | "inactive"
qoptionalstring, max 254Part of an email address.
consentoptionalstringOnly people who have granted this consent now, e.g. "email_marketing", or a built-in: "waitlist" and "changelog".
detailoptionalstring, max 250"name" for people who have that detail, or "name=value" for that value (case-insensitive), e.g. "role=founder".
limitoptionalnumber, 1–100
cursoroptionalstring

get_contact

Read-only

Get one person across every primitive

contact_idrequiredstring, max 64Contact id, e.g. "ct_...".

get_contact_journey

Read-onlyBuilder

One person's visits before they signed up or paid

contact_idrequiredstring, max 64

update_contact

Set a contact's stage, note, details or consents

contact_idrequiredstring, max 64
stageoptional"potential" | "in_talks" | "customer" | "recurring" | "not_a_fit" | "inactive"
noteoptionalstring, max 5,000
detailsoptionalobjectName to value; null removes. Reuse names from list_contact_fields, e.g. {"role": "founder"}.
consentsoptionalobjectPurpose to true (granted) or false (withdrawn), only as the person said, e.g. {"email_marketing": true}.

list_contact_fields

Read-only

List the detail names and consents in use on contacts

No arguments.

export_contacts

Read-onlyIndie and Builder

Export contacts as a CSV download link

consentoptionalstringOnly people who have granted this consent now, e.g. "email_marketing", or a built-in: "waitlist" and "changelog".
detailoptionalstring, max 250"name" for people who have that detail, or "name=value" for that value (case-insensitive), e.g. "role=founder".
payingoptionalboolean
has_feedbackoptionalboolean
statusoptional"waiting" | "invited" | "unsubscribed"
sourceoptionalstring, max 255
stageoptional"potential" | "in_talks" | "customer" | "recurring" | "not_a_fit" | "inactive"
qoptionalstring, max 254Part of an email address.

Behaviour worth knowing

  • People are matched on normalised email: lowercase, +alias removed, dots ignored on Gmail.
  • update_contact changes the stage, the note, and the person's details and consents. It cannot change an email, a waitlist status or anything in Stripe, and a new note replaces the old one.
  • Details are named values about a person (role, company size); consents are permissions they gave (email_marketing), granted or withdrawn, with when and how. The agent is told to reuse the names list_contact_fields returns and to record a consent only when the person gave it.
  • export_contacts returns a CSV download link for the same filters as list_contacts, for example everyone who granted email_marketing. The link works for 15 minutes. Indie plan and up.
  • It works without Stripe connected; every contact then has Stripe status none.
  • On the Free plan only waitlist people are listed, in a single page.
  • A contact is removed when the person no longer exists in any source, for example after their signup is deleted.
  • Tools appear to the model as mcp__nordva__<tool>, which is the form to use in permission allowlists.
  • Read-only tools are marked as such by the server; Claude Code still asks before the first call to each tool unless you allow it.