- OpenTelemetry JS 3.x (#51, same move as mapbox/mcp-server#325).
@opentelemetry/sdk-trace-baseis deprecated in every 2.x release and removed in 3.0, and the ox-security scan flags it (mapbox/mcp-server#319). The OpenTelemetry set moves to the 3.0 line:sdk-trace3.0.0 replacessdk-trace-base, along withresources3.0.0,sdk-node,instrumentationandexporter-trace-otlp-http0.300.0,auto-instrumentations-node0.82.0 andapi1.10.0.- Code: the console exporter is now imported from
sdk-trace. - Node:
enginesis now>=22.15.0, the 3.x minimum (it was>=22). - Checked: the built server (ESM and CommonJS) sent
tool.search_mapbox_docs_tooland its undiciGETspans to a local OTLP endpoint.
- Code: the console exporter is now imported from
- MCP TypeScript SDK v2 (#46, same move as mapbox/mcp-server#296). The server and the
/tools,/resourcesand/utilsexports now use@modelcontextprotocol/server2.4.0 instead of@modelcontextprotocol/sdk1.x. v2 is where new MCP features land.- For code that imports our tools or resources:
installTo(server)needs a v2McpServer, so the hosted server has to move to v2 in the same release it picks this version up in.getAllTools(),getAllResources()andinstallTo()themselves are unchanged. Handlers get the v2ServerContextinstead ofRequestHandlerExtra. - Clients: nothing changes. It still negotiates 2025-11-25 with current clients, and tool input schemas now go out as JSON Schema 2020-12.
- Mostly the codemod:
npx @modelcontextprotocol/codemod v1-to-v2 .did the import paths and context types. None of our tools have an output schema, so v2's stricter output validation doesn't affect us.@modelcontextprotocol/clientis a dev dependency, used byscripts/test-resources.tsand the tests. - Testing: the tool tests call
run()directly and never touch the SDK, so there's a new test that installs every tool and resource on a real v2McpServerand goes throughtools/list,tools/call,resources/listandresources/read. Also checked the built server over stdio, including a live search and document fetch. - Tests are typechecked in CI now:
npm run typecheckcheckssrcandtesttogether. The tests weren't typechecked before, andSearchDocsTool.test.tshad 7 errors on main (the v2 types fix those).tsconfig.test.jsongetsnoEmitso a plaintscrun can't write.jsfiles next to the sources.
- For code that imports our tools or resources:
- chore: harden document fetching. Breaking for some URLs:
get_document_toolandbatch_get_documents_toolnow accept onlyhttps://docs.mapbox.comURLs (plusMAPBOX_DOCS_HOST_OVERRIDEwhen set); baremapbox.comanddocs.tilestream.net(without the override) are rejected. The shared HTTP pipeline no longer follows redirects; document fetches follow up to 3 redirects, each only to an allowed docs URL.access_tokendetection is now case-insensitive (#45) - fix: the CommonJS build works again.
require('@mapbox/mcp-docs-server/tools')(and/resources,/utils) threw "Cannot use 'import.meta' outside a module", sincesrc/utils/versionUtils.tsusesimport.meta.urland tshy compiled it intodist/commonjsas is. There's now aversionUtils-cjs.ctsthat tshy uses for the CommonJS build instead, readingversion.jsonfrom__dirname, same as mcp-server does. ESM was never affected, and hosted-mcp-server uses ESM. (#47) - docs: fix two stale tool descriptions left over from the Algolia-to-
llms.txtsearch migration.search_mapbox_docs_tool's README entry still said it used "Algolia full-text search" — that was removed a while back (see the "Replace Algolia search with self-contained llms.txt search" entry below) and it now searches the self-hostedllms.txtindex. Separately,get_document_tool's own description (the text shown to the LLM, not just docs) referenced a tool namedget_latest_mapbox_docs_tool, which doesn't exist — it should have saidsearch_mapbox_docs_tool, and was actively misdirecting tool-chaining behavior. - fix: startup/shutdown/error logging messages now actually reach clients. The
McpServernever declared theloggingcapability, so everysendLoggingMessagecall (including the existing "server started"/"shutting down"/"Fatal error" messages) was a silent no-op regardless of when it was sent. Declaredlogging: {}in the server's capabilities. - feat: the server now identifies which MCP client connected to it.
server.server.getClientVersion()(populated from theclientInfosent in the client'sinitializerequest) is now logged on connect, e.g.Client identified as: claude-ai v1.0.0. Reading it required moving the read to aserver.server.oninitializedcallback rather than right afterserver.connect(), sincegetClientVersion()is only populated once the client'sinitializerequest has actually been processed, which is not guaranteed by the timeconnect()'s promise resolves. Also recorded asmcp.client.name/mcp.client.versionon every subsequent tool-execution trace span (withToolSpan), so OTel-backed traces can be filtered or grouped by client. Matches the equivalent changes landing in@mapbox/mcp-serverand@mapbox/mcp-devkit-server. - chore: bump
@modelcontextprotocol/sdkto1.30.0. Verified this version's ownSUPPORTED_PROTOCOL_VERSIONSconstant does not include the2026-07-28spec revision (https://blog.modelcontextprotocol.io/posts/2026-07-28/) — this repo uses neither elicitation nor sampling, so that migration is lower-priority here regardless; tracked in #40. - chore: add
scripts/check-llms-links.cjs(npm run check-llms-links) to report broken links across allllms.txtfiles exposed from docs.mapbox.com, and flag drift between the curated list indocsSearchIndex.tsand the live root index;npm run check-llms-links:deep(--deep) additionally crawls every docs.mapbox.com sub-link referenced in those files (currently ~1,400 URLs) to proactively catch broken doc pages before customers hit them (#39) - docs: note in CONTRIBUTING.md that unsolicited third-party directory/discovery listing PRs are out of scope and will be closed without review
- security: restrict document tool URL allowlist to documentation hosts and block access_token params (#34)
- chore: upgrade @opentelemetry/* packages to latest minor versions (#TBD)
- Added
src/utils/tracing.tswithinitializeTracing(),shutdownTracing(),getTracer(), andwithToolSpan()— mirrors the tracing implementation inmcp-serverandmcp-devkit-server BaseTool.run()now wraps every tool execution in atool.<name>span viawithToolSpan(); markstool.error=trueon tool-level errorsindex.tscallsinitializeTracing()on startup andshutdownTracing()on graceful exit- OTEL is a no-op unless
OTEL_EXPORTER_OTLP_ENDPOINTorOTEL_EXPORTER_CONSOLE_ENABLED=trueis set; fully suppresses diagnostic output on stdio to preserve MCP protocol - Exports
initializeTracing,shutdownTracing,isTracingInitialized,getTracer,withToolSpanfrom@mapbox/mcp-docs-server/utils - Dependencies:
@opentelemetry/api@^1.9.1,@opentelemetry/resources@^2.6.1,@opentelemetry/sdk-trace-base@^2.6.1,@opentelemetry/sdk-node@^0.214.0,@opentelemetry/instrumentation@^0.214.0,@opentelemetry/exporter-trace-otlp-http@^0.214.0,@opentelemetry/auto-instrumentations-node@^0.72.0,@opentelemetry/semantic-conventions@^1.40.0
docs.mapbox.com restructured its documentation so that llms.txt files now exist at every product level (e.g. docs.mapbox.com/api/llms.txt, docs.mapbox.com/help/llms.txt, docs.mapbox.com/mapbox-gl-js/llms.txt) alongside llms-full.txt files containing full page content. The root docs.mapbox.com/llms.txt is now a pure index of links to these sublevel files rather than a monolithic content file. The previous resources all filtered the root file by category keyword — now that the root contains only link lists, they were effectively returning empty or useless content.
Updated resources to use the appropriate sublevel llms.txt files:
resource://mapbox-api-referencenow fetchesdocs.mapbox.com/api/llms.txt— a clean, structured index of every Mapbox REST API grouped by service (Maps, Navigation, Search, Accounts) with links to full API reference pagesresource://mapbox-guidesnow fetchesdocs.mapbox.com/help/llms.txt(39KB) — the full Mapbox Help Center index with troubleshooting guides, how-to tutorials, and walkthroughsresource://mapbox-sdk-docsnow fetchesdocs.mapbox.com/mapbox-gl-js/llms.txt(34KB) — the GL JS documentation index listing all guides, API reference pages, and examples for the primary web mapping SDKresource://mapbox-referencenow fetches the rootllms.txtwithout filtering and returns the complete product catalog — useful for discovering what documentation exists and findingllms.txtURLs for any productresource://mapbox-examplescontinues to extract playground/demo/example sections from the root index (API Playgrounds, Demos & Projects)
docFetcher.fetchCachedText — new shared helper that fetches a URL and stores it in docCache, used by all five resources to avoid duplicating the fetch+cache pattern.
docFetcher.toMarkdownUrl — no longer rewrites URLs already ending in .txt, .md, or .json. Previously get_document_tool would try to fetch llms.txt.md before falling back; now it fetches llms.txt directly on the first attempt.
search_mapbox_docs_tool no longer depends on the Algolia third-party service. The hosted server shares a single Algolia free-tier quota across all users, making it prone to throttling as usage grows. The new implementation searches directly against the llms.txt index files that now exist at every product level on docs.mapbox.com.
How it works:
On first search, the tool fetches 12 product llms.txt files in parallel (~220KB total). Each file contains a structured list of documentation pages with titles, URLs, and one-line descriptions. These files are cached for the standard 1-hour TTL, so subsequent searches are pure in-memory keyword matching — no network calls.
Products indexed:
- API Reference (
api/llms.txt) - Mapbox GL JS (
mapbox-gl-js/llms.txt) - Help Center (
help/llms.txt) - Style Specification (
style-spec/llms.txt) - Studio Manual (
studio-manual/llms.txt) - Mapbox Search JS (
mapbox-search-js/llms.txt) - Maps SDK for iOS and Android
- Navigation SDK for iOS and Android
- Mapbox Tiling Service
- Tilesets
Scoring: Title matches (3×) outrank description matches (1×) and URL path matches (1×). Results are deduplicated by URL across sources and capped at the requested limit.
Reliability: Failed sources are silently skipped — if any single product llms.txt is unreachable, the remaining sources still return results.
fetchCachedText(url, httpRequest) — new helper in docFetcher.ts that fetches a URL and stores the response in docCache. Used by docsSearchIndex.ts to share the cache with the resource layer (which also caches llms.txt files). Fixed a subtle bug where empty-string responses ('') were not treated as cache hits due to falsy check — now uses !== null.
- Hard cap raised from 2 MB → 5 MB — allows
llms-full.txtfiles (Style Spec 466 KB, iOS Nav 696 KB, GL JS 1.6 MB) to be cached after being fetched viaget_document_tool - Warning at 1 MB —
console.warnwhen an entry between 1 MB and 5 MB is cached, so operators can see large entries in server logs - Warning on rejection — entries exceeding the 5 MB cap now log
[docCache] Entry too large to cacheinstead of being silently dropped
- Upgrade
tshyto^4.1.1,vitestto^4.1.4,typescriptto^6.0.2— removed deprecatedbaseUrlfromtsconfig.base.json(TS6), added"types": ["node"](required because tshy compiles from.tshy/and does not auto-discover@types/nodein CI); downgraded@types/nodeto^22.0.0for LTS consistency with other repos; bumpedtypescript-eslintpackages to^8.58.2for TypeScript 6 support
docs.mapbox.com restructured its documentation so that llms.txt files now exist at every product level (e.g. docs.mapbox.com/api/llms.txt, docs.mapbox.com/help/llms.txt, docs.mapbox.com/mapbox-gl-js/llms.txt) alongside llms-full.txt files containing full page content. The root docs.mapbox.com/llms.txt is now a pure index of links to these sublevel files rather than a monolithic content file. The previous resources all filtered the root file by category keyword — now that the root contains only link lists, they were effectively returning empty or useless content.
Updated resources to use the appropriate sublevel llms.txt files:
resource://mapbox-api-referencenow fetchesdocs.mapbox.com/api/llms.txt— a clean, structured index of every Mapbox REST API grouped by service (Maps, Navigation, Search, Accounts) with links to full API reference pagesresource://mapbox-guidesnow fetchesdocs.mapbox.com/help/llms.txt(39KB) — the full Mapbox Help Center index with troubleshooting guides, how-to tutorials, and walkthroughsresource://mapbox-sdk-docsnow fetchesdocs.mapbox.com/mapbox-gl-js/llms.txt(34KB) — the GL JS documentation index listing all guides, API reference pages, and examples for the primary web mapping SDKresource://mapbox-referencenow fetches the rootllms.txtwithout filtering and returns the complete product catalog — useful for discovering what documentation exists and findingllms.txtURLs for any productresource://mapbox-examplescontinues to extract playground/demo/example sections from the root index (API Playgrounds, Demos & Projects)
docFetcher.fetchCachedText — new shared helper that fetches a URL and stores it in docCache, used by all five resources to avoid duplicating the fetch+cache pattern.
docFetcher.toMarkdownUrl — no longer rewrites URLs already ending in .txt, .md, or .json. Previously get_document_tool would try to fetch llms.txt.md before falling back; now it fetches llms.txt directly on the first attempt.
- CVE-2026-4926: Upgraded
@modelcontextprotocol/sdkto^1.29.0, resolvingpath-to-regexpto8.4.1and fixing the ReDoS vulnerability GHSA-j3q9-mxjg-w52f
- New
search_mapbox_docs_toolsearches all Mapbox documentation via the Algolia index powering docs.mapbox.com - Returns ranked results with titles, URLs, and content excerpts — use
get_document_toolto fetch the full page content - Supports 1–20 results per query (default 5)
@mapbox/mcp-docs-serveris now available as a hosted MCP endpoint athttps://mcp-docs.mapbox.com/mcp— no install or token required- Connect directly from Claude Code, Claude Desktop, Cursor, or VS Code using the
urlfield in your MCP config
- Replaced stale tool name references with
get_document_toolandbatch_get_documents_tool - Removed "coming soon" markers from all resources in the resources table
- Dropped deprecated
resource://mapbox-documentationentry
- Added
.github/workflows/claude-review.ymlusinganthropics/claude-code-action@v1 - Triggers automatically on PRs with ≥ 300 lines changed, or on any PR when a reviewer comments
@claude
- Added barrel files
src/tools/index.ts,src/resources/index.ts, andsrc/utils/index.ts - Exposed
./tools,./resources, and./utilssub-path exports viatshyand theexportsmap inpackage.json - Enables hosted-mcp-server and other consumers to import server internals directly without bundling the full entry point
- Deduplicate intra-batch URLs by normalized key: multiple input URLs that resolve to the same page (e.g. cache-busting query params) now share a single HTTP request and a single buffered body instead of each triggering a separate fetch
- Add streaming response body size cap via
readBodyWithLimit: aborts reads that exceed 2 MB before the full body is buffered; also rejects onContent-Lengthbefore reading begins - Apply the same body size cap to
get_document_tool
- Added a 512-entry LRU eviction limit to prevent unbounded Map growth
- Added a 2 MB per-entry cap — oversized responses are not cached
- Added a 50 MB total cache size cap with oldest-first eviction
- Normalized cache keys by stripping query parameters and hash fragments, preventing cache-busting query strings from inflating the entry count
- Added 22 unit tests covering all new cache invariants
- MCP documentation server forked from
mcp-devkit-server, retaining only documentation-related tools and resources - No API token required: All tools work without a Mapbox access token
- Dual ESM/CJS build via
tshy - TypeScript with strict mode, ESLint, Prettier, Husky + lint-staged
- Vitest test suite with
passWithNoTests - GitHub Actions CI workflow