@skyphusion/search-mcp 0.4.0 → 0.5.0
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/README.md +16 -1
- package/package.json +4 -1
- package/scripts/sync.mjs +26 -3
package/README.md
CHANGED
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
Open-source toolkit for [Cloudflare AI Search](https://developers.cloudflare.com/ai-search/):
|
|
8
8
|
|
|
9
|
-
1. **MCP Worker** (`src/mcp.ts`) -- bearer-gated Streamable-HTTP MCP
|
|
9
|
+
1. **MCP Worker** (`src/mcp.ts`) -- bearer-gated Streamable-HTTP MCP for agents:
|
|
10
|
+
`search`, `list_repos`, `get_file`, `ask`, `corpus_status`, plus `corpus://` resources.
|
|
10
11
|
2. **Query Worker** (`src/index.ts`) -- CORS + Turnstile + rate-limited `POST /ask` that streams answers for a browser widget.
|
|
11
12
|
3. **Corpus sync** (`scripts/sync.mjs`, `scripts/sync-runner.mjs`) -- git-tracked sources to R2, with extension remapping so TypeScript, Dockerfiles, and other text AI Search would otherwise skip get indexed.
|
|
12
13
|
|
|
@@ -104,6 +105,20 @@ wrangler secret put TURNSTILE_SECRET # optional; skips verification when unset
|
|
|
104
105
|
|
|
105
106
|
`MCP_TOKEN` accepts a single token or comma-separated `name=token` pairs for per-consumer attribution in logs.
|
|
106
107
|
|
|
108
|
+
### MCP tools (agents)
|
|
109
|
+
|
|
110
|
+
| Tool | Role |
|
|
111
|
+
| --- | --- |
|
|
112
|
+
| `list_repos` | Exact repo names for filters (`CORPUS_REPOS` or R2 prefixes) |
|
|
113
|
+
| `search` | Hybrid/keyword/vector chunks; optional `repos`, `path_prefix`, `min_score`, `rewrite` |
|
|
114
|
+
| `get_file` | Capped R2 read by `repo` + `path` (needs `CORPUS` binding) |
|
|
115
|
+
| `ask` | One grounded answer via chatCompletions + source list |
|
|
116
|
+
| `corpus_status` | Last sync metadata (`_meta/corpus-status.json` from `sync.mjs`) |
|
|
117
|
+
|
|
118
|
+
Resources: `corpus://catalog`, `corpus://skill`. Prefer **list_repos → search → get_file**; use **ask** when you want prose rather than raw chunks.
|
|
119
|
+
|
|
120
|
+
Bind the same R2 bucket the sync uploads to as `CORPUS` on the MCP Worker so `get_file` and status work. Optional `CORPUS_REPOS` JSON pins the catalog without listing R2.
|
|
121
|
+
|
|
107
122
|
## Corpus sync
|
|
108
123
|
|
|
109
124
|
```sh
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skyphusion/search-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Bearer-gated MCP server and streaming query Worker over Cloudflare AI Search, plus a git-to-R2 corpus sync toolkit.",
|
|
5
5
|
"license": "AGPL-3.0-only",
|
|
6
6
|
"author": "Conrad Rockenhaus <conrad@skyphusion.org>",
|
|
@@ -76,5 +76,8 @@
|
|
|
76
76
|
"typescript": "^7.0.2",
|
|
77
77
|
"vitest": "^4.1.10",
|
|
78
78
|
"wrangler": "^4.110.0"
|
|
79
|
+
},
|
|
80
|
+
"overrides": {
|
|
81
|
+
"undici": "7.29.0"
|
|
79
82
|
}
|
|
80
83
|
}
|
package/scripts/sync.mjs
CHANGED
|
@@ -350,13 +350,36 @@ async function main() {
|
|
|
350
350
|
ContinuationToken = res.IsTruncated ? res.NextContinuationToken : undefined;
|
|
351
351
|
} while (ContinuationToken);
|
|
352
352
|
|
|
353
|
-
|
|
354
|
-
|
|
353
|
+
// Never prune operator/meta keys written for MCP corpus_status.
|
|
354
|
+
const stalePrune = stale.filter((o) => o.Key && !o.Key.startsWith("_meta/"));
|
|
355
|
+
for (let i = 0; i < stalePrune.length; i += 1000) {
|
|
356
|
+
const batch = stalePrune.slice(i, i + 1000);
|
|
355
357
|
await s3.send(
|
|
356
358
|
new DeleteObjectsCommand({ Bucket, Delete: { Objects: batch } }),
|
|
357
359
|
);
|
|
358
360
|
}
|
|
359
|
-
console.log(`Pruned ${
|
|
361
|
+
console.log(`Pruned ${stalePrune.length} stale objects.`);
|
|
362
|
+
|
|
363
|
+
// MCP corpus_status + list_repos freshness (search-mcp agent tooling).
|
|
364
|
+
const status = {
|
|
365
|
+
ts: Date.now(),
|
|
366
|
+
ok: true,
|
|
367
|
+
target: targetName,
|
|
368
|
+
bucket: target.bucket,
|
|
369
|
+
instance: target.instance,
|
|
370
|
+
objectCount: plan.length,
|
|
371
|
+
repos: [...target.repos],
|
|
372
|
+
note: "Written by scripts/sync.mjs after successful upload+prune.",
|
|
373
|
+
};
|
|
374
|
+
await s3.send(
|
|
375
|
+
new PutObjectCommand({
|
|
376
|
+
Bucket,
|
|
377
|
+
Key: "_meta/corpus-status.json",
|
|
378
|
+
Body: Buffer.from(JSON.stringify(status, null, 2), "utf8"),
|
|
379
|
+
ContentType: "application/json",
|
|
380
|
+
}),
|
|
381
|
+
);
|
|
382
|
+
console.log("Wrote _meta/corpus-status.json for MCP corpus_status.");
|
|
360
383
|
console.log("Done. AI Search will re-index on its next sync.");
|
|
361
384
|
}
|
|
362
385
|
|