Agents and Slack

    MCP server

    Connect Claude, Cursor, VS Code, Codex or any other MCP client to Zuse, and ask about licensed professionals in your own words.


    MCP is a connection that lets AI assistants use Zuse's tools directly. It stands for Model Context Protocol: a standard way for an AI application, such as Claude, Cursor, VS Code or Codex, to call outside tools. Once connected, you ask the assistant a question and it looks people up in Zuse for you.

    Zuse runs a hosted server that works in any MCP client that can send a header:

    text
    https://mcp.zuse.live/mcp

    Three things to know before you start:

    • It signs in with an API key. Create one in the console. The connection belongs to the team the key was made in.
    • There is nothing separate to buy. MCP is not its own product or plan. What the assistant does through the connection comes out of that team's credit, at the same prices as the REST API and the console.
    • The same limits apply. Tool calls count towards the team's rate limits, and each one appears in the console's Request history with the source MCP.

    Install

    Replace YOUR_ZUSE_KEY with a key from the console.

    Claude Code

    bash
    claude mcp add --transport http zuse https://mcp.zuse.live/mcp \
      --header "Authorization: Bearer YOUR_ZUSE_KEY"

    Start a new session and ask for something Zuse knows. /mcp lists the servers that are connected.

    Claude Desktop

    Open Settings, then Developer, then Edit Config, and add Zuse. Claude Desktop reaches a server that signs in with a key through a small bridge, which needs Node.js on the computer:

    json
    {
      "mcpServers": {
        "zuse": {
          "command": "npx",
          "args": ["-y", "mcp-remote", "https://mcp.zuse.live/mcp", "--header", "Authorization:${ZUSE_AUTH}"],
          "env": { "ZUSE_AUTH": "Bearer YOUR_ZUSE_KEY" }
        }
      }
    }

    Restart Claude Desktop. The "Add connector" screen in Claude on the web and in Claude Desktop expects a sign-in in the browser, which Zuse does not offer yet, so Zuse cannot be added there.

    Cursor

    Add Zuse to ~/.cursor/mcp.json (Cursor Settings, then MCP, then Add new MCP server):

    json
    {
      "mcpServers": {
        "zuse": {
          "url": "https://mcp.zuse.live/mcp",
          "headers": { "Authorization": "Bearer YOUR_ZUSE_KEY" }
        }
      }
    }

    VS Code

    Create .vscode/mcp.json in your project. VS Code asks for the key the first time the server starts and stores it for you, so the key is not written into a file you might commit:

    json
    {
      "servers": {
        "zuse": {
          "type": "http",
          "url": "https://mcp.zuse.live/mcp",
          "headers": { "Authorization": "Bearer ${input:zuse-key}" }
        }
      },
      "inputs": [
        { "id": "zuse-key", "type": "promptString", "description": "Zuse API key", "password": true }
      ]
    }

    Codex

    Put the key in your environment as ZUSE_API_KEY, then add Zuse to ~/.codex/config.toml:

    toml
    [mcp_servers.zuse]
    url = "https://mcp.zuse.live/mcp"
    bearer_token_env_var = "ZUSE_API_KEY"

    ChatGPT's own connector screen expects a sign-in in the browser, which Zuse does not offer yet. Codex, with the key as above, works today.

    Other clients

    Any client that can reach a remote MCP server over streamable HTTP and send a header will work. Most use this shape:

    json
    {
      "mcpServers": {
        "zuse": {
          "type": "http",
          "url": "https://mcp.zuse.live/mcp",
          "headers": { "Authorization": "Bearer YOUR_ZUSE_KEY" }
        }
      }
    }
    ClientWhere to add itWhat it calls the address
    Windsurf~/.codeium/windsurf/mcp_config.json, under mcpServersserverUrl
    Gemini CLI~/.gemini/settings.json, under mcpServershttpUrl
    Zedsettings.json, under context_serversurl

    Clients change where their settings live. If one of these has moved, the client's own documentation is the place to check. A client that only runs local servers can use the bridge shown under Claude Desktop.

    Authentication

    Way inStatusHow
    API keyAvailableSend Authorization: Bearer YOUR_ZUSE_KEY on every request. Usage belongs to the key's team.
    Sign in in the browser (OAuth)Not yetNeeded by the connector screens in Claude and ChatGPT on the web. Planned.
    No keyNot offeredEvery request is tied to a team, so there is no anonymous use.

    A key is shown once, when it is made. If one is exposed, revoke it in the console: it stops working on the next request.

    Tools

    ToolDoesArguments
    source_professionalsLists licensed professionals, or veterinary practices, near a location, a page at a time.A location: postal_code, or latitude and longitude together. Optionally radius_miles, profession (veterinarian, vet_tech, vet_assistant, or premises for practices), jurisdiction (the licensing state, such as NJ), certification (any, vts, or a specialty such as Avian), min_years_licensed, max_years_licensed, practice_type, active_only, sort, limit (10 if omitted, at most 50), cursor
    verify_licenseChecks a person against the board of record, by name, by license number, or both.name or license_number (a number alone finds whoever holds it), and optionally jurisdiction, profession (veterinarian, vet_tech or vet_assistant), limit, cursor
    enrich_personReturns cited, web-derived context for one person: where they work, education, public contact details.first_name, last_name, and optionally city, state, title, license_number, license_state, refresh
    research_briefWrites intro notes on one person: a summary, recent changes, and talking points for a first message.first_name, last_name, and optionally city, state, title, current_employer, license_number, license_state, refresh
    find_people_on_webFinds people in a role no board licenses (groomers, receptionists, kennel staff, practice managers) on their public profiles near a ZIP code.role, postal_code, and optionally radius_miles (25 if omitted), include_contacts
    find_clinicsLists veterinary clinics near a location (state boards' premises registers, practice managers' clinics, OpenStreetMap), a page at a time.A location: postal_code, or latitude and longitude together. Optionally radius_miles, kind (plain words: emergency, mobile, VCA), sort, limit (10 if omitted, at most 50), cursor
    get_clinicOne clinic with the people tied to it: the veterinarian in charge, practice managers, and the vets and techs on record at its address.clinic (a ref from find_clinics)
    research_clinicResearches one clinic's owner, team, phone, email, website and hours on the public web.clinic, and optionally refresh
    find_contactFinds one person's email and phone (People Data Labs), cross-checked against what is known about them.first_name, last_name, and optionally city, state, postal_code, linkedin_url, current_employer, email, phone, license_number, license_state, refresh

    The tools read the same data as the v2 resources and are metered the same way. Their results are flat JSON rather than the v2 envelope, with dates as the board publishes them (08-31-2027).

    Each tool's JSON Schema is published by the server in tools/list, with a description on every argument, the values an argument may take, a display name (title) and behaviour hints (annotations): the two lookups are marked read-only, and the research, web search and contact tools are marked as reaching the open web.

    The server accepts exactly what the schema lists. An argument it does not have (radius for radius_miles, say), a value outside the listed ones, a search with no location, or half a coordinate pair comes back as invalid_arguments with the reason, and is not charged. It is never answered with an empty result, because an assistant would repeat "nobody found" as a fact.

    Research is kept

    What enrich_person, research_brief, find_contact and research_clinic find is kept on your team's records. When the assistant asks about a person your team has already researched, on any channel, the result comes back with from_records: true and cost_usd: 0, and nothing is researched again. refresh: true runs it again, at the usual price; the tool descriptions tell the model to use it only when you ask for new research.

    What to ask

    One conversation can take an opening from "who is out there" to a first message. You speak plainly; the assistant picks the tool.

    You sayThe assistant callsWhat comes back
    "Who are the licensed vet techs within 10 miles of 90013? Show me the ten nearest."source_professionalsNames, credentials, distance and years licensed. One request.
    "Is the third one's license active, and when does it expire?"verify_licenseThe board record, which the assistant can state as fact and attribute to the board.
    "Find out where the first three work now and how to reach them."enrich_person, three timesEmployer, education and public contact details, with the pages they came from. Kept on your team's records, so the same question tomorrow is free.
    "Write what I should say to the second one in a first message."research_briefNotes the assistant drafts from. Read the draft before you send it: it is written from public web pages.
    "Find dog groomers within 15 miles of 85281."find_people_on_webNamed groomers from their own public profiles, with title, employer and town. People with veterinary experience come first.
    "Which emergency clinics are within 10 miles of 85004?"find_clinicsClinics nearest first, each with its kind, address and, where known, phone and website.
    "Who owns the second one, and who works there?"research_clinicThe owner, medical director and team from the clinic's own pages, each matched to a board licence where one fits.
    "Get me a phone and personal email for the first one."find_contactEvery email and phone on record, each marked recommended, work, older or lower confidence, and how confident the contact match is.

    Every result carries cost_usd and credit_remaining_usd, so you can ask the assistant what a step cost and what is left.

    Troubleshooting

    What you seeWhat it meansWhat to do
    401, missing or invalid API keyThe header is absent or wrong, or the key was revoked, or its owner was removed from the team.The header must read Authorization: Bearer followed by the whole key, which starts with zuse_sk_. Create a new key if needed.
    402, credit used upThe team has spent its credit.Top up in Billing ($10, $25, $50 or any amount); a practice's plan also adds $10 of credit each month. Reading back research your team already has still works.
    402, no planA practice account has no live plan.Start the practice plan from Billing (first month free).
    429, too many requestsThe team reached a rate limit.The answer carries retry_after_seconds. See Rate limits.
    The tools do not appearMost clients read their configuration only when they start.Save the file, then restart the client or open a new session.
    The client asks you to sign inIt is trying a browser sign-in, which Zuse does not offer yet.Use a way that sends the API key as a header: Claude Code, Cursor, VS Code, Codex, or the bridge shown under Claude Desktop.
    403, origin not allowedThe request came from a web page on a site Zuse does not know.The MCP server is for assistants and servers, not for calling from a browser page.

    Results

    A tool call returns its result twice: as text in content[0].text, and as an object in structuredContent. cost_usd and credit_remaining_usd are on every metered result.

    json
    {
      "content": [{ "type": "text", "text": "{\"classification\": \"found\", ...}" }],
      "structuredContent": { "classification": "found", "matches": [], "cost_usd": 0.02, "credit_remaining_usd": 9.98 },
      "isError": false
    }

    When a call fails because of its arguments, the tool returns isError: true with an explanation the model can act on, instead of a protocol error:

    json
    {
      "structuredContent": {
        "error": "invalid_arguments",
        "detail": [{ "type": "missing", "loc": ["first_name"], "msg": "Field required" }]
      },
      "isError": true
    }

    A misnamed argument also lists the ones the tool does have:

    json
    {
      "structuredContent": {
        "error": "invalid_arguments",
        "detail": [{ "type": "unknown_argument", "loc": ["radius"], "msg": "source_professionals has no argument called radius." }],
        "arguments": ["active_only", "cursor", "latitude", "limit", "longitude", "max_years_licensed", "min_years_licensed", "postal_code", "practice_type", "profession", "radius_miles", "sort"]
      },
      "isError": true
    }

    Paging

    source_professionals returns ten people unless limit asks for more (up to 100). Each answer carries total (everyone who matches), remaining (how many come after this page), has_more and next_cursor. The tool description tells the model to say how many remain and offer the next ten, so in practice you see ten people and are asked whether you want more. When you say yes, the agent calls the tool again with the same arguments plus cursor.

    Each call is charged by the number of people it returns: the base price covers the first ten, so a page of ten is the base price with nothing added. Asking for a longer list in one call costs the base price plus the fee for each record after the tenth. See Pricing and metering.

    The REST API is unchanged: GET /v2/professionals returns 50 a page unless limit says otherwise.

    Limits and errors

    A tool call that runs into a limit, an empty credit balance, or a restriction comes back as isError: true with the HTTP status and the same detail the REST API gives, including retry_after_seconds for a rate limit:

    json
    {
      "structuredContent": {
        "error": "request_failed",
        "status": 429,
        "detail": { "error": "rate_limited", "message": "Too many source calls in a minute. Wait 24 seconds and retry.", "retry_after_seconds": 24 }
      },
      "isError": true
    }

    The limits are the ones in Rate limits and retries, shared with the REST API.

    Check the connection

    bash
    curl https://mcp.zuse.live/mcp \
      -H "Authorization: Bearer $ZUSE_KEY" \
      -H "Content-Type: application/json" \
      -d '{ "jsonrpc": "2.0", "id": 1, "method": "tools/list" }'

    Protocol details

    • The server is stateless. Each POST carries one JSON-RPC message and is answered with application/json. There is no session to initialize or resume.
    • Supported protocol versions: 2025-06-18, 2025-03-26, 2024-11-05.
    • Supported methods: initialize, ping, tools/list, tools/call.
    • GET /mcp returns 405: the server does not open a server-to-client stream.
    • A missing or invalid key returns HTTP 401 before any JSON-RPC handling.

    Billing

    Tool calls are metered exactly like the REST endpoints they map to. initialize, ping, and tools/list are free. A result read from your team's records (from_records: true) is free too. See Pricing and metering.

    Guidance for agents

    verify_license answers from the board of record and can be stated as fact, with the board named as the source. find_people_on_web lists people from their public profiles: never call them licensed. find_contact comes from People Data Labs: use personal_email, work_email and the mobile phone for outreach, and when confidence is check, say the record may be someone else. enrich_person and research_brief are web-derived: present them as reported context, cite the source URLs they return, and do not describe them as verified. When a result has from_records: true, say when it was researched (researched_at or written_at) and offer to refresh it rather than refreshing unasked.