MCP server
Tools
The nine Sprouts tools — what each one is for, what it costs, which scope it needs — plus how to narrow the set and the ChatGPT compatibility pair.
Nine tools cover search, look-alikes, enrichment, the relationship graph, deep research, coverage, usage, feedback and top-up. All nine are enabled by default. You never have to opt anything in: ?tools= only ever narrows the set.
Why all nine are on by default
That is a reversal of how this server shipped, and the reason explains the cost you are being charged.
Every tool schema sits in the model's context on every request whether it is used or not, so a lean default set really does keep prompts smaller and tool selection sharper. What that reasoning left out is the cost of a tool nobody can find. Nothing in a session mentions that ?tools= exists, while the platform guide documents the entity routes in full. So a model reading the guide, seeing two tools, and concluding "the API has enrichment and this server does not expose it" was reasoning correctly from everything available to it.
A capability the caller cannot discover costs more than a schema.
The nine#
| Tool | Use it when | Cost | Scope |
|---|---|---|---|
sprouts_search | You are describing who to find | 0.5 (Basic) or 0.595 (AI) for the first 10 results, then 0.08 (Basic) or 0.085 (AI) per extra result | dsp.search.read |
sprouts_similar | You can name example companies | 2 for the first 10 results, then 1 per next 10 | dsp.search.read |
sprouts_entity_lookup | You already hold identifiers | 1 per record found; misses are free | dsp.entities.read |
sprouts_relationships | The question has two sides | 2 for the first 10 results, then 1 per next 10; shared institutions 2 flat | dsp.search.read |
sprouts_research_run | One search cannot answer it | 1.02 to 85 credits per run, by effort, charged only if the run succeeds | dsp.agents.write to start or cancel a run; dsp.agents.read is enough to resume and list |
sprouts_coverage | "What do you actually hold?" | Free | dsp.search.read |
sprouts_usage | "What has this cost?" / "show those results again" | Free | dsp.usage.read |
sprouts_feedback | A result was wrong, missing or stale | Free | dsp.search.read or dsp.usage.read |
sprouts_top_up | Out of credits, or you ask to buy more | Free: opens a page you pay on | dsp.usage.read |
Picking between them#
The server tells the model this before its first call, because the expensive mistakes are all the same mistake: reaching for a specialised tool when the general one was right, or the reverse. Pick by the shape of the question, not by keyword:
- Describing who to find ("payments companies in Germany", "security leaders at Acme") →
sprouts_search. This is the default, and it is never the wrong first guess. "Who works at X" is a search withcategory: "person", not a relationship question. - Naming example companies to find more like ("more like Adyen and Checkout") →
sprouts_similar. Do not paraphrase the examples into a description; that throws away the signal. - Holding identifiers already (domains, LinkedIn URLs, record ids) →
sprouts_entity_lookup. Do not search for something you can look up. - A question with two sides ("who at Adyen do we know from Stripe", "who can introduce me") →
sprouts_relationships. One company and no second side is a person search. - Several steps, or several corpora joined (per-row criteria to check, named enrichment columns to fill) →
sprouts_research_run. It costs credits and takes minutes, so never use it as a slower search. - Out of credits, or asked to buy more →
sprouts_top_up. Never speculatively, and never twice in a row.
Search#
sprouts_search searches the corpus over nine categories: companies, people, patents, news articles, trends, market reports, funding rounds, research papers and job openings.
query(natural language) is the primary interface.filtersis a vetted override, not a place to restate the query.mode: "fast"is the default, and it does no query parsing: a constraint stated only in words (a country, a headcount, an industry) is ignored, and the results come back the wrong shape rather than empty. Usefastwhen the constraints are infiltersor the query is a literal string. Usemode: "auto"whenever the constraints live in the sentence: it costs more and takes around 12 seconds rather than one or two, because a model reads the query into filters.- A page is 10 rows unless
limit(1–100) says otherwise: the API's own default, the rows a search's base price covers, and the same page size every paged tool sends. A later page costs only the results it adds.
The category enum is built from live coverage, not from a hard-coded list. The tool advertises only what this deployment can actually answer, so a category absent from the schema is not indexed here yet. It is also why the set can change under a running session: the server emits tools/list_changed when it really changes, and only then.
Three things in the response change what an answer means. They are surfaced as prose rather than as codes to look up:
resolved_searchshows how the query was interpreted. If the inferred filters are wrong, set them explicitly and call again rather than rewording.- A total marked as an estimate is a floor. It is reported as "N+", never as a bare N.
- The caveats block names anything that limited the answer. "Nothing degraded" means it was checked.
Similar Companies#
sprouts_similar takes 1–10 anchor companies as domains, LinkedIn URLs or names, and returns companies that resemble them.
combine: "and"reads as "like all of these together";combine: "or"as "like any of them".- Narrowing
filtersapply on top.
The response carries the anchors you sent, with their weights, including any sent with weight: 0, which therefore did not count. It does not say which anchors resolved, because the API does not report that. If some fail, the call still succeeds on the rest, so a result list is never proof that it matches every anchor.
Record Lookup#
sprouts_entity_lookup is the enrichment tool. It returns full records for identifiers you already hold, in batch, across nine categories behind one category enum.
- Misses are explained, not dropped. A batch that finds nine of ten comes back saying which one it did not find and why. A hash that is not in the index reads differently from a domain that resolved to nothing, and both read differently from a category this deployment does not serve.
- Batch ceilings are enforced locally, so an oversized request is refused before it is billed rather than truncated after.
Relationships#
sprouts_relationships walks the affiliation graph (470M edges over companies and people) and answers questions with two sides:
relation | What it answers |
|---|---|
between_companies | Who bridges two companies, and how |
via_institution | Who connects through a shared employer or school |
shared_institutions | The bridge list alone: institutions with per-side counts, no people and no paging |
reach | The one-person question: who at a target company this person can reach, and by what path |
There is also a natural-language query mode, in which the planner derives the structure and returns it so the model can check and correct it. Send no relation alongside a query.
Every row carries match_confidence and the basis of the connection. That matters more here than anywhere else in the platform: a shared employer with zero months of overlap is a failed constraint, not a curiosity, and a name match is not an established shared history.
Research Agent#
sprouts_research_run is one tool for the whole lifecycle of an asynchronous run (submit, resume, page, cancel), keyed by run_id. Use it for briefs a single search cannot answer: per-row criteria to verify, named enrichment columns to fill, exclusions to apply. It returns rows plus coverage and cited insights.
- Effort tiers are
minimal(1.02 credits),low(2.125),medium(8.5, the default),high(42.5) andxhigh(85).autoholds 85 and is charged at the effort it runs, never more. A run takes minutes rather than seconds. high,xhighandautoalways ask for confirmation before spending, whatever the session's call count. See Limits.- Submitting holds the price; success pays it. Submitting places a hold for the tier's price. The charge is settled the first time the finished run is read, which the tool does itself when it sees the run finish. A run that fails or is cancelled is charged nothing, and its hold is released. Resuming, listing, paging and cancelling are free calls in themselves.
- A long run comes back as
status: running. Each call waits up towait_seconds(default 25, at most 55) for the run. A run that outlives the wait returns itsrun_id, and calling again with thatrun_idkeeps waiting. That is the normal flow, not a failure. Never submit the same question again while a run is live: that is a second run and a second charge. - Collect what you start. The hold lasts 35 minutes from submission. If nobody reads the finished run within that time, it is never charged and reports
credits_charged: 0. Until a run has settled,credits_chargedisnull, not0. - Results come back 10 rows a page by default (
limit, 1–100). Ask for more in one call only if you mean to read them all; the next page costs nothing. - Lost a
run_id?list: truereturns your runs, free. Check it before starting a run that may already exist.
Coverage, usage and feedback#
These three are free and never count against the spend cap.
sprouts_coverage reports what the index holds per corpus, plus not_in_index[]: the gaps, in plain language. The gaps are published deliberately. They are the part that answers "can we actually deliver this?" before anyone promises it.
sprouts_usage reports:
- the credit balance
- this key's spend, bucketed by hour, day, month or in total
- the caller's own prior runs, including the stored rows a past search returned
Those rows replay without re-billing, which makes "show me those results again" free rather than a second search. Run history pages 10 at a time by default (limit, 1–100), and paging it is free. When the balance is at or below the server's low-balance line (100 credits by default), the answer says so, and asks the model to mention it to you rather than open a top-up page unprompted.
sprouts_feedback reports a result that was wrong, missing, stale or badly ordered, against the request_id of the response in question. Reporting a bad result costs nothing, by design: if it cost anything, nobody would report. It is a report of what a user actually said, not a model's own judgement of the data, and an empty result is not itself a defect. "We do not hold that" is often the correct answer.
Top-up#
sprouts_top_up is how you buy credits without leaving the conversation. It takes no arguments: there is no amount to name, because you choose it in your browser, and no account, because that comes from the credential. Nothing the model sends can change who is charged or how much.
It charges nothing itself:
- It asks the API for a top-up link (
POST /v1/billing/top-up/intents, a free route) and hands it over. - The link opens the dashboard, where you sign in and pay. The purchase is made by that browser session and checked against your own permission to manage credits. An API key can ask for a link, but cannot buy anything.
- The id in the link authorises nothing either. It only answers "has this been paid yet?", which is what makes it safe to pass through a chat transcript.
- A link stays live for about 15 minutes.
How the link reaches you depends on your host:
| Your host | What happens |
|---|---|
| Supports URL-mode elicitation | The host shows its own consent dialog naming the domain, and the client is told when the payment lands |
| Does not | The link comes back as text, and the assistant gives it to you. The assistant is not notified when you have paid: tell it once you have, and it checks the balance again with sprouts_usage |
Either way the server watches the link through GET /v1/billing/top-up/intents/{topup_id} (also free) until it is paid or expires, and refreshes the balance it reports once the payment lands.
Other outcomes
Other outcomes are stated rather than left to be guessed:
- A declined dialog opens nothing and charges nothing.
- A deployment that cannot prepare a page says to add credits from the dashboard instead.
- A deployment can switch the tool off. It is then missing from
tools/list, and running out of credits reads exactly as it did before top-up existed.
When it runs, and why your host may ask first
It is not gated on your balance: buying ahead of a large research run is an ordinary thing to want.
It is the one free tool not marked read-only, because each call creates a short-lived record on the Sprouts side, so your host may ask before running it.
The model is told not to call it speculatively, not to call it twice in a row, and, after you pay, to retry only the call that failed, and only once.
Narrowing the set#
tools= on the URL replaces the default set with exactly the names you list, so a research-only agent can stop paying context for the other eight:
https://dashboard.sproutsdata.ai/mcp?client=cursor&tools=sprouts_search,sprouts_entity_lookupOn a local (stdio) server the same thing is an environment variable:
SPROUTS_MCP_TOOLS=sprouts_search,sprouts_entity_lookupA misspelled tool name is reported rather than silently ignored. A typo that quietly yields a different set is a support ticket that looks like a server bug.
ChatGPT compatibility#
ChatGPT's connector framework expects two unprefixed tools with fixed shapes, so the server also serves a compatibility pair. It is opt-in only, via ?tools=search,fetch, and never part of any default set:
searchtakes aqueryand returns{ results: [{ id, title, url }] }for citation.fetchtakes one of thoseidvalues and returns the full record as{ id, title, text, url, metadata }.
Ids are category:value pairs, such as company:acme.com. A citation url is always a real company domain or LinkedIn profile, or empty. Never fabricated.
The pair stays out of the standard set because the names are unprefixed: in a client that flattens tool namespaces, a bare search would collide with another server's. These two are also never rendered as cards. Their structuredContent is a fixed contract that ChatGPT parses strictly, and widening it would break the parse.