@promptev/context-engine 0.0.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/LICENSE.md +202 -0
- package/NOTICE +17 -0
- package/README.md +112 -0
- package/dist/cli.js +11998 -0
- package/dist/cli.js.map +1 -0
- package/dist/config-Bl9U789m.d.cts +174 -0
- package/dist/config-Bt9bUQqU.d.ts +174 -0
- package/dist/embeddings-B-jZ42mk.d.cts +67 -0
- package/dist/embeddings-DaSdAZN3.d.ts +67 -0
- package/dist/express.cjs +3173 -0
- package/dist/express.cjs.map +1 -0
- package/dist/express.d.cts +24 -0
- package/dist/express.d.ts +24 -0
- package/dist/express.js +3170 -0
- package/dist/express.js.map +1 -0
- package/dist/fastify.cjs +3184 -0
- package/dist/fastify.cjs.map +1 -0
- package/dist/fastify.d.cts +16 -0
- package/dist/fastify.d.ts +16 -0
- package/dist/fastify.js +3181 -0
- package/dist/fastify.js.map +1 -0
- package/dist/governance-BDkcv4qZ.d.cts +79 -0
- package/dist/governance-XIScatRO.d.ts +79 -0
- package/dist/graph/index.cjs +1428 -0
- package/dist/graph/index.cjs.map +1 -0
- package/dist/graph/index.d.cts +104 -0
- package/dist/graph/index.d.ts +104 -0
- package/dist/graph/index.js +1413 -0
- package/dist/graph/index.js.map +1 -0
- package/dist/hono.cjs +3183 -0
- package/dist/hono.cjs.map +1 -0
- package/dist/hono.d.cts +39 -0
- package/dist/hono.d.ts +39 -0
- package/dist/hono.js +3179 -0
- package/dist/hono.js.map +1 -0
- package/dist/index.cjs +11731 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +851 -0
- package/dist/index.d.ts +851 -0
- package/dist/index.js +11676 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp.cjs +181 -0
- package/dist/mcp.cjs.map +1 -0
- package/dist/mcp.d.cts +26 -0
- package/dist/mcp.d.ts +26 -0
- package/dist/mcp.js +179 -0
- package/dist/mcp.js.map +1 -0
- package/dist/migrations/sql/0001.sql +119 -0
- package/dist/migrations/sql/0002_graph.sql +48 -0
- package/dist/migrations/sql/0003_tools.sql +61 -0
- package/dist/migrations/sql/0004_acl_indexes.sql +4 -0
- package/dist/redaction-BmDSWJ7h.d.cts +98 -0
- package/dist/redaction-BmDSWJ7h.d.ts +98 -0
- package/dist/redaction-presidio.cjs +79 -0
- package/dist/redaction-presidio.cjs.map +1 -0
- package/dist/redaction-presidio.d.cts +22 -0
- package/dist/redaction-presidio.d.ts +22 -0
- package/dist/redaction-presidio.js +73 -0
- package/dist/redaction-presidio.js.map +1 -0
- package/dist/router-CrxZ2y_Z.d.ts +82 -0
- package/dist/router-OPgSoYAB.d.cts +82 -0
- package/dist/skills/context-engine/SKILL.md +160 -0
- package/package.json +184 -0
- package/src/migrations/sql/0001.sql +119 -0
- package/src/migrations/sql/0002_graph.sql +48 -0
- package/src/migrations/sql/0003_tools.sql +61 -0
- package/src/migrations/sql/0004_acl_indexes.sql +4 -0
- package/src/skills/context-engine/SKILL.md +160 -0
package/dist/mcp.cjs
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/errors.ts
|
|
4
|
+
var ExtraMissingError = class extends Error {
|
|
5
|
+
constructor(extra, pkg, what) {
|
|
6
|
+
super(`${what} requires the '${pkg}' package (optional extra: ${extra}): npm install ${pkg}`);
|
|
7
|
+
this.name = "ExtraMissingError";
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// src/extras.ts
|
|
12
|
+
async function requireExtra(specifier, extra, what) {
|
|
13
|
+
try {
|
|
14
|
+
return await import(specifier);
|
|
15
|
+
} catch (_err) {
|
|
16
|
+
throw new ExtraMissingError(extra, specifier, what);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// src/tools/mcp-tools.ts
|
|
21
|
+
var SCOPE_NOTE = " Results are scoped to the caller's permissions (resolved by the server's injected principals dependency \u2014 never a caller-supplied argument) and to the given source_ids, if any.";
|
|
22
|
+
async function resolvePrincipalsFn(principals) {
|
|
23
|
+
const result = await Promise.resolve(principals());
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
26
|
+
function registerToolGateway(mcp, engine, principals) {
|
|
27
|
+
mcp.tool(
|
|
28
|
+
"search_tools",
|
|
29
|
+
"Keyword search over the tools this deployment has registered (http/db/mcp/function) \u2014 the ACL-visible name, kind, description, and JSON Schema params of each match, so a caller can discover what it can then invoke with `execute_tool`." + SCOPE_NOTE,
|
|
30
|
+
{ query: { type: "string" }, limit: { type: "number" } },
|
|
31
|
+
async (...raw) => {
|
|
32
|
+
const args = raw[0] ?? {};
|
|
33
|
+
const callerPrincipals = await resolvePrincipalsFn(principals);
|
|
34
|
+
const tools = await engine.searchTools(String(args.query ?? ""), {
|
|
35
|
+
principals: callerPrincipals,
|
|
36
|
+
limit: args.limit ?? 10
|
|
37
|
+
});
|
|
38
|
+
return { tools };
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
mcp.tool(
|
|
42
|
+
"execute_tool",
|
|
43
|
+
"Governed execution of a tool previously discovered via `search_tools` (ACL check, approval gate, audit). Returns `{result, usage}` on success, or an `approval_required` payload when the call needs a human approval that isn't already granted \u2014 the caller must not retry until that approval resolves." + SCOPE_NOTE,
|
|
44
|
+
{ name: { type: "string" }, args: { type: "object" } },
|
|
45
|
+
async (...raw) => {
|
|
46
|
+
const body = raw[0] ?? {};
|
|
47
|
+
const callerPrincipals = await resolvePrincipalsFn(principals);
|
|
48
|
+
return engine.executeTool(String(body.name), body.args ?? null, {
|
|
49
|
+
principals: callerPrincipals,
|
|
50
|
+
source: "mcp"
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// src/version.ts
|
|
57
|
+
var __version__ = "0.0.0";
|
|
58
|
+
|
|
59
|
+
// src/mcp.ts
|
|
60
|
+
function asMcpResult(data) {
|
|
61
|
+
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
62
|
+
}
|
|
63
|
+
async function createMcpApp(engine, opts) {
|
|
64
|
+
if (!opts?.principals) {
|
|
65
|
+
throw new TypeError("createMcpApp requires principals");
|
|
66
|
+
}
|
|
67
|
+
let McpServer;
|
|
68
|
+
let StreamableHTTPServerTransport;
|
|
69
|
+
try {
|
|
70
|
+
const serverMod = await requireExtra(
|
|
71
|
+
"@modelcontextprotocol/sdk/server/mcp.js",
|
|
72
|
+
"mcp",
|
|
73
|
+
"MCP server"
|
|
74
|
+
);
|
|
75
|
+
const httpMod = await requireExtra("@modelcontextprotocol/sdk/server/streamableHttp.js", "mcp", "MCP server");
|
|
76
|
+
McpServer = serverMod.McpServer;
|
|
77
|
+
StreamableHTTPServerTransport = httpMod.StreamableHTTPServerTransport;
|
|
78
|
+
} catch (exc) {
|
|
79
|
+
if (exc instanceof ExtraMissingError) throw exc;
|
|
80
|
+
throw new ExtraMissingError("mcp", "@modelcontextprotocol/sdk", "MCP server");
|
|
81
|
+
}
|
|
82
|
+
const mcp = new McpServer({ name: "context-engine", version: __version__ });
|
|
83
|
+
const tool = (name, description, schema, handler2) => {
|
|
84
|
+
mcp.tool(
|
|
85
|
+
name,
|
|
86
|
+
description,
|
|
87
|
+
schema,
|
|
88
|
+
async (args) => asMcpResult(await handler2(args))
|
|
89
|
+
);
|
|
90
|
+
};
|
|
91
|
+
tool(
|
|
92
|
+
"search_knowledge_base",
|
|
93
|
+
`Hybrid search (full-text + trigram + vector, RRF-fused) over the ingested corpus. Returns the top-matching chunks with their source document.${SCOPE_NOTE}`,
|
|
94
|
+
{
|
|
95
|
+
query: { type: "string" },
|
|
96
|
+
source_ids: { type: "array", items: { type: "string" } },
|
|
97
|
+
top_k: { type: "number" },
|
|
98
|
+
mode: { type: "string", enum: ["hybrid", "graph"] }
|
|
99
|
+
},
|
|
100
|
+
async (args) => {
|
|
101
|
+
const callerPrincipals = await resolvePrincipalsFn(opts.principals);
|
|
102
|
+
const result = await engine.search(String(args.query ?? ""), {
|
|
103
|
+
sourceIds: args.source_ids,
|
|
104
|
+
principals: callerPrincipals,
|
|
105
|
+
topK: args.top_k ?? 10,
|
|
106
|
+
mode: args.mode ?? "hybrid"
|
|
107
|
+
});
|
|
108
|
+
return {
|
|
109
|
+
hits: (result.hits ?? []).map((hit) => {
|
|
110
|
+
const h = hit;
|
|
111
|
+
return {
|
|
112
|
+
document_name: h.document_name ?? h.documentName,
|
|
113
|
+
chunk_text: h.chunk_text ?? h.chunkText,
|
|
114
|
+
score: h.score,
|
|
115
|
+
source_id: h.source_id ?? h.sourceId
|
|
116
|
+
};
|
|
117
|
+
}),
|
|
118
|
+
usage: result.usage
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
);
|
|
122
|
+
tool(
|
|
123
|
+
"get_document",
|
|
124
|
+
`Fetch one document's full text and metadata by id.${SCOPE_NOTE}`,
|
|
125
|
+
{ document_id: { type: "string" } },
|
|
126
|
+
async (args) => {
|
|
127
|
+
const callerPrincipals = await resolvePrincipalsFn(opts.principals);
|
|
128
|
+
return engine.getDocument(String(args.document_id), { principals: callerPrincipals });
|
|
129
|
+
}
|
|
130
|
+
);
|
|
131
|
+
if (engine.config.llm != null) {
|
|
132
|
+
tool(
|
|
133
|
+
"query_structured",
|
|
134
|
+
`Answer a question against documents' extracted structured data (only documents with structured data are candidates).${SCOPE_NOTE}`,
|
|
135
|
+
{ question: { type: "string" }, source_ids: { type: "array", items: { type: "string" } } },
|
|
136
|
+
async (args) => {
|
|
137
|
+
const callerPrincipals = await resolvePrincipalsFn(opts.principals);
|
|
138
|
+
if (!engine.queryStructured) throw new Error("queryStructured is not available on this engine");
|
|
139
|
+
return engine.queryStructured(String(args.question), {
|
|
140
|
+
sourceIds: args.source_ids,
|
|
141
|
+
principals: callerPrincipals
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
);
|
|
145
|
+
if (engine.config.enableCodeExecution) {
|
|
146
|
+
tool(
|
|
147
|
+
"compute",
|
|
148
|
+
`Run LLM-authored JavaScript over in-scope spreadsheet documents and return the computed result.${SCOPE_NOTE}`,
|
|
149
|
+
{ instruction: { type: "string" }, source_ids: { type: "array", items: { type: "string" } } },
|
|
150
|
+
async (args) => {
|
|
151
|
+
const callerPrincipals = await resolvePrincipalsFn(opts.principals);
|
|
152
|
+
if (!engine.compute) throw new Error("compute is not available on this engine");
|
|
153
|
+
return engine.compute(String(args.instruction), {
|
|
154
|
+
sourceIds: args.source_ids,
|
|
155
|
+
principals: callerPrincipals
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
registerToolGateway(
|
|
162
|
+
{
|
|
163
|
+
tool: (name, description, schema, handler2) => {
|
|
164
|
+
tool(name, description, schema, async (args) => handler2(args));
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
engine,
|
|
168
|
+
opts.principals
|
|
169
|
+
);
|
|
170
|
+
const handler = (async (req, res) => {
|
|
171
|
+
const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: void 0 });
|
|
172
|
+
await mcp.connect(transport);
|
|
173
|
+
await transport.handleRequest(req, res);
|
|
174
|
+
});
|
|
175
|
+
handler.mcp = mcp;
|
|
176
|
+
return handler;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
exports.createMcpApp = createMcpApp;
|
|
180
|
+
//# sourceMappingURL=mcp.cjs.map
|
|
181
|
+
//# sourceMappingURL=mcp.cjs.map
|
package/dist/mcp.cjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/extras.ts","../src/tools/mcp-tools.ts","../src/version.ts","../src/mcp.ts"],"names":["handler"],"mappings":"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","file":"mcp.cjs","sourcesContent":["/** Action-surface errors — user-facing / data-dependent failures (not found, ACL, bad input).\n * Config/programming errors stay as TypeError / RangeError / Error.\n */\nexport class EngineActionError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"EngineActionError\";\n }\n}\n\n/** Missing vs forbidden document: identical message so callers cannot distinguish. */\nexport class DocumentNotFoundError extends Error {\n constructor(documentId: string) {\n super(`document not found: ${documentId}`);\n this.name = \"DocumentNotFoundError\";\n }\n}\n\nexport class GraphLegUnavailable extends Error {\n constructor(message = \"graph ranked list was not supplied\") {\n super(message);\n this.name = \"GraphLegUnavailable\";\n }\n}\n\nexport class ApprovalNotPending extends Error {\n constructor(message = \"approval is not pending\") {\n super(message);\n this.name = \"ApprovalNotPending\";\n }\n}\n\nexport class ApprovalExpired extends Error {\n constructor(message = \"approval has expired\") {\n super(message);\n this.name = \"ApprovalExpired\";\n }\n}\n\nexport class CodeExecutionError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"CodeExecutionError\";\n }\n}\n\nexport class CodeExecutionTimeout extends Error {\n constructor(message = \"code execution timed out\") {\n super(message);\n this.name = \"CodeExecutionTimeout\";\n }\n}\n\nexport class ExtraMissingError extends Error {\n constructor(extra: string, pkg: string, what: string) {\n super(`${what} requires the '${pkg}' package (optional extra: ${extra}): npm install ${pkg}`);\n this.name = \"ExtraMissingError\";\n }\n}\n","import { ExtraMissingError } from \"./errors.js\";\n\nexport async function tryImport<T = unknown>(specifier: string): Promise<T | null> {\n try {\n return (await import(specifier)) as T;\n } catch {\n return null;\n }\n}\n\nexport async function requireExtra<T = unknown>(specifier: string, extra: string, what: string): Promise<T> {\n try {\n return (await import(specifier)) as T;\n } catch (_err) {\n throw new ExtraMissingError(extra, specifier, what);\n }\n}\n","export type PrincipalsFn = () => unknown | Promise<unknown>;\n\nexport const SCOPE_NOTE =\n \" Results are scoped to the caller's permissions (resolved by the server's \" +\n \"injected principals dependency — never a caller-supplied argument) and to \" +\n \"the given source_ids, if any.\";\n\nexport async function resolvePrincipalsFn(principals: PrincipalsFn): Promise<string[] | null> {\n const result = await Promise.resolve(principals());\n return result as string[] | null;\n}\n\nexport type McpToolHost = {\n tool(\n name: string,\n description: string,\n schema: Record<string, unknown>,\n handler: (...args: never[]) => Promise<unknown>,\n ): unknown;\n};\n\nexport function registerToolGateway(\n mcp: McpToolHost,\n engine: {\n searchTools: (query: string, opts?: Record<string, unknown>) => Promise<unknown[]>;\n executeTool: (\n name: string,\n args: Record<string, unknown> | null,\n opts?: Record<string, unknown>,\n ) => Promise<Record<string, unknown>>;\n },\n principals: PrincipalsFn,\n): void {\n mcp.tool(\n \"search_tools\",\n \"Keyword search over the tools this deployment has registered \" +\n \"(http/db/mcp/function) — the ACL-visible name, kind, description, \" +\n \"and JSON Schema params of each match, so a caller can discover what \" +\n \"it can then invoke with `execute_tool`.\" +\n SCOPE_NOTE,\n { query: { type: \"string\" }, limit: { type: \"number\" } },\n async (...raw: never[]) => {\n const args = (raw[0] ?? {}) as { query?: string; limit?: number };\n const callerPrincipals = await resolvePrincipalsFn(principals);\n const tools = await engine.searchTools(String(args.query ?? \"\"), {\n principals: callerPrincipals,\n limit: args.limit ?? 10,\n });\n return { tools };\n },\n );\n\n mcp.tool(\n \"execute_tool\",\n \"Governed execution of a tool previously discovered via \" +\n \"`search_tools` (ACL check, approval gate, audit). Returns \" +\n \"`{result, usage}` on success, or an `approval_required` payload \" +\n \"when the call needs a human approval that isn't already granted — \" +\n \"the caller must not retry until that approval resolves.\" +\n SCOPE_NOTE,\n { name: { type: \"string\" }, args: { type: \"object\" } },\n async (...raw: never[]) => {\n const body = (raw[0] ?? {}) as { name?: string; args?: Record<string, unknown> };\n const callerPrincipals = await resolvePrincipalsFn(principals);\n return engine.executeTool(String(body.name), body.args ?? null, {\n principals: callerPrincipals,\n source: \"mcp\",\n });\n },\n );\n}\n","/** Bumped by CI on every main merge; 0.0.0 = pre-first-release. */\nexport const __version__ = \"0.0.0\";\n","import { ExtraMissingError } from \"./errors.js\";\nimport { requireExtra } from \"./extras.js\";\nimport {\n type PrincipalsFn,\n registerToolGateway,\n resolvePrincipalsFn,\n SCOPE_NOTE,\n} from \"./tools/mcp-tools.js\";\nimport { __version__ } from \"./version.js\";\n\ntype Engine = {\n config: { llm?: unknown; enableCodeExecution?: boolean };\n search: (query: string, opts?: Record<string, unknown>) => Promise<{ hits: unknown[]; usage?: unknown }>;\n getDocument: (id: string, opts?: Record<string, unknown>) => Promise<unknown>;\n queryStructured?: (question: string, opts?: Record<string, unknown>) => Promise<unknown>;\n compute?: (instruction: string, opts?: Record<string, unknown>) => Promise<unknown>;\n searchTools: (query: string, opts?: Record<string, unknown>) => Promise<unknown[]>;\n executeTool: (\n name: string,\n args: Record<string, unknown> | null,\n opts?: Record<string, unknown>,\n ) => Promise<Record<string, unknown>>;\n};\n\nfunction asMcpResult(data: unknown): { content: Array<{ type: \"text\"; text: string }> } {\n return { content: [{ type: \"text\", text: JSON.stringify(data) }] };\n}\n\nexport async function createMcpApp(\n engine: Engine,\n opts: { principals: PrincipalsFn },\n): Promise<\n ((req: import(\"node:http\").IncomingMessage, res: import(\"node:http\").ServerResponse) => Promise<void>) & {\n mcp: unknown;\n }\n> {\n if (!opts?.principals) {\n throw new TypeError(\"createMcpApp requires principals\");\n }\n\n let McpServer: new (info: {\n name: string;\n version: string;\n }) => {\n tool: (...args: unknown[]) => unknown;\n connect: (t: unknown) => Promise<void>;\n };\n let StreamableHTTPServerTransport: new (opts: {\n sessionIdGenerator?: undefined;\n }) => {\n handleRequest: (req: unknown, res: unknown, body?: unknown) => Promise<void>;\n };\n try {\n const serverMod = await requireExtra<{ McpServer: typeof McpServer }>(\n \"@modelcontextprotocol/sdk/server/mcp.js\",\n \"mcp\",\n \"MCP server\",\n );\n const httpMod = await requireExtra<{\n StreamableHTTPServerTransport: typeof StreamableHTTPServerTransport;\n }>(\"@modelcontextprotocol/sdk/server/streamableHttp.js\", \"mcp\", \"MCP server\");\n McpServer = serverMod.McpServer;\n StreamableHTTPServerTransport = httpMod.StreamableHTTPServerTransport;\n } catch (exc) {\n if (exc instanceof ExtraMissingError) throw exc;\n throw new ExtraMissingError(\"mcp\", \"@modelcontextprotocol/sdk\", \"MCP server\");\n }\n\n const mcp = new McpServer({ name: \"context-engine\", version: __version__ });\n\n const tool = (\n name: string,\n description: string,\n schema: Record<string, unknown>,\n handler: (args: Record<string, unknown>) => Promise<unknown>,\n ) => {\n mcp.tool(name, description, schema, async (args: Record<string, unknown>) =>\n asMcpResult(await handler(args)),\n );\n };\n\n tool(\n \"search_knowledge_base\",\n `Hybrid search (full-text + trigram + vector, RRF-fused) over the ingested corpus. Returns the top-matching chunks with their source document.${SCOPE_NOTE}`,\n {\n query: { type: \"string\" },\n source_ids: { type: \"array\", items: { type: \"string\" } },\n top_k: { type: \"number\" },\n mode: { type: \"string\", enum: [\"hybrid\", \"graph\"] },\n },\n async (args) => {\n const callerPrincipals = await resolvePrincipalsFn(opts.principals);\n const result = await engine.search(String(args.query ?? \"\"), {\n sourceIds: args.source_ids,\n principals: callerPrincipals,\n topK: args.top_k ?? 10,\n mode: args.mode ?? \"hybrid\",\n });\n return {\n hits: (result.hits ?? []).map((hit) => {\n const h = hit as Record<string, unknown>;\n return {\n document_name: h.document_name ?? h.documentName,\n chunk_text: h.chunk_text ?? h.chunkText,\n score: h.score,\n source_id: h.source_id ?? h.sourceId,\n };\n }),\n usage: result.usage,\n };\n },\n );\n\n tool(\n \"get_document\",\n `Fetch one document's full text and metadata by id.${SCOPE_NOTE}`,\n { document_id: { type: \"string\" } },\n async (args) => {\n const callerPrincipals = await resolvePrincipalsFn(opts.principals);\n return engine.getDocument(String(args.document_id), { principals: callerPrincipals });\n },\n );\n\n if (engine.config.llm != null) {\n tool(\n \"query_structured\",\n `Answer a question against documents' extracted structured data (only documents with structured data are candidates).${SCOPE_NOTE}`,\n { question: { type: \"string\" }, source_ids: { type: \"array\", items: { type: \"string\" } } },\n async (args) => {\n const callerPrincipals = await resolvePrincipalsFn(opts.principals);\n if (!engine.queryStructured) throw new Error(\"queryStructured is not available on this engine\");\n return engine.queryStructured(String(args.question), {\n sourceIds: args.source_ids,\n principals: callerPrincipals,\n });\n },\n );\n if (engine.config.enableCodeExecution) {\n tool(\n \"compute\",\n `Run LLM-authored JavaScript over in-scope spreadsheet documents and return the computed result.${SCOPE_NOTE}`,\n { instruction: { type: \"string\" }, source_ids: { type: \"array\", items: { type: \"string\" } } },\n async (args) => {\n const callerPrincipals = await resolvePrincipalsFn(opts.principals);\n if (!engine.compute) throw new Error(\"compute is not available on this engine\");\n return engine.compute(String(args.instruction), {\n sourceIds: args.source_ids,\n principals: callerPrincipals,\n });\n },\n );\n }\n }\n\n registerToolGateway(\n {\n tool: (name, description, schema, handler) => {\n tool(name, description, schema, async (args) => handler(args as never));\n },\n },\n engine,\n opts.principals,\n );\n\n const handler = (async (\n req: import(\"node:http\").IncomingMessage,\n res: import(\"node:http\").ServerResponse,\n ) => {\n const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });\n await mcp.connect(transport);\n await transport.handleRequest(req, res);\n }) as ((\n req: import(\"node:http\").IncomingMessage,\n res: import(\"node:http\").ServerResponse,\n ) => Promise<void>) & { mcp: unknown };\n handler.mcp = mcp;\n return handler;\n}\n"]}
|
package/dist/mcp.d.cts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import * as node_http from 'node:http';
|
|
2
|
+
|
|
3
|
+
type PrincipalsFn = () => unknown | Promise<unknown>;
|
|
4
|
+
|
|
5
|
+
type Engine = {
|
|
6
|
+
config: {
|
|
7
|
+
llm?: unknown;
|
|
8
|
+
enableCodeExecution?: boolean;
|
|
9
|
+
};
|
|
10
|
+
search: (query: string, opts?: Record<string, unknown>) => Promise<{
|
|
11
|
+
hits: unknown[];
|
|
12
|
+
usage?: unknown;
|
|
13
|
+
}>;
|
|
14
|
+
getDocument: (id: string, opts?: Record<string, unknown>) => Promise<unknown>;
|
|
15
|
+
queryStructured?: (question: string, opts?: Record<string, unknown>) => Promise<unknown>;
|
|
16
|
+
compute?: (instruction: string, opts?: Record<string, unknown>) => Promise<unknown>;
|
|
17
|
+
searchTools: (query: string, opts?: Record<string, unknown>) => Promise<unknown[]>;
|
|
18
|
+
executeTool: (name: string, args: Record<string, unknown> | null, opts?: Record<string, unknown>) => Promise<Record<string, unknown>>;
|
|
19
|
+
};
|
|
20
|
+
declare function createMcpApp(engine: Engine, opts: {
|
|
21
|
+
principals: PrincipalsFn;
|
|
22
|
+
}): Promise<((req: node_http.IncomingMessage, res: node_http.ServerResponse) => Promise<void>) & {
|
|
23
|
+
mcp: unknown;
|
|
24
|
+
}>;
|
|
25
|
+
|
|
26
|
+
export { createMcpApp };
|
package/dist/mcp.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import * as node_http from 'node:http';
|
|
2
|
+
|
|
3
|
+
type PrincipalsFn = () => unknown | Promise<unknown>;
|
|
4
|
+
|
|
5
|
+
type Engine = {
|
|
6
|
+
config: {
|
|
7
|
+
llm?: unknown;
|
|
8
|
+
enableCodeExecution?: boolean;
|
|
9
|
+
};
|
|
10
|
+
search: (query: string, opts?: Record<string, unknown>) => Promise<{
|
|
11
|
+
hits: unknown[];
|
|
12
|
+
usage?: unknown;
|
|
13
|
+
}>;
|
|
14
|
+
getDocument: (id: string, opts?: Record<string, unknown>) => Promise<unknown>;
|
|
15
|
+
queryStructured?: (question: string, opts?: Record<string, unknown>) => Promise<unknown>;
|
|
16
|
+
compute?: (instruction: string, opts?: Record<string, unknown>) => Promise<unknown>;
|
|
17
|
+
searchTools: (query: string, opts?: Record<string, unknown>) => Promise<unknown[]>;
|
|
18
|
+
executeTool: (name: string, args: Record<string, unknown> | null, opts?: Record<string, unknown>) => Promise<Record<string, unknown>>;
|
|
19
|
+
};
|
|
20
|
+
declare function createMcpApp(engine: Engine, opts: {
|
|
21
|
+
principals: PrincipalsFn;
|
|
22
|
+
}): Promise<((req: node_http.IncomingMessage, res: node_http.ServerResponse) => Promise<void>) & {
|
|
23
|
+
mcp: unknown;
|
|
24
|
+
}>;
|
|
25
|
+
|
|
26
|
+
export { createMcpApp };
|
package/dist/mcp.js
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var ExtraMissingError = class extends Error {
|
|
3
|
+
constructor(extra, pkg, what) {
|
|
4
|
+
super(`${what} requires the '${pkg}' package (optional extra: ${extra}): npm install ${pkg}`);
|
|
5
|
+
this.name = "ExtraMissingError";
|
|
6
|
+
}
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
// src/extras.ts
|
|
10
|
+
async function requireExtra(specifier, extra, what) {
|
|
11
|
+
try {
|
|
12
|
+
return await import(specifier);
|
|
13
|
+
} catch (_err) {
|
|
14
|
+
throw new ExtraMissingError(extra, specifier, what);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// src/tools/mcp-tools.ts
|
|
19
|
+
var SCOPE_NOTE = " Results are scoped to the caller's permissions (resolved by the server's injected principals dependency \u2014 never a caller-supplied argument) and to the given source_ids, if any.";
|
|
20
|
+
async function resolvePrincipalsFn(principals) {
|
|
21
|
+
const result = await Promise.resolve(principals());
|
|
22
|
+
return result;
|
|
23
|
+
}
|
|
24
|
+
function registerToolGateway(mcp, engine, principals) {
|
|
25
|
+
mcp.tool(
|
|
26
|
+
"search_tools",
|
|
27
|
+
"Keyword search over the tools this deployment has registered (http/db/mcp/function) \u2014 the ACL-visible name, kind, description, and JSON Schema params of each match, so a caller can discover what it can then invoke with `execute_tool`." + SCOPE_NOTE,
|
|
28
|
+
{ query: { type: "string" }, limit: { type: "number" } },
|
|
29
|
+
async (...raw) => {
|
|
30
|
+
const args = raw[0] ?? {};
|
|
31
|
+
const callerPrincipals = await resolvePrincipalsFn(principals);
|
|
32
|
+
const tools = await engine.searchTools(String(args.query ?? ""), {
|
|
33
|
+
principals: callerPrincipals,
|
|
34
|
+
limit: args.limit ?? 10
|
|
35
|
+
});
|
|
36
|
+
return { tools };
|
|
37
|
+
}
|
|
38
|
+
);
|
|
39
|
+
mcp.tool(
|
|
40
|
+
"execute_tool",
|
|
41
|
+
"Governed execution of a tool previously discovered via `search_tools` (ACL check, approval gate, audit). Returns `{result, usage}` on success, or an `approval_required` payload when the call needs a human approval that isn't already granted \u2014 the caller must not retry until that approval resolves." + SCOPE_NOTE,
|
|
42
|
+
{ name: { type: "string" }, args: { type: "object" } },
|
|
43
|
+
async (...raw) => {
|
|
44
|
+
const body = raw[0] ?? {};
|
|
45
|
+
const callerPrincipals = await resolvePrincipalsFn(principals);
|
|
46
|
+
return engine.executeTool(String(body.name), body.args ?? null, {
|
|
47
|
+
principals: callerPrincipals,
|
|
48
|
+
source: "mcp"
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// src/version.ts
|
|
55
|
+
var __version__ = "0.0.0";
|
|
56
|
+
|
|
57
|
+
// src/mcp.ts
|
|
58
|
+
function asMcpResult(data) {
|
|
59
|
+
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
60
|
+
}
|
|
61
|
+
async function createMcpApp(engine, opts) {
|
|
62
|
+
if (!opts?.principals) {
|
|
63
|
+
throw new TypeError("createMcpApp requires principals");
|
|
64
|
+
}
|
|
65
|
+
let McpServer;
|
|
66
|
+
let StreamableHTTPServerTransport;
|
|
67
|
+
try {
|
|
68
|
+
const serverMod = await requireExtra(
|
|
69
|
+
"@modelcontextprotocol/sdk/server/mcp.js",
|
|
70
|
+
"mcp",
|
|
71
|
+
"MCP server"
|
|
72
|
+
);
|
|
73
|
+
const httpMod = await requireExtra("@modelcontextprotocol/sdk/server/streamableHttp.js", "mcp", "MCP server");
|
|
74
|
+
McpServer = serverMod.McpServer;
|
|
75
|
+
StreamableHTTPServerTransport = httpMod.StreamableHTTPServerTransport;
|
|
76
|
+
} catch (exc) {
|
|
77
|
+
if (exc instanceof ExtraMissingError) throw exc;
|
|
78
|
+
throw new ExtraMissingError("mcp", "@modelcontextprotocol/sdk", "MCP server");
|
|
79
|
+
}
|
|
80
|
+
const mcp = new McpServer({ name: "context-engine", version: __version__ });
|
|
81
|
+
const tool = (name, description, schema, handler2) => {
|
|
82
|
+
mcp.tool(
|
|
83
|
+
name,
|
|
84
|
+
description,
|
|
85
|
+
schema,
|
|
86
|
+
async (args) => asMcpResult(await handler2(args))
|
|
87
|
+
);
|
|
88
|
+
};
|
|
89
|
+
tool(
|
|
90
|
+
"search_knowledge_base",
|
|
91
|
+
`Hybrid search (full-text + trigram + vector, RRF-fused) over the ingested corpus. Returns the top-matching chunks with their source document.${SCOPE_NOTE}`,
|
|
92
|
+
{
|
|
93
|
+
query: { type: "string" },
|
|
94
|
+
source_ids: { type: "array", items: { type: "string" } },
|
|
95
|
+
top_k: { type: "number" },
|
|
96
|
+
mode: { type: "string", enum: ["hybrid", "graph"] }
|
|
97
|
+
},
|
|
98
|
+
async (args) => {
|
|
99
|
+
const callerPrincipals = await resolvePrincipalsFn(opts.principals);
|
|
100
|
+
const result = await engine.search(String(args.query ?? ""), {
|
|
101
|
+
sourceIds: args.source_ids,
|
|
102
|
+
principals: callerPrincipals,
|
|
103
|
+
topK: args.top_k ?? 10,
|
|
104
|
+
mode: args.mode ?? "hybrid"
|
|
105
|
+
});
|
|
106
|
+
return {
|
|
107
|
+
hits: (result.hits ?? []).map((hit) => {
|
|
108
|
+
const h = hit;
|
|
109
|
+
return {
|
|
110
|
+
document_name: h.document_name ?? h.documentName,
|
|
111
|
+
chunk_text: h.chunk_text ?? h.chunkText,
|
|
112
|
+
score: h.score,
|
|
113
|
+
source_id: h.source_id ?? h.sourceId
|
|
114
|
+
};
|
|
115
|
+
}),
|
|
116
|
+
usage: result.usage
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
);
|
|
120
|
+
tool(
|
|
121
|
+
"get_document",
|
|
122
|
+
`Fetch one document's full text and metadata by id.${SCOPE_NOTE}`,
|
|
123
|
+
{ document_id: { type: "string" } },
|
|
124
|
+
async (args) => {
|
|
125
|
+
const callerPrincipals = await resolvePrincipalsFn(opts.principals);
|
|
126
|
+
return engine.getDocument(String(args.document_id), { principals: callerPrincipals });
|
|
127
|
+
}
|
|
128
|
+
);
|
|
129
|
+
if (engine.config.llm != null) {
|
|
130
|
+
tool(
|
|
131
|
+
"query_structured",
|
|
132
|
+
`Answer a question against documents' extracted structured data (only documents with structured data are candidates).${SCOPE_NOTE}`,
|
|
133
|
+
{ question: { type: "string" }, source_ids: { type: "array", items: { type: "string" } } },
|
|
134
|
+
async (args) => {
|
|
135
|
+
const callerPrincipals = await resolvePrincipalsFn(opts.principals);
|
|
136
|
+
if (!engine.queryStructured) throw new Error("queryStructured is not available on this engine");
|
|
137
|
+
return engine.queryStructured(String(args.question), {
|
|
138
|
+
sourceIds: args.source_ids,
|
|
139
|
+
principals: callerPrincipals
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
);
|
|
143
|
+
if (engine.config.enableCodeExecution) {
|
|
144
|
+
tool(
|
|
145
|
+
"compute",
|
|
146
|
+
`Run LLM-authored JavaScript over in-scope spreadsheet documents and return the computed result.${SCOPE_NOTE}`,
|
|
147
|
+
{ instruction: { type: "string" }, source_ids: { type: "array", items: { type: "string" } } },
|
|
148
|
+
async (args) => {
|
|
149
|
+
const callerPrincipals = await resolvePrincipalsFn(opts.principals);
|
|
150
|
+
if (!engine.compute) throw new Error("compute is not available on this engine");
|
|
151
|
+
return engine.compute(String(args.instruction), {
|
|
152
|
+
sourceIds: args.source_ids,
|
|
153
|
+
principals: callerPrincipals
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
registerToolGateway(
|
|
160
|
+
{
|
|
161
|
+
tool: (name, description, schema, handler2) => {
|
|
162
|
+
tool(name, description, schema, async (args) => handler2(args));
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
engine,
|
|
166
|
+
opts.principals
|
|
167
|
+
);
|
|
168
|
+
const handler = (async (req, res) => {
|
|
169
|
+
const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: void 0 });
|
|
170
|
+
await mcp.connect(transport);
|
|
171
|
+
await transport.handleRequest(req, res);
|
|
172
|
+
});
|
|
173
|
+
handler.mcp = mcp;
|
|
174
|
+
return handler;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export { createMcpApp };
|
|
178
|
+
//# sourceMappingURL=mcp.js.map
|
|
179
|
+
//# sourceMappingURL=mcp.js.map
|
package/dist/mcp.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/extras.ts","../src/tools/mcp-tools.ts","../src/version.ts","../src/mcp.ts"],"names":["handler"],"mappings":"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","file":"mcp.js","sourcesContent":["/** Action-surface errors — user-facing / data-dependent failures (not found, ACL, bad input).\n * Config/programming errors stay as TypeError / RangeError / Error.\n */\nexport class EngineActionError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"EngineActionError\";\n }\n}\n\n/** Missing vs forbidden document: identical message so callers cannot distinguish. */\nexport class DocumentNotFoundError extends Error {\n constructor(documentId: string) {\n super(`document not found: ${documentId}`);\n this.name = \"DocumentNotFoundError\";\n }\n}\n\nexport class GraphLegUnavailable extends Error {\n constructor(message = \"graph ranked list was not supplied\") {\n super(message);\n this.name = \"GraphLegUnavailable\";\n }\n}\n\nexport class ApprovalNotPending extends Error {\n constructor(message = \"approval is not pending\") {\n super(message);\n this.name = \"ApprovalNotPending\";\n }\n}\n\nexport class ApprovalExpired extends Error {\n constructor(message = \"approval has expired\") {\n super(message);\n this.name = \"ApprovalExpired\";\n }\n}\n\nexport class CodeExecutionError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"CodeExecutionError\";\n }\n}\n\nexport class CodeExecutionTimeout extends Error {\n constructor(message = \"code execution timed out\") {\n super(message);\n this.name = \"CodeExecutionTimeout\";\n }\n}\n\nexport class ExtraMissingError extends Error {\n constructor(extra: string, pkg: string, what: string) {\n super(`${what} requires the '${pkg}' package (optional extra: ${extra}): npm install ${pkg}`);\n this.name = \"ExtraMissingError\";\n }\n}\n","import { ExtraMissingError } from \"./errors.js\";\n\nexport async function tryImport<T = unknown>(specifier: string): Promise<T | null> {\n try {\n return (await import(specifier)) as T;\n } catch {\n return null;\n }\n}\n\nexport async function requireExtra<T = unknown>(specifier: string, extra: string, what: string): Promise<T> {\n try {\n return (await import(specifier)) as T;\n } catch (_err) {\n throw new ExtraMissingError(extra, specifier, what);\n }\n}\n","export type PrincipalsFn = () => unknown | Promise<unknown>;\n\nexport const SCOPE_NOTE =\n \" Results are scoped to the caller's permissions (resolved by the server's \" +\n \"injected principals dependency — never a caller-supplied argument) and to \" +\n \"the given source_ids, if any.\";\n\nexport async function resolvePrincipalsFn(principals: PrincipalsFn): Promise<string[] | null> {\n const result = await Promise.resolve(principals());\n return result as string[] | null;\n}\n\nexport type McpToolHost = {\n tool(\n name: string,\n description: string,\n schema: Record<string, unknown>,\n handler: (...args: never[]) => Promise<unknown>,\n ): unknown;\n};\n\nexport function registerToolGateway(\n mcp: McpToolHost,\n engine: {\n searchTools: (query: string, opts?: Record<string, unknown>) => Promise<unknown[]>;\n executeTool: (\n name: string,\n args: Record<string, unknown> | null,\n opts?: Record<string, unknown>,\n ) => Promise<Record<string, unknown>>;\n },\n principals: PrincipalsFn,\n): void {\n mcp.tool(\n \"search_tools\",\n \"Keyword search over the tools this deployment has registered \" +\n \"(http/db/mcp/function) — the ACL-visible name, kind, description, \" +\n \"and JSON Schema params of each match, so a caller can discover what \" +\n \"it can then invoke with `execute_tool`.\" +\n SCOPE_NOTE,\n { query: { type: \"string\" }, limit: { type: \"number\" } },\n async (...raw: never[]) => {\n const args = (raw[0] ?? {}) as { query?: string; limit?: number };\n const callerPrincipals = await resolvePrincipalsFn(principals);\n const tools = await engine.searchTools(String(args.query ?? \"\"), {\n principals: callerPrincipals,\n limit: args.limit ?? 10,\n });\n return { tools };\n },\n );\n\n mcp.tool(\n \"execute_tool\",\n \"Governed execution of a tool previously discovered via \" +\n \"`search_tools` (ACL check, approval gate, audit). Returns \" +\n \"`{result, usage}` on success, or an `approval_required` payload \" +\n \"when the call needs a human approval that isn't already granted — \" +\n \"the caller must not retry until that approval resolves.\" +\n SCOPE_NOTE,\n { name: { type: \"string\" }, args: { type: \"object\" } },\n async (...raw: never[]) => {\n const body = (raw[0] ?? {}) as { name?: string; args?: Record<string, unknown> };\n const callerPrincipals = await resolvePrincipalsFn(principals);\n return engine.executeTool(String(body.name), body.args ?? null, {\n principals: callerPrincipals,\n source: \"mcp\",\n });\n },\n );\n}\n","/** Bumped by CI on every main merge; 0.0.0 = pre-first-release. */\nexport const __version__ = \"0.0.0\";\n","import { ExtraMissingError } from \"./errors.js\";\nimport { requireExtra } from \"./extras.js\";\nimport {\n type PrincipalsFn,\n registerToolGateway,\n resolvePrincipalsFn,\n SCOPE_NOTE,\n} from \"./tools/mcp-tools.js\";\nimport { __version__ } from \"./version.js\";\n\ntype Engine = {\n config: { llm?: unknown; enableCodeExecution?: boolean };\n search: (query: string, opts?: Record<string, unknown>) => Promise<{ hits: unknown[]; usage?: unknown }>;\n getDocument: (id: string, opts?: Record<string, unknown>) => Promise<unknown>;\n queryStructured?: (question: string, opts?: Record<string, unknown>) => Promise<unknown>;\n compute?: (instruction: string, opts?: Record<string, unknown>) => Promise<unknown>;\n searchTools: (query: string, opts?: Record<string, unknown>) => Promise<unknown[]>;\n executeTool: (\n name: string,\n args: Record<string, unknown> | null,\n opts?: Record<string, unknown>,\n ) => Promise<Record<string, unknown>>;\n};\n\nfunction asMcpResult(data: unknown): { content: Array<{ type: \"text\"; text: string }> } {\n return { content: [{ type: \"text\", text: JSON.stringify(data) }] };\n}\n\nexport async function createMcpApp(\n engine: Engine,\n opts: { principals: PrincipalsFn },\n): Promise<\n ((req: import(\"node:http\").IncomingMessage, res: import(\"node:http\").ServerResponse) => Promise<void>) & {\n mcp: unknown;\n }\n> {\n if (!opts?.principals) {\n throw new TypeError(\"createMcpApp requires principals\");\n }\n\n let McpServer: new (info: {\n name: string;\n version: string;\n }) => {\n tool: (...args: unknown[]) => unknown;\n connect: (t: unknown) => Promise<void>;\n };\n let StreamableHTTPServerTransport: new (opts: {\n sessionIdGenerator?: undefined;\n }) => {\n handleRequest: (req: unknown, res: unknown, body?: unknown) => Promise<void>;\n };\n try {\n const serverMod = await requireExtra<{ McpServer: typeof McpServer }>(\n \"@modelcontextprotocol/sdk/server/mcp.js\",\n \"mcp\",\n \"MCP server\",\n );\n const httpMod = await requireExtra<{\n StreamableHTTPServerTransport: typeof StreamableHTTPServerTransport;\n }>(\"@modelcontextprotocol/sdk/server/streamableHttp.js\", \"mcp\", \"MCP server\");\n McpServer = serverMod.McpServer;\n StreamableHTTPServerTransport = httpMod.StreamableHTTPServerTransport;\n } catch (exc) {\n if (exc instanceof ExtraMissingError) throw exc;\n throw new ExtraMissingError(\"mcp\", \"@modelcontextprotocol/sdk\", \"MCP server\");\n }\n\n const mcp = new McpServer({ name: \"context-engine\", version: __version__ });\n\n const tool = (\n name: string,\n description: string,\n schema: Record<string, unknown>,\n handler: (args: Record<string, unknown>) => Promise<unknown>,\n ) => {\n mcp.tool(name, description, schema, async (args: Record<string, unknown>) =>\n asMcpResult(await handler(args)),\n );\n };\n\n tool(\n \"search_knowledge_base\",\n `Hybrid search (full-text + trigram + vector, RRF-fused) over the ingested corpus. Returns the top-matching chunks with their source document.${SCOPE_NOTE}`,\n {\n query: { type: \"string\" },\n source_ids: { type: \"array\", items: { type: \"string\" } },\n top_k: { type: \"number\" },\n mode: { type: \"string\", enum: [\"hybrid\", \"graph\"] },\n },\n async (args) => {\n const callerPrincipals = await resolvePrincipalsFn(opts.principals);\n const result = await engine.search(String(args.query ?? \"\"), {\n sourceIds: args.source_ids,\n principals: callerPrincipals,\n topK: args.top_k ?? 10,\n mode: args.mode ?? \"hybrid\",\n });\n return {\n hits: (result.hits ?? []).map((hit) => {\n const h = hit as Record<string, unknown>;\n return {\n document_name: h.document_name ?? h.documentName,\n chunk_text: h.chunk_text ?? h.chunkText,\n score: h.score,\n source_id: h.source_id ?? h.sourceId,\n };\n }),\n usage: result.usage,\n };\n },\n );\n\n tool(\n \"get_document\",\n `Fetch one document's full text and metadata by id.${SCOPE_NOTE}`,\n { document_id: { type: \"string\" } },\n async (args) => {\n const callerPrincipals = await resolvePrincipalsFn(opts.principals);\n return engine.getDocument(String(args.document_id), { principals: callerPrincipals });\n },\n );\n\n if (engine.config.llm != null) {\n tool(\n \"query_structured\",\n `Answer a question against documents' extracted structured data (only documents with structured data are candidates).${SCOPE_NOTE}`,\n { question: { type: \"string\" }, source_ids: { type: \"array\", items: { type: \"string\" } } },\n async (args) => {\n const callerPrincipals = await resolvePrincipalsFn(opts.principals);\n if (!engine.queryStructured) throw new Error(\"queryStructured is not available on this engine\");\n return engine.queryStructured(String(args.question), {\n sourceIds: args.source_ids,\n principals: callerPrincipals,\n });\n },\n );\n if (engine.config.enableCodeExecution) {\n tool(\n \"compute\",\n `Run LLM-authored JavaScript over in-scope spreadsheet documents and return the computed result.${SCOPE_NOTE}`,\n { instruction: { type: \"string\" }, source_ids: { type: \"array\", items: { type: \"string\" } } },\n async (args) => {\n const callerPrincipals = await resolvePrincipalsFn(opts.principals);\n if (!engine.compute) throw new Error(\"compute is not available on this engine\");\n return engine.compute(String(args.instruction), {\n sourceIds: args.source_ids,\n principals: callerPrincipals,\n });\n },\n );\n }\n }\n\n registerToolGateway(\n {\n tool: (name, description, schema, handler) => {\n tool(name, description, schema, async (args) => handler(args as never));\n },\n },\n engine,\n opts.principals,\n );\n\n const handler = (async (\n req: import(\"node:http\").IncomingMessage,\n res: import(\"node:http\").ServerResponse,\n ) => {\n const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });\n await mcp.connect(transport);\n await transport.handleRequest(req, res);\n }) as ((\n req: import(\"node:http\").IncomingMessage,\n res: import(\"node:http\").ServerResponse,\n ) => Promise<void>) & { mcp: unknown };\n handler.mcp = mcp;\n return handler;\n}\n"]}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
-- 0001_initial — documents, chunks, meta, structured_keys
|
|
2
|
+
-- dim is substituted by the migrator (default 1536)
|
|
3
|
+
|
|
4
|
+
CREATE EXTENSION IF NOT EXISTS vector;
|
|
5
|
+
CREATE EXTENSION IF NOT EXISTS pg_trgm;
|
|
6
|
+
CREATE EXTENSION IF NOT EXISTS unaccent;
|
|
7
|
+
|
|
8
|
+
CREATE OR REPLACE FUNCTION immutable_unaccent(text)
|
|
9
|
+
RETURNS text
|
|
10
|
+
LANGUAGE sql
|
|
11
|
+
IMMUTABLE
|
|
12
|
+
STRICT
|
|
13
|
+
PARALLEL SAFE
|
|
14
|
+
AS $fn$
|
|
15
|
+
SELECT unaccent($1)
|
|
16
|
+
$fn$;
|
|
17
|
+
|
|
18
|
+
CREATE TABLE context_engine_documents (
|
|
19
|
+
id UUID PRIMARY KEY,
|
|
20
|
+
source_id TEXT,
|
|
21
|
+
external_id TEXT,
|
|
22
|
+
name TEXT,
|
|
23
|
+
description TEXT,
|
|
24
|
+
meta_data JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
25
|
+
acl TEXT[],
|
|
26
|
+
mode TEXT NOT NULL DEFAULT 'hybrid',
|
|
27
|
+
mime_type TEXT,
|
|
28
|
+
lang TEXT,
|
|
29
|
+
text TEXT,
|
|
30
|
+
text_search TSVECTOR GENERATED ALWAYS AS (
|
|
31
|
+
to_tsvector('simple'::regconfig,
|
|
32
|
+
left(coalesce(name,'') || ' ' || coalesce(description,'') || ' ' || coalesce(text,''), 500000))
|
|
33
|
+
) STORED,
|
|
34
|
+
modified_time TIMESTAMPTZ,
|
|
35
|
+
revision TEXT,
|
|
36
|
+
ingest_hash BYTEA,
|
|
37
|
+
status TEXT NOT NULL DEFAULT 'queued',
|
|
38
|
+
error TEXT,
|
|
39
|
+
started_at TIMESTAMPTZ,
|
|
40
|
+
completed_at TIMESTAMPTZ,
|
|
41
|
+
document_type TEXT,
|
|
42
|
+
structured_data JSONB,
|
|
43
|
+
structured_keys TEXT[],
|
|
44
|
+
structured_quality JSONB,
|
|
45
|
+
extraction_version TEXT,
|
|
46
|
+
media_bytes BYTEA,
|
|
47
|
+
media_size BIGINT,
|
|
48
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
49
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
CREATE INDEX ix_context_engine_documents_source_id ON context_engine_documents (source_id);
|
|
53
|
+
CREATE INDEX ix_context_engine_documents_status ON context_engine_documents (status);
|
|
54
|
+
CREATE INDEX ix_context_engine_documents_meta_data_gin ON context_engine_documents USING gin (meta_data);
|
|
55
|
+
CREATE INDEX ix_context_engine_documents_text_search ON context_engine_documents USING gin (text_search);
|
|
56
|
+
|
|
57
|
+
CREATE UNIQUE INDEX ix_context_engine_documents_uniq_source_external
|
|
58
|
+
ON context_engine_documents (COALESCE(source_id, ''), external_id)
|
|
59
|
+
WHERE external_id IS NOT NULL;
|
|
60
|
+
|
|
61
|
+
CREATE UNIQUE INDEX ix_context_engine_documents_uniq_source_name
|
|
62
|
+
ON context_engine_documents (COALESCE(source_id, ''), name)
|
|
63
|
+
WHERE external_id IS NULL;
|
|
64
|
+
|
|
65
|
+
CREATE TABLE context_engine_chunks (
|
|
66
|
+
id UUID PRIMARY KEY,
|
|
67
|
+
document_id UUID NOT NULL REFERENCES context_engine_documents(id) ON DELETE CASCADE,
|
|
68
|
+
source_id TEXT,
|
|
69
|
+
acl TEXT[],
|
|
70
|
+
idx INTEGER,
|
|
71
|
+
text TEXT,
|
|
72
|
+
meta_data JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
73
|
+
text_trgm_norm TEXT GENERATED ALWAYS AS (coalesce(text, '')) STORED,
|
|
74
|
+
text_search TSVECTOR GENERATED ALWAYS AS (
|
|
75
|
+
to_tsvector('simple'::regconfig, left(coalesce(text,''), 500000))
|
|
76
|
+
) STORED,
|
|
77
|
+
lang TEXT,
|
|
78
|
+
embedding vector(__DIM__),
|
|
79
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
CREATE INDEX ix_context_engine_chunks_document_id ON context_engine_chunks (document_id);
|
|
83
|
+
CREATE INDEX ix_context_engine_chunks_source_id ON context_engine_chunks (source_id);
|
|
84
|
+
CREATE INDEX ix_context_engine_chunks_text_search ON context_engine_chunks USING gin (text_search) WHERE text IS NOT NULL;
|
|
85
|
+
CREATE INDEX ix_context_engine_chunks_text_trgm_norm ON context_engine_chunks USING gin (text_trgm_norm gin_trgm_ops) WHERE text IS NOT NULL;
|
|
86
|
+
CREATE INDEX ix_context_engine_chunks_embedding_hnsw ON context_engine_chunks USING hnsw (embedding vector_cosine_ops) WHERE embedding IS NOT NULL;
|
|
87
|
+
|
|
88
|
+
CREATE TABLE context_engine_meta (
|
|
89
|
+
id INTEGER PRIMARY KEY,
|
|
90
|
+
embedding_provider TEXT,
|
|
91
|
+
embedding_model TEXT,
|
|
92
|
+
embedding_dim INTEGER,
|
|
93
|
+
schema_version INTEGER NOT NULL DEFAULT 1,
|
|
94
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
95
|
+
CONSTRAINT chk_context_engine_meta_singleton CHECK (id = 1)
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
CREATE TABLE context_engine_structured_keys (
|
|
99
|
+
id UUID PRIMARY KEY,
|
|
100
|
+
source_id TEXT,
|
|
101
|
+
doc_type TEXT NOT NULL,
|
|
102
|
+
key_norm TEXT NOT NULL,
|
|
103
|
+
synonyms TEXT[] NOT NULL DEFAULT '{}',
|
|
104
|
+
data_type TEXT NOT NULL,
|
|
105
|
+
example_values TEXT[],
|
|
106
|
+
frequency INTEGER NOT NULL DEFAULT 1,
|
|
107
|
+
embedding vector(__DIM__),
|
|
108
|
+
co_occurrence_fields JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
109
|
+
value_stats JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
110
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
111
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
112
|
+
CONSTRAINT uq_context_engine_structured_keys_norm UNIQUE (source_id, doc_type, key_norm)
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
CREATE INDEX ix_context_engine_structured_keys_source_doctype ON context_engine_structured_keys (source_id, doc_type);
|
|
116
|
+
CREATE INDEX ix_context_engine_structured_keys_synonyms_gin ON context_engine_structured_keys USING gin (synonyms);
|
|
117
|
+
CREATE INDEX ix_context_engine_structured_keys_co_occurrence_gin ON context_engine_structured_keys USING gin (co_occurrence_fields);
|
|
118
|
+
CREATE INDEX ix_context_engine_structured_keys_value_stats_gin ON context_engine_structured_keys USING gin (value_stats);
|
|
119
|
+
CREATE INDEX ix_context_engine_structured_keys_embedding_hnsw ON context_engine_structured_keys USING hnsw (embedding vector_cosine_ops) WHERE embedding IS NOT NULL;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
-- 0002_graph — entities, relationships, chunk_entities, communities
|
|
2
|
+
|
|
3
|
+
CREATE TABLE context_engine_entities (
|
|
4
|
+
id UUID PRIMARY KEY,
|
|
5
|
+
name TEXT NOT NULL,
|
|
6
|
+
normalized_name TEXT NOT NULL,
|
|
7
|
+
type TEXT NOT NULL,
|
|
8
|
+
frequency INTEGER NOT NULL DEFAULT 1,
|
|
9
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
10
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
11
|
+
CONSTRAINT uq_context_engine_entities_normalized_name UNIQUE (normalized_name)
|
|
12
|
+
);
|
|
13
|
+
CREATE INDEX ix_context_engine_entities_type ON context_engine_entities (type);
|
|
14
|
+
|
|
15
|
+
CREATE TABLE context_engine_entity_relationships (
|
|
16
|
+
id UUID PRIMARY KEY,
|
|
17
|
+
source_entity_id UUID NOT NULL REFERENCES context_engine_entities(id) ON DELETE CASCADE,
|
|
18
|
+
target_entity_id UUID NOT NULL REFERENCES context_engine_entities(id) ON DELETE CASCADE,
|
|
19
|
+
category TEXT NOT NULL,
|
|
20
|
+
label TEXT NOT NULL,
|
|
21
|
+
evidence TEXT,
|
|
22
|
+
chunk_id UUID REFERENCES context_engine_chunks(id) ON DELETE CASCADE,
|
|
23
|
+
confidence DOUBLE PRECISION NOT NULL DEFAULT 1.0,
|
|
24
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
25
|
+
);
|
|
26
|
+
CREATE INDEX ix_context_engine_entity_rel_source ON context_engine_entity_relationships (source_entity_id);
|
|
27
|
+
CREATE INDEX ix_context_engine_entity_rel_target ON context_engine_entity_relationships (target_entity_id);
|
|
28
|
+
CREATE INDEX ix_context_engine_entity_rel_category ON context_engine_entity_relationships (category);
|
|
29
|
+
CREATE INDEX ix_context_engine_entity_rel_chunk ON context_engine_entity_relationships (chunk_id);
|
|
30
|
+
|
|
31
|
+
CREATE TABLE context_engine_chunk_entities (
|
|
32
|
+
chunk_id UUID NOT NULL REFERENCES context_engine_chunks(id) ON DELETE CASCADE,
|
|
33
|
+
entity_id UUID NOT NULL REFERENCES context_engine_entities(id) ON DELETE CASCADE,
|
|
34
|
+
PRIMARY KEY (chunk_id, entity_id)
|
|
35
|
+
);
|
|
36
|
+
CREATE INDEX ix_context_engine_chunk_entities_entity ON context_engine_chunk_entities (entity_id);
|
|
37
|
+
|
|
38
|
+
CREATE TABLE context_engine_communities (
|
|
39
|
+
id UUID PRIMARY KEY,
|
|
40
|
+
level INTEGER NOT NULL DEFAULT 0,
|
|
41
|
+
entity_ids JSONB NOT NULL DEFAULT '[]'::jsonb,
|
|
42
|
+
entity_count INTEGER NOT NULL DEFAULT 0,
|
|
43
|
+
relationship_count INTEGER NOT NULL DEFAULT 0,
|
|
44
|
+
summary TEXT,
|
|
45
|
+
embedding vector(__DIM__),
|
|
46
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
47
|
+
);
|
|
48
|
+
CREATE INDEX ix_context_engine_communities_level ON context_engine_communities (level);
|