ARES Explorer
MCP server that turns the Czech business register (ARES) into an interactive force-directed graph of company management and ownership ties, allowing users to explore and expand the graph live within Claude.
README
ARES Explorer π¨πΏ β MCP App
What is this? An MCP App that turns the Czech business register (ARES) into an interactive relationship graph. Ask Claude about a company and a force-directed graph of its management and ownership ties renders right in the chat β then click any company node to expand it live and watch the network grow. Built with the MCP Apps SDK, a serverless MCP endpoint (
mcp-handleron Vercel), and D3.
How to use it in Claude
This is not a website you click on β it's an MCP App connector. You don't open it in a browser; you add it to Claude as a custom connector and then talk to it in chat.
Connector endpoint:
https://ares-explorer-mcp.vercel.app/api/mcp
Mind the /api/mcp path β that exact path is the MCP endpoint (Streamable HTTP). Opening the URL in a browser shows nothing useful; it's an MCP server, not a web page. The bare domain or any other path won't work as a connector.
Connect it (one-time):
- In Claude on web or desktop, go to Connectors (now under the Customize section β it used to live under Settings).
- Click Add custom connector.
- Paste
https://ares-explorer-mcp.vercel.app/api/mcpand confirm.
Requires a paid Claude plan (Pro / Max / Team). Custom connectors are not available on the free plan.
Harmless sign-in warning. While adding the connector, Claude may show an OAuth / sign-in message such as "Couldn't register with sign-in service." It's safe to ignore β just dismiss it. The server is public and needs no login, and the tools load regardless.
Try it. Once connected, ask in chat:
- βUkaΕΎ graf vazeb firmy s IΔO 24130222." (Show the relationship graph for the company with IΔO 24130222.) β then click company nodes and the graph grows live.
- βVykresli vlastnickou strukturu firmy s IΔO 27604977." (Draw the ownership structure of the company with IΔO 27604977.)
- βNajdi firmu Seznam.cz a ukaΕΎ jejΓ vazby." (Find the company Seznam.cz and show its ties.)
What it is
ARES Explorer is an MCP App that takes the open data of the Czech ARES register and builds an interactive graph of a company's ties β its statutory body, members/owners, and connected companies β rendering it directly inside Claude. It isn't just a static picture: company nodes are clickable and the graph grows live as the app calls back to the server (the "bidirectional loop" of MCP Apps).
Type something like βUkaΕΎ mi vazby firmy s IΔO 24130222." (Show me the relationships of the company with IΔO 24130222.) and you get a canvas where you can explore the ownership and personnel structure by clicking.
Why it's interesting
- An MCP App, not just a tool. Most MCP servers return text. Here a full UI runs in a sandbox and initiates further tool calls on its own based on what the user does. Click a node β
app.callServerTool("expand-node")β new data is merged into the graph. - Real open data. No mocks β the server talks live to the public ARES REST API.
- Tolerant parser. The VR (veΕejnΓ½ rejstΕΓk, public register) JSON is deeply nested and varies by legal form. The parser therefore walks the record recursively and pulls out anything that looks like a person (
jmeno+prijmeni) or a connected company (ico+obchodniJmeno), inferring the role (jednatel, spoleΔnΓk, β¦) from context. Resilient to schema changes.
What it looks like

The expanded graph (55 nodes Β· 59 ties). The inspector lists the statutory-body members (Δlen statutΓ‘rnΓho orgΓ‘nu) of the selected company, Corporate Consulting a.s., each with a deep link out to ARES.

Click a person node for its detail: RenΓ© Sommer, born 1966, sits on the supervisory board (Δlen dozorΔΓ rady) of Kofola ΔeskoSlovensko a.s.
- Companies = amber rounded square, people = teal circle (distinguished by both shape and color).
- A node with
+can be expanded. The side inspector shows detail, ties, and a link out to ARES. - The toolbar lets you paste any IΔO to attach another company to the graph.
Architecture
βββββββββββββββββββββββββββββ MCP host (Claude) βββββββββββββββββββββββββββββ
β β
β company-graph(ico) sandboxed iframe (ui://) β
β β tool result (GraphData) ββββββββββββββββββββββββββββββββ β
β βΌ ββββββββββββββββββββββββββββΆ β D3 force graph β β
β βββββββββββββββ β node click ββββ β β
β β /api/mcp β βββ expand-node(ico) ββββ βββββββββββββββ callServerToolβ
β β (serverless)β ββββ GraphData βββββββββΆβ merge β graph grows β β
β ββββββ¬βββββββββ ββββββββββββββββββββββββββββββββ β
β β fetch β
ββββββββββΌβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βΌ
ARES REST API (ares.gov.cz)
β’ /ekonomicke-subjekty/{ico} β base record
β’ /ekonomicke-subjekty-vr/{ico} β public register (ties)
β’ /ekonomicke-subjekty/vyhledat β search by name
Server tools
| Tool | UI? | What it does |
|---|---|---|
ares-search |
no | Najde firmy podle nΓ‘zvu, vrΓ‘tΓ IΔO. |
company-graph |
yes | OtevΕe interaktivnΓ graf vazeb (IΔO nebo nΓ‘zev). |
expand-node |
no | VrΓ‘tΓ podgraf jednΓ© firmy β volΓ‘ appka pΕi rozkliknutΓ uzlu. |
Tool titles and descriptions are intentionally kept in Czech β the app and its data are Czech, so this is how they read to both the user and the model.
The data contract (src/types.ts) is shared by the server and the UI, keeping both sides in sync. The UI never talks to ARES itself β it only renders GraphData and asks the server to expand nodes.
Architecture decision: from Express to serverless
The first version ran as a long-lived Express process exposing the MCP server over Streamable HTTP. It was rewritten as a single Vercel serverless function via mcp-handler's createMcpHandler (app/api/mcp/route.ts). Streamable HTTP is the recommended MCP transport, so a stateless request/response function maps onto it cleanly β there's no socket to keep alive, and the platform autoscales with load. Vercel's Fluid compute keeps instances warm and reuses them across invocations, avoiding the cold-start lag of sleeping free-tier processes while still scaling down when idle. The one build artifact the function depends on β the app's UI HTML β is inlined into the bundle at build time, so there's no runtime filesystem dependency in the serverless environment.
Tech stack
- TypeScript (server and UI), strict mode
@modelcontextprotocol/ext-appsβ MCP Apps SDK (server helpers + clientAppclass)@modelcontextprotocol/sdkβ MCP server + Streamable HTTP transportmcp-handler+ Next.js 15 App Router β MCP over a single serverless function (app/api/mcp/route.ts), no long-lived process. Next.js is used purely as the routing + build wrapper for that one handler β no pages, nonext/*imports in code.react/react-domare pulled in only as Next's required peers, not used by the app (the UI is plain D3 in inlined HTML)- zod β tool input validation
- D3 (force-directed graph, zoom/pan, drag)
- Vite +
vite-plugin-singlefileβ the UI is bundled into one HTML file that the build inlines directly into the serverless function (no external origins β simple CSP)
Local development
You need Node.js 20+.
npm install # .npmrc sets legacy-peer-deps (see "Deploy to Vercel")
npm run dev # vite build β inline UI into the function β next dev
The MCP endpoint then runs at http://localhost:3000/api/mcp (Streamable HTTP, POST). As with production, the /api/mcp path is the endpoint β http://localhost:3000 on its own serves nothing useful (this is an API-only Next.js app).
Other scripts:
npm run build # production build: vite + inline + next build
npm run typecheck # tsc --noEmit
npm test # unit tests for the ties parser (no network)
The inlined-HTML step
The route handler imports the UI from a build-generated, gitignored module β app/api/mcp/route.ts does import { ARES_EXPLORER_HTML } from "./ares-explorer-html", and that file (app/api/mcp/ares-explorer-html.ts) only exists after the build emits it. Both npm run dev and npm run build regenerate it for you: they bundle the UI with Vite into dist/ares-explorer.html, then scripts/inline-html.mjs embeds it as a string into the module. The serverless function therefore has no runtime filesystem dependency β the HTML is part of the bundle.
Always start the dev server with
npm run dev, not a barenext dev. The npm script runsbuild:app+inlinefirst; runningnext devdirectly on a clean checkout skips those steps and Next will fail to compile on the missing./ares-explorer-htmlimport. If you ever hit that, runnpm run dev(or justnpm run buildonce) to generate the module.
Testing the server without Claude β MCP Inspector
To exercise the endpoint without wiring it into Claude, point the MCP Inspector at your local server:
npx @modelcontextprotocol/inspector
Connect it to http://localhost:3000/api/mcp (transport: Streamable HTTP) and you can drive the protocol directly β initialize, tools/list, resources/list β and call the tools, getting their results back as JSON. This is the fastest way to confirm the server is up and the tools are wired correctly.
The Inspector only shows raw JSON β
company-graphreturnsGraphData, not the rendered graph. The interactive D3 UI only paints inside an MCP host (Claude), so for the full visual experience use the tunnel flow below.
Testing the full UI in Claude β via a tunnel
Because the graph renders only inside the MCP host's sandbox, to see the real UI you need to expose your local server over a public URL and add it to Claude as a second custom connector. A quick tunnel:
cloudflared tunnel --url http://localhost:3000
This prints a public https://<random>.trycloudflare.com URL. Add https://<random>.trycloudflare.com/api/mcp as an additional custom connector in Claude (same steps as How to use it in Claude, just your tunnel URL) β keep the production connector too β and you can dogfood your local changes with the full clickable graph before opening a PR.
cloudflaredis installed separately (e.g.brew install cloudflared); there's intentionally no npm script for it, since tunnelling is an ad-hoc debugging step, not part of the build.
For host-free local debugging you can also drive the app with basic-host from the ext-apps repo.
Recommended workflow
- Iterate locally with
npm run dev+ the MCP Inspector for fast JSON-level checks. - Verify the real UI in Claude through the cloudflared tunnel once the behaviour looks right.
- Open a PR β only then does it go through CI and review. Production is reached strictly via merge to
main, as described in Who can deploy, and how: PR β CI (typecheck + tests + build) β maintainer review β merge tomainβ production deploy. Nothing ships any other way.
Deploy to Vercel
The project is an API-only Next.js app β the only route is the MCP endpoint app/api/mcp/route.ts, which serves Streamable HTTP via mcp-handler. No long-lived process, no state between requests.
Via the dashboard: import the repo at vercel.com/new. The framework (Next.js) and build are detected automatically from vercel.json; nothing needs to be configured by hand. After deploy, the endpoint lives at https://<project>.vercel.app/api/mcp.
Via the CLI:
npm i -g vercel
vercel # preview deploy
vercel --prod # production deploy
What's wired up for deployment:
vercel.jsonβframework: nextjs,buildCommand: npm run build(runs vite build β inline HTML β next build), andmaxDuration: 60 sfor the/api/mcpfunction..npmrcwithlegacy-peer-deps=trueβmcp-handler@1.1.0pins its@modelcontextprotocol/sdkpeer to exactly1.26.0, whereasext-appsrequires^1.29.0. The APIs in use (McpServer+ Streamable HTTP transport) are stable across those versions, so we stay on1.29.x. Vercel reads this file at install time too, so the same resolution applies in CI.- Inlined HTML β the app's UI is embedded straight into the function at build time (see above), so the serverless environment never needs to read
dist/from disk.
After deploying, add https://<project>.vercel.app/api/mcp as a custom connector in Claude (see How to use it in Claude).
Who can deploy, and how (contribution process)
Production deploys are gated β they don't happen on a whim, and not everyone can trigger one.
mainis protected. No direct pushes for contributors. Every change lands through a pull request that must pass CI (.github/workflows/ci.ymlβ typecheck + tests + build) and get a maintainer's approving review before it can merge.- Production = a merge to
main. Vercel deploysmainto production. Since only reviewed, CI-green PRs (or the maintainer's own pushes) reachmain, nothing ships to production without the maintainer's sign-off. - Fork previews are not automatic. Vercel's Git fork protection is on, so a PR from a fork won't build a preview until a maintainer authorizes it β outside code never builds in this project unprompted.
- CLI production deploys (
vercel --prod) are restricted to the maintainer via Vercel team membership. This is the one path that bypasses GitHub, so team access is kept tight on purpose.
So a new contributor's flow is: fork β branch β open a PR β CI runs β maintainer reviews and approves β maintainer merges β production deploys. No task gets to production any other way.
Project structure
ares-explorer-mcp/
βββ app/
β βββ api/mcp/
β βββ route.ts # MCP endpoint: createMcpHandler β tools + UI resource
β βββ ares-explorer-html.ts # build-generated (gitignored): inlined UI HTML
βββ scripts/
β βββ inline-html.mjs # embeds dist/ares-explorer.html into the function as a string
βββ ares-explorer.html # app entry HTML (inline styles)
βββ src/
β βββ types.ts # shared data contract (GraphData β¦)
β βββ ares.ts # ARES REST client + tolerant ties parser
β βββ mcp-app.ts # UI: D3 force graph, node expansion
βββ test/
β βββ graph.test.ts # parser unit tests (fixtures, no network)
βββ vercel.json # Vercel: framework, build, maxDuration
βββ next.config.mjs
βββ vite.config.ts
βββ tsconfig.json
βββ package.json
Notes & limits
- ARES data is for information only and has no character of an official document (see the ARES terms). The API is rate-limited to 500 requests/min.
- The parser covers the most common forms (s.r.o., a.s., spolek). For exotic structures some ties may be missing β it deliberately omits rather than guesses. The logic is covered by unit tests.
- Subjects with no VR record (e.g. some sole traders / OSVΔ) show up as a standalone node with no ties.
- Graph depth is capped (~80 ties per record) to stay readable; deeper levels are filled in by expanding nodes.
License
MIT β see LICENSE.
Data: Β© ARES / Ministry of Finance of the Czech Republic, provided as open data.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.