@cyanheads/cyanheads-mcp-server
Fleet discovery for the cyanheads MCP ecosystem — semantic search + install snippets.
2 Tools • 0 Resources • 0 Prompts
Overview
Find the right MCP tool for the job across the cyanheads fleet. Describe a task in plain language to search every tool and server, then get a description, connection URL, and install snippet for your client.
Tools
Skills
Capability reference
cyanheads_search_catalog tool
query 1–500 raw characters, with non-whitespace text required; surrounding whitespace is trimmed before embedding and echo. scope selects tools (default) or servers; optional category: research, government, public-data, utility; limit 1–1000 (default 5), served at most 20 per call: when a larger limit leaves matches past the page, the response adds truncated, shown, cap, and a notice naming the offset to continue from.
- Results carry cosine-similarity
score ([0, 1], comparable within one response). Tool searches include a servers roll-up with ten entries per page and serversTotal; an unloaded catalog returns retryable catalog_empty.
- Page results with
offset and the tools-scope roll-up independently with serversOffset (both default to 0). Reuse the same query, scope, category, and limit with nextOffset / nextServersOffset; null means exhausted. Each call uses the current catalog, so a refresh between pages can change ordering. Servers scope requires serversOffset: 0 and omits roll-up fields.
SIMILARITY_FLOOR (default 0.3) filters matches before the limit applies.
- An empty
category string is treated as omitted; other unknown category values are rejected. Categories are catalog labels, not publisher types, and a wrong one drops the matching server without a notice unless nothing else matches.
cyanheads_describe_entry tool
name 1–64 characters accepts a tool or server name, auto-detected or pinned via kind. Exact names win, then unique case-insensitive names; output uses canonical names. client optionally selects claude-code, cline, codex, cursor, gemini, streamable-http (generic mcpServers JSON), or curl.
server (optional, 1–64 characters) names the owning server: a search result's name + server describes exactly that row, in either scope. It is required when more than one server owns the tool name; with a server name, it must name the same server.
- Empty
kind, client, and server strings are treated as omitted. Other unknown kind or client values are rejected.
- Both kinds return connection metadata and install snippets; server results also include the full tool inventory. Published servers get local snippets; hosted servers also get HTTP snippets. For local-only entries,
client: "curl" returns successful metadata with an installNotice naming a stdio client to try. Required environment variables remain visible even without snippets; they list what the server's manifest marks required, so a key it leaves optional is absent.
- Descriptions are catalog text; obtain tool schemas from the connected server's
tools/list.
- Failures return
not_found, ambiguous_kind (set kind), ambiguous_owner (set server; the error lists the owners), or retryable catalog_empty.
Features
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.
Catalog-specific:
- Hourly background catalog refresh (
CATALOG_REFRESH_SECONDS, default 3600) with an atomic index swap when generatedAt changes — no restart needed
- Empty catalogs, conflicting duplicate identities, and vectors that can't be normalized (wrong dimension, all zeros, or a non-finite component) fail before index replacement; refresh retains the last valid catalog. Identical duplicates collapse before indexing, with a bounded load-time warning; servers with no tools remain valid.
- Query embeddings are computed at request time via
@huggingface/transformers; document embeddings are pre-computed, L2-normalized, and Matryoshka-truncated, shipped inside fleet.json. The server normalizes each document vector again at load, so scores stay cosine similarities even when a catalog's vectors drift from unit length, and a bounded warning names vectors more than 1e-4 off.
- The embedding model is warmed up during startup, before OpenTelemetry's HTTP instrumentation patches
fetch — avoids a cold-cache model-load failure under OTEL
- Self-describing:
cyanheads_describe_entry resolves this server's own name and tools from a static fallback record, consulted only when the remote catalog doesn't carry an entry for it
CATALOG_URL can point at any endpoint serving the same schema, to front a custom fleet
Agent-friendly output:
- Search responses echo the effective query, report the total match count before the limit, include broadening guidance when nothing matches, and name the offset to continue from when a
limit above 20 is cut to the per-call cap
- Discriminated
result.kind (tool | server) on cyanheads_describe_entry lets callers branch on data, not string parsing
- Every search result carries a
score field for trust calibration, plus a servers roll-up so agents can see which servers matched without a second call
Getting started
Connect to the hosted instance, no install:
Or run it locally:
For other clients, add this to the MCP config file:
The Claude Desktop bundle (the install badge above) runs the embedding model on ONNX WebAssembly, so it needs no platform-specific native libraries; npm and Docker installs use native CPU inference. Either way, the first start downloads the embedding model and later starts reuse the model cache. For Docker or a source build, see Running the server.
Configuration
All configuration is validated at startup via Zod schemas in src/config/server-config.ts. Every variable has a sensible default — out of the box, the server points at the canonical cyanheads fleet.
See .env.example for the full list of optional overrides.
Running the server
Local development
Requires Bun v1.4.0 or higher (or Node.js v24+).
Docker
The image defaults to HTTP transport, stateless session mode, and logs to /var/log/cyanheads-mcp-server. To run it over stdio from an MCP client, use "command": "docker" with "args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "ghcr.io/cyanheads/cyanheads-mcp-server:latest"]. To build locally, docker build -t cyanheads-mcp-server .; OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
Project structure
Development guide
See CLAUDE.md for development guidelines and architectural rules. The short version:
- Handlers throw, framework catches — no
try/catch in tool logic
- Use
ctx.log for logging, ctx.state for storage
- Register new tools in the
tools array passed to createApp() in src/index.ts
- Wrap external data: validate raw → normalize to domain type → return output schema; never fabricate missing fields
Contributing
Issues are welcome. Run checks and tests before submitting:
License
Apache-2.0 — see LICENSE for details.