@cyanheads/cyanheads-mcp-server 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +367 -0
- package/CLAUDE.md +367 -0
- package/Dockerfile +99 -0
- package/LICENSE +201 -0
- package/README.md +143 -0
- package/changelog/0.1.x/0.1.0.md +12 -0
- package/changelog/0.1.x/0.1.1.md +38 -0
- package/changelog/template.md +127 -0
- package/dist/config/server-config.d.ts +19 -0
- package/dist/config/server-config.d.ts.map +1 -0
- package/dist/config/server-config.js +66 -0
- package/dist/config/server-config.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-server/tools/definitions/describe.tool.d.ts +67 -0
- package/dist/mcp-server/tools/definitions/describe.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/describe.tool.js +192 -0
- package/dist/mcp-server/tools/definitions/describe.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/search.tool.d.ts +53 -0
- package/dist/mcp-server/tools/definitions/search.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/search.tool.js +123 -0
- package/dist/mcp-server/tools/definitions/search.tool.js.map +1 -0
- package/dist/services/catalog/catalog-service.d.ts +50 -0
- package/dist/services/catalog/catalog-service.d.ts.map +1 -0
- package/dist/services/catalog/catalog-service.js +233 -0
- package/dist/services/catalog/catalog-service.js.map +1 -0
- package/dist/services/catalog/embeddings-runtime.d.ts +21 -0
- package/dist/services/catalog/embeddings-runtime.d.ts.map +1 -0
- package/dist/services/catalog/embeddings-runtime.js +62 -0
- package/dist/services/catalog/embeddings-runtime.js.map +1 -0
- package/dist/services/catalog/remote-catalog-provider.d.ts +20 -0
- package/dist/services/catalog/remote-catalog-provider.d.ts.map +1 -0
- package/dist/services/catalog/remote-catalog-provider.js +84 -0
- package/dist/services/catalog/remote-catalog-provider.js.map +1 -0
- package/dist/services/catalog/snippets.d.ts +16 -0
- package/dist/services/catalog/snippets.d.ts.map +1 -0
- package/dist/services/catalog/snippets.js +51 -0
- package/dist/services/catalog/snippets.js.map +1 -0
- package/dist/services/catalog/types.d.ts +135 -0
- package/dist/services/catalog/types.d.ts.map +1 -0
- package/dist/services/catalog/types.js +8 -0
- package/dist/services/catalog/types.js.map +1 -0
- package/package.json +83 -0
- package/server.json +141 -0
package/README.md
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# cyanheads-mcp-server
|
|
2
|
+
|
|
3
|
+
**One MCP endpoint. 40+ hosted servers. Semantic search over every tool.**
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
https://cyanheads.caseyjhand.com/mcp
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Add that URL to your MCP client. Your agent gets two tools — `cyanheads_search` and `cyanheads_describe` — and uses them to discover and install any server in the cyanheads fleet without you maintaining a sprawling local config.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Add it to your client
|
|
14
|
+
|
|
15
|
+
### Claude Desktop
|
|
16
|
+
|
|
17
|
+
Open `~/Library/Application Support/Claude/claude_desktop_config.json` and merge into `mcpServers`:
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"mcpServers": {
|
|
22
|
+
"cyanheads": {
|
|
23
|
+
"type": "sse",
|
|
24
|
+
"url": "https://cyanheads.caseyjhand.com/mcp"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Claude Code
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
claude mcp add --transport sse cyanheads https://cyanheads.caseyjhand.com/mcp
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Cursor
|
|
37
|
+
|
|
38
|
+
Merge into `.cursor/mcp.json`:
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{
|
|
42
|
+
"mcpServers": {
|
|
43
|
+
"cyanheads": {
|
|
44
|
+
"type": "sse",
|
|
45
|
+
"url": "https://cyanheads.caseyjhand.com/mcp"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Cline
|
|
52
|
+
|
|
53
|
+
Merge into Cline's MCP settings:
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"cyanheads": {
|
|
58
|
+
"type": "sse",
|
|
59
|
+
"url": "https://cyanheads.caseyjhand.com/mcp",
|
|
60
|
+
"disabled": false,
|
|
61
|
+
"autoApprove": []
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## What you can ask
|
|
69
|
+
|
|
70
|
+
| You say | Agent finds |
|
|
71
|
+
|:--|:--|
|
|
72
|
+
| "search recent arxiv papers about quantum computing" | `arxiv_search` (arxiv-mcp-server), via semantic match on "research papers" |
|
|
73
|
+
| "look up earthquake activity in California" | `earthquake_search` (earthquake-mcp-server) |
|
|
74
|
+
| "what server handles federal spending data?" | `usaspending-mcp-server` (scope: servers) |
|
|
75
|
+
| "find a tool that resolves a place name to coordinates" | `openstreetmap_geocode` (openstreetmap-mcp-server) |
|
|
76
|
+
| "how do I add the bioRxiv server to Cursor?" | Install snippet via `cyanheads_describe` |
|
|
77
|
+
|
|
78
|
+
After each search match, the agent can ask `cyanheads_describe` to get the connection URL and per-client install snippet so you can add the underlying server directly if you want it always-on.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## What's in the fleet
|
|
83
|
+
|
|
84
|
+
40+ MCP servers spanning four domains. The catalog is regenerated on every portfolio deploy by walking each server's live endpoint — descriptions and tool names always match what the server actually exposes.
|
|
85
|
+
|
|
86
|
+
| Category | Examples |
|
|
87
|
+
|:--|:--|
|
|
88
|
+
| **Research** | arXiv, bioRxiv, ORCID, Crossref, Wikipedia, Wikidata, OpenLibrary |
|
|
89
|
+
| **Government** | OpenStates, USAspending, CourtListener, NIST NVD, Library of Congress |
|
|
90
|
+
| **Public Data** | Earthquake (USGS), NOAA Weather, GBIF Biodiversity, World Bank, WHO, Eurostat |
|
|
91
|
+
| **Utility** | OpenStreetMap geocoding, Reference Data (constants, timezones, units), WSDOT |
|
|
92
|
+
|
|
93
|
+
Each server is open source and individually addressable — `cyanheads_describe` returns the direct connection URL alongside the install snippet.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## How it works
|
|
98
|
+
|
|
99
|
+
Two tools, semantic ranking, hosted catalog.
|
|
100
|
+
|
|
101
|
+
- **`cyanheads_search`** embeds your natural-language query with [Snowflake Arctic Embed M v1.5](https://huggingface.co/Snowflake/snowflake-arctic-embed-m-v1.5) (Matryoshka-truncated to 256 dimensions) and computes cosine similarity against the catalog's pre-computed document vectors. Returns the top-N matching tools or servers.
|
|
102
|
+
- **`cyanheads_describe`** returns the description, connection URL, and per-client install snippet for any tool or server name.
|
|
103
|
+
|
|
104
|
+
The catalog itself lives at [`caseyjhand.com/fleet.json`](https://caseyjhand.com/fleet.json) — a single JSON file with baked embeddings, regenerated when servers are added or updated. This server polls it hourly and serves search out of an in-memory vector index.
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Self-hosting
|
|
109
|
+
|
|
110
|
+
You probably don't need this — the hosted endpoint is the product. The source is open for reference and the rare case where you want to front your own fleet.
|
|
111
|
+
|
|
112
|
+
```sh
|
|
113
|
+
git clone https://github.com/cyanheads/cyanheads-mcp-server.git
|
|
114
|
+
cd cyanheads-mcp-server
|
|
115
|
+
bun install
|
|
116
|
+
bun run build
|
|
117
|
+
bun run start:http
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Environment variables (all optional):
|
|
121
|
+
|
|
122
|
+
| Variable | Default | Description |
|
|
123
|
+
|:--|:--|:--|
|
|
124
|
+
| `CATALOG_URL` | `https://caseyjhand.com/fleet.json` | Remote fleet.json endpoint (must be schema v2 with baked embeddings). |
|
|
125
|
+
| `CATALOG_REFRESH_SECONDS` | `3600` | Background poll interval. 0 disables. |
|
|
126
|
+
| `EMBEDDING_MODEL_ID` | `Snowflake/snowflake-arctic-embed-m-v1.5` | Must match `fleet.json.embeddingModel`. |
|
|
127
|
+
| `SIMILARITY_FLOOR` | `0.3` | Cosine similarity threshold below which results are dropped. |
|
|
128
|
+
| `MCP_TRANSPORT_TYPE` | `stdio` | `stdio` or `http`. |
|
|
129
|
+
| `MCP_HTTP_PORT` | `3000` | HTTP port when transport is `http`. |
|
|
130
|
+
|
|
131
|
+
To point at a different catalog, change `CATALOG_URL` to your own hosted JSON file. See [the cyanheads-mcp-server design doc](./docs/design.md) for the producer-side script and schema.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Built with
|
|
136
|
+
|
|
137
|
+
- [`@cyanheads/mcp-ts-core`](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) — TypeScript MCP server framework
|
|
138
|
+
- [`@huggingface/transformers`](https://www.npmjs.com/package/@huggingface/transformers) — ONNX-based runtime for embeddings inference
|
|
139
|
+
- [Snowflake Arctic Embed M v1.5](https://huggingface.co/Snowflake/snowflake-arctic-embed-m-v1.5) — embedding model (Apache 2.0)
|
|
140
|
+
|
|
141
|
+
## License
|
|
142
|
+
|
|
143
|
+
Apache 2.0. See [LICENSE](./LICENSE).
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Initial scaffold bootstrap from @cyanheads/mcp-ts-core init"
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.1.0 — 2026-05-28
|
|
8
|
+
|
|
9
|
+
## Added
|
|
10
|
+
|
|
11
|
+
- Initial scaffold generated by `bunx @cyanheads/mcp-ts-core init`.
|
|
12
|
+
- Project structure, framework wiring, devcheck configuration, baseline project skills.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "First public release — cyanheads_search semantic discovery over the cyanheads MCP fleet, cyanheads_describe with per-client install snippets"
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.1.1 — 2026-05-28
|
|
8
|
+
|
|
9
|
+
First substantive release. The scaffold tag (`v0.1.0`) carried no functionality; this release lands the full fleet discovery surface.
|
|
10
|
+
|
|
11
|
+
## Added
|
|
12
|
+
|
|
13
|
+
- **`cyanheads_search`** — semantic search over fleet tools and servers. Embeds the query at runtime with [`Snowflake/snowflake-arctic-embed-m-v1.5`](https://huggingface.co/Snowflake/snowflake-arctic-embed-m-v1.5), dot-products against L2-normalized 256-dim Matryoshka-truncated document vectors, filters by category and similarity floor, returns ranked matches. Auth scope: `tool:cyanheads_search:read`.
|
|
14
|
+
- **`cyanheads_describe`** — returns description, hosted connection URL, and per-client install snippets (Claude Desktop, Claude Code, Cursor, Cline) for any named tool or server. Auto-detects kind from name format (underscores → tool, hyphens → server). Auth scope: `tool:cyanheads_describe:read`.
|
|
15
|
+
- **`CatalogService`** — in-memory packed `Float32Array` vector index, atomic-swap refresh on every `fleet.json` `generatedAt` change. Polls hourly by default.
|
|
16
|
+
- **`TransformersEmbeddingsRuntime`** — wraps `@huggingface/transformers`'s `feature-extraction` pipeline. Loads the model once at startup and reuses it for every query.
|
|
17
|
+
- **`RemoteJsonCatalogProvider`** — fetches and Zod-validates the v2 `fleet.json` payload from `CATALOG_URL` (default `https://caseyjhand.com/fleet.json`). Refuses to load on `embeddingModel` mismatch.
|
|
18
|
+
- **Env vars:** `CATALOG_URL`, `CATALOG_FETCH_TIMEOUT_MS`, `CATALOG_REFRESH_SECONDS`, `EMBEDDING_MODEL_ID`, `SIMILARITY_FLOOR`.
|
|
19
|
+
- **Marketing-style README** positioning the hosted endpoint (`https://cyanheads.caseyjhand.com/mcp`) as the product, with per-client install blocks and a category table for the fleet.
|
|
20
|
+
|
|
21
|
+
## Changed
|
|
22
|
+
|
|
23
|
+
- **npm name** scoped to `@cyanheads/cyanheads-mcp-server`.
|
|
24
|
+
- **`mcpName`** added (`io.github.cyanheads/cyanheads-mcp-server`) for MCP Registry resolution.
|
|
25
|
+
- **`server.json`** declares all server-specific env vars on both stdio and HTTP package entries.
|
|
26
|
+
|
|
27
|
+
## Removed
|
|
28
|
+
|
|
29
|
+
- **Echo scaffold** — five definition files and three tests carried over from `bunx init` removed once real definitions landed.
|
|
30
|
+
- **`manifest.json` / `.mcpbignore` / `.codex-plugin/` / `.claude-plugin/`** — the `.mcpb` bundle and plugin marketplace metadata assumed an npx-stdio install path that conflicts with the hosted-endpoint positioning. The corresponding `bundle` and `lint:packaging` scripts went with them.
|
|
31
|
+
|
|
32
|
+
Dependencies:
|
|
33
|
+
|
|
34
|
+
- `@cyanheads/mcp-ts-core` `^0.9.11`
|
|
35
|
+
- `@huggingface/transformers` `4.2.0`
|
|
36
|
+
- `zod` `^4.4.3`
|
|
37
|
+
|
|
38
|
+
46 tests pass; `bun run devcheck` clean.
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
---
|
|
2
|
+
# FORMAT REFERENCE — do not edit. Copy this file to
|
|
3
|
+
# `changelog/<major.minor>.x/<version>.md` (e.g. `changelog/0.8.x/0.8.6.md`)
|
|
4
|
+
# to author a new release. Set that file's H1 to `# <version> — YYYY-MM-DD`
|
|
5
|
+
# with a concrete date.
|
|
6
|
+
|
|
7
|
+
# Required. One-line GitHub Release-style headline. 350 character cap.
|
|
8
|
+
# Default short and scannable. Don't pad, don't stitch unrelated changes with
|
|
9
|
+
# semicolons — pick the headline. Quotes required: unquoted YAML treats `: `
|
|
10
|
+
# inside the value as a key separator and fails GitHub's strict parser.
|
|
11
|
+
summary: ""
|
|
12
|
+
|
|
13
|
+
# Set `true` when consumers must change code to upgrade: API removals,
|
|
14
|
+
# signature changes, config renames, behavior changes that break existing
|
|
15
|
+
# usage. Flagged as `Breaking` in the rollup.
|
|
16
|
+
breaking: false
|
|
17
|
+
|
|
18
|
+
# Set `true` if this release contains any security fix. Pairs with the
|
|
19
|
+
# `## Security` section below. Flagged as `Security` in the rollup so
|
|
20
|
+
# users can triage upgrade urgency at a glance.
|
|
21
|
+
security: false
|
|
22
|
+
|
|
23
|
+
# Optional free-form notes for maintenance agents processing this release.
|
|
24
|
+
# Not rendered in CHANGELOG — consumed by agents running `maintenance` on
|
|
25
|
+
# downstream servers. Use for adoption instructions that don't fit the
|
|
26
|
+
# human-facing sections: new files to create, fields to populate, one-time
|
|
27
|
+
# migration steps. Omit the field entirely when there's nothing to say.
|
|
28
|
+
# agent-notes: |
|
|
29
|
+
# <instructions for downstream maintenance agents>
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
# <version> — YYYY-MM-DD
|
|
33
|
+
|
|
34
|
+
<!--
|
|
35
|
+
AUTHORING GUIDE — applies to the new per-version file you create from this
|
|
36
|
+
template.
|
|
37
|
+
|
|
38
|
+
Audience: someone scanning release notes to decide what affects them. Lead
|
|
39
|
+
each bullet with the symbol or concept name in **bold** so they can skip
|
|
40
|
+
what's irrelevant and zoom in on what's not.
|
|
41
|
+
|
|
42
|
+
Tone: terse, fact-dense, not verbose. Default to one sentence per bullet —
|
|
43
|
+
name the symbol, state what changed, stop. Use a second sentence only when
|
|
44
|
+
it carries weight. If a bullet feels long, it is.
|
|
45
|
+
|
|
46
|
+
Cut: mechanism walkthroughs (those belong in JSDoc, AGENTS.md, or the
|
|
47
|
+
relevant skill), ceremonial framings ("This release introduces…",
|
|
48
|
+
backwards-compat paragraphs), file-by-file test enumerations, internal
|
|
49
|
+
implementation notes. Prefer code/symbol names over English re-explanations.
|
|
50
|
+
|
|
51
|
+
Narrative intro: skip by default. Add one short sentence only when the
|
|
52
|
+
release theme genuinely needs framing the bullets can't carry.
|
|
53
|
+
|
|
54
|
+
Sections: Keep a Changelog order — Added, Changed, Deprecated, Removed,
|
|
55
|
+
Fixed, Security. Include only sections with entries; delete the rest
|
|
56
|
+
(including the commented-out scaffolding below). Don't ship empty headers.
|
|
57
|
+
|
|
58
|
+
Include: every distinct fact a reader needs to adopt or audit the release —
|
|
59
|
+
new exports, signatures, lint rule IDs, env vars, breaking changes, version
|
|
60
|
+
bumps on shipped skills. Nothing more.
|
|
61
|
+
|
|
62
|
+
Links: link issues, PRs, docs, or skills where they help a reader jump to
|
|
63
|
+
context. Once per item per entry — don't re-link the same issue in summary,
|
|
64
|
+
narrative, and bullet. Skip links for inline symbol names; code spans speak
|
|
65
|
+
for themselves.
|
|
66
|
+
|
|
67
|
+
Issue/PR URLs: use full URLs. GitHub's bare `#NN` auto-link only resolves
|
|
68
|
+
inside its own UI, not in npm reads or local editors.
|
|
69
|
+
|
|
70
|
+
[#38](https://github.com/cyanheads/mcp-ts-core/issues/38) ← issue
|
|
71
|
+
[#42](https://github.com/cyanheads/mcp-ts-core/pull/42) ← PR
|
|
72
|
+
|
|
73
|
+
Verify numbers exist before linking (`gh issue view NN`, `gh pr view NN`).
|
|
74
|
+
Never speculate on a future number — `#42` for an upcoming PR silently
|
|
75
|
+
resolves to whatever real item already owns 42, and timeline previews pull
|
|
76
|
+
in that unrelated item's metadata.
|
|
77
|
+
|
|
78
|
+
TAG ANNOTATIONS — the annotated tag body renders as the GitHub Release body
|
|
79
|
+
via `gh release create --notes-from-tag`. The tag is a derivative of this
|
|
80
|
+
changelog entry — a condensed, scannable version, not a copy. Format:
|
|
81
|
+
|
|
82
|
+
<theme — omit version number, GitHub prepends it>
|
|
83
|
+
← blank line
|
|
84
|
+
<1-2 sentence context: what this release does>
|
|
85
|
+
← blank line
|
|
86
|
+
Dependency bumps: ← section header
|
|
87
|
+
← blank line
|
|
88
|
+
- `@cyanheads/mcp-ts-core` ^0.9.1 → ^0.9.6 ← bullet
|
|
89
|
+
← blank line
|
|
90
|
+
Changed: ← only sections with entries
|
|
91
|
+
← blank line
|
|
92
|
+
- `format()` output includes `query` in text mode
|
|
93
|
+
← blank line
|
|
94
|
+
Added:
|
|
95
|
+
← blank line
|
|
96
|
+
- `manifest.json` scaffolded for MCPB bundle support
|
|
97
|
+
- Install badges (Claude Desktop, Cursor, VS Code)
|
|
98
|
+
← blank line
|
|
99
|
+
<N> tests pass; `bun run devcheck` clean. ← footer
|
|
100
|
+
|
|
101
|
+
Never a flat comma-separated string. Always structured markdown with
|
|
102
|
+
sections. The tag must scan well as a rendered GitHub Release page.
|
|
103
|
+
-->
|
|
104
|
+
|
|
105
|
+
## Added
|
|
106
|
+
|
|
107
|
+
-
|
|
108
|
+
|
|
109
|
+
## Changed
|
|
110
|
+
|
|
111
|
+
-
|
|
112
|
+
|
|
113
|
+
<!-- ## Deprecated
|
|
114
|
+
|
|
115
|
+
- -->
|
|
116
|
+
|
|
117
|
+
<!-- ## Removed
|
|
118
|
+
|
|
119
|
+
- -->
|
|
120
|
+
|
|
121
|
+
## Fixed
|
|
122
|
+
|
|
123
|
+
-
|
|
124
|
+
|
|
125
|
+
<!-- ## Security
|
|
126
|
+
|
|
127
|
+
- -->
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Server-specific configuration schema and lazy accessor.
|
|
3
|
+
* Separate from the framework's core config — never merge these two schemas.
|
|
4
|
+
* @module config/server-config
|
|
5
|
+
*/
|
|
6
|
+
import { z } from '@cyanheads/mcp-ts-core';
|
|
7
|
+
declare const ServerConfigSchema: z.ZodObject<{
|
|
8
|
+
catalogUrl: z.ZodDefault<z.ZodString>;
|
|
9
|
+
catalogFetchTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
10
|
+
catalogRefreshSeconds: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
11
|
+
embeddingModelId: z.ZodDefault<z.ZodString>;
|
|
12
|
+
similarityFloor: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
13
|
+
}, z.core.$strip>;
|
|
14
|
+
export type ServerConfig = z.infer<typeof ServerConfigSchema>;
|
|
15
|
+
export declare function getServerConfig(): ServerConfig;
|
|
16
|
+
/** Reset cached config (test-only). */
|
|
17
|
+
export declare function resetServerConfig(): void;
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=server-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-config.d.ts","sourceRoot":"","sources":["../../src/config/server-config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAG3C,QAAA,MAAM,kBAAkB;;;;;;iBAgDtB,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAI9D,wBAAgB,eAAe,IAAI,YAAY,CAS9C;AAED,uCAAuC;AACvC,wBAAgB,iBAAiB,IAAI,IAAI,CAExC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Server-specific configuration schema and lazy accessor.
|
|
3
|
+
* Separate from the framework's core config — never merge these two schemas.
|
|
4
|
+
* @module config/server-config
|
|
5
|
+
*/
|
|
6
|
+
import { z } from '@cyanheads/mcp-ts-core';
|
|
7
|
+
import { parseEnvConfig } from '@cyanheads/mcp-ts-core/config';
|
|
8
|
+
const ServerConfigSchema = z.object({
|
|
9
|
+
/**
|
|
10
|
+
* Remote catalog JSON endpoint. Must return a JSON body matching the FleetPayload (v2) schema.
|
|
11
|
+
* Loaded at server startup via RemoteJsonCatalogProvider.
|
|
12
|
+
*/
|
|
13
|
+
catalogUrl: z
|
|
14
|
+
.string()
|
|
15
|
+
.default('https://caseyjhand.com/fleet.json')
|
|
16
|
+
.describe('URL of the remote fleet.json catalog endpoint.'),
|
|
17
|
+
/**
|
|
18
|
+
* Timeout in milliseconds for the remote catalog fetch.
|
|
19
|
+
*/
|
|
20
|
+
catalogFetchTimeoutMs: z.coerce
|
|
21
|
+
.number()
|
|
22
|
+
.default(10000)
|
|
23
|
+
.describe('HTTP timeout for remote catalog fetch in milliseconds.'),
|
|
24
|
+
/**
|
|
25
|
+
* Background poll interval. The service re-fetches fleet.json on this cadence
|
|
26
|
+
* and swaps in the new vector index if `generatedAt` changed.
|
|
27
|
+
* Set to 0 to disable background refresh.
|
|
28
|
+
*/
|
|
29
|
+
catalogRefreshSeconds: z.coerce
|
|
30
|
+
.number()
|
|
31
|
+
.default(3600)
|
|
32
|
+
.describe('Seconds between background catalog re-fetches. 0 disables background refresh.'),
|
|
33
|
+
/**
|
|
34
|
+
* Embedding model identifier. Must match `embeddingModel` declared in fleet.json,
|
|
35
|
+
* or the server refuses to load (since vectors live in the same space as the
|
|
36
|
+
* model that produced them).
|
|
37
|
+
*/
|
|
38
|
+
embeddingModelId: z
|
|
39
|
+
.string()
|
|
40
|
+
.default('Snowflake/snowflake-arctic-embed-m-v1.5')
|
|
41
|
+
.describe('Hugging Face model id used for query embedding at search time. Must match fleet.json.embeddingModel.'),
|
|
42
|
+
/**
|
|
43
|
+
* Minimum cosine similarity for a result to surface in cyanheads_search output.
|
|
44
|
+
* Tunable post-launch based on observed query patterns.
|
|
45
|
+
*/
|
|
46
|
+
similarityFloor: z.coerce
|
|
47
|
+
.number()
|
|
48
|
+
.default(0.3)
|
|
49
|
+
.describe('Minimum cosine similarity in [0, 1] for a match to appear in search results.'),
|
|
50
|
+
});
|
|
51
|
+
let _config;
|
|
52
|
+
export function getServerConfig() {
|
|
53
|
+
_config ??= parseEnvConfig(ServerConfigSchema, {
|
|
54
|
+
catalogUrl: 'CATALOG_URL',
|
|
55
|
+
catalogFetchTimeoutMs: 'CATALOG_FETCH_TIMEOUT_MS',
|
|
56
|
+
catalogRefreshSeconds: 'CATALOG_REFRESH_SECONDS',
|
|
57
|
+
embeddingModelId: 'EMBEDDING_MODEL_ID',
|
|
58
|
+
similarityFloor: 'SIMILARITY_FLOOR',
|
|
59
|
+
});
|
|
60
|
+
return _config;
|
|
61
|
+
}
|
|
62
|
+
/** Reset cached config (test-only). */
|
|
63
|
+
export function resetServerConfig() {
|
|
64
|
+
_config = undefined;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=server-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-config.js","sourceRoot":"","sources":["../../src/config/server-config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAE/D,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC;;;OAGG;IACH,UAAU,EAAE,CAAC;SACV,MAAM,EAAE;SACR,OAAO,CAAC,mCAAmC,CAAC;SAC5C,QAAQ,CAAC,gDAAgD,CAAC;IAE7D;;OAEG;IACH,qBAAqB,EAAE,CAAC,CAAC,MAAM;SAC5B,MAAM,EAAE;SACR,OAAO,CAAC,KAAK,CAAC;SACd,QAAQ,CAAC,wDAAwD,CAAC;IAErE;;;;OAIG;IACH,qBAAqB,EAAE,CAAC,CAAC,MAAM;SAC5B,MAAM,EAAE;SACR,OAAO,CAAC,IAAI,CAAC;SACb,QAAQ,CAAC,+EAA+E,CAAC;IAE5F;;;;OAIG;IACH,gBAAgB,EAAE,CAAC;SAChB,MAAM,EAAE;SACR,OAAO,CAAC,yCAAyC,CAAC;SAClD,QAAQ,CACP,sGAAsG,CACvG;IAEH;;;OAGG;IACH,eAAe,EAAE,CAAC,CAAC,MAAM;SACtB,MAAM,EAAE;SACR,OAAO,CAAC,GAAG,CAAC;SACZ,QAAQ,CAAC,8EAA8E,CAAC;CAC5F,CAAC,CAAC;AAIH,IAAI,OAAiC,CAAC;AAEtC,MAAM,UAAU,eAAe;IAC7B,OAAO,KAAK,cAAc,CAAC,kBAAkB,EAAE;QAC7C,UAAU,EAAE,aAAa;QACzB,qBAAqB,EAAE,0BAA0B;QACjD,qBAAqB,EAAE,yBAAyB;QAChD,gBAAgB,EAAE,oBAAoB;QACtC,eAAe,EAAE,kBAAkB;KACpC,CAAC,CAAC;IACH,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,uCAAuC;AACvC,MAAM,UAAU,iBAAiB;IAC/B,OAAO,GAAG,SAAS,CAAC;AACtB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;GAGG"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview cyanheads-mcp-server entry point — fleet discovery and passthrough gateway.
|
|
4
|
+
* @module index
|
|
5
|
+
*/
|
|
6
|
+
import { createApp } from '@cyanheads/mcp-ts-core';
|
|
7
|
+
import { getServerConfig } from './config/server-config.js';
|
|
8
|
+
import { describeTool } from './mcp-server/tools/definitions/describe.tool.js';
|
|
9
|
+
import { searchTool } from './mcp-server/tools/definitions/search.tool.js';
|
|
10
|
+
import { getCatalogService, initCatalogService } from './services/catalog/catalog-service.js';
|
|
11
|
+
await createApp({
|
|
12
|
+
name: 'cyanheads-mcp-server',
|
|
13
|
+
tools: [searchTool, describeTool],
|
|
14
|
+
resources: [],
|
|
15
|
+
prompts: [],
|
|
16
|
+
instructions: 'This server is the discovery front door to the cyanheads MCP fleet. ' +
|
|
17
|
+
'Use cyanheads_search to find tools or servers by describing what you want to do. ' +
|
|
18
|
+
'Use cyanheads_describe to get full schemas and per-client install snippets for any result. ' +
|
|
19
|
+
'Scope "tools" (default) finds individual tools; scope "servers" finds which server owns a workflow.',
|
|
20
|
+
async setup() {
|
|
21
|
+
const config = getServerConfig();
|
|
22
|
+
initCatalogService(config);
|
|
23
|
+
await getCatalogService().initialize();
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,iDAAiD,CAAC;AAC/E,OAAO,EAAE,UAAU,EAAE,MAAM,+CAA+C,CAAC;AAC3E,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAE9F,MAAM,SAAS,CAAC;IACd,IAAI,EAAE,sBAAsB;IAC5B,KAAK,EAAE,CAAC,UAAU,EAAE,YAAY,CAAC;IACjC,SAAS,EAAE,EAAE;IACb,OAAO,EAAE,EAAE;IACX,YAAY,EACV,sEAAsE;QACtE,mFAAmF;QACnF,6FAA6F;QAC7F,qGAAqG;IAEvG,KAAK,CAAC,KAAK;QACT,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;QACjC,kBAAkB,CAAC,MAAM,CAAC,CAAC;QAC3B,MAAM,iBAAiB,EAAE,CAAC,UAAU,EAAE,CAAC;IACzC,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview cyanheads_describe — return connection URL and per-client install snippets
|
|
3
|
+
* for a named tool or server.
|
|
4
|
+
* Uses z.discriminatedUnion on 'kind' so the linter walks each branch independently
|
|
5
|
+
* and format() can dispatch cleanly.
|
|
6
|
+
* @module mcp-server/tools/definitions/describe
|
|
7
|
+
*/
|
|
8
|
+
import { z } from '@cyanheads/mcp-ts-core';
|
|
9
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
10
|
+
export declare const describeTool: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
|
|
11
|
+
name: z.ZodString;
|
|
12
|
+
kind: z.ZodOptional<z.ZodEnum<{
|
|
13
|
+
server: "server";
|
|
14
|
+
tool: "tool";
|
|
15
|
+
}>>;
|
|
16
|
+
client: z.ZodOptional<z.ZodEnum<{
|
|
17
|
+
"claude-desktop": "claude-desktop";
|
|
18
|
+
"claude-code": "claude-code";
|
|
19
|
+
cursor: "cursor";
|
|
20
|
+
cline: "cline";
|
|
21
|
+
}>>;
|
|
22
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
23
|
+
result: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
24
|
+
kind: z.ZodLiteral<"tool">;
|
|
25
|
+
name: z.ZodString;
|
|
26
|
+
description: z.ZodString;
|
|
27
|
+
server: z.ZodString;
|
|
28
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
29
|
+
kind: z.ZodLiteral<"server">;
|
|
30
|
+
name: z.ZodString;
|
|
31
|
+
displayName: z.ZodString;
|
|
32
|
+
description: z.ZodString;
|
|
33
|
+
version: z.ZodString;
|
|
34
|
+
npm: z.ZodString;
|
|
35
|
+
github: z.ZodString;
|
|
36
|
+
endpoint: z.ZodString;
|
|
37
|
+
auth: z.ZodString;
|
|
38
|
+
toolCount: z.ZodNumber;
|
|
39
|
+
installSnippets: z.ZodArray<z.ZodObject<{
|
|
40
|
+
client: z.ZodEnum<{
|
|
41
|
+
"claude-desktop": "claude-desktop";
|
|
42
|
+
"claude-code": "claude-code";
|
|
43
|
+
cursor: "cursor";
|
|
44
|
+
cline: "cline";
|
|
45
|
+
}>;
|
|
46
|
+
label: z.ZodString;
|
|
47
|
+
payload: z.ZodString;
|
|
48
|
+
}, z.core.$strip>>;
|
|
49
|
+
}, z.core.$strip>], "kind">;
|
|
50
|
+
}, z.core.$strip>, readonly [{
|
|
51
|
+
readonly reason: "not_found";
|
|
52
|
+
readonly code: JsonRpcErrorCode.NotFound;
|
|
53
|
+
readonly when: "No tool or server with the given name exists in the catalog.";
|
|
54
|
+
readonly recovery: "Use cyanheads_search to find the correct name, then call cyanheads_describe again.";
|
|
55
|
+
}, {
|
|
56
|
+
readonly reason: "ambiguous_kind";
|
|
57
|
+
readonly code: JsonRpcErrorCode.InvalidParams;
|
|
58
|
+
readonly when: "Name matches both a tool and a server (collision in catalog).";
|
|
59
|
+
readonly recovery: "Set the kind parameter to \"tool\" or \"server\" to disambiguate.";
|
|
60
|
+
}, {
|
|
61
|
+
readonly reason: "catalog_empty";
|
|
62
|
+
readonly code: JsonRpcErrorCode.ServiceUnavailable;
|
|
63
|
+
readonly when: "Catalog has not finished loading.";
|
|
64
|
+
readonly recovery: "Retry in a few seconds; the catalog is still loading.";
|
|
65
|
+
readonly retryable: true;
|
|
66
|
+
}]>;
|
|
67
|
+
//# sourceMappingURL=describe.tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"describe.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/describe.tool.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAIjE,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8MvB,CAAC"}
|