hsm-mcp

hsm-mcp

Enables querying the Dutch IND public register of recognised sponsors for work/residence permits. Offers tools to search sponsors by name or KvK number and check register status.

Category
Visit Server

README

hsm-mcp

Remote MCP server that mirrors the IND public register of recognised sponsors (Work) — the list of Dutch organisations that can sponsor work / highly-skilled-migrant residence permits — and makes it queryable by AI assistants.

IND publishes the register as a monthly-updated HTML page with no API. This Worker scrapes it daily (write-on-change), stores it in KV with monthly snapshots, and serves two MCP tools over Streamable HTTP:

  • search_sponsors — company name or 8-digit KvK number in, ranked candidate matches out (exact / base-name / substring / fuzzy). Deliberately returns candidates, not a yes/no verdict: the register lists registered legal names, queries use trade names, and the calling LLM is the right judge of whether "Adyen N.V." is the "Adyen" you meant. See docs/adr/0001.
  • get_register_status — register date, scrape health, staleness flag.

Runs entirely on the Cloudflare free tier: Workers + KV + SQLite-backed Durable Objects (McpAgent) + cron + Email Routing for scrape-failure alerts.

Use

Connect the server (no auth; rate limited to 30 req/min per IP):

Claude Code

claude mcp add --transport http ind-sponsors https://hsm.codealan.com/mcp

claude.ai / Claude Desktop — Settings → Connectors → Add custom connector → https://hsm.codealan.com/mcp

Any MCP client (Cursor, etc.)

{ "mcpServers": { "ind-sponsors": { "url": "https://hsm.codealan.com/mcp" } } }

Then just ask in plain language — the assistant calls the tools itself:

  • "Is Adyen a recognised sponsor for highly skilled migrants?"
  • "Check these five companies from my shortlist against the IND register."
  • "KvK 56317441 — who is this and can they sponsor?"
  • "How fresh is the sponsor data?" (hits get_register_status)

Reading the answers: tools return ranked candidates, never a yes/no verdict. A base_name/exact_name match at score ≥0.95 is a solid yes; a KvK-number match is identity-grade; an empty result is not a "no" — the register lists registered legal names while companies go by trade names, so try the legal name (often ends in B.V./N.V.) or the KvK number. Always confirm against the official register before acting on it.

Architecture

flowchart LR
    client["AI client<br/>(Claude, any MCP client)"]
    ind["ind.nl Work register<br/>(HTML page, updated ~monthly)"]
    inbox["Owner's inbox"]

    subgraph gh["GitHub Actions"]
        ci["CI: push to main<br/>test → deploy"]
        health["Health check (daily)<br/>GET /health, 503 = stale"]
    end

    subgraph cf["Cloudflare (free plan)"]
        worker["Worker: routing +<br/>30 req/min per-IP rate limit"]
        mcpdo["HsmMcp Durable Object<br/>McpAgent tools:<br/>search_sponsors · get_register_status<br/>(cached fuzzy-match index)"]
        scrdo["Scraper Durable Object<br/>parse + sanity gates<br/>(DO dodges 10 ms Worker CPU cap)"]
        kv[("KV<br/>register:current<br/>snapshot:YYYY-MM-DD<br/>status")]
        cron["Cron 06:17 UTC daily"]
        mail["Email Routing"]
    end

    client -- "MCP (streamable HTTP) /mcp" --> worker --> mcpdo
    mcpdo -- "read + cache per version" --> kv
    cron --> scrdo
    worker -- "POST /admin/scrape (bearer)" --> scrdo
    scrdo -- "fetch HTML" --> ind
    scrdo -- "write-on-change<br/>+ monthly snapshot" --> kv
    scrdo -- "3 consecutive failures" --> mail --> inbox
    health -- "probe" --> worker
    ci -- "wrangler deploy" --> worker

Key design points, in one breath: the scraper polls daily but writes only when IND's own "last updated" date changes; sanity gates (row count, KvK format, date parse) mean a broken scrape can never replace good data with garbage; searches run against an in-memory index rebuilt only when the register version changes; and every snapshot is kept forever so a future diff feature can answer "when did company X appear?".

Path What happens
Query client → /mcp → HsmMcp DO → ranked candidates from cached index
Refresh cron (or POST /admin/scrape) → Scraper DO → gates → KV
Monitoring GitHub Action probes /health daily; 503 fails the run → GitHub emails the owner
Deploy push to main → tests → wrangler deploy (config from repo secrets)

Setup, file-by-file architecture notes, and deploy steps: see CLAUDE.md.

Unofficial project; data © IND, republished for easier checking. Always verify with the official register before acting on it.

Recommended Servers

playwright-mcp

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.

Official
Featured
TypeScript
Magic Component Platform (MCP)

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.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

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.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

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.

Official
Featured
TypeScript
Kagi MCP Server

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.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

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.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured