@bluenotelogic/mcp 0.2.2

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.
Files changed (47) hide show
  1. package/README.md +85 -0
  2. package/dist/api.d.ts +25 -0
  3. package/dist/api.js +74 -0
  4. package/dist/api.js.map +1 -0
  5. package/dist/http.d.ts +25 -0
  6. package/dist/http.js +158 -0
  7. package/dist/http.js.map +1 -0
  8. package/dist/index.d.ts +20 -0
  9. package/dist/index.js +59 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/prompts/draft_with_refs.d.ts +6 -0
  12. package/dist/prompts/draft_with_refs.js +42 -0
  13. package/dist/prompts/draft_with_refs.js.map +1 -0
  14. package/dist/prompts/summarize.d.ts +6 -0
  15. package/dist/prompts/summarize.js +36 -0
  16. package/dist/prompts/summarize.js.map +1 -0
  17. package/dist/resources/corpora.d.ts +8 -0
  18. package/dist/resources/corpora.js +24 -0
  19. package/dist/resources/corpora.js.map +1 -0
  20. package/dist/resources/documents.d.ts +8 -0
  21. package/dist/resources/documents.js +29 -0
  22. package/dist/resources/documents.js.map +1 -0
  23. package/dist/server.d.ts +8 -0
  24. package/dist/server.js +48 -0
  25. package/dist/server.js.map +1 -0
  26. package/dist/tools/corpus_stats.d.ts +3 -0
  27. package/dist/tools/corpus_stats.js +21 -0
  28. package/dist/tools/corpus_stats.js.map +1 -0
  29. package/dist/tools/get_document.d.ts +3 -0
  30. package/dist/tools/get_document.js +35 -0
  31. package/dist/tools/get_document.js.map +1 -0
  32. package/dist/tools/ingest_text.d.ts +3 -0
  33. package/dist/tools/ingest_text.js +43 -0
  34. package/dist/tools/ingest_text.js.map +1 -0
  35. package/dist/tools/list_corpora.d.ts +3 -0
  36. package/dist/tools/list_corpora.js +28 -0
  37. package/dist/tools/list_corpora.js.map +1 -0
  38. package/dist/tools/list_profiles.d.ts +3 -0
  39. package/dist/tools/list_profiles.js +30 -0
  40. package/dist/tools/list_profiles.js.map +1 -0
  41. package/dist/tools/search.d.ts +3 -0
  42. package/dist/tools/search.js +70 -0
  43. package/dist/tools/search.js.map +1 -0
  44. package/dist/types.d.ts +76 -0
  45. package/dist/types.js +6 -0
  46. package/dist/types.js.map +1 -0
  47. package/package.json +52 -0
package/README.md ADDED
@@ -0,0 +1,85 @@
1
+ # @bluenotelogic/mcp
2
+
3
+ MCP server for CaveauAI — inject corpus content into Claude Code, Claude Desktop, Cursor, Continue, or any other MCP host at runtime, scoped to your retrieval profiles. Published under Blue Note Logic's npm scope; serves the CaveauAI product.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npx @bluenotelogic/mcp@latest --stdio
9
+ ```
10
+
11
+ ## Configure
12
+
13
+ Set two environment variables:
14
+
15
+ | Variable | Required | Default | Notes |
16
+ |----------|----------|---------|-------|
17
+ | `CAVEAU_API_TOKEN` | yes (stdio) | — | Mint one in the portal at `caveauai.bluenotelogic.com/app/mcp`. Shown once. |
18
+ | `CAVEAU_BASE_URL` | no | `https://ai.bluenotelogic.com` | Set this if you self-host or talk to staging. |
19
+
20
+ ## Claude Desktop
21
+
22
+ Add to `claude_desktop_config.json`:
23
+
24
+ ```json
25
+ {
26
+ "mcpServers": {
27
+ "caveau": {
28
+ "command": "npx",
29
+ "args": ["-y", "@bluenotelogic/mcp", "--stdio"],
30
+ "env": {
31
+ "CAVEAU_API_TOKEN": "mcp_…"
32
+ }
33
+ }
34
+ }
35
+ }
36
+ ```
37
+
38
+ ## Claude Code
39
+
40
+ ```bash
41
+ claude mcp add caveau -- npx -y @bluenotelogic/mcp --stdio
42
+ # Then set CAVEAU_API_TOKEN in your shell or via `claude mcp env`
43
+ ```
44
+
45
+ ## Hosted Streamable HTTP
46
+
47
+ For hosts that support remote MCP (Claude Desktop, Cursor with the latest connectors), use the hosted URL instead of npx:
48
+
49
+ ```
50
+ https://mcp.caveauai.bluenotelogic.com/mcp
51
+ Authorization: Bearer mcp_…
52
+ ```
53
+
54
+ ## Tools
55
+
56
+ | Tool | Purpose |
57
+ |------|---------|
58
+ | `caveau.search` | RAG search; returns ranked chunks with source metadata. Optional `profile`, `top_k`, `category`. |
59
+ | `caveau.list_profiles` | List your saved retrieval profiles (named criteria sets). |
60
+ | `caveau.list_corpora` | List corpora you can query — your private ones plus shared subscriptions. |
61
+ | `caveau.get_document` | Fetch a single document and its chunks by id. |
62
+ | `caveau.corpus_stats` | Per-corpus document/chunk counts plus your plan caps. |
63
+ | `caveau.ingest_text` | Add text to one of your private corpora (plan-gated). |
64
+
65
+ ## Retrieval profiles
66
+
67
+ A profile is a saved bundle of *what to retrieve*: which corpora, which search method (vector/keyword/hybrid), top_k, recency cutoff, category and tag whitelists, embedding-model override. Build them in the portal at `caveauai.bluenotelogic.com/app/mcp` and reference them by slug from `caveau.search`.
68
+
69
+ ## Local development
70
+
71
+ ```bash
72
+ npm install
73
+ npm run build
74
+ CAVEAU_API_TOKEN=… node dist/index.js --stdio
75
+ ```
76
+
77
+ Test the server end-to-end with the official inspector:
78
+
79
+ ```bash
80
+ npx @modelcontextprotocol/inspector node dist/index.js --stdio
81
+ ```
82
+
83
+ ## License
84
+
85
+ UNLICENSED — © Blue Note Logic.
package/dist/api.d.ts ADDED
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Thin HTTP client for the CaveauAI MCP runtime API at /api/mcp/*.
3
+ * All calls forward the client's MCP token via the X-MCP-Token header.
4
+ * The server enforces tenant isolation and quota; this client just bubbles
5
+ * up the JSON body and HTTP status.
6
+ */
7
+ export interface ApiConfig {
8
+ baseUrl: string;
9
+ token: string;
10
+ timeoutMs?: number;
11
+ }
12
+ export declare class ApiError extends Error {
13
+ readonly status: number;
14
+ readonly body: unknown;
15
+ constructor(status: number, body: unknown, message: string);
16
+ }
17
+ export declare class CaveauApi {
18
+ private readonly base;
19
+ private readonly token;
20
+ private readonly timeoutMs;
21
+ constructor(cfg: ApiConfig);
22
+ get<T>(path: string): Promise<T>;
23
+ post<T>(path: string, body: unknown): Promise<T>;
24
+ private request;
25
+ }
package/dist/api.js ADDED
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Thin HTTP client for the CaveauAI MCP runtime API at /api/mcp/*.
3
+ * All calls forward the client's MCP token via the X-MCP-Token header.
4
+ * The server enforces tenant isolation and quota; this client just bubbles
5
+ * up the JSON body and HTTP status.
6
+ */
7
+ export class ApiError extends Error {
8
+ status;
9
+ body;
10
+ constructor(status, body, message) {
11
+ super(message);
12
+ this.status = status;
13
+ this.body = body;
14
+ this.name = "ApiError";
15
+ }
16
+ }
17
+ export class CaveauApi {
18
+ base;
19
+ token;
20
+ timeoutMs;
21
+ constructor(cfg) {
22
+ this.base = cfg.baseUrl.replace(/\/+$/, "");
23
+ this.token = cfg.token;
24
+ this.timeoutMs = cfg.timeoutMs ?? 30_000;
25
+ if (!this.token)
26
+ throw new Error("CAVEAU_API_TOKEN is required");
27
+ if (!this.base)
28
+ throw new Error("CAVEAU_BASE_URL is required");
29
+ }
30
+ async get(path) {
31
+ return this.request("GET", path);
32
+ }
33
+ async post(path, body) {
34
+ return this.request("POST", path, body);
35
+ }
36
+ async request(method, path, body) {
37
+ const url = `${this.base}/api/mcp${path.startsWith("/") ? path : `/${path}`}`;
38
+ const ctrl = new AbortController();
39
+ const timer = setTimeout(() => ctrl.abort(), this.timeoutMs);
40
+ try {
41
+ const res = await fetch(url, {
42
+ method,
43
+ headers: {
44
+ "X-MCP-Token": this.token,
45
+ "Content-Type": "application/json",
46
+ Accept: "application/json",
47
+ },
48
+ body: body !== undefined ? JSON.stringify(body) : undefined,
49
+ signal: ctrl.signal,
50
+ });
51
+ const text = await res.text();
52
+ let parsed = null;
53
+ if (text.length > 0) {
54
+ try {
55
+ parsed = JSON.parse(text);
56
+ }
57
+ catch {
58
+ parsed = text;
59
+ }
60
+ }
61
+ if (!res.ok) {
62
+ const detail = parsed && typeof parsed === "object" && "error" in parsed
63
+ ? String(parsed.error)
64
+ : `HTTP ${res.status}`;
65
+ throw new ApiError(res.status, parsed, detail);
66
+ }
67
+ return parsed;
68
+ }
69
+ finally {
70
+ clearTimeout(timer);
71
+ }
72
+ }
73
+ }
74
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
package/dist/http.d.ts ADDED
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Streamable HTTP transport for caveau-mcp.
3
+ *
4
+ * Multi-tenant: each MCP session is tied to a per-client token presented as
5
+ * `Authorization: Bearer <token>` on the initialize request. The token is
6
+ * validated upfront by hitting /api/mcp/profiles (cheap, tenant-scoped). All
7
+ * subsequent tool calls in the session reuse that token.
8
+ *
9
+ * Three routes per the MCP spec:
10
+ * POST /mcp JSON-RPC requests (initialize + subsequent calls)
11
+ * GET /mcp SSE stream from server to client
12
+ * DELETE /mcp Tear down a session
13
+ *
14
+ * Plus an unauthenticated /healthz for Caddy + Uptime Kuma.
15
+ */
16
+ export interface HttpServerOptions {
17
+ port: number;
18
+ apiBaseUrl: string;
19
+ /**
20
+ * If true, allow requests without a Bearer token (token is then taken from
21
+ * CAVEAU_API_TOKEN env). Useful for single-tenant test deployments. Default false.
22
+ */
23
+ allowEnvFallback?: boolean;
24
+ }
25
+ export declare function startHttpServer(opts: HttpServerOptions): Promise<void>;
package/dist/http.js ADDED
@@ -0,0 +1,158 @@
1
+ /**
2
+ * Streamable HTTP transport for caveau-mcp.
3
+ *
4
+ * Multi-tenant: each MCP session is tied to a per-client token presented as
5
+ * `Authorization: Bearer <token>` on the initialize request. The token is
6
+ * validated upfront by hitting /api/mcp/profiles (cheap, tenant-scoped). All
7
+ * subsequent tool calls in the session reuse that token.
8
+ *
9
+ * Three routes per the MCP spec:
10
+ * POST /mcp JSON-RPC requests (initialize + subsequent calls)
11
+ * GET /mcp SSE stream from server to client
12
+ * DELETE /mcp Tear down a session
13
+ *
14
+ * Plus an unauthenticated /healthz for Caddy + Uptime Kuma.
15
+ */
16
+ import express from "express";
17
+ import { randomUUID } from "node:crypto";
18
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
19
+ import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
20
+ import { buildServer } from "./server.js";
21
+ export async function startHttpServer(opts) {
22
+ const sessions = new Map();
23
+ const app = express();
24
+ // Health route (no auth, no body parsing) — wired before json middleware so it never blocks
25
+ app.get("/healthz", (_req, res) => {
26
+ res.status(200).json({
27
+ status: "ok",
28
+ service: "caveau-mcp",
29
+ sessions: sessions.size,
30
+ time: new Date().toISOString(),
31
+ });
32
+ });
33
+ app.use(express.json({ limit: "1mb" }));
34
+ app.post("/mcp", async (req, res) => {
35
+ try {
36
+ const sessionId = headerString(req, "mcp-session-id");
37
+ let entry = sessionId ? sessions.get(sessionId) : undefined;
38
+ if (!entry && sessionId) {
39
+ // Session id supplied but unknown — likely stale
40
+ respondError(res, -32000, "Unknown or expired session", 404);
41
+ return;
42
+ }
43
+ if (!entry) {
44
+ // Brand-new session — must be an initialize request
45
+ if (!isInitializeRequest(req.body)) {
46
+ respondError(res, -32000, "First request must be initialize", 400);
47
+ return;
48
+ }
49
+ const token = extractBearer(req) ?? (opts.allowEnvFallback ? (process.env.CAVEAU_API_TOKEN ?? "") : "");
50
+ if (!token) {
51
+ respondError(res, -32001, "Authorization: Bearer <mcp-token> required", 401);
52
+ return;
53
+ }
54
+ const ok = await validateToken(opts.apiBaseUrl, token);
55
+ if (!ok) {
56
+ respondError(res, -32001, "Invalid or revoked MCP token", 401);
57
+ return;
58
+ }
59
+ const transport = new StreamableHTTPServerTransport({
60
+ sessionIdGenerator: () => randomUUID(),
61
+ onsessioninitialized: (id) => {
62
+ sessions.set(id, { transport, token, createdAt: Date.now() });
63
+ console.log(`[caveau-mcp] session ${id} opened (${sessions.size} active)`);
64
+ },
65
+ });
66
+ transport.onclose = () => {
67
+ if (transport.sessionId) {
68
+ sessions.delete(transport.sessionId);
69
+ console.log(`[caveau-mcp] session ${transport.sessionId} closed (${sessions.size} active)`);
70
+ }
71
+ };
72
+ const server = buildServer({
73
+ apiBaseUrl: opts.apiBaseUrl,
74
+ apiToken: token,
75
+ });
76
+ await server.connect(transport);
77
+ await transport.handleRequest(req, res, req.body);
78
+ return;
79
+ }
80
+ await entry.transport.handleRequest(req, res, req.body);
81
+ }
82
+ catch (err) {
83
+ console.error("[caveau-mcp] POST /mcp error:", err);
84
+ if (!res.headersSent) {
85
+ respondError(res, -32603, "Internal error", 500);
86
+ }
87
+ }
88
+ });
89
+ app.get("/mcp", async (req, res) => {
90
+ const sessionId = headerString(req, "mcp-session-id");
91
+ const entry = sessionId ? sessions.get(sessionId) : undefined;
92
+ if (!entry) {
93
+ res.status(404).json({ error: "Unknown or expired session" });
94
+ return;
95
+ }
96
+ await entry.transport.handleRequest(req, res);
97
+ });
98
+ app.delete("/mcp", async (req, res) => {
99
+ const sessionId = headerString(req, "mcp-session-id");
100
+ const entry = sessionId ? sessions.get(sessionId) : undefined;
101
+ if (!entry) {
102
+ res.status(404).json({ error: "Unknown or expired session" });
103
+ return;
104
+ }
105
+ await entry.transport.handleRequest(req, res);
106
+ });
107
+ await new Promise((resolve) => {
108
+ app.listen(opts.port, () => {
109
+ console.log(`[caveau-mcp] Streamable HTTP listening on :${opts.port}`);
110
+ resolve();
111
+ });
112
+ });
113
+ }
114
+ function headerString(req, name) {
115
+ const v = req.headers[name];
116
+ if (typeof v === "string")
117
+ return v;
118
+ if (Array.isArray(v))
119
+ return v[0];
120
+ return undefined;
121
+ }
122
+ function extractBearer(req) {
123
+ const auth = headerString(req, "authorization");
124
+ if (!auth)
125
+ return undefined;
126
+ const m = /^Bearer\s+(.+)$/i.exec(auth);
127
+ return m?.[1]?.trim();
128
+ }
129
+ async function validateToken(apiBaseUrl, token) {
130
+ try {
131
+ const url = `${apiBaseUrl.replace(/\/+$/, "")}/api/mcp/profiles`;
132
+ const ctrl = new AbortController();
133
+ const timer = setTimeout(() => ctrl.abort(), 8_000);
134
+ try {
135
+ const res = await fetch(url, {
136
+ method: "GET",
137
+ headers: { "X-MCP-Token": token, Accept: "application/json" },
138
+ signal: ctrl.signal,
139
+ });
140
+ return res.ok;
141
+ }
142
+ finally {
143
+ clearTimeout(timer);
144
+ }
145
+ }
146
+ catch (err) {
147
+ console.error("[caveau-mcp] token validation failed:", err);
148
+ return false;
149
+ }
150
+ }
151
+ function respondError(res, code, message, http) {
152
+ res.status(http).json({
153
+ jsonrpc: "2.0",
154
+ error: { code, message },
155
+ id: null,
156
+ });
157
+ }
158
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * caveau-mcp — CaveauAI's MCP server.
4
+ *
5
+ * Two transports from a single binary:
6
+ * --stdio Pipe Claude Code/Desktop stdio to the CaveauAI runtime API.
7
+ * This is what `npx @caveauai/mcp --stdio` runs.
8
+ * --http Streamable HTTP transport on PORT (default 3000). This is the
9
+ * hosted-mode binary that runs in Docker on Colin behind Caddy at
10
+ * mcp.caveauai.bluenotelogic.com.
11
+ *
12
+ * Required env:
13
+ * CAVEAU_API_TOKEN the per-client MCP token minted in the portal
14
+ * CAVEAU_BASE_URL base URL for ai-portal (default https://ai.bluenotelogic.com)
15
+ *
16
+ * In --http mode, CAVEAU_API_TOKEN is unused at startup; each request supplies
17
+ * its own token via the standard MCP Authorization header (forwarded as
18
+ * X-MCP-Token).
19
+ */
20
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * caveau-mcp — CaveauAI's MCP server.
4
+ *
5
+ * Two transports from a single binary:
6
+ * --stdio Pipe Claude Code/Desktop stdio to the CaveauAI runtime API.
7
+ * This is what `npx @caveauai/mcp --stdio` runs.
8
+ * --http Streamable HTTP transport on PORT (default 3000). This is the
9
+ * hosted-mode binary that runs in Docker on Colin behind Caddy at
10
+ * mcp.caveauai.bluenotelogic.com.
11
+ *
12
+ * Required env:
13
+ * CAVEAU_API_TOKEN the per-client MCP token minted in the portal
14
+ * CAVEAU_BASE_URL base URL for ai-portal (default https://ai.bluenotelogic.com)
15
+ *
16
+ * In --http mode, CAVEAU_API_TOKEN is unused at startup; each request supplies
17
+ * its own token via the standard MCP Authorization header (forwarded as
18
+ * X-MCP-Token).
19
+ */
20
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
21
+ import { buildServer } from "./server.js";
22
+ import { startHttpServer } from "./http.js";
23
+ const args = new Set(process.argv.slice(2));
24
+ const useStdio = args.has("--stdio");
25
+ const useHttp = args.has("--http");
26
+ if (useStdio === useHttp) {
27
+ // Default to stdio when neither is given (the npx case).
28
+ if (!useStdio && !useHttp) {
29
+ args.add("--stdio");
30
+ }
31
+ else {
32
+ fail("Pass exactly one of --stdio or --http");
33
+ }
34
+ }
35
+ const baseUrl = (process.env.CAVEAU_BASE_URL ?? "https://ai.bluenotelogic.com").replace(/\/+$/, "");
36
+ if (args.has("--stdio")) {
37
+ const token = process.env.CAVEAU_API_TOKEN ?? "";
38
+ if (!token)
39
+ fail("CAVEAU_API_TOKEN env var is required for --stdio mode");
40
+ const server = buildServer({ apiBaseUrl: baseUrl, apiToken: token });
41
+ const transport = new StdioServerTransport();
42
+ await server.connect(transport);
43
+ // Block; transport stays open until the host closes stdin.
44
+ }
45
+ else {
46
+ const port = parseInt(process.env.PORT ?? "3000", 10);
47
+ if (!Number.isFinite(port) || port < 1 || port > 65535)
48
+ fail(`Bad PORT: ${process.env.PORT}`);
49
+ await startHttpServer({
50
+ port,
51
+ apiBaseUrl: baseUrl,
52
+ allowEnvFallback: process.env.CAVEAU_ALLOW_ENV_FALLBACK === "1",
53
+ });
54
+ }
55
+ function fail(msg) {
56
+ process.stderr.write(`caveau-mcp: ${msg}\n`);
57
+ process.exit(2);
58
+ }
59
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAE5C,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AACrC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAEnC,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;IACzB,yDAAyD;IACzD,IAAI,CAAC,QAAQ,IAAI,CAAC,OAAO,EAAE,CAAC;QAC1B,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACtB,CAAC;SAAM,CAAC;QACN,IAAI,CAAC,uCAAuC,CAAC,CAAC;IAChD,CAAC;AACH,CAAC;AAED,MAAM,OAAO,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,8BAA8B,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAEpG,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;IACxB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,EAAE,CAAC;IACjD,IAAI,CAAC,KAAK;QAAE,IAAI,CAAC,uDAAuD,CAAC,CAAC;IAC1E,MAAM,MAAM,GAAG,WAAW,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;IACrE,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,2DAA2D;AAC7D,CAAC;KAAM,CAAC;IACN,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,MAAM,EAAE,EAAE,CAAC,CAAC;IACtD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,KAAK;QAAE,IAAI,CAAC,aAAa,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IAC9F,MAAM,eAAe,CAAC;QACpB,IAAI;QACJ,UAAU,EAAE,OAAO;QACnB,gBAAgB,EAAE,OAAO,CAAC,GAAG,CAAC,yBAAyB,KAAK,GAAG;KAChE,CAAC,CAAC;AACL,CAAC;AAED,SAAS,IAAI,CAAC,GAAW;IACvB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;IAC7C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ /**
3
+ * "Draft <doc> citing my corpus" — primes the model to write a longer artefact
4
+ * (memo, brief, email) grounded in CaveauAI corpus chunks with footnotes.
5
+ */
6
+ export declare function registerDraftWithRefsPrompt(server: McpServer): void;
@@ -0,0 +1,42 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * "Draft <doc> citing my corpus" — primes the model to write a longer artefact
4
+ * (memo, brief, email) grounded in CaveauAI corpus chunks with footnotes.
5
+ */
6
+ export function registerDraftWithRefsPrompt(server) {
7
+ server.registerPrompt("caveau.draft_with_refs", {
8
+ title: "Draft a document citing my corpus",
9
+ description: "Draft a longer artefact (memo, briefing, email) backed by retrieved chunks from the client's CaveauAI corpus, with footnote citations.",
10
+ argsSchema: {
11
+ artefact: z
12
+ .string()
13
+ .describe("What to draft (e.g. 'a one-page board memo on the new merger filing rules')."),
14
+ audience: z
15
+ .string()
16
+ .optional()
17
+ .describe("Who it's for (e.g. 'CEO', 'external counsel'). Shapes tone and depth."),
18
+ profile: z.string().optional().describe("Optional retrieval profile slug."),
19
+ },
20
+ }, ({ artefact, audience, profile }) => {
21
+ const profileLine = profile ? ` (profile \`${profile}\`)` : "";
22
+ const audienceLine = audience ? ` Audience: ${audience}.` : "";
23
+ return {
24
+ messages: [
25
+ {
26
+ role: "user",
27
+ content: {
28
+ type: "text",
29
+ text: `Draft ${artefact}.${audienceLine}\n\n` +
30
+ `Process:\n` +
31
+ `1. Use \`caveau.list_corpora\` to confirm what's available if you're unsure.\n` +
32
+ `2. Run \`caveau.search\`${profileLine} — at least once, ideally twice with different angles.\n` +
33
+ `3. Write the artefact in the appropriate format. Every load-bearing factual claim needs a numbered footnote.\n` +
34
+ `4. After the artefact, list the footnotes — each with the source title and source_url.\n` +
35
+ `5. If a claim isn't supported by retrieved chunks, either remove it or flag it as "[unsourced]".`,
36
+ },
37
+ },
38
+ ],
39
+ };
40
+ });
41
+ }
42
+ //# sourceMappingURL=draft_with_refs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"draft_with_refs.js","sourceRoot":"","sources":["../../src/prompts/draft_with_refs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;GAGG;AACH,MAAM,UAAU,2BAA2B,CAAC,MAAiB;IAC3D,MAAM,CAAC,cAAc,CACnB,wBAAwB,EACxB;QACE,KAAK,EAAE,mCAAmC;QAC1C,WAAW,EACT,wIAAwI;QAC1I,UAAU,EAAE;YACV,QAAQ,EAAE,CAAC;iBACR,MAAM,EAAE;iBACR,QAAQ,CAAC,8EAA8E,CAAC;YAC3F,QAAQ,EAAE,CAAC;iBACR,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,uEAAuE,CAAC;YACpF,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kCAAkC,CAAC;SAC5E;KACF,EACD,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE;QAClC,MAAM,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC,eAAe,OAAO,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/D,MAAM,YAAY,GAAG,QAAQ,CAAC,CAAC,CAAC,cAAc,QAAQ,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/D,OAAO;YACL,QAAQ,EAAE;gBACR;oBACE,IAAI,EAAE,MAAM;oBACZ,OAAO,EAAE;wBACP,IAAI,EAAE,MAAM;wBACZ,IAAI,EACF,SAAS,QAAQ,IAAI,YAAY,MAAM;4BACvC,YAAY;4BACZ,gFAAgF;4BAChF,2BAA2B,WAAW,0DAA0D;4BAChG,gHAAgH;4BAChH,0FAA0F;4BAC1F,kGAAkG;qBACrG;iBACF;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ /**
3
+ * "Summarize <topic> using my CaveauAI corpus" — primes the host model to use
4
+ * caveau.search before answering.
5
+ */
6
+ export declare function registerSummarizePrompt(server: McpServer): void;
@@ -0,0 +1,36 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * "Summarize <topic> using my CaveauAI corpus" — primes the host model to use
4
+ * caveau.search before answering.
5
+ */
6
+ export function registerSummarizePrompt(server) {
7
+ server.registerPrompt("caveau.summarize_with_corpus", {
8
+ title: "Summarise from my corpus",
9
+ description: "Ask the model to summarise a topic by first searching the client's CaveauAI corpus and citing the chunks it used.",
10
+ argsSchema: {
11
+ topic: z.string().describe("What to summarise (e.g. 'EU AI Act enforcement timeline')."),
12
+ profile: z.string().optional().describe("Optional retrieval profile slug to bias the search."),
13
+ max_words: z.string().optional().describe("Optional length cap as a number (e.g. '300')."),
14
+ },
15
+ }, ({ topic, profile, max_words }) => {
16
+ const profileLine = profile ? ` (use profile \`${profile}\`)` : "";
17
+ const lengthLine = max_words ? ` Keep it under ${max_words} words.` : "";
18
+ return {
19
+ messages: [
20
+ {
21
+ role: "user",
22
+ content: {
23
+ type: "text",
24
+ text: `Summarise the following from my CaveauAI corpus: ${topic}.\n\n` +
25
+ `1. First call \`caveau.search\` with a query that captures the topic${profileLine}.\n` +
26
+ `2. Read the returned chunks. If they're sparse, run a second search with a refined query.\n` +
27
+ `3. Write a tight summary using ONLY the retrieved chunks as evidence.\n` +
28
+ `4. End with a "Sources" section listing each chunk you actually used (title + source_url).\n` +
29
+ `${lengthLine}`,
30
+ },
31
+ },
32
+ ],
33
+ };
34
+ });
35
+ }
36
+ //# sourceMappingURL=summarize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summarize.js","sourceRoot":"","sources":["../../src/prompts/summarize.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAAC,MAAiB;IACvD,MAAM,CAAC,cAAc,CACnB,8BAA8B,EAC9B;QACE,KAAK,EAAE,0BAA0B;QACjC,WAAW,EACT,mHAAmH;QACrH,UAAU,EAAE;YACV,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,4DAA4D,CAAC;YACxF,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qDAAqD,CAAC;YAC9F,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+CAA+C,CAAC;SAC3F;KACF,EACD,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE;QAChC,MAAM,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC,mBAAmB,OAAO,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QACnE,MAAM,UAAU,GAAG,SAAS,CAAC,CAAC,CAAC,kBAAkB,SAAS,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;QACzE,OAAO;YACL,QAAQ,EAAE;gBACR;oBACE,IAAI,EAAE,MAAM;oBACZ,OAAO,EAAE;wBACP,IAAI,EAAE,MAAM;wBACZ,IAAI,EACF,oDAAoD,KAAK,OAAO;4BAChE,uEAAuE,WAAW,KAAK;4BACvF,6FAA6F;4BAC7F,yEAAyE;4BACzE,8FAA8F;4BAC9F,GAAG,UAAU,EAAE;qBAClB;iBACF;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { CaveauApi } from "../api.js";
3
+ /**
4
+ * Exposes the client's accessible corpora as a single MCP resource. Hosts that
5
+ * support resource browsing (Claude Desktop "Attach context") can pull the
6
+ * full list and let the user pick from it before posing a question.
7
+ */
8
+ export declare function registerCorporaResource(server: McpServer, api: CaveauApi): void;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Exposes the client's accessible corpora as a single MCP resource. Hosts that
3
+ * support resource browsing (Claude Desktop "Attach context") can pull the
4
+ * full list and let the user pick from it before posing a question.
5
+ */
6
+ export function registerCorporaResource(server, api) {
7
+ server.registerResource("caveau-corpora", "caveau://corpora", {
8
+ title: "Corpora",
9
+ description: "All corpora this CaveauAI client can query.",
10
+ mimeType: "application/json",
11
+ }, async (uri) => {
12
+ const res = await api.get("/corpora");
13
+ return {
14
+ contents: [
15
+ {
16
+ uri: uri.href,
17
+ mimeType: "application/json",
18
+ text: JSON.stringify(res, null, 2),
19
+ },
20
+ ],
21
+ };
22
+ });
23
+ }
24
+ //# sourceMappingURL=corpora.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"corpora.js","sourceRoot":"","sources":["../../src/resources/corpora.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,MAAiB,EAAE,GAAc;IACvE,MAAM,CAAC,gBAAgB,CACrB,gBAAgB,EAChB,kBAAkB,EAClB;QACE,KAAK,EAAE,SAAS;QAChB,WAAW,EAAE,6CAA6C;QAC1D,QAAQ,EAAE,kBAAkB;KAC7B,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,GAAG,CAAkB,UAAU,CAAC,CAAC;QACvD,OAAO;YACL,QAAQ,EAAE;gBACR;oBACE,GAAG,EAAE,GAAG,CAAC,IAAI;oBACb,QAAQ,EAAE,kBAAkB;oBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;iBACnC;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { CaveauApi } from "../api.js";
3
+ /**
4
+ * URI-template resource: caveau://documents/{id} resolves to the full text +
5
+ * chunk metadata of one of the client's documents. Useful when search returns
6
+ * a chunk and the host wants to pull the full document into context.
7
+ */
8
+ export declare function registerDocumentsResource(server: McpServer, api: CaveauApi): void;
@@ -0,0 +1,29 @@
1
+ import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ /**
3
+ * URI-template resource: caveau://documents/{id} resolves to the full text +
4
+ * chunk metadata of one of the client's documents. Useful when search returns
5
+ * a chunk and the host wants to pull the full document into context.
6
+ */
7
+ export function registerDocumentsResource(server, api) {
8
+ server.registerResource("caveau-document", new ResourceTemplate("caveau://documents/{id}", { list: undefined }), {
9
+ title: "Document",
10
+ description: "Fetch a single CaveauAI document by id (with all chunks).",
11
+ mimeType: "application/json",
12
+ }, async (uri, vars) => {
13
+ const id = String(vars.id ?? "");
14
+ if (!/^\d+$/.test(id)) {
15
+ throw new Error(`document id must be numeric, got "${id}"`);
16
+ }
17
+ const res = await api.get(`/documents/${id}`);
18
+ return {
19
+ contents: [
20
+ {
21
+ uri: uri.href,
22
+ mimeType: "application/json",
23
+ text: JSON.stringify(res, null, 2),
24
+ },
25
+ ],
26
+ };
27
+ });
28
+ }
29
+ //# sourceMappingURL=documents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"documents.js","sourceRoot":"","sources":["../../src/resources/documents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAK3E;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CAAC,MAAiB,EAAE,GAAc;IACzE,MAAM,CAAC,gBAAgB,CACrB,iBAAiB,EACjB,IAAI,gBAAgB,CAAC,yBAAyB,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,EACpE;QACE,KAAK,EAAE,UAAU;QACjB,WAAW,EAAE,2DAA2D;QACxE,QAAQ,EAAE,kBAAkB;KAC7B,EACD,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QAClB,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QACjC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CAAC,qCAAqC,EAAE,GAAG,CAAC,CAAC;QAC9D,CAAC;QACD,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,GAAG,CAAmB,cAAc,EAAE,EAAE,CAAC,CAAC;QAChE,OAAO;YACL,QAAQ,EAAE;gBACR;oBACE,GAAG,EAAE,GAAG,CAAC,IAAI;oBACb,QAAQ,EAAE,kBAAkB;oBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;iBACnC;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export interface BuildOptions {
3
+ apiBaseUrl: string;
4
+ apiToken: string;
5
+ name?: string;
6
+ version?: string;
7
+ }
8
+ export declare function buildServer(opts: BuildOptions): McpServer;
package/dist/server.js ADDED
@@ -0,0 +1,48 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { CaveauApi } from "./api.js";
3
+ import { registerSearch } from "./tools/search.js";
4
+ import { registerListProfiles } from "./tools/list_profiles.js";
5
+ import { registerListCorpora } from "./tools/list_corpora.js";
6
+ import { registerGetDocument } from "./tools/get_document.js";
7
+ import { registerCorpusStats } from "./tools/corpus_stats.js";
8
+ import { registerIngestText } from "./tools/ingest_text.js";
9
+ import { registerCorporaResource } from "./resources/corpora.js";
10
+ import { registerDocumentsResource } from "./resources/documents.js";
11
+ import { registerSummarizePrompt } from "./prompts/summarize.js";
12
+ import { registerDraftWithRefsPrompt } from "./prompts/draft_with_refs.js";
13
+ export function buildServer(opts) {
14
+ const server = new McpServer({
15
+ name: opts.name ?? "caveau-mcp",
16
+ version: opts.version ?? "0.2.2",
17
+ }, {
18
+ capabilities: {
19
+ tools: {},
20
+ resources: {},
21
+ prompts: {},
22
+ },
23
+ instructions: "CaveauAI MCP server. Tools: caveau.list_corpora (see queryable corpora), " +
24
+ "caveau.list_profiles (saved retrieval criteria), caveau.search (RAG search " +
25
+ "returning ranked chunks with source citations), caveau.get_document (full " +
26
+ "document by id), caveau.corpus_stats (counts + plan caps), caveau.ingest_text " +
27
+ "(add text to a private corpus, plan-gated). Resources: caveau://corpora, " +
28
+ "caveau://documents/{id}. Prompts: caveau.summarize_with_corpus, " +
29
+ "caveau.draft_with_refs. The active client and tenant scope are determined by " +
30
+ "the MCP token configured at startup.",
31
+ });
32
+ const api = new CaveauApi({
33
+ baseUrl: opts.apiBaseUrl,
34
+ token: opts.apiToken,
35
+ });
36
+ registerSearch(server, api);
37
+ registerListProfiles(server, api);
38
+ registerListCorpora(server, api);
39
+ registerGetDocument(server, api);
40
+ registerCorpusStats(server, api);
41
+ registerIngestText(server, api);
42
+ registerCorporaResource(server, api);
43
+ registerDocumentsResource(server, api);
44
+ registerSummarizePrompt(server);
45
+ registerDraftWithRefsPrompt(server);
46
+ return server;
47
+ }
48
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,2BAA2B,EAAE,MAAM,8BAA8B,CAAC;AAS3E,MAAM,UAAU,WAAW,CAAC,IAAkB;IAC5C,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B;QACE,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,YAAY;QAC/B,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,OAAO;KACjC,EACD;QACE,YAAY,EAAE;YACZ,KAAK,EAAE,EAAE;YACT,SAAS,EAAE,EAAE;YACb,OAAO,EAAE,EAAE;SACZ;QACD,YAAY,EACV,2EAA2E;YAC3E,6EAA6E;YAC7E,4EAA4E;YAC5E,gFAAgF;YAChF,2EAA2E;YAC3E,kEAAkE;YAClE,+EAA+E;YAC/E,sCAAsC;KACzC,CACF,CAAC;IAEF,MAAM,GAAG,GAAG,IAAI,SAAS,CAAC;QACxB,OAAO,EAAE,IAAI,CAAC,UAAU;QACxB,KAAK,EAAE,IAAI,CAAC,QAAQ;KACrB,CAAC,CAAC;IAEH,cAAc,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,oBAAoB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAClC,mBAAmB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACjC,mBAAmB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACjC,mBAAmB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACjC,kBAAkB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAEhC,uBAAuB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACrC,yBAAyB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAEvC,uBAAuB,CAAC,MAAM,CAAC,CAAC;IAChC,2BAA2B,CAAC,MAAM,CAAC,CAAC;IAEpC,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { CaveauApi } from "../api.js";
3
+ export declare function registerCorpusStats(server: McpServer, api: CaveauApi): void;
@@ -0,0 +1,21 @@
1
+ export function registerCorpusStats(server, api) {
2
+ server.registerTool("caveau.corpus_stats", {
3
+ title: "Corpus stats",
4
+ description: "Show document and chunk counts for each of this client's private corpora, plus their plan caps. Useful for sanity-checking before a large query session.",
5
+ inputSchema: {},
6
+ }, async () => {
7
+ const res = await api.get("/corpus_stats");
8
+ const lines = [
9
+ `Total: ${res.totals.documents} documents, ${res.totals.chunks} chunks`,
10
+ `Plan: ${res.plan.mcp_calls_per_month.toLocaleString()} MCP calls/month, max ${res.plan.max_mcp_tools} tools`,
11
+ "",
12
+ "Per corpus:",
13
+ ...res.corpora.map((c) => ` ${c.slug.padEnd(28)} ${String(c.documents).padStart(5)} docs / ${String(c.chunks).padStart(6)} chunks (${c.name})`),
14
+ ];
15
+ return {
16
+ content: [{ type: "text", text: lines.join("\n") }],
17
+ structuredContent: res,
18
+ };
19
+ });
20
+ }
21
+ //# sourceMappingURL=corpus_stats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"corpus_stats.js","sourceRoot":"","sources":["../../src/tools/corpus_stats.ts"],"names":[],"mappings":"AASA,MAAM,UAAU,mBAAmB,CAAC,MAAiB,EAAE,GAAc;IACnE,MAAM,CAAC,YAAY,CACjB,qBAAqB,EACrB;QACE,KAAK,EAAE,cAAc;QACrB,WAAW,EACT,0JAA0J;QAC5J,WAAW,EAAE,EAAE;KAChB,EACD,KAAK,IAAI,EAAE;QACT,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,GAAG,CAAc,eAAe,CAAC,CAAC;QACxD,MAAM,KAAK,GAAa;YACtB,UAAU,GAAG,CAAC,MAAM,CAAC,SAAS,eAAe,GAAG,CAAC,MAAM,CAAC,MAAM,SAAS;YACvE,SAAS,GAAG,CAAC,IAAI,CAAC,mBAAmB,CAAC,cAAc,EAAE,yBAAyB,GAAG,CAAC,IAAI,CAAC,aAAa,QAAQ;YAC7G,EAAE;YACF,aAAa;YACb,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAChB,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,IAAI,GAAG,CAC/H;SACF,CAAC;QACF,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACnD,iBAAiB,EAAE,GAAyC;SAC7D,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { CaveauApi } from "../api.js";
3
+ export declare function registerGetDocument(server: McpServer, api: CaveauApi): void;
@@ -0,0 +1,35 @@
1
+ import { z } from "zod";
2
+ export function registerGetDocument(server, api) {
3
+ server.registerTool("caveau.get_document", {
4
+ title: "Get document",
5
+ description: "Fetch a single document by id along with its chunked content. Use this when caveau.search returns a chunk and you need surrounding context or the full source text.",
6
+ inputSchema: {
7
+ document_id: z
8
+ .number()
9
+ .int()
10
+ .positive()
11
+ .describe("The document_id field returned by caveau.search."),
12
+ },
13
+ }, async (args) => {
14
+ const res = await api.get(`/documents/${args.document_id}`);
15
+ const d = res.document;
16
+ const head = [
17
+ `# ${d.title ?? "(untitled)"}`,
18
+ d.author ? `Author: ${d.author}` : null,
19
+ d.published_at ? `Published: ${d.published_at}` : null,
20
+ d.category ? `Category: ${d.category}` : null,
21
+ d.source_url ? `Source: ${d.source_url}` : null,
22
+ `Chunks: ${res.chunks.length}`,
23
+ ]
24
+ .filter(Boolean)
25
+ .join("\n");
26
+ const body = res.chunks
27
+ .map((c) => `--- chunk ${c.chunk_index}${c.section_title ? ` (${c.section_title})` : ""} ---\n${c.content}`)
28
+ .join("\n\n");
29
+ return {
30
+ content: [{ type: "text", text: `${head}\n\n${body}` }],
31
+ structuredContent: res,
32
+ };
33
+ });
34
+ }
35
+ //# sourceMappingURL=get_document.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get_document.js","sourceRoot":"","sources":["../../src/tools/get_document.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,MAAM,UAAU,mBAAmB,CAAC,MAAiB,EAAE,GAAc;IACnE,MAAM,CAAC,YAAY,CACjB,qBAAqB,EACrB;QACE,KAAK,EAAE,cAAc;QACrB,WAAW,EACT,qKAAqK;QACvK,WAAW,EAAE;YACX,WAAW,EAAE,CAAC;iBACX,MAAM,EAAE;iBACR,GAAG,EAAE;iBACL,QAAQ,EAAE;iBACV,QAAQ,CAAC,kDAAkD,CAAC;SAChE;KACF,EACD,KAAK,EAAE,IAAI,EAAE,EAAE;QACb,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,GAAG,CAAmB,cAAc,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QAC9E,MAAM,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC;QACvB,MAAM,IAAI,GAAG;YACX,KAAK,CAAC,CAAC,KAAK,IAAI,YAAY,EAAE;YAC9B,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI;YACvC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI;YACtD,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI;YAC7C,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,IAAI;YAC/C,WAAW,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE;SAC/B;aACE,MAAM,CAAC,OAAO,CAAC;aACf,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM;aACpB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC;aAC3G,IAAI,CAAC,MAAM,CAAC,CAAC;QAChB,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,OAAO,IAAI,EAAE,EAAE,CAAC;YACvD,iBAAiB,EAAE,GAAyC;SAC7D,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { CaveauApi } from "../api.js";
3
+ export declare function registerIngestText(server: McpServer, api: CaveauApi): void;
@@ -0,0 +1,43 @@
1
+ import { z } from "zod";
2
+ export function registerIngestText(server, api) {
3
+ server.registerTool("caveau.ingest_text", {
4
+ title: "Ingest text",
5
+ description: "Add a piece of text to one of this client's private corpora. Chunks, embeds, and stores in Qdrant. Plan-gated server-side; returns the resulting document id and chunk count.",
6
+ inputSchema: {
7
+ title: z.string().min(1).max(500).describe("Document title."),
8
+ content: z
9
+ .string()
10
+ .min(30)
11
+ .max(2_000_000)
12
+ .describe("Document body. 30 chars min, 2 MB max."),
13
+ corpus: z
14
+ .string()
15
+ .max(100)
16
+ .optional()
17
+ .describe("Corpus slug. Omit to use the client's default corpus."),
18
+ category: z.string().max(120).optional(),
19
+ tags: z.array(z.string()).optional(),
20
+ source_url: z.string().url().optional(),
21
+ },
22
+ }, async (args) => {
23
+ const res = await api.post("/ingest", {
24
+ title: args.title,
25
+ content: args.content,
26
+ corpus: args.corpus,
27
+ category: args.category,
28
+ tags: args.tags,
29
+ source_url: args.source_url,
30
+ });
31
+ const d = res.document;
32
+ return {
33
+ content: [
34
+ {
35
+ type: "text",
36
+ text: `Ingested "${d.title}" (id ${d.id}) into corpus "${d.corpus_slug ?? "default"}" — ${d.chunks} chunks indexed.`,
37
+ },
38
+ ],
39
+ structuredContent: res,
40
+ };
41
+ });
42
+ }
43
+ //# sourceMappingURL=ingest_text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ingest_text.js","sourceRoot":"","sources":["../../src/tools/ingest_text.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAcxB,MAAM,UAAU,kBAAkB,CAAC,MAAiB,EAAE,GAAc;IAClE,MAAM,CAAC,YAAY,CACjB,oBAAoB,EACpB;QACE,KAAK,EAAE,aAAa;QACpB,WAAW,EACT,+KAA+K;QACjL,WAAW,EAAE;YACX,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,iBAAiB,CAAC;YAC7D,OAAO,EAAE,CAAC;iBACP,MAAM,EAAE;iBACR,GAAG,CAAC,EAAE,CAAC;iBACP,GAAG,CAAC,SAAS,CAAC;iBACd,QAAQ,CAAC,wCAAwC,CAAC;YACrD,MAAM,EAAE,CAAC;iBACN,MAAM,EAAE;iBACR,GAAG,CAAC,GAAG,CAAC;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,uDAAuD,CAAC;YACpE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;YACxC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;YACpC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;SACxC;KACF,EACD,KAAK,EAAE,IAAI,EAAE,EAAE;QACb,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,IAAI,CAAiB,SAAS,EAAE;YACpD,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,UAAU,EAAE,IAAI,CAAC,UAAU;SAC5B,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC;QACvB,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,aAAa,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC,WAAW,IAAI,SAAS,OAAO,CAAC,CAAC,MAAM,kBAAkB;iBACrH;aACF;YACD,iBAAiB,EAAE,GAAyC;SAC7D,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { CaveauApi } from "../api.js";
3
+ export declare function registerListCorpora(server: McpServer, api: CaveauApi): void;
@@ -0,0 +1,28 @@
1
+ export function registerListCorpora(server, api) {
2
+ server.registerTool("caveau.list_corpora", {
3
+ title: "List corpora",
4
+ description: "List all corpora this client can search: their private corpora and any shared/subscribed packages. Use the slugs in corpus_slugs[] when configuring a retrieval profile.",
5
+ inputSchema: {},
6
+ }, async () => {
7
+ const res = await api.get("/corpora");
8
+ const lines = [];
9
+ lines.push(`Private (${res.private.length}):`);
10
+ for (const c of res.private) {
11
+ lines.push(` • ${c.slug} — ${c.name}` +
12
+ (c.is_default ? " [default]" : "") +
13
+ ` — ${c.doc_count} docs` +
14
+ (c.description ? `\n ${c.description}` : ""));
15
+ }
16
+ lines.push("");
17
+ lines.push(`Subscribed shared packages (${res.subscribed.length}):`);
18
+ for (const c of res.subscribed) {
19
+ lines.push(` • ${c.slug} — ${c.name} — ${c.doc_count} docs / ${c.chunk_count ?? 0} chunks` +
20
+ (c.description ? `\n ${c.description}` : ""));
21
+ }
22
+ return {
23
+ content: [{ type: "text", text: lines.join("\n") }],
24
+ structuredContent: res,
25
+ };
26
+ });
27
+ }
28
+ //# sourceMappingURL=list_corpora.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list_corpora.js","sourceRoot":"","sources":["../../src/tools/list_corpora.ts"],"names":[],"mappings":"AAIA,MAAM,UAAU,mBAAmB,CAAC,MAAiB,EAAE,GAAc;IACnE,MAAM,CAAC,YAAY,CACjB,qBAAqB,EACrB;QACE,KAAK,EAAE,cAAc;QACrB,WAAW,EACT,0KAA0K;QAC5K,WAAW,EAAE,EAAE;KAChB,EACD,KAAK,IAAI,EAAE;QACT,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,GAAG,CAAkB,UAAU,CAAC,CAAC;QACvD,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,KAAK,CAAC,IAAI,CAAC,YAAY,GAAG,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC;QAC/C,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;YAC5B,KAAK,CAAC,IAAI,CACR,OAAO,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,IAAI,EAAE;gBACzB,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;gBAClC,MAAM,CAAC,CAAC,SAAS,OAAO;gBACxB,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CACpD,CAAC;QACJ,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,+BAA+B,GAAG,CAAC,UAAU,CAAC,MAAM,IAAI,CAAC,CAAC;QACrE,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC;YAC/B,KAAK,CAAC,IAAI,CACR,OAAO,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,SAAS,WAAW,CAAC,CAAC,WAAW,IAAI,CAAC,SAAS;gBAC9E,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CACpD,CAAC;QACJ,CAAC;QACD,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACnD,iBAAiB,EAAE,GAAyC;SAC7D,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { CaveauApi } from "../api.js";
3
+ export declare function registerListProfiles(server: McpServer, api: CaveauApi): void;
@@ -0,0 +1,30 @@
1
+ export function registerListProfiles(server, api) {
2
+ server.registerTool("caveau.list_profiles", {
3
+ title: "List retrieval profiles",
4
+ description: "List the named retrieval profiles configured for this client. Each profile is a saved bundle of corpora, search method, top_k, and filters. Pass a profile slug to caveau.search to use it.",
5
+ inputSchema: {},
6
+ }, async () => {
7
+ const res = await api.get("/profiles");
8
+ const lines = [`${res.count} profile${res.count === 1 ? "" : "s"}`];
9
+ for (const p of res.profiles) {
10
+ const tags = [];
11
+ tags.push(p.search_method);
12
+ tags.push(`top_k=${p.top_k}`);
13
+ if (p.recency_days !== null)
14
+ tags.push(`recency=${p.recency_days}d`);
15
+ if (p.corpus_slugs && p.corpus_slugs.length > 0)
16
+ tags.push(`corpora=${p.corpus_slugs.join(",")}`);
17
+ if (p.categories && p.categories.length > 0)
18
+ tags.push(`categories=${p.categories.join(",")}`);
19
+ if (p.is_default)
20
+ tags.push("DEFAULT");
21
+ lines.push(`• ${p.slug} (${p.name}) — ${tags.join(" / ")}` +
22
+ (p.description ? `\n ${p.description}` : ""));
23
+ }
24
+ return {
25
+ content: [{ type: "text", text: lines.join("\n") }],
26
+ structuredContent: res,
27
+ };
28
+ });
29
+ }
30
+ //# sourceMappingURL=list_profiles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list_profiles.js","sourceRoot":"","sources":["../../src/tools/list_profiles.ts"],"names":[],"mappings":"AAIA,MAAM,UAAU,oBAAoB,CAAC,MAAiB,EAAE,GAAc;IACpE,MAAM,CAAC,YAAY,CACjB,sBAAsB,EACtB;QACE,KAAK,EAAE,yBAAyB;QAChC,WAAW,EACT,6LAA6L;QAC/L,WAAW,EAAE,EAAE;KAChB,EACD,KAAK,IAAI,EAAE;QACT,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,GAAG,CAAmB,WAAW,CAAC,CAAC;QACzD,MAAM,KAAK,GAAG,CAAC,GAAG,GAAG,CAAC,KAAK,WAAW,GAAG,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;QACpE,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;YAC7B,MAAM,IAAI,GAAa,EAAE,CAAC;YAC1B,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;YAC3B,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;YAC9B,IAAI,CAAC,CAAC,YAAY,KAAK,IAAI;gBAAE,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC;YACrE,IAAI,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC;gBAC7C,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACnD,IAAI,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC;gBACzC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACpD,IAAI,CAAC,CAAC,UAAU;gBAAE,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACvC,KAAK,CAAC,IAAI,CACR,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;gBAC7C,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAClD,CAAC;QACJ,CAAC;QACD,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACnD,iBAAiB,EAAE,GAAyC;SAC7D,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { CaveauApi } from "../api.js";
3
+ export declare function registerSearch(server: McpServer, api: CaveauApi): void;
@@ -0,0 +1,70 @@
1
+ import { z } from "zod";
2
+ const Input = {
3
+ query: z.string().min(1).max(4000).describe("The user's question or search phrase."),
4
+ profile: z
5
+ .string()
6
+ .max(64)
7
+ .optional()
8
+ .describe("Slug of a saved retrieval profile (corpora, top_k, filters). Omit to use the client's default profile."),
9
+ top_k: z
10
+ .number()
11
+ .int()
12
+ .min(1)
13
+ .max(50)
14
+ .optional()
15
+ .describe("Override the profile's top_k. Bounded 1-50."),
16
+ category: z
17
+ .string()
18
+ .max(120)
19
+ .optional()
20
+ .describe("One-shot category filter applied on top of any profile filters."),
21
+ };
22
+ export function registerSearch(server, api) {
23
+ server.registerTool("caveau.search", {
24
+ title: "Search corpus",
25
+ description: "Run a RAG search across the client's accessible corpora and return ranked chunks with source metadata. Use the result chunks as context for your reply; cite source_url and title.",
26
+ inputSchema: Input,
27
+ }, async (args) => {
28
+ const res = await api.post("/search", {
29
+ query: args.query,
30
+ profile: args.profile,
31
+ top_k: args.top_k,
32
+ category: args.category,
33
+ });
34
+ return {
35
+ content: [
36
+ {
37
+ type: "text",
38
+ text: res.results.length === 0
39
+ ? `No matches for "${args.query}" under profile "${res.profile}".`
40
+ : formatHits(res),
41
+ },
42
+ ],
43
+ structuredContent: res,
44
+ };
45
+ });
46
+ }
47
+ function formatHits(res) {
48
+ const lines = [
49
+ `Profile: ${res.profile} — ${res.count} result${res.count === 1 ? "" : "s"}`,
50
+ "",
51
+ ];
52
+ for (const [i, h] of res.results.entries()) {
53
+ const head = `[${i + 1}] ${h.title ?? "(untitled)"}` +
54
+ (h.section_title ? ` — ${h.section_title}` : "") +
55
+ (h.score !== null ? ` (score ${h.score.toFixed(3)})` : "");
56
+ lines.push(head);
57
+ if (h.source_url)
58
+ lines.push(` ${h.source_url}`);
59
+ lines.push(indent(h.content.trim()));
60
+ lines.push("");
61
+ }
62
+ return lines.join("\n").trimEnd();
63
+ }
64
+ function indent(s) {
65
+ return s
66
+ .split("\n")
67
+ .map((l) => ` ${l}`)
68
+ .join("\n");
69
+ }
70
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Wire types for /api/mcp/* responses. These mirror what the PHP runtime
3
+ * controller returns (see ai-portal/api/mcp/index.php).
4
+ */
5
+ export interface SearchHit {
6
+ chunk_id: string | number | null;
7
+ document_id: string | number | null;
8
+ title: string | null;
9
+ content: string;
10
+ section_title: string | null;
11
+ category: string | null;
12
+ tags: string[] | null;
13
+ source_url: string | null;
14
+ score: number | null;
15
+ corpus_slug: string | null;
16
+ published_at: string | null;
17
+ }
18
+ export interface SearchResponse {
19
+ profile: string;
20
+ count: number;
21
+ results: SearchHit[];
22
+ }
23
+ export interface Corpus {
24
+ kind: "private" | "shared";
25
+ slug: string;
26
+ name: string;
27
+ description: string | null;
28
+ doc_count: number;
29
+ chunk_count?: number;
30
+ is_default?: boolean;
31
+ }
32
+ export interface CorporaResponse {
33
+ private: Corpus[];
34
+ subscribed: Corpus[];
35
+ }
36
+ export interface Profile {
37
+ slug: string;
38
+ name: string;
39
+ description: string | null;
40
+ search_method: "vector" | "keyword" | "hybrid";
41
+ corpus_slugs: string[] | null;
42
+ top_k: number;
43
+ recency_days: number | null;
44
+ categories: string[] | null;
45
+ tags: string[] | null;
46
+ embed_model: string | null;
47
+ is_default: boolean;
48
+ }
49
+ export interface ProfilesResponse {
50
+ profiles: Profile[];
51
+ count: number;
52
+ }
53
+ export interface DocumentChunk {
54
+ id: number;
55
+ chunk_index: number;
56
+ section_title: string | null;
57
+ content: string;
58
+ }
59
+ export interface DocumentResponse {
60
+ document: {
61
+ id: number;
62
+ title: string | null;
63
+ category: string | null;
64
+ tags: string[] | null;
65
+ author: string | null;
66
+ source_url: string | null;
67
+ published_at: string | null;
68
+ status: string;
69
+ corpus_id: number | null;
70
+ chunk_count: number;
71
+ content: string | null;
72
+ created_at: string;
73
+ updated_at: string;
74
+ };
75
+ chunks: DocumentChunk[];
76
+ }
package/dist/types.js ADDED
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Wire types for /api/mcp/* responses. These mirror what the PHP runtime
3
+ * controller returns (see ai-portal/api/mcp/index.php).
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@bluenotelogic/mcp",
3
+ "version": "0.2.2",
4
+ "description": "CaveauAI MCP server — RAG context injection for Claude Code/Desktop and other MCP hosts. Each client uses their own token + retrieval profiles.",
5
+ "type": "module",
6
+ "bin": {
7
+ "caveau-mcp": "dist/index.js"
8
+ },
9
+ "main": "./dist/index.js",
10
+ "files": [
11
+ "dist",
12
+ "README.md"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "dev": "tsx watch src/index.ts --stdio",
17
+ "start": "node dist/index.js --stdio",
18
+ "start:http": "node dist/index.js --http",
19
+ "lint": "tsc --noEmit",
20
+ "prepublishOnly": "npm run build"
21
+ },
22
+ "engines": {
23
+ "node": ">=20"
24
+ },
25
+ "dependencies": {
26
+ "@modelcontextprotocol/sdk": "^1.0.0",
27
+ "express": "^5.2.1",
28
+ "zod": "^3.23.8"
29
+ },
30
+ "devDependencies": {
31
+ "@types/express": "^5.0.6",
32
+ "@types/node": "^22.0.0",
33
+ "tsx": "^4.19.0",
34
+ "typescript": "^5.6.0"
35
+ },
36
+ "publishConfig": {
37
+ "access": "public"
38
+ },
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "https://git.bluenotelogic.com/daveadmin/caveau-mcp"
42
+ },
43
+ "keywords": [
44
+ "mcp",
45
+ "model-context-protocol",
46
+ "rag",
47
+ "caveauai",
48
+ "claude"
49
+ ],
50
+ "license": "UNLICENSED",
51
+ "author": "Blue Note Logic"
52
+ }