About cyanheads-mcp-server
A semantic catalog for discovering tools and servers across the cyanheads MCP fleet. It returns ranked matches and can provide descriptions, connection details, and client-specific installation snippets.
Key features
- 01Search tools and servers with natural-language queries
- 02Rank matches by semantic similarity
- 03Retrieve entry descriptions and connection URLs
- 04Generate per-client installation snippets
- 05Refresh the catalog in the background
Use cases
- 01Find an MCP tool for a described task
- 02Identify which server owns a matching tool
- 03Get connection and setup details for a catalog entry
MCP support
Exposes catalog search and entry-description tools to MCP clients, including connection URLs and installation snippets. Supports STDIO and Streamable HTTP transports.
Configuration
Remote servers need no local install. Pick your client, then copy the config or install in one click.
https://cyanheads.caseyjhand.com/mcpclaude mcp add --transport http cyanheads-cyanheads https://cyanheads.caseyjhand.com/mcp{"mcpServers":{"cyanheads-cyanheads":{"type":"http","url":"https://cyanheads.caseyjhand.com/mcp"}}}Open in Cursor{"servers":{"cyanheads-cyanheads":{"type":"http","url":"https://cyanheads.caseyjhand.com/mcp"}}}Open in VS Code{"mcpServers":{"cyanheads-cyanheads":{"type":"http","url":"https://cyanheads.caseyjhand.com/mcp"}}}{"mcpServers":{"cyanheads-cyanheads":{"serverUrl":"https://cyanheads.caseyjhand.com/mcp"}}}Run commands in a terminal; paste JSON into the client’s MCP config and restart. Servers that need sign-in will prompt on first connect.
Tools
2| Parameter | Type | Required | Description |
|---|---|---|---|
| limit | integer | No | Maximum number of results to return (1-20). Default 5. |
| query | string | Yes | Natural language search query. Describe what you want to accomplish, a workflow, or a capability area. 1-500 raw characters; surrounding whitespace is trimmed. Must contain non-whitespace text. |
| scope | enum | No | What to search. "tools" returns individual tool matches; "servers" returns server-level matches.tools | servers |
| offset | integer | No | Result offset. Use nextOffset with the same query, scope, category, and limit; pages use the current catalog. |
| category | enum | No | Filter by catalog category. Omit to search all categories.research | government | public-data | utility |
| serversOffset | integer | No | Independent server roll-up offset (10 per page). Use nextServersOffset; must be zero in servers scope. |
Details
From the project README@cyanheads/cyanheads-mcp-server
Fleet discovery for the cyanheads MCP ecosystem — semantic search + install snippets.
Public Hosted Server: https://cyanheads.caseyjhand.com/mcp
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
| Tool | Description |
|---|---|
cyanheads_search_catalog | Search fleet tools and servers by natural-language query. Returns ranked matches with brief summaries and the owning server. |
cyanheads_describe_entry | Return the description, connection URL, and per-client install snippet for a named tool or server. |
Capability reference
cyanheads_search_catalog tool
query1–500 raw characters, with non-whitespace text required; surrounding whitespace is trimmed before embedding and echo.scopeselectstools(default) orservers; optionalcategory:research,government,public-data,utility;limit1–1000 (default 5), served at most 20 per call: when a largerlimitleaves matches past the page, the response addstruncated,shown,cap, and anoticenaming the offset to continue from.- Results carry cosine-similarity
score([0, 1], comparable within one response). Tool searches include aserversroll-up with ten entries per page andserversTotal; an unloaded catalog returns retryablecatalog_empty. - Page results with
offsetand the tools-scope roll-up independently withserversOffset(both default to 0). Reuse the same query, scope, category, and limit withnextOffset/nextServersOffset; null means exhausted. Each call uses the current catalog, so a refresh between pages can change ordering. Servers scope requiresserversOffset: 0and omits roll-up fields. SIMILARITY_FLOOR(default0.3) filters matches before the limit applies.- An empty
categorystring is treated as omitted; other unknown category values are rejected.
cyanheads_describe_entry tool
name1–64 characters accepts a tool or server name, auto-detected or pinned viakind. Exact names win, then unique case-insensitive names; output uses canonical names.clientoptionally selectsclaude-code,cline,codex,cursor,gemini,streamable-http(genericmcpServersJSON), orcurl.server(optional, 1–64 characters) names the owning server: a search result'sname+serverdescribes 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, andserverstrings are treated as omitted. Other unknownkindorclientvalues 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 aninstallNoticenaming a stdio client to try. Required environment variables remain visible even without snippets. - Descriptions are catalog text; obtain tool schemas from the connected server's
tools/list. - Failures return
not_found,ambiguous_kind(setkind),ambiguous_owner(setserver; the error lists the owners), or retryablecatalog_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, default3600) with an atomic index swap whengeneratedAtchanges — 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 insidefleet.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 than1e-4off. - 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_entryresolves 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_URLcan 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
limitabove 20 is cut to the per-call cap - Discriminated
result.kind(tool|server) oncyanheads_describe_entrylets callers branch on data, not string parsing - Every search result carries a
scorefield for trust calibration, plus aserversroll-up so agents can see which servers matched without a second call
Getting started
Public Hosted Instance
A public instance is available at https://cyanheads.caseyjhand.com/mcp — no installation required. It serves Streamable HTTP; each client takes its own config shape.
For Claude Code:
claude mcp add --transport http cyanheads https://cyanheads.caseyjhand.com/mcp
For Cline (cline_mcp_settings.json):
{
"mcpServers": {
"cyanheads-mcp-server": {
"type": "streamableHttp",
"url": "https://cyanheads.caseyjhand.com/mcp"
}
}
}
For Cursor (mcp.json):
{
"mcpServers": {
"cyanheads-mcp-server": {
"url": "https://cyanheads.caseyjhand.com/mcp"
}
}
}
Claude Desktop adds remote servers under Settings → Connectors.
Claude Desktop bundle
Download the MCPB bundle for a local stdio install. It includes ONNX WebAssembly inference, so it does not need platform-specific native libraries. The first start downloads the embedding model; subsequent starts reuse the model cache. npm and Docker installs use native CPU inference.
Self-Hosted / Local
Add the following to your MCP client configuration file.
{
"mcpServers": {
"cyanheads-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/cyanheads-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"cyanheads-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/cyanheads-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with Docker:
{
"mcpServers": {
"cyanheads-mcp-server": {
"type": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "ghcr.io/cyanheads/cyanheads-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
Prerequisites
- Bun v1.4.0 or higher (or Node.js v24+).
Installation
- Clone the repository:
git clone https://github.com/cyanheads/cyanheads-mcp-server.git
- Navigate into the directory:
cd cyanheads-mcp-server
- Install dependencies:
bun install
- Configure environment:
cp .env.example .env
# edit .env to override any defaults
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.
| Variable | Description | Default |
|---|---|---|
MCP_TRANSPORT_TYPE | Transport: stdio or http | stdio |
MCP_HTTP_PORT | HTTP server port | 3010 |
MCP_HTTP_HOST | HTTP server bind host | 127.0.0.1 |
MCP_HTTP_ENDPOINT_PATH | HTTP endpoint path where the MCP server is mounted | /mcp |
MCP_AUTH_MODE | Authentication: none, jwt, or oauth | none |
MCP_SESSION_MODE | HTTP session posture: auto, stateful, or stateless. src/index.ts declares stateless; set this only to override it. | stateless |
MCP_LOG_LEVEL | Log level (debug, info, warning, error, etc.) | info |
CATALOG_URL | Remote fleet.json endpoint (schema v2 with baked embeddings). Must be an absolute URL. Override to front your own fleet. | https://caseyjhand.com/fleet.json |
CATALOG_FETCH_TIMEOUT_MS | Per-request timeout for fleet.json fetches: integer milliseconds, 1–2147483647. | 10000 |
CATALOG_REFRESH_SECONDS | Background poll interval for fleet.json refresh. 0 disables; positive values up to 2147483.647 seconds use the runtime's millisecond timer resolution. | 3600 |
EMBEDDING_MODEL_ID | Hugging Face model id for query embedding. Must match fleet.json.embeddingModel. | Snowflake/snowflake-arctic-embed-m-v1.5 |
SIMILARITY_FLOOR | Cosine similarity cutoff for cyanheads_search_catalog results. Must be within [0, 1]. | 0.3 |
OTEL_ENABLED | Enable OpenTelemetry | false |
OTEL_EXPORTER_OTLP_ENDPOINT | OTLP base URL for traces and metrics | Unset |
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT | Explicit OTLP logs URL; requires the OTel log peers included in the default Docker build | Unset |
LOG_TOOL_FAILURE_PAYLOADS | Log failed arguments and results, redacted by key name. Secrets inside free-form values are not redacted. | false |
LOG_TOOL_FAILURE_PAYLOAD_MAX_BYTES | UTF-8 byte cap for each logged failure payload | 16384 |
See .env.example for the full list of optional overrides.
Running the server
Local development
-
Build and run the production version:
# One-time build bun run rebuild # Run the built server bun run start:http # or bun run start:stdio -
Run checks and tests:
bun run devcheck # Lints, formats, type-checks, runs MCP and packaging linters bun run test # Runs the test suite
Docker
docker build -t cyanheads-mcp-server .
docker run --rm -p 3010:3010 cyanheads-mcp-server
The Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/cyanheads-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
Project structure
| Directory | Purpose |
|---|---|
src/mcp-server/tools | Tool definitions (*.tool.ts). Two tools — cyanheads_search_catalog and cyanheads_describe_entry. |
src/services/catalog | Catalog service — remote fleet.json provider with atomic-swap refresh, vector index, snippet builders, the self-description fallback record, and the query-time embedding runtime (@huggingface/transformers, behind an injectable interface for deterministic tests). |
src/config | Server-specific environment variable parsing and validation with Zod. |
tests/ | Unit and integration tests, mirroring the src/ structure. |
docs/ | Design doc and schema reference. |
Development guide
See CLAUDE.md for development guidelines and architectural rules. The short version:
- Handlers throw, framework catches — no
try/catchin tool logic - Use
ctx.logfor logging,ctx.statefor storage - Register new tools in the
toolsarray passed tocreateApp()insrc/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:
bun run devcheck
bun run test
License
Apache-2.0 — see LICENSE for details.
Comments
New to MCP?
From what the protocol is to installing your first server, these answers cover most first questions.
An open protocol that defines how AI applications connect to external tools and data in a uniform way. Clients talk to the model; MCP servers provide tools, resources and prompt templates. They exchange standard messages, so one server can be reused by many clients.