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
访问服务器

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.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选