Inven MCP Server
Description
The Inven MCP Server gives AI assistants (Claude, Cursor, ChatGPT, and others) direct access to Inven's database of over 20 million private companies, investors, public companies, and M&A / funding deals.
Through natural language alone you can search for companies, retrieve structured financial and operational data, explore your saved Inven lists, and look up detailed profiles for people and deals — all without leaving your AI client.
Features
- Company search: Translate a natural language description into a structured search across 20M+ private companies. Filter by industry, geography, headcount, revenue, funding stage, ownership type, founding year, and dozens more criteria.
- Investor search: Discover VCs, PE firms, angels, and family offices by geography, stage focus, portfolio themes, and fund type.
- Public company search: Build a multiples universe of listed companies by sector, exchange, size, and valuation.
- Deal search: Find M&A deals and funding rounds by deal type, size, date, acquirer/target characteristics, and geography.
- People search: Find professionals by current role, title, employer characteristics, past company, or founder background. Returns paginated member preview rows (name, title, employer, location) ready for further enrichment.
- Contact lookup: Resolve verified emails, phone numbers, LinkedIn URLs, and job titles for contacts — by company domain, by member/experience pair, by LinkedIn URL, or by name + domain, with optional title filtering.
- Rich data columns: Choose exactly which data fields to retrieve per result — financials, headcount, web traffic, funding history, contacts, and more.
- Saved lists: Access your existing Inven company, deal, and people lists and enrich them with structured data.
- Upstream dedupe: Exclude one or more saved lists (or explicit domains) from a company search at build time, so the search only ever returns companies you do not already have — and you never spend export credits on names you would discard. The same works in reverse: restrict a search to a saved list or an exact set of domains.
- Point-lookup: Retrieve detailed profiles for specific companies, people, or deals by name, domain, or ID.
- Public-company filings: Ask
get_company_infofor "annual reports", "10-K", "10-Q", "earnings release", or similar and it appends a list of available filings (with directly fetchable external URLs, e.g. SEC EDGAR) for resolved listed companies. - Raw SQL (opt-in): Run paginated Snowflake
SELECTstatements directly against curatedMCP_PUBLICviews (companies, members, member experiences, member metrics, M&A transactions, private financials). Includes a free two-step schema-discovery tool with units and enum hints, plus a free 5-row dry-run for iterating on filters before paying credits. Available only to organisations with the SQL tools package enabled.
Setup
Option A — OAuth 2.1 (recommended for Claude.ai and ChatGPT)
- Visit the Anthropic MCP Directory at claude.com/connectors and find Inven.
- Click Connect and complete the OAuth sign-in using your existing Inven account.
- No additional configuration is required — the client discovers all endpoints automatically.
Option B — Legacy Bearer key (for Claude Desktop, Cursor, and programmatic access)
- Obtain an MCP key from your Inven administrator (
POST /admin-api/mcp-key). - Add the following block to your MCP client configuration:
{
"mcpServers": {
"inven": {
"type": "streamable-http",
"url": "https://api.inven.ai/mcp/v1",
"headers": {
"Authorization": "Bearer <your-mcp-key>"
}
}
}
}
Authentication
Two authentication methods are supported simultaneously:
OAuth 2.1 (Authorization Code + PKCE)
The server presents itself as an OAuth 2.1 Authorization Server and proxies the flow to Cognito. PKCE is required and S256 is the only supported challenge method.
| Endpoint | Description |
|---|---|
GET /.well-known/oauth-protected-resource | Protected resource metadata (RFC 9728) |
GET /.well-known/oauth-authorization-server | Authorization server metadata |
POST /register | Dynamic Client Registration |
GET /authorize | Starts the OAuth flow |
GET /auth/callback | Cognito redirect target |
POST /token | Token exchange and refresh |
An unauthenticated request to /mcp/v1 returns 401 with a WWW-Authenticate header whose resource_metadata parameter points at the protected resource document, so a client can discover the whole flow from the MCP endpoint alone.
Legacy static MCP key
Pass a pre-issued key in every request:
Authorization: Bearer <your-mcp-key>
Examples
Example 1: Search for B2B SaaS companies in the Nordics
User prompt: "Find B2B SaaS companies in the Nordic countries with 50–500 employees that have raised Series A or B funding"
What happens:
build_company_searchtranslates the description into a structured search and returns asearch_idwith an estimated result count.build_company_columnsselects relevant columns (company name, country, headcount, funding stage, last round date).run_company_searchexecutes the search and returns a paginated table of matching companies.
Example 2: Look up financials (and filings) for a list of known companies
User prompt: "Get the latest revenue, EBITDA, and headcount for Stripe, Klarna, and Revolut"
What happens:
get_company_inforesolves each company name against the Inven database, calls an LLM to select the relevant data fields, and returns structured rows for all three companies in a single call — no search or column selection step needed.- If the data description mentions filings (e.g. "annual report", "10-K", "10-Q", "earnings release"), the response also appends a list of available public-company filings (with directly fetchable external URLs) for any resolved listed companies. This requires the
profile_public_financialspermission.
Example 3: Explore recent fintech M&A deals
User prompt: "Show me European fintech acquisitions from 2023 and 2024 with deal values above €50M, including buyer names and deal size"
What happens:
build_deal_searchtranslates the deal criteria into a structured deal search and returns asearch_id.build_deal_columnsselects the requested columns (buyer name, target name, deal size, close date).run_deal_searchexecutes the search and returns a paginated table of matching deals.
Example 4: Enrich a saved Inven list
User prompt: "Take my 'Pipeline Q2' company list and give me the headcount trend and last funding round for each company"
What happens:
get_company_listsreturns all of the user's saved lists with IDs and names.get_company_list_domainsfetches the website domains of all positively-marked companies on the chosen list.get_company_info(called in batches of up to 100 domains) retrieves headcount and funding data for every company and returns the results as a structured table.
Example 5: Find only companies that are not already on a saved list
User prompt: "Find UK accounting firms with 50–500 employees, but skip anything already on my master list"
What happens:
get_company_listsreturns the user's saved lists; the master list'slist_idis picked from the result.build_company_searchis called with the description andexclude_list_ids=[<list_id>]. The exclusion is part of the search itself, so theestimated_total_resultsalready has the list's companies removed — both the ones marked positive and the ones marked negative, matching what the Inven UI does when you exclude a list from a search.run_company_searchreturns only new names, so no export credits are spent on companies the user already has.
Notes:
exclude_list_idsis a structured parameter, not an instruction insidedescription. Asking for a list exclusion in the description alone is interpreted by the language model and is not guaranteed to be applied; the parameter always is. An id you cannot access is returned as an error rather than being ignored.- Use
exclude_domainsfor domains you already hold (e.g. from a spreadsheet). They are resolved by exact lookup rather than by name similarity, so a domain is never swapped for a similarly-named company's. refine_company_searchcarries the original search's exclusions over automatically and unions in any new ones, so exclusions cannot be lost by refining.- There is no need to call
get_company_list_domainsfirst when the exclusion source is a saved list. include_list_idsandinclude_domainsare the mirror image: they restrict the search to a saved list or an exact set of domains. Each inclusion source narrows the search, so passing both returns only companies that are on one of the lists and in the domain set. Refining replaces inclusions rather than accumulating them (pass nothing to keep the current one), and a company matched by both an inclusion and an exclusion is dropped.- Do not use
include_domainsfor reference companies you want lookalikes of — put those indescription, where semantic ranking runs over the whole universe.
Example 6: Find European growth-stage VCs focused on climate tech
User prompt: "Find European VCs that invest in climate tech or cleantech at Series A and B stage"
What happens:
build_company_search(dataset="investor")translates the description into a structured investor search and returns asearch_id.build_company_columnsselects overview columns (fund name, country, focus areas, AUM).run_company_searchreturns a paginated list of matching investors.
Example 7: Find CFOs and finance leaders at European fintechs
User prompt: "Find current CFOs and VPs of Finance at European fintech companies with 100–1000 employees"
What happens:
build_people_searchtranslates the description into a structured people search and returns asearch_id.run_people_searchexecutes the search and returns paginated rows with name, title, employer domain, and location — no column selection step needed.- Optionally, pass the returned
member_id/experience_idpairs toget_people_infofor full profile data.
To get one company's people list instead — the equivalent of the People section of an Inven company profile — name that company in the description: "list the people at acme.com". Scoping to a single company raises the per-company cap from 3 to a full roster of up to 500, so run_people_search returns the staff list with names and titles, which the assistant can then filter by title. Names and titles cost no contact credits; resolve the shortlisted people's emails and phone numbers afterwards with get_company_contacts.
Example 8: Look up CEO contacts for a short list of companies
User prompt: "Find verified email addresses and phone numbers for the CEOs of stripe.com, klarna.com, and revolut.com"
What happens:
get_company_contactsis called withdomainsand atitles=["CEO"]filter. Common abbreviations are expanded server-side (so "CEO" also matches "Chief Executive Officer").- The tool returns the top contacts per domain with verified email, phone, LinkedIn URL, job title, and location. One contact credit is deducted per newly-resolved contact.
You can also resolve contacts for specific people instead of (or in addition to) domains:
people: member_id/experience_id pairs fromrun_people_searchorget_people_list.linkedin_urls: objects with the required keylinkedin_url(noturl), e.g.{"linkedin_url": "https://linkedin.com/in/jane", "name": "Jane Smith"}.named_people: a person name + company domain for fuzzy matching (falls back to Inven people data if contact providers miss the name).
Up to 10 total lookups per call across all input modes combined.
Example 9: Quantitative analysis directly against the Inven data warehouse (SQL tools)
User prompt: "What's the median headcount growth over the last 12 months for SaaS companies in the Nordics with 50–500 employees?"
What happens (requires the SQL tools package to be enabled for the organisation):
get_sql_schema()returns the available schema selection groups (companies,people,deals,private-financials) without column metadata.get_sql_schema(selections=["companies"])returns column metadata, units, and known enum values for just the requested groups.dry_run_sql(sql)runs the candidate SnowflakeSELECTcapped at 5 rows for free, so the query can be iterated on without paying credits.run_sql(sql, limit, offset)runs the full paginated query (1 screening credit per call + 1 export credit per returned row, ≤1000 rows/page, 60-second timeout).
Tools
Company search
Investor and listed-company searches run through these same tools by passing a dataset argument — build_company_search(dataset="investor") or build_company_search(dataset="public") (default "company"), and likewise preview_company_search(dataset=...). There are no separate build_investor_search / build_public_company_search tools; results always come back via run_company_search. The argument is authoritative: "investor" and "public" restrict the universe even when the description carries no criteria specific to it, and the result says so in interpretation_notes.
Every build/preview/refine result carries parameters (the filters that were actually applied) alongside interpretation_notes — the caveats the query interpreter raised: criteria it could not express as a filter, assumptions it had to make, and criteria it dropped. A criterion that appears in neither parameters nor interpretation_notes was understood and applied; one that appears only in the notes was not.
estimated_total_results is 0 when the filters match nothing; null means the estimate was unavailable. An interpretation is reused for a few minutes per user, so repeating a description — previewing it and then building it, most commonly — returns the same filters and the same estimate, and the repeat call spends no tokens and costs no screening credits. Estimates from two different descriptions are still not comparable: each is interpreted separately into a different semantic prompt, which moves the estimate on its own, so measure a filter's effect by holding the description fixed and varying only the structured parameters.
Structured filters decide which companies are in the result set; the semantic prompt only decides what order they come back in. There is no relevance cut-off, so a broad description over a large filter set puts the on-topic matches first and keeps going well past them. Narrow with structured filters rather than paging deeper, and treat estimated_total_results as the size of the filter match, not as a count of relevant companies.
The topical half of a description is the part most likely to be lost in interpretation, and a search that lost it looks normal: a plausible count over a set nothing has ranked. When no descriptivePrompt, keywords or example companies survive, the result says so in interpretation_notes under search_relevance. Treat that note as a failed search rather than a broad one — no page of it is more relevant than any other — and re-run with the business activity stated plainly. It is not raised when you pinned the search with include_domains or include_list_ids: you chose the members yourself, so there is no ranking question to answer.
Some filters are inferred from the description and restrict results more than their wording suggests. portfolioTenure: N is the one to watch: it does not merely prefer companies that might sell, it keeps only companies currently held in a private-equity portfolio whose last equity deal was N–15 years ago, dropping every company that is not PE-owned. It appears in parameters.filters and, when applied, in interpretation_notes. Re-run without the holding-period wording if you did not intend it.
Each company is stored under exactly one domain, and it is not always the one you would type. Spotify is lifeatspotify.com; spotify.com is an alias that identifies the company but is not a company row itself. Both get_company_info and the include_domains / exclude_domains filters follow aliases to the domain the company is stored under, and both say when they did — potential_issues for the first, interpretation_notes for the second. A domain that is a company in its own right is never remapped, so a subsidiary keeps matching itself rather than its parent group. Reuse the resolved domain, since it is the one that appears in run_company_search rows.
A domain matching no company at all is reported the same way rather than passing silently, which is what previously made a typo indistinguishable from a filter that worked. potential_issues also names the identifier behind each caveat, so a bulk lookup tells you which of your inputs failed rather than how many.
dataset accepts only company, investor and public. Anything else is an error rather than a fallback to the default, since a misspelled dataset would otherwise return a plausible result from the wrong universe.
| Tool | Annotation | Description |
|---|---|---|
build_company_search | side-effecting | Persist a natural language company search to history (pass dataset="investor" or "public" for those universes). Optional exclude_list_ids / exclude_domains remove saved lists or explicit domains inside the search itself; include_list_ids / include_domains restrict it to them. Returns search_id and interpretation_notes. Costs screening credits in proportion to the LLM tokens used. |
preview_company_search | side-effecting | Preview a company search without saving (supports the same dataset and list-filter arguments). Costs screening credits in proportion to the LLM tokens used. |
refine_company_search | side-effecting | Refine an existing search; saves as a new entry. Carries the original search's exclusions over and unions in any new exclude_list_ids / exclude_domains; inclusions are carried over unless you pass new ones. Because exclusions accumulate, an include_list_ids naming an already-excluded list returns nothing — interpretation_notes reports it. Costs screening credits in proportion to the LLM tokens used. |
build_company_columns | side-effecting | Select data columns via natural language. Returns column_selection_id. Costs screening credits in proportion to the LLM tokens used. |
refine_company_columns | side-effecting | Add columns to an existing column selection. Costs screening credits in proportion to the LLM tokens used. |
get_available_company_columns | side-effecting | Browse the company field catalogue by category. Call with no categories to list category names with field counts, then with categories=[...] to get the field ids in those categories. Costs 1 screening credit per call. |
run_company_search | side-effecting | Execute a search and return paginated company rows. Each row's domain is the matched company's own domain, which for a subsidiary is not its parent group's domain. A company the data store cannot hydrate is omitted rather than returned as an empty row, so a full page can return fewer rows than limit. Costs 1 screening credit per call plus 1 export credit per row returned. |
get_company_info | side-effecting | Retrieve structured data for up to 100 specific companies by name or domain. When the data description mentions filings (e.g. "annual report", "10-K", "10-Q", "earnings release"), also appends available public-company filings (with fetchable external URLs) for resolved listed companies — requires the profile_public_financials permission. Costs screening credits in proportion to the LLM tokens used, plus 1 export credit per row returned. |
Deal search
| Tool | Annotation | Description |
|---|---|---|
build_deal_search | side-effecting | Persist a natural language deal search. Returns search_id. Costs screening credits in proportion to the LLM tokens used. |
preview_deal_search | side-effecting | Preview a deal search without saving. Costs screening credits in proportion to the LLM tokens used. |
refine_deal_search | side-effecting | Refine an existing deal search; saves as a new entry. Costs screening credits in proportion to the LLM tokens used. |
build_deal_columns | side-effecting | Select deal data columns via natural language. Returns column_selection_id. Costs screening credits in proportion to the LLM tokens used. |
get_available_deal_columns | side-effecting | Browse all available deal field names. Costs 1 screening credit per call. |
run_deal_search | side-effecting | Execute a deal search and return paginated deal rows. Costs 1 screening credit per call plus 1 export credit per row returned. |
get_deal_info | side-effecting | Retrieve structured data for specific deal IDs. Costs screening credits in proportion to the LLM tokens used, plus 1 export credit per row returned. |
People search
| Tool | Annotation | Description |
|---|---|---|
build_people_search | side-effecting | Persist a natural language people search. Returns search_id. Naming a specific employer (by company name or domain) or an Inven saved list scopes the search to it and raises the per-company cap to a full roster of up to 500 people; an unscoped search returns only the top 3 people per company. Costs screening credits in proportion to the LLM tokens used. |
preview_people_search | side-effecting | Preview a people search without saving. Costs screening credits in proportion to the LLM tokens used. |
refine_people_search | side-effecting | Refine an existing people search; saves as a new entry. Costs screening credits in proportion to the LLM tokens used. |
run_people_search | side-effecting | Execute a people search and return paginated member preview rows. No column selection needed. Costs 1 screening credit per call plus 1 export credit per row returned. |
Saved lists
| Tool | Annotation | Description |
|---|---|---|
get_company_lists | side-effecting | List the user's Inven company lists with IDs and names. Costs 1 screening credit per call. |
get_company_list_domains | side-effecting | Return website domains of positively-marked companies on a list. Costs 1 screening credit per call. |
get_deal_lists | side-effecting | List the user's Inven deal lists. Costs 1 screening credit per call. |
get_deal_list_ids | side-effecting | Return deal IDs of positively-marked entries on a list. Costs 1 screening credit per call. |
get_people_lists | side-effecting | List the user's Inven people lists. Costs 1 screening credit per call. |
get_people_list | side-effecting | Return member/experience ID pairs of positively-marked people on a list. Costs 1 screening credit per call. |
get_people_info | side-effecting | Load full profile data for specific member/experience pairs. Costs 1 screening credit per call plus 1 export credit per row returned. |
Contacts
| Tool | Annotation | Description |
|---|---|---|
get_company_contacts | side-effecting | Resolve verified emails, phone numbers, LinkedIn URLs, and job titles for up to 10 lookups per call. Input modes: domains (optional titles filter and max_contacts_per_domain), people (member_id/experience_id pairs from people search), linkedin_urls (objects with required key linkedin_url, not url; optional name/title/company_name hints), or named_people (name + company domain, with Inven people DB fallback). At least one input mode required. Costs one contact credit per newly-resolved contact (already-resolved contacts are not charged again). |
Raw SQL (opt-in, organisation-gated)
Available only to organisations with the SQL tools package enabled. Targets curated MCP_PUBLIC_DB.MCP_PUBLIC.* Snowflake views (COMPANIES, MEMBERS, MEMBER_EXPERIENCES, MEMBER_METRICS, MNA_TRANSACTIONS, plus private-financial views). All statements run with a 60-second server-side timeout; multi-statement scripts are rejected and trailing semicolons are stripped. Only SELECT / WITH statements are allowed.
Statements you supply are additionally screened server-side and rejected if they reference INFORMATION_SCHEMA, the SNOWFLAKE shared database, Snowflake history functions, RESULT_SCAN / LAST_QUERY_ID, IDENTIFIER(...), GET_DDL, or SYSTEM$ functions. This applies to your SQL only — get_sql_schema reads INFORMATION_SCHEMA.COLUMNS itself to describe the views, which is why it can return column metadata that your own queries cannot reach.
Recommended flow: get_sql_schema() (free; lists selection groups) → get_sql_schema(selections=[...]) (free; columns for the requested groups) → dry_run_sql(sql) (free, 5-row preview) → run_sql(sql, limit, offset) for paginated results. Always include an ORDER BY when paginating so page boundaries stay stable.
| Tool | Annotation | Description |
|---|---|---|
get_sql_schema | read-only | List available schema selection groups (companies, people, deals, private-financials) when called with no selections, or return live INFORMATION_SCHEMA.COLUMNS metadata for the requested groups, augmented with curated per-column descriptions (units, format conventions, ARRAY / VARIANT notes) and enum_values for known categorical columns. Free. |
dry_run_sql | read-only | Run a Snowflake SELECT against the MCP_PUBLIC views, capped at 5 rows. Free; surfaces Snowflake errors (syntax, timeout, etc.) via the error field. Use for fast iteration on filters before calling run_sql. |
run_sql | side-effecting | Run a paginated Snowflake SELECT against the MCP_PUBLIC views (≤1000 rows/page). Costs 1 screening credit per call plus 1 export credit per returned row (no export credits charged on error). Errors are surfaced via the error field. |
Utility
| Tool | Annotation | Description |
|---|---|---|
status_tool | read-only | Health check — confirms the server is reachable and that the credentials resolve to an Inven user, returning that username and organisation. Free. |
get_credit_balance | read-only | Return current export_credits, contact_credits, and ai_enrichment_credits balances for the authenticated user. |
open_search_in_inven | side-effecting | Open a previously built search as a tab in the user's Inven web app. No credits are charged. |
Privacy policy
See our privacy policy at https://www.inven.ai/privacy-policy.
Support
- Email: support@inven.ai
- Documentation: https://inven.ai/mcp-docs
