Browser compatibility and Baseline status for any web feature — offline, from bundled MDN data.
Browser compatibility and Baseline status for any web feature — offline, from MDN's browser-compat-data, web-features, and caniuse. STDIO or Streamable HTTP.
Public Hosted Server: https://browser-compat.caseyjhand.com/mcp
Web platform compatibility for frontend work: per-browser support from MDN's @mdn/browser-compat-data, Baseline state and dates from web-features, and browserslist target resolution weighted by caniuse-lite usage figures. Every dataset ships inside the package, so there are no runtime network calls, no API key, no rate limit, and no upstream to be down — the same answers come back air-gapped. Runs as a stdio process, a local Streamable HTTP server, or the public hosted endpoint above.
| Tool | Description |
|---|---|
browsercompat_list_reference | Enumerate the reference vocabulary the other tools expect — BCD namespaces and browser ids, browserslist agents, Baseline states, groups, and ECMAScript snapshots. |
browsercompat_get_feature | Full compatibility record for one feature: Baseline state, standards status, per-browser versions with flags and prefixes, MDN and specification links. |
browsercompat_check_baseline | Ship-or-not across up to 20 features: Baseline state and date, the limiting browser, deprecation flags, and the traffic share requiring it would exclude. |
browsercompat_search_features | Find features by plain name, keyword, or code notation when the canonical key is unknown, ranked with the field that matched, filterable by group or ECMAScript snapshot, and pageable. |
browsercompat_compare_support | Check features against an explicit browserslist target query, reporting the failing target per feature and every target that could not be evaluated. |
browsercompat_list_reference tooltopic: bcd_namespaces (12), bcd_browsers (17), browserslist_agents (19), baseline_states (4), groups (104), snapshots (11)id, label, and detail, plus count, reported, bcd_browser, usage_percent, maps_from, or spec_url where the topic has themgroups and snapshots ids are the values browsercompat_search_features takes as group and snapshotbrowserslist_agents gives each agent's browser-compat-data counterpart or null — the null ones can never be evaluated and always land in unchecked_targetsbrowsercompat_get_feature toolfeature string, 1–200 characters: a BCD key (css.selectors.has) or a web-features id (has); resolved_as echoes which one matched and howresolve: true falls back to the search index for a plain name or notation (Container queries, Element.prototype.animate) and accepts its best exact matches only when they name one feature: one key resolves to that key, several keys of one feature resolve to the feature with compat_keys, and two features are a miss. Off by default, so a typo returns a miss rather than a confident answer about the wrong featureinclude_runtimes: true adds bun, deno, nodejs, and oculus rows to the 13 reported desktop and mobile browsersoutcome is found | no_compat_data | miss — a miss is found: false with guidance, never an errorsupport, status, limiting_browser, mdn_url, spec_urls) and returns compat_keys to re-call withinvalid_feature_input (whitespace-only feature)browsercompat_check_baseline toollimiting_browser, deprecated / experimental / discouraged, and usage_percent_excluded alongside the usage_source it is a share ofusage_percent_excluded is absent — never zero — when the feature reaches no caniuse idall_widely_available answers the Baseline question alone: every entry resolved at widely, one miss forces it false, and deprecation does not enter itinvalid_feature_input (a whitespace-only entry)browsercompat_search_features toolquery 1–100 characters: a plain name, a keyword, or code notation such as Array.prototype.at, display: grid, or <dialog>namespace (one of the 12 BCD namespaces), baseline (widely | newly | limited | not_mapped), group (a web-features group, nested groups included), and snapshot (an ECMAScript edition such as ecmascript-2023)limit 1–50, default 10, and offset (default 0) to page through the full ranking; nextOffset is present while matches remainmatched_on, the field that matched, so the six-tier ranking is inspectable rather than a score; path_suffix marks a key whose trailing segments match the dotted or property-value notation typedsupport_summary is one line across the seven Baseline core browsers, with — for unsupported and ? for unknowntotalCount counts every match, and an offset past it returns an empty page with a noticeinvalid_query (a query that normalizes to zero tokens), unknown_group, unknown_snapshotbrowsercompat_compare_support tooltargets browserslist query (defaults, > 0.5%, last 2 versions) — required so browserslist never falls back to config in the server's working directoryverdict per feature: clears | fails | inconclusive | miss | ambiguous; failing_targets names each failing target with the verdict behind it (partial, prefixed, flagged, removed, unsupported, preview_only)unchecked_targets lists every target the server declined to judge, with no_bcd_browser | unknown_version | no_bcd_data; all_clear requires that list to be emptytarget_coverage_percent and unchecked_coverage_percent give the caniuse-derived traffic share of the evaluated and unevaluated tokensinvalid_target_query, no_targets_resolved, invalid_feature_input| Package | Version | License | Supplies |
|---|---|---|---|
@mdn/browser-compat-data | ^8.1.2 | CC0-1.0 | Per-browser support, standards status, MDN and specification links |
web-features | ^3.39.0 | Apache-2.0 | Baseline state and dates, discouraged flags, groups, ECMAScript snapshots |
caniuse-lite | ^1.0.30001810 | CC-BY-4.0 | Usage weighting, plus feature titles for the search index |
browserslist | ^4.29.0 | MIT | Target query resolution and coverage figures |
CC BY 4.0 requires attribution wherever the caniuse data travels, so every response carrying a usage figure carries this string: Usage data from caniuse.com, © Can I Use contributors, CC BY 4.0. Figures are a share of the ~96.7% of global traffic caniuse tracks. Full license texts and notices are in THIRD_PARTY_NOTICES.md.
Built on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.
Browser-compat-specific:
status.by_compat_key, never rolled up from the feature level, because keys under one feature legitimately disagreemoved redirect, and only under resolve: true the search index's best exact matches, when they name one featuresafari 16.0 ↔ 16, samsung 20 ↔ 20.0)Agent-friendly output:
data_version — the version of each bundled dataset behind the answer, since a pinned snapshot goes stale on exactly the newest featuresunchecked_targets and the feature to inconclusivefound: false with guidance naming the next call, and typed error reasons carrying recovery hints for the input a caller has to fixA public instance is available at https://browser-compat.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP:
{
"mcpServers": {
"browser-compat-mcp-server": {
"type": "streamable-http",
"url": "https://browser-compat.caseyjhand.com/mcp"
}
}
}
Add the following to your MCP client configuration file:
{
"mcpServers": {
"browser-compat-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/browser-compat-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"browser-compat-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/browser-compat-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with Docker:
{
"mcpServers": {
"browser-compat-mcp-server": {
"type": "stdio",
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "MCP_TRANSPORT_TYPE=stdio",
"ghcr.io/cyanheads/browser-compat-mcp-server:latest"
]
}
}
}
For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcp
git clone https://github.com/cyanheads/browser-compat-mcp-server.git
cd browser-compat-mcp-server
bun install
cp .env.example .env
# edit .env if you want to override transport or logging defaults
There are no server-specific environment variables: no API keys, no base URLs, and deliberately no browserslist configuration variable — the target query is always a tool input rather than ambient state. Only the framework transport settings apply.
| Variable | Description | Default |
|---|---|---|
MCP_TRANSPORT_TYPE | Transport: stdio or http. | stdio |
MCP_HTTP_PORT | Port for the HTTP server. | 3010 |
See .env.example for the full list of optional framework overrides.
# One-time build
bun run rebuild
# Run the built server
bun run start:stdio
# or
bun run start:http
bun run devcheck # Lint, format, typecheck, security
bun run test # Vitest test suite
bun run lint:mcp # Validate MCP definitions against spec
docker build -t browser-compat-mcp-server .
docker run --rm -p 3010:3010 browser-compat-mcp-server
The Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/browser-compat-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
| Directory | Purpose |
|---|---|
src/index.ts | createApp() entry point — registers the tools and warms the datasets. |
src/data/ | The browserslist agent to browser-compat-data browser map. |
src/mcp-server/tools/ | Tool definitions (*.tool.ts) and the output shapes they share. |
src/services/ | bcd, baseline, targets, search, and data-version services over the bundled datasets. |
src/types/ | Ambient module declaration for caniuse-lite, which ships no types. |
tests/ | Vitest suites mirroring src/. |
docs/ | design.md — the surface, the data shapes behind it, and the decisions log. |
changelog/ | Per-version changelog files. |
The generated file tree is docs/tree.md.
See CLAUDE.md for development guidelines and architectural rules. The short version:
try/catch in tool logicctx.log for request-scoped logging, ctx.state for tenant-scoped storagesrc/index.tsIssues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
Apache-2.0 — see LICENSE for details.
Source-derived launch command. Check the maintainer’s required arguments and credentials before running:
npx -y @cyanheads/browser-compat-mcp-serverMerge this template into ~/Library/Application Support/Claude/claude_desktop_config.json. Keep existing servers. Add any arguments, credentials, and permissions required by the maintainer; this template has not been install-tested.
{
"mcpServers": {
"io-github-cyanheads-browser-compat-mcp-server": {
"command": "npx",
"args": [
"-y",
"@cyanheads/browser-compat-mcp-server"
]
}
}
}Restart Claude Desktop completely for changes to take effect. Confirm the server appears connected in the client’s tool list, then try a read-only example from its documentation.
Claude Desktop setup referenceio.github.cyanheads/browser-compat-mcp-server works with any MCP-compatible client. Copy the config snippet from the Configuration section above and add it to the file shown for your client, then restart the application.
~/Library/Application Support/Claude/claude_desktop_config.jsonRestart Claude Desktop completely for changes to take effect.~/.cursor/mcp.jsonRestart Cursor for changes to take effect..vscode/mcp.jsonReload VS Code window for changes to take effect.~/.codeium/windsurf/mcp_config.jsonRestart Windsurf for changes to take effect..mcp.jsonSave at the project root, then start Claude Code in that project and review the MCP server approval prompt. Keep real credentials out of shared files.