MCP server for Openmart business search and decision-maker enrichment.
It supports two transports:
- Local stdio for Claude Code CLI and local development.
- Remote Streamable HTTP for hosted MCP deployments like
https://mcp.openmart.ai/mcp.
Two jobs — finding companies and finding people — across three tools.
find_business— find companies. WrapsPOST /api/v1/search. Every filter (rating, reviews, location count, ownership type, price tier, keywords, dates, website flags) is a flat top-level parameter. Returns each matching business plustotal_countand anext_cursorfor pagination.find_decision_maker— find people. WrapsPOST /api/v1/task/batch/find_people: submits one or more batches (company lists longer than 100 are split automatically), polls each batch, then fetches the completed task results. Transient HTTP failures are retried with exponential back-off.get_batch_results— collect the results of an async batch. When a largefind_decision_makerrun is still processing at its timeout it returnspending_batch_ids; pass them here to finish collecting the contacts.
Every user brings their own Openmart API key:
- Register at app.openmart.com/register.
- Subscribe to a paid plan.
- Create a key on the API management page.
Provide that key to the server as the OPENMART_API_KEY environment variable
(local stdio) or as an X-API-Key request header (remote HTTP).
Add the server to any MCP client with npx — no clone or build needed. For
Claude Code:
claude mcp add openmart -- env OPENMART_API_KEY="YOUR_OPENMART_API_KEY" npx -y openmart-mcp-serverFor other MCP clients (Claude Desktop, Cursor, VS Code, …), add the equivalent entry to their MCP config:
{
"mcpServers": {
"openmart": {
"command": "npx",
"args": ["-y", "openmart-mcp-server"],
"env": { "OPENMART_API_KEY": "YOUR_OPENMART_API_KEY" }
}
}
}Then ask the assistant, for example:
Use openmart to find 3 hair salons in San Francisco with valid websites.
npm install
npm run build
claude mcp add openmart -- env OPENMART_API_KEY="YOUR_OPENMART_API_KEY" node "$(pwd)/dist/index.js"The server can also be packed as an MCPB desktop extension
— a single .mcpb file that installs into Claude Desktop in one click and
prompts the user for their API key, with no terminal or config editing.
Build the bundle:
npm run pack:mcpbThis bundles the stdio server into openmart-mcp-server.mcpb. To install it,
open Claude Desktop → Settings → Extensions and add the file, then paste your
Openmart API key when prompted. This bundle is also the artifact submitted to
Anthropic's Connectors Directory.
This repo also exposes a Claude Code plugin marketplace. See PLUGIN.md.
Add the marketplace:
/plugin marketplace add OpenmartAI/openmart-mcp-server
Install the plugin:
/plugin install openmart@openmart-plugins
Use the namespaced skills:
/openmart:find-leads 3 hair salons in San Francisco with valid websites
/openmart:enrich-contacts owner emails for these businesses
Run locally:
npm install
npm run build
PORT=3000 npm run start:httpConnect Claude Code to the hosted server:
claude mcp add --transport http openmart https://mcp.openmart.ai/mcp \
--header "X-API-Key: YOUR_OPENMART_API_KEY"Bearer auth also works:
claude mcp add --transport http openmart https://mcp.openmart.ai/mcp \
--header "Authorization: Bearer YOUR_OPENMART_API_KEY"The remote server does not use a shared server-side Openmart key. It reads the user key from each MCP request and forwards it to Openmart as X-API-Key.
The repo includes a Dockerfile and render.yaml.
Minimal Docker deploy:
docker build -t openmart-mcp-server .
docker run -p 3000:3000 openmart-mcp-serverHealth check:
curl https://mcp.openmart.ai/healthzMCP endpoint:
https://mcp.openmart.ai/mcp
Before publishing:
npm test
npm run typecheck
npm run build
npm pack --dry-runPublish:
npm publish --access publicThe package exposes two binaries:
openmart-mcp-server: stdio serveropenmart-mcp-http: HTTP server
Two GitHub Actions workflows (.github/workflows/):
ci.yml— runs tests, typecheck, and build on every push and pull request.release.yml— builds the.mcpbbundle, creates the GitHub Release with it attached, and publishes to npm. Triggered by av*tag, or run it manually from the Actions tab with a version-bump choice (it then bumps, tags, and releases).
release.yml publishes to npm via trusted publishing
(OIDC) — no token. The package's trusted publisher must be configured on
npmjs.com to allow this repository and the release.yml workflow.
Use .mcp.example.json as a template if you want to commit a team-shared Claude Code project configuration:
cp .mcp.example.json .mcp.jsonEach developer still needs to provide OPENMART_API_KEY in their shell environment.
OPENMART_API_KEY=your_openmart_api_key
OPENMART_API_BASE_URL=https://api.openmart.ai
OPENMART_POLL_INTERVAL_MS=2000
OPENMART_TIMEOUT_MS=120000
PORT=3000
HOST=0.0.0.0
CORS_ORIGIN=*OPENMART_API_KEY is required for stdio. It is not required at HTTP server startup because remote users pass the key per request.
find_business — all filters are flat, top-level keys. There is no nested
filters object; anything wrapped in one is ignored by /api/v1/search.
{
"query": "hair salon",
"location": [{ "country": "US", "state": "CA", "city": "San Francisco" }],
"limit": 50,
"has_valid_website": true,
"has_contact_info": true,
"max_locations": 5,
"min_total_reviews": 20,
"min_overall_rating": 4.0,
"ownership_type": "INDEPENDENT",
"open_date_after": "2025-01-01"
}Search target: pass query, tags, or store_name — tags wins over
store_name, which wins over query.
The response carries businesses, total_count (full match count),
has_more, and next_cursor. To page, repeat the call with cursor set to
the previous next_cursor while has_more is true; stop when it is false.
find_decision_maker accepts either companies or the businesses returned by find_business:
{
"businesses": [
{
"openmart_id": "54ff8cd5-7497-4f46-9c0c-c6b8c0d10d04",
"business_name": "Blue Bottle Coffee",
"root_domain": "bluebottlecoffee.com",
"city": "San Francisco",
"state": "CA",
"country": "US"
}
],
"title": "Owner",
"max_k": 3,
"info_access": ["EMAIL", "PHONE"]
}Rows without a domain are skipped and returned in skipped_rows with reason: "missing_domain".
get_batch_results resumes a find_decision_maker run that returned status processing:
{
"batch_ids": ["ccd0e75a-1d3f-449c-afa4-a687de36c994"]
}It returns the contacts collected so far; if some batches are still running it returns status processing again with the remaining pending_batch_ids — wait a few seconds and call it again with those.
npm test
npm run typecheck
npm run buildnpm test runs three layers:
- unit (
test/openmart.test.ts) — pure helpers (domain parsing, list chunking). - contract (
test/contract.test.ts) —openmart.tsagainst canned responses shaped like the real Openmart API: flat search body, async batch flow, retries. - end-to-end (
test/e2e.test.ts) — spawns the real stdio server, connects a real MCP client, and drivestools/listplus every tool over JSON-RPC. A local HTTP server stands in forapi.openmart.ai, so it needs no API key and no credits.
Drive the server against the live Openmart API with the official inspector UI:
npm run build
OPENMART_API_KEY="YOUR_OPENMART_API_KEY" npx @modelcontextprotocol/inspector node dist/index.jsnpm run build
claude mcp add openmart -- env OPENMART_API_KEY="YOUR_OPENMART_API_KEY" node "$(pwd)/dist/index.js"Then ask Claude, for example: find 3 coffee shops in San Francisco with valid websites and get their owner emails.
- What is collected — when you call a tool, this server receives only the parameters you pass it (business categories, locations, company domains, people's names) and your Openmart API key. It does not read anything else from your machine.
- How it is used and stored — the parameters are sent to the Openmart API over HTTPS to fulfil the request. The server keeps no data of its own: nothing is written to disk and nothing is retained between calls. Your API key stays in your local environment / Claude Desktop's secure storage and is sent only as the request's auth header.
- Third parties — requests go solely to the Openmart API
(
api.openmart.ai). No other third party receives your data. - Retention, deletion, and contact — how Openmart collects, uses, retains, and deletes the data sent to its API, and how to contact Openmart with privacy questions, are covered by the Openmart privacy policy.