@gmickel/gno 1.28.0 → 1.29.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -20
- package/assets/skill/SKILL.md +33 -0
- package/browser-extension/artifacts/gno-browser-clipper-v1.29.1.zip +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v1.29.1.zip.sha256 +1 -0
- package/browser-extension/dist/chunk-b2zm0jjd.js +50 -0
- package/browser-extension/dist/manifest.json +1 -1
- package/browser-extension/dist/preview.html +1 -1
- package/browser-extension/dist/service-worker.js +6 -6
- package/package.json +1 -1
- package/spec/cli.md +41 -1
- package/spec/db/schema.sql +19 -0
- package/spec/mcp.md +66 -0
- package/spec/output-schemas/ask.schema.json +31 -1
- package/spec/output-schemas/browser-clip-preview.schema.json +30 -0
- package/spec/output-schemas/collection-egress-check.schema.json +91 -0
- package/spec/output-schemas/collection-egress-policy-set.schema.json +56 -0
- package/spec/output-schemas/collection-egress-policy.schema.json +41 -0
- package/spec/output-schemas/context-capsule-v1.schema.json +89 -2
- package/spec/output-schemas/context-capsule-verification.schema.json +1 -1
- package/spec/output-schemas/egress-audit-management.schema.json +88 -0
- package/spec/output-schemas/mcp-http-error.schema.json +113 -2
- package/spec/output-schemas/publish-artifact.schema.json +32 -0
- package/spec/output-schemas/record-import.schema.json +30 -0
- package/spec/output-schemas/retrieval-trace-common.schema.json +31 -0
- package/spec/output-schemas/retrieval-trace-export.schema.json +3 -0
- package/spec/output-schemas/retrieval-trace-qrels.schema.json +3 -0
- package/spec/output-schemas/retrieval-trace-summary.schema.json +4 -0
- package/spec/output-schemas/search-results.schema.json +30 -0
- package/src/app/context-runtime-contract.ts +16 -7
- package/src/cli/commands/ask.ts +7 -0
- package/src/cli/commands/collection/index.ts +5 -0
- package/src/cli/commands/collection/policy.ts +126 -0
- package/src/cli/commands/context-build.ts +5 -0
- package/src/cli/commands/daemon.ts +45 -3
- package/src/cli/commands/egress-audit.ts +68 -0
- package/src/cli/commands/embed.ts +2 -0
- package/src/cli/commands/query.ts +12 -0
- package/src/cli/commands/replay.ts +13 -3
- package/src/cli/commands/vsearch.ts +3 -1
- package/src/cli/program.ts +123 -0
- package/src/config/index.ts +9 -0
- package/src/config/types.ts +50 -0
- package/src/core/browser-clip.ts +16 -1
- package/src/core/collection-egress-policy-projection.ts +28 -0
- package/src/core/collection-egress-policy-service.ts +443 -0
- package/src/core/collection-egress-policy-validation.ts +242 -0
- package/src/core/config-mutation.ts +31 -19
- package/src/core/context-capsule-schema.ts +111 -1
- package/src/core/context-capsule-validation.ts +4 -4
- package/src/core/context-capsule-verification.ts +5 -1
- package/src/core/context-capsule.ts +177 -132
- package/src/core/context-evidence.ts +86 -14
- package/src/core/destination-classifier.ts +402 -0
- package/src/core/egress-audit.ts +239 -0
- package/src/core/egress-authorization.ts +50 -0
- package/src/core/egress-enforcement.ts +264 -0
- package/src/core/egress-policy.ts +440 -0
- package/src/core/egress-provenance.ts +336 -0
- package/src/core/job-manager.ts +37 -0
- package/src/core/network-boundary-inventory.ts +261 -0
- package/src/core/retrieval-qrels.ts +6 -0
- package/src/core/retrieval-replay.ts +18 -4
- package/src/core/retrieval-trace-export.ts +23 -4
- package/src/core/retrieval-trace-management-helpers.ts +1 -0
- package/src/core/retrieval-trace-management-types.ts +3 -0
- package/src/core/retrieval-trace-management.ts +9 -1
- package/src/core/retrieval-trace-session.ts +94 -0
- package/src/core/retrieval-trace.ts +22 -0
- package/src/ingestion/record-adapter.ts +12 -1
- package/src/ingestion/record-container.ts +38 -22
- package/src/ingestion/sync.ts +15 -0
- package/src/ingestion/types.ts +2 -0
- package/src/llm/errors.ts +10 -0
- package/src/llm/http-inference.ts +175 -0
- package/src/llm/http-policy.ts +537 -0
- package/src/llm/httpEmbedding.ts +47 -28
- package/src/llm/httpGeneration.ts +31 -18
- package/src/llm/httpRerank.ts +30 -18
- package/src/llm/index.ts +1 -0
- package/src/llm/nodeLlamaCpp/adapter.ts +55 -20
- package/src/llm/pinned-http-connection.ts +177 -0
- package/src/mcp/context.ts +53 -1
- package/src/mcp/http-egress.ts +220 -0
- package/src/mcp/http-security.ts +32 -21
- package/src/mcp/http-session.ts +13 -2
- package/src/mcp/http-transport.ts +96 -6
- package/src/mcp/sync-egress.ts +24 -0
- package/src/mcp/tools/add-collection.ts +4 -0
- package/src/mcp/tools/ask.ts +1 -1
- package/src/mcp/tools/context.ts +9 -2
- package/src/mcp/tools/egress.ts +247 -0
- package/src/mcp/tools/embed.ts +1 -0
- package/src/mcp/tools/index-cmd.ts +7 -0
- package/src/mcp/tools/index.ts +98 -0
- package/src/mcp/tools/query.ts +10 -0
- package/src/mcp/tools/remove-collection.ts +4 -0
- package/src/mcp/tools/sync.ts +6 -0
- package/src/mcp/tools/trace.ts +7 -1
- package/src/mcp/tools/vsearch.ts +1 -0
- package/src/pipeline/egress-lineage.ts +124 -0
- package/src/pipeline/hybrid.ts +14 -0
- package/src/pipeline/search.ts +12 -0
- package/src/pipeline/types.ts +3 -0
- package/src/pipeline/vsearch.ts +41 -20
- package/src/publish/artifact.ts +31 -3
- package/src/publish/export-service.ts +25 -0
- package/src/sdk/client.ts +119 -2
- package/src/sdk/embed.ts +1 -0
- package/src/sdk/types.ts +33 -0
- package/src/serve/clipper-capture.ts +5 -1
- package/src/serve/closed-json.ts +61 -0
- package/src/serve/config-sync.ts +4 -1
- package/src/serve/context.ts +1 -0
- package/src/serve/doc-events.ts +110 -39
- package/src/serve/public/components/CollectionEgressCheckPanel.tsx +411 -0
- package/src/serve/public/components/CollectionEgressPolicyEditor.tsx +78 -0
- package/src/serve/public/components/CollectionModelDialog.tsx +93 -9
- package/src/serve/public/components/EgressAuditPanel.tsx +278 -0
- package/src/serve/public/globals.built.css +1 -1
- package/src/serve/public/pages/Collections.tsx +3 -0
- package/src/serve/resident-request.ts +80 -3
- package/src/serve/resident-runtime.ts +63 -1
- package/src/serve/routes/api.ts +174 -0
- package/src/serve/routes/clipper.ts +64 -1
- package/src/serve/routes/mcp.ts +6 -0
- package/src/serve/routes/traces.ts +27 -4
- package/src/serve/server.ts +118 -7
- package/src/store/migrations/023-collection-egress-policy.ts +61 -0
- package/src/store/migrations/024-egress-derived-lineage.ts +121 -0
- package/src/store/migrations/025-collection-egress-policy-revision.ts +40 -0
- package/src/store/migrations/index.ts +6 -0
- package/src/store/retrieval-trace-codec.ts +15 -0
- package/src/store/sqlite/adapter.ts +170 -7
- package/src/store/sqlite/change-journal-store.ts +41 -2
- package/src/store/sqlite/egress-audit-store.ts +485 -0
- package/src/store/sqlite/retrieval-trace-management-store.ts +47 -6
- package/src/store/sqlite/retrieval-trace-retention.ts +2 -0
- package/src/store/sqlite/retrieval-trace-rows.ts +8 -1
- package/src/store/sqlite/retrieval-trace-store.ts +104 -5
- package/src/store/types.ts +126 -1
- package/browser-extension/artifacts/gno-browser-clipper-v1.28.0.zip +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v1.28.0.zip.sha256 +0 -1
- package/browser-extension/dist/chunk-vn5f663b.js +0 -50
package/src/mcp/tools/context.ts
CHANGED
|
@@ -119,7 +119,7 @@ export const disposeContextModelOwners = async (
|
|
|
119
119
|
|
|
120
120
|
export const createMcpModelPorts = async (
|
|
121
121
|
context: ToolContext,
|
|
122
|
-
|
|
122
|
+
collections?: readonly string[],
|
|
123
123
|
factoryOverride?: McpModelPortFactory,
|
|
124
124
|
options: { generation?: boolean } = {}
|
|
125
125
|
): Promise<McpModelPorts> => {
|
|
@@ -128,6 +128,10 @@ export const createMcpModelPorts = async (
|
|
|
128
128
|
const lease = factory.acquireModelLease?.();
|
|
129
129
|
const policy = resolveDownloadPolicy(process.env, {});
|
|
130
130
|
const progress = createNonTtyProgressRenderer();
|
|
131
|
+
const egressCollections = collections?.length
|
|
132
|
+
? collections
|
|
133
|
+
: ("all" as const);
|
|
134
|
+
const collection = collections?.length === 1 ? collections[0] : undefined;
|
|
131
135
|
const embedUri = resolveModelUri(
|
|
132
136
|
context.config,
|
|
133
137
|
"embed",
|
|
@@ -141,6 +145,7 @@ export const createMcpModelPorts = async (
|
|
|
141
145
|
let vectorIndex: VectorIndexPort | null = null;
|
|
142
146
|
try {
|
|
143
147
|
const embedResult = await factory.createEmbeddingPort(embedUri, {
|
|
148
|
+
egressCollections,
|
|
144
149
|
policy,
|
|
145
150
|
onProgress: (value) => progress("embed", value),
|
|
146
151
|
});
|
|
@@ -160,6 +165,7 @@ export const createMcpModelPorts = async (
|
|
|
160
165
|
const rerankResult = await factory.createRerankPort(
|
|
161
166
|
resolveModelUri(context.config, "rerank", undefined, collection),
|
|
162
167
|
{
|
|
168
|
+
egressCollections,
|
|
163
169
|
policy,
|
|
164
170
|
onProgress: (value) => progress("rerank", value),
|
|
165
171
|
}
|
|
@@ -169,6 +175,7 @@ export const createMcpModelPorts = async (
|
|
|
169
175
|
const genResult = await factory.createGenerationPort(
|
|
170
176
|
resolveModelUri(context.config, "gen", undefined, collection),
|
|
171
177
|
{
|
|
178
|
+
egressCollections,
|
|
172
179
|
policy,
|
|
173
180
|
onProgress: (value) => progress("gen", value),
|
|
174
181
|
}
|
|
@@ -269,7 +276,7 @@ export const handleContext = (
|
|
|
269
276
|
if (!traceStart.ok) throw new Error(traceStart.error.message);
|
|
270
277
|
traceSession = traceStart.value ?? undefined;
|
|
271
278
|
modelPorts = useModels
|
|
272
|
-
? await createMcpModelPorts(context,
|
|
279
|
+
? await createMcpModelPorts(context, parsed.input.collections)
|
|
273
280
|
: null;
|
|
274
281
|
const capsule = await buildContextCapsule(parsed.input, {
|
|
275
282
|
store: context.store,
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/** MCP collection egress policy and content-free audit management tools. */
|
|
2
|
+
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
|
|
5
|
+
import type { ToolContext } from "../server";
|
|
6
|
+
|
|
7
|
+
import { projectCollectionEgressPolicy } from "../../core/collection-egress-policy-projection";
|
|
8
|
+
import { CollectionEgressPolicyService } from "../../core/collection-egress-policy-service";
|
|
9
|
+
import { applyConfigChange } from "../../core/config-mutation";
|
|
10
|
+
import { EgressAuditService } from "../../core/egress-audit";
|
|
11
|
+
import { runTool, type ToolResult } from "./index";
|
|
12
|
+
|
|
13
|
+
const policy = z.enum(["local_only", "lan", "remote"]);
|
|
14
|
+
|
|
15
|
+
export const egressPolicyGetInputSchema = z
|
|
16
|
+
.object({
|
|
17
|
+
collection: z.string().min(1).max(64),
|
|
18
|
+
})
|
|
19
|
+
.strict();
|
|
20
|
+
|
|
21
|
+
export const egressPolicySetInputSchema = z
|
|
22
|
+
.object({
|
|
23
|
+
collection: z.string().min(1).max(64),
|
|
24
|
+
policy,
|
|
25
|
+
confirmation: z
|
|
26
|
+
.object({
|
|
27
|
+
collection: z.string().min(1).max(64),
|
|
28
|
+
currentPolicy: policy,
|
|
29
|
+
currentRevision: z.number().int().nonnegative(),
|
|
30
|
+
targetPolicy: policy,
|
|
31
|
+
acknowledged: z.literal(true),
|
|
32
|
+
})
|
|
33
|
+
.strict()
|
|
34
|
+
.optional(),
|
|
35
|
+
})
|
|
36
|
+
.strict();
|
|
37
|
+
|
|
38
|
+
export const egressCheckInputSchema = z
|
|
39
|
+
.object({
|
|
40
|
+
collections: z.array(z.string().min(1).max(64)).min(1).max(64).optional(),
|
|
41
|
+
action: z.enum([
|
|
42
|
+
"retrieve",
|
|
43
|
+
"serve",
|
|
44
|
+
"publish",
|
|
45
|
+
"remote_inference",
|
|
46
|
+
"export",
|
|
47
|
+
"clip_write",
|
|
48
|
+
]),
|
|
49
|
+
destinationZone: z.enum(["local_process", "loopback", "lan", "remote"]),
|
|
50
|
+
caller: z
|
|
51
|
+
.object({
|
|
52
|
+
authenticated: z.boolean(),
|
|
53
|
+
operationAuthorized: z.boolean(),
|
|
54
|
+
})
|
|
55
|
+
.strict(),
|
|
56
|
+
contentClass: z.enum([
|
|
57
|
+
"source",
|
|
58
|
+
"snippet",
|
|
59
|
+
"metadata",
|
|
60
|
+
"attachment",
|
|
61
|
+
"embedding",
|
|
62
|
+
"capsule",
|
|
63
|
+
"audit_log",
|
|
64
|
+
"retrieval_trace",
|
|
65
|
+
]),
|
|
66
|
+
partialResults: z.enum(["deny", "explicit"]).default("deny"),
|
|
67
|
+
})
|
|
68
|
+
.strict();
|
|
69
|
+
|
|
70
|
+
export const egressAuditListInputSchema = z
|
|
71
|
+
.object({
|
|
72
|
+
limit: z.number().int().min(1).max(1000).default(100),
|
|
73
|
+
cursor: z.string().min(1).max(512).optional(),
|
|
74
|
+
})
|
|
75
|
+
.strict();
|
|
76
|
+
|
|
77
|
+
export const egressAuditIdInputSchema = z
|
|
78
|
+
.object({
|
|
79
|
+
auditId: z.string().min(1).max(128),
|
|
80
|
+
})
|
|
81
|
+
.strict();
|
|
82
|
+
|
|
83
|
+
export const egressAuditStatusInputSchema = z.object({}).strict();
|
|
84
|
+
|
|
85
|
+
export const egressAuditPurgeInputSchema = z
|
|
86
|
+
.object({
|
|
87
|
+
confirm: z.literal(true),
|
|
88
|
+
})
|
|
89
|
+
.strict();
|
|
90
|
+
|
|
91
|
+
const json = (value: unknown): string => JSON.stringify(value, null, 2);
|
|
92
|
+
|
|
93
|
+
const unwrap = <T>(
|
|
94
|
+
result:
|
|
95
|
+
| { ok: true; value: T }
|
|
96
|
+
| { ok: false; error: { code: string; message: string } }
|
|
97
|
+
): T => {
|
|
98
|
+
if (result.ok) return result.value;
|
|
99
|
+
throw new Error(`${result.error.code}: ${result.error.message}`);
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const requireWrite = (ctx: ToolContext): void => {
|
|
103
|
+
if (!ctx.enableWrite) {
|
|
104
|
+
throw new Error(
|
|
105
|
+
"WRITE_DISABLED: Egress policy and audit mutations require gateway.enableWrite or --mcp-enable-write"
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
export const handleEgressPolicyGet = (
|
|
111
|
+
args: z.infer<typeof egressPolicyGetInputSchema>,
|
|
112
|
+
ctx: ToolContext
|
|
113
|
+
): Promise<ToolResult> =>
|
|
114
|
+
runTool(
|
|
115
|
+
ctx,
|
|
116
|
+
"gno_egress_policy_get",
|
|
117
|
+
async () => {
|
|
118
|
+
const state = new CollectionEgressPolicyService({
|
|
119
|
+
getConfig: () => ctx.config,
|
|
120
|
+
}).get(args.collection);
|
|
121
|
+
if (!state.ok) throw new Error(`${state.code}: ${state.error}`);
|
|
122
|
+
return state.value;
|
|
123
|
+
},
|
|
124
|
+
json
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
export const handleEgressPolicySet = (
|
|
128
|
+
args: z.infer<typeof egressPolicySetInputSchema>,
|
|
129
|
+
ctx: ToolContext
|
|
130
|
+
): Promise<ToolResult> =>
|
|
131
|
+
runTool(
|
|
132
|
+
ctx,
|
|
133
|
+
"gno_egress_policy_set",
|
|
134
|
+
async () => {
|
|
135
|
+
requireWrite(ctx);
|
|
136
|
+
const service = new CollectionEgressPolicyService({
|
|
137
|
+
getConfig: () => ctx.config,
|
|
138
|
+
mutateConfig: (mutate) =>
|
|
139
|
+
applyConfigChange(
|
|
140
|
+
{
|
|
141
|
+
store: ctx.store,
|
|
142
|
+
configPath: ctx.actualConfigPath,
|
|
143
|
+
onConfigUpdated: (config) => {
|
|
144
|
+
ctx.config = config;
|
|
145
|
+
},
|
|
146
|
+
projectStore: (store, config) =>
|
|
147
|
+
projectCollectionEgressPolicy(store, config, args.collection),
|
|
148
|
+
},
|
|
149
|
+
mutate
|
|
150
|
+
),
|
|
151
|
+
onPolicyChanged: async () =>
|
|
152
|
+
(await ctx.invalidateEgressPolicy?.()) ?? {
|
|
153
|
+
policyEpoch: "egress-epoch-standalone",
|
|
154
|
+
queuedJobsInvalidated: 0,
|
|
155
|
+
sessionsInvalidated: 0,
|
|
156
|
+
staleWorkMustRetry: true,
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
const result = await service.set(args);
|
|
160
|
+
if (!result.ok) throw new Error(`${result.code}: ${result.error}`);
|
|
161
|
+
const epoch = result.value.invalidation?.policyEpoch;
|
|
162
|
+
if (epoch) ctx.advanceRequestAuthorizationEpoch?.(epoch);
|
|
163
|
+
return result.value;
|
|
164
|
+
},
|
|
165
|
+
json
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
export const handleEgressCheck = (
|
|
169
|
+
args: z.infer<typeof egressCheckInputSchema>,
|
|
170
|
+
ctx: ToolContext
|
|
171
|
+
): Promise<ToolResult> =>
|
|
172
|
+
runTool(
|
|
173
|
+
ctx,
|
|
174
|
+
"gno_egress_check",
|
|
175
|
+
async () => {
|
|
176
|
+
const result = new CollectionEgressPolicyService({
|
|
177
|
+
getConfig: () => ctx.config,
|
|
178
|
+
}).explain(args);
|
|
179
|
+
if (!result.ok) throw new Error(`${result.code}: ${result.error}`);
|
|
180
|
+
return result.value;
|
|
181
|
+
},
|
|
182
|
+
json
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
export const handleEgressAuditList = (
|
|
186
|
+
args: z.infer<typeof egressAuditListInputSchema>,
|
|
187
|
+
ctx: ToolContext
|
|
188
|
+
): Promise<ToolResult> =>
|
|
189
|
+
runTool(
|
|
190
|
+
ctx,
|
|
191
|
+
"gno_egress_audit_list",
|
|
192
|
+
async () => unwrap(await new EgressAuditService(ctx.store).list(args)),
|
|
193
|
+
json
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
export const handleEgressAuditShow = (
|
|
197
|
+
args: z.infer<typeof egressAuditIdInputSchema>,
|
|
198
|
+
ctx: ToolContext
|
|
199
|
+
): Promise<ToolResult> =>
|
|
200
|
+
runTool(
|
|
201
|
+
ctx,
|
|
202
|
+
"gno_egress_audit_show",
|
|
203
|
+
async () =>
|
|
204
|
+
unwrap(await new EgressAuditService(ctx.store).show(args.auditId)),
|
|
205
|
+
json
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
export const handleEgressAuditStatus = (
|
|
209
|
+
_args: z.infer<typeof egressAuditStatusInputSchema>,
|
|
210
|
+
ctx: ToolContext
|
|
211
|
+
): Promise<ToolResult> =>
|
|
212
|
+
runTool(
|
|
213
|
+
ctx,
|
|
214
|
+
"gno_egress_audit_status",
|
|
215
|
+
async () => unwrap(await new EgressAuditService(ctx.store).status()),
|
|
216
|
+
json
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
export const handleEgressAuditDelete = (
|
|
220
|
+
args: z.infer<typeof egressAuditIdInputSchema>,
|
|
221
|
+
ctx: ToolContext
|
|
222
|
+
): Promise<ToolResult> =>
|
|
223
|
+
runTool(
|
|
224
|
+
ctx,
|
|
225
|
+
"gno_egress_audit_delete",
|
|
226
|
+
async () => {
|
|
227
|
+
requireWrite(ctx);
|
|
228
|
+
return unwrap(
|
|
229
|
+
await new EgressAuditService(ctx.store).delete(args.auditId)
|
|
230
|
+
);
|
|
231
|
+
},
|
|
232
|
+
json
|
|
233
|
+
);
|
|
234
|
+
|
|
235
|
+
export const handleEgressAuditPurge = (
|
|
236
|
+
_args: z.infer<typeof egressAuditPurgeInputSchema>,
|
|
237
|
+
ctx: ToolContext
|
|
238
|
+
): Promise<ToolResult> =>
|
|
239
|
+
runTool(
|
|
240
|
+
ctx,
|
|
241
|
+
"gno_egress_audit_purge",
|
|
242
|
+
async () => {
|
|
243
|
+
requireWrite(ctx);
|
|
244
|
+
return unwrap(await new EgressAuditService(ctx.store).purge());
|
|
245
|
+
},
|
|
246
|
+
json
|
|
247
|
+
);
|
package/src/mcp/tools/embed.ts
CHANGED
|
@@ -87,6 +87,7 @@ export function handleEmbed(
|
|
|
87
87
|
// Create LLM adapter with offline policy (fail-fast, no download)
|
|
88
88
|
const llm = new LlmAdapter(ctx.config);
|
|
89
89
|
const embedResult = await llm.createEmbeddingPort(modelUri, {
|
|
90
|
+
egressCollections: collection ? [collection.name] : "all",
|
|
90
91
|
policy: { offline: true, allowDownload: false },
|
|
91
92
|
});
|
|
92
93
|
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
createVectorIndexPort,
|
|
24
24
|
createVectorStatsPort,
|
|
25
25
|
} from "../../store/vector";
|
|
26
|
+
import { enforceSyncCommandEgress } from "../sync-egress";
|
|
26
27
|
import { runTool, type ToolResult } from "./index";
|
|
27
28
|
|
|
28
29
|
interface IndexInput {
|
|
@@ -107,6 +108,11 @@ export function handleIndex(
|
|
|
107
108
|
},
|
|
108
109
|
ctx.config
|
|
109
110
|
);
|
|
111
|
+
enforceSyncCommandEgress(ctx, {
|
|
112
|
+
collectionNames: collections,
|
|
113
|
+
gitPull: options.gitPull,
|
|
114
|
+
runUpdateCmd: options.runUpdateCmd,
|
|
115
|
+
});
|
|
110
116
|
|
|
111
117
|
const modelUri = resolveModelUri(
|
|
112
118
|
ctx.config,
|
|
@@ -144,6 +150,7 @@ export function handleIndex(
|
|
|
144
150
|
// Phase 2: Embed
|
|
145
151
|
const llm = new LlmAdapter(ctx.config);
|
|
146
152
|
const embedResult = await llm.createEmbeddingPort(modelUri, {
|
|
153
|
+
egressCollections: collections,
|
|
147
154
|
policy: { offline: true, allowDownload: false },
|
|
148
155
|
});
|
|
149
156
|
|
package/src/mcp/tools/index.ts
CHANGED
|
@@ -31,6 +31,23 @@ import {
|
|
|
31
31
|
} from "./changes";
|
|
32
32
|
import { handleClearCollectionEmbeddings } from "./clear-collection-embeddings";
|
|
33
33
|
import { handleContext, handleContextVerify } from "./context";
|
|
34
|
+
import {
|
|
35
|
+
egressAuditIdInputSchema,
|
|
36
|
+
egressAuditListInputSchema,
|
|
37
|
+
egressAuditPurgeInputSchema,
|
|
38
|
+
egressAuditStatusInputSchema,
|
|
39
|
+
egressCheckInputSchema,
|
|
40
|
+
egressPolicyGetInputSchema,
|
|
41
|
+
egressPolicySetInputSchema,
|
|
42
|
+
handleEgressAuditDelete,
|
|
43
|
+
handleEgressAuditList,
|
|
44
|
+
handleEgressAuditPurge,
|
|
45
|
+
handleEgressAuditShow,
|
|
46
|
+
handleEgressAuditStatus,
|
|
47
|
+
handleEgressCheck,
|
|
48
|
+
handleEgressPolicyGet,
|
|
49
|
+
handleEgressPolicySet,
|
|
50
|
+
} from "./egress";
|
|
34
51
|
import { handleEmbed } from "./embed";
|
|
35
52
|
import { handleGet } from "./get";
|
|
36
53
|
import { handleIndex } from "./index-cmd";
|
|
@@ -125,6 +142,9 @@ export const MCP_WRITE_TOOL_NAMES = new Set([
|
|
|
125
142
|
"gno_trace_export",
|
|
126
143
|
"gno_trace_delete",
|
|
127
144
|
"gno_trace_purge",
|
|
145
|
+
"gno_egress_policy_set",
|
|
146
|
+
"gno_egress_audit_delete",
|
|
147
|
+
"gno_egress_audit_purge",
|
|
128
148
|
]);
|
|
129
149
|
|
|
130
150
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -1059,6 +1079,54 @@ export function registerTools(server: McpServer, ctx: ToolContext): void {
|
|
|
1059
1079
|
(args) => handleStatus(args, ctx)
|
|
1060
1080
|
);
|
|
1061
1081
|
|
|
1082
|
+
server.registerTool(
|
|
1083
|
+
"gno_egress_policy_get",
|
|
1084
|
+
{
|
|
1085
|
+
description:
|
|
1086
|
+
"Show one collection's configured and effective egress policy, provenance source, and confirmation-bound version.",
|
|
1087
|
+
inputSchema: egressPolicyGetInputSchema,
|
|
1088
|
+
},
|
|
1089
|
+
(args) => handleEgressPolicyGet(args, ctx)
|
|
1090
|
+
);
|
|
1091
|
+
|
|
1092
|
+
server.registerTool(
|
|
1093
|
+
"gno_egress_check",
|
|
1094
|
+
{
|
|
1095
|
+
description:
|
|
1096
|
+
"Check or explain an exact action, destination, caller, content class, and collection scope without performing the action.",
|
|
1097
|
+
inputSchema: egressCheckInputSchema,
|
|
1098
|
+
},
|
|
1099
|
+
(args) => handleEgressCheck(args, ctx)
|
|
1100
|
+
);
|
|
1101
|
+
|
|
1102
|
+
server.registerTool(
|
|
1103
|
+
"gno_egress_audit_list",
|
|
1104
|
+
{
|
|
1105
|
+
description:
|
|
1106
|
+
"List content-free local egress decisions newest-first through an opaque cursor.",
|
|
1107
|
+
inputSchema: egressAuditListInputSchema,
|
|
1108
|
+
},
|
|
1109
|
+
(args) => handleEgressAuditList(args, ctx)
|
|
1110
|
+
);
|
|
1111
|
+
|
|
1112
|
+
server.registerTool(
|
|
1113
|
+
"gno_egress_audit_show",
|
|
1114
|
+
{
|
|
1115
|
+
description: "Inspect one content-free local egress decision receipt.",
|
|
1116
|
+
inputSchema: egressAuditIdInputSchema,
|
|
1117
|
+
},
|
|
1118
|
+
(args) => handleEgressAuditShow(args, ctx)
|
|
1119
|
+
);
|
|
1120
|
+
|
|
1121
|
+
server.registerTool(
|
|
1122
|
+
"gno_egress_audit_status",
|
|
1123
|
+
{
|
|
1124
|
+
description: "Show local egress audit retention and storage status.",
|
|
1125
|
+
inputSchema: egressAuditStatusInputSchema,
|
|
1126
|
+
},
|
|
1127
|
+
(args) => handleEgressAuditStatus(args, ctx)
|
|
1128
|
+
);
|
|
1129
|
+
|
|
1062
1130
|
server.tool(
|
|
1063
1131
|
"gno_changes",
|
|
1064
1132
|
"List retained metadata-only document changes with opaque cursor pagination and retention disclosure.",
|
|
@@ -1151,6 +1219,36 @@ export function registerTools(server: McpServer, ctx: ToolContext): void {
|
|
|
1151
1219
|
);
|
|
1152
1220
|
|
|
1153
1221
|
if (ctx.enableWrite) {
|
|
1222
|
+
server.registerTool(
|
|
1223
|
+
"gno_egress_policy_set",
|
|
1224
|
+
{
|
|
1225
|
+
description:
|
|
1226
|
+
"Set one collection policy. Relaxation requires confirmation bound to the current policy and version.",
|
|
1227
|
+
inputSchema: egressPolicySetInputSchema,
|
|
1228
|
+
},
|
|
1229
|
+
(args) => handleEgressPolicySet(args, ctx)
|
|
1230
|
+
);
|
|
1231
|
+
|
|
1232
|
+
server.registerTool(
|
|
1233
|
+
"gno_egress_audit_delete",
|
|
1234
|
+
{
|
|
1235
|
+
description:
|
|
1236
|
+
"Delete exactly one local egress audit receipt with physical cleanup status.",
|
|
1237
|
+
inputSchema: egressAuditIdInputSchema,
|
|
1238
|
+
},
|
|
1239
|
+
(args) => handleEgressAuditDelete(args, ctx)
|
|
1240
|
+
);
|
|
1241
|
+
|
|
1242
|
+
server.registerTool(
|
|
1243
|
+
"gno_egress_audit_purge",
|
|
1244
|
+
{
|
|
1245
|
+
description:
|
|
1246
|
+
"Purge local egress audit receipts only. Requires confirm=true.",
|
|
1247
|
+
inputSchema: egressAuditPurgeInputSchema,
|
|
1248
|
+
},
|
|
1249
|
+
(args) => handleEgressAuditPurge(args, ctx)
|
|
1250
|
+
);
|
|
1251
|
+
|
|
1154
1252
|
server.tool(
|
|
1155
1253
|
"gno_trace_label",
|
|
1156
1254
|
"Append an explicit relevant, irrelevant, or missing_expected judgment to a local retrieval trace.",
|
package/src/mcp/tools/query.ts
CHANGED
|
@@ -279,6 +279,9 @@ export function handleQuery(
|
|
|
279
279
|
if (!traceStart.ok) throw new Error(traceStart.error.message);
|
|
280
280
|
traceSession = traceStart.value ?? undefined;
|
|
281
281
|
const llm = new LlmAdapter(ctx.config);
|
|
282
|
+
const egressCollections = args.collection
|
|
283
|
+
? [args.collection]
|
|
284
|
+
: ("all" as const);
|
|
282
285
|
|
|
283
286
|
// Resolve download policy from env (MCP has no CLI flags)
|
|
284
287
|
const policy = resolveDownloadPolicy(process.env, {});
|
|
@@ -288,6 +291,7 @@ export function handleQuery(
|
|
|
288
291
|
|
|
289
292
|
// Create embedding port (for vector search) - optional
|
|
290
293
|
const embedResult = await llm.createEmbeddingPort(embedUri, {
|
|
294
|
+
egressCollections,
|
|
291
295
|
policy,
|
|
292
296
|
onProgress: (progress) => downloadProgress("embed", progress),
|
|
293
297
|
});
|
|
@@ -298,6 +302,7 @@ export function handleQuery(
|
|
|
298
302
|
// Create expansion port - optional
|
|
299
303
|
if (expandUri) {
|
|
300
304
|
const genResult = await llm.createExpansionPort(expandUri, {
|
|
305
|
+
egressCollections,
|
|
301
306
|
policy,
|
|
302
307
|
onProgress: (progress) => downloadProgress("expand", progress),
|
|
303
308
|
});
|
|
@@ -309,6 +314,7 @@ export function handleQuery(
|
|
|
309
314
|
// Create rerank port - optional
|
|
310
315
|
if (rerankUri) {
|
|
311
316
|
const rerankResult = await llm.createRerankPort(rerankUri, {
|
|
317
|
+
egressCollections,
|
|
312
318
|
policy,
|
|
313
319
|
onProgress: (progress) => downloadProgress("rerank", progress),
|
|
314
320
|
});
|
|
@@ -425,6 +431,7 @@ export function handleQueryDiagnose(
|
|
|
425
431
|
const llm = new LlmAdapter(ctx.config);
|
|
426
432
|
const policy = resolveDownloadPolicy(process.env, {});
|
|
427
433
|
const downloadProgress = createNonTtyProgressRenderer();
|
|
434
|
+
const egressCollections = collection ? [collection] : ("all" as const);
|
|
428
435
|
|
|
429
436
|
let embedPort: EmbeddingPort | null = null;
|
|
430
437
|
let expandPort: GenerationPort | null = null;
|
|
@@ -456,6 +463,7 @@ export function handleQueryDiagnose(
|
|
|
456
463
|
|
|
457
464
|
if (!args.fast) {
|
|
458
465
|
const embedResult = await llm.createEmbeddingPort(embedUri, {
|
|
466
|
+
egressCollections,
|
|
459
467
|
policy,
|
|
460
468
|
onProgress: (progress) => downloadProgress("embed", progress),
|
|
461
469
|
});
|
|
@@ -468,6 +476,7 @@ export function handleQueryDiagnose(
|
|
|
468
476
|
const genResult = await llm.createExpansionPort(
|
|
469
477
|
resolveModelUri(ctx.config, "expand", undefined, collection),
|
|
470
478
|
{
|
|
479
|
+
egressCollections,
|
|
471
480
|
policy,
|
|
472
481
|
onProgress: (progress) => downloadProgress("expand", progress),
|
|
473
482
|
}
|
|
@@ -481,6 +490,7 @@ export function handleQueryDiagnose(
|
|
|
481
490
|
const rerankResult = await llm.createRerankPort(
|
|
482
491
|
resolveModelUri(ctx.config, "rerank", undefined, collection),
|
|
483
492
|
{
|
|
493
|
+
egressCollections,
|
|
484
494
|
policy,
|
|
485
495
|
onProgress: (progress) => downloadProgress("rerank", progress),
|
|
486
496
|
}
|
|
@@ -89,6 +89,10 @@ export function handleRemoveCollection(
|
|
|
89
89
|
if (!mutationResult.ok) {
|
|
90
90
|
throw mapConfigError(mutationResult.code, mutationResult.error);
|
|
91
91
|
}
|
|
92
|
+
const invalidation = await ctx.invalidateEgressPolicy?.();
|
|
93
|
+
if (invalidation) {
|
|
94
|
+
ctx.advanceRequestAuthorizationEpoch?.(invalidation.policyEpoch);
|
|
95
|
+
}
|
|
92
96
|
ctx.markContentMutation?.();
|
|
93
97
|
ctx.markIndexMutation?.();
|
|
94
98
|
|
package/src/mcp/tools/sync.ts
CHANGED
|
@@ -14,6 +14,7 @@ import { JobError } from "../../core/job-manager";
|
|
|
14
14
|
import { recordContentMutation } from "../../core/mutation-generations";
|
|
15
15
|
import { normalizeCollectionName } from "../../core/validation";
|
|
16
16
|
import { defaultSyncService, withContentTypeRules } from "../../ingestion";
|
|
17
|
+
import { enforceSyncCommandEgress } from "../sync-egress";
|
|
17
18
|
import { runTool, type ToolResult } from "./index";
|
|
18
19
|
|
|
19
20
|
interface SyncInput {
|
|
@@ -109,6 +110,11 @@ export function handleSync(
|
|
|
109
110
|
},
|
|
110
111
|
ctx.config
|
|
111
112
|
);
|
|
113
|
+
enforceSyncCommandEgress(ctx, {
|
|
114
|
+
collectionNames: collections,
|
|
115
|
+
gitPull: options.gitPull,
|
|
116
|
+
runUpdateCmd: options.runUpdateCmd,
|
|
117
|
+
});
|
|
112
118
|
|
|
113
119
|
const jobId = await ctx.jobManager.startJobWithLock(
|
|
114
120
|
"sync",
|
package/src/mcp/tools/trace.ts
CHANGED
|
@@ -106,7 +106,13 @@ const runTraceWrite = <T>(
|
|
|
106
106
|
async () => {
|
|
107
107
|
if (!ctx.enableWrite) return writeDisabled();
|
|
108
108
|
return withWriteLock(ctx.writeLockPath, async () =>
|
|
109
|
-
unwrap(
|
|
109
|
+
unwrap(
|
|
110
|
+
await operation(
|
|
111
|
+
new RetrievalTraceManagementService(ctx.store, {
|
|
112
|
+
authorizeExport: ctx.authorizeTraceExport,
|
|
113
|
+
})
|
|
114
|
+
)
|
|
115
|
+
)
|
|
110
116
|
);
|
|
111
117
|
},
|
|
112
118
|
jsonText
|
package/src/mcp/tools/vsearch.ts
CHANGED
|
@@ -180,6 +180,7 @@ export function handleVsearch(
|
|
|
180
180
|
// Create LLM adapter for embeddings
|
|
181
181
|
const llm = new LlmAdapter(ctx.config);
|
|
182
182
|
const embedResult = await llm.createEmbeddingPort(modelUri, {
|
|
183
|
+
egressCollections: args.collection ? [args.collection] : "all",
|
|
183
184
|
policy,
|
|
184
185
|
onProgress: (progress) => downloadProgress("embed", progress),
|
|
185
186
|
});
|