@cyanmycelium/mcp-persistence 0.0.0-stage → 0.1.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 +201 -0
- package/README.md +183 -2
- package/contracts/persistence.v1.json +9606 -0
- package/dist/conformance/persistence.conformance.d.ts +4 -0
- package/dist/conformance/persistence.conformance.js +56 -0
- package/dist/conformance/persistence.conformance.js.map +1 -0
- package/dist/contract/errors.d.ts +5 -0
- package/dist/contract/errors.js +9 -0
- package/dist/contract/errors.js.map +1 -0
- package/dist/contract/persistence.protocol.d.ts +83 -0
- package/dist/contract/persistence.protocol.js +75 -0
- package/dist/contract/persistence.protocol.js.map +1 -0
- package/dist/contract/persistence.store.d.ts +29 -0
- package/dist/contract/persistence.store.js +2 -0
- package/dist/contract/persistence.store.js.map +1 -0
- package/dist/contract/persistence.types.d.ts +115 -0
- package/dist/contract/persistence.types.js +2 -0
- package/dist/contract/persistence.types.js.map +1 -0
- package/dist/contract/validation.d.ts +7 -0
- package/dist/contract/validation.js +43 -0
- package/dist/contract/validation.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/provider/artifact.http.d.ts +8 -0
- package/dist/provider/artifact.http.js +69 -0
- package/dist/provider/artifact.http.js.map +1 -0
- package/dist/provider/main.d.ts +2 -0
- package/dist/provider/main.js +82 -0
- package/dist/provider/main.js.map +1 -0
- package/dist/server/declaration.d.ts +18 -0
- package/dist/server/declaration.js +23 -0
- package/dist/server/declaration.js.map +1 -0
- package/dist/server/persistence.behavior.d.ts +16 -0
- package/dist/server/persistence.behavior.js +173 -0
- package/dist/server/persistence.behavior.js.map +1 -0
- package/dist/server/persistence.slot.store.d.ts +45 -0
- package/dist/server/persistence.slot.store.js +94 -0
- package/dist/server/persistence.slot.store.js.map +1 -0
- package/dist/sqlite/sqlite.persistence.store.d.ts +72 -0
- package/dist/sqlite/sqlite.persistence.store.js +561 -0
- package/dist/sqlite/sqlite.persistence.store.js.map +1 -0
- package/docs/assets/logo.png +0 -0
- package/docs/assets/mcp-broker-family.png +0 -0
- package/docs/mcp-contract.md +189 -0
- package/package.json +81 -6
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServerBuilder } from "@cyanmycelium/mcp-core";
|
|
3
|
+
import { DirectTransport } from "@cyanmycelium/mcp-broker-provider";
|
|
4
|
+
import { BrokerAccessGuard, openGuard } from "@cyanmycelium/mcp-uns";
|
|
5
|
+
import { SqlitePersistenceStore } from "../sqlite/sqlite.persistence.store.js";
|
|
6
|
+
import { PersistenceBehavior } from "../server/persistence.behavior.js";
|
|
7
|
+
import { buildPersistenceDeclaration } from "../server/declaration.js";
|
|
8
|
+
import { createArtifactTransferServer } from "./artifact.http.js";
|
|
9
|
+
import { integer } from "../contract/validation.js";
|
|
10
|
+
async function main() {
|
|
11
|
+
const dev = process.argv.includes("--dev");
|
|
12
|
+
if (process.argv.slice(2).some(arg => arg !== "--dev"))
|
|
13
|
+
throw new Error("Usage: mcp-persistence [--dev]");
|
|
14
|
+
const root = process.env.MCP_PERSISTENCE_RESOURCE_ROOT ?? "/local/persistence";
|
|
15
|
+
const brokerBase = process.env.MCP_PERSISTENCE_BROKER_URL ?? "http://127.0.0.1:3000";
|
|
16
|
+
const brokerUrl = new URL(brokerBase);
|
|
17
|
+
if (!["http:", "https:"].includes(brokerUrl.protocol) || brokerUrl.username || brokerUrl.password || brokerUrl.pathname !== "/" || brokerUrl.search || brokerUrl.hash)
|
|
18
|
+
throw new Error("Broker URL must be an HTTP(S) origin without credentials");
|
|
19
|
+
const loopback = ["127.0.0.1", "localhost", "[::1]"].includes(brokerUrl.hostname);
|
|
20
|
+
const secret = process.env.MCP_PERSISTENCE_PROVIDER_SECRET;
|
|
21
|
+
if (!dev && !secret)
|
|
22
|
+
throw new Error("Production requires MCP_PERSISTENCE_PROVIDER_SECRET; use --dev explicitly for the local open guard");
|
|
23
|
+
if (!dev && brokerUrl.protocol !== "https:" && !loopback)
|
|
24
|
+
throw new Error("Remote production broker requires HTTPS");
|
|
25
|
+
if (dev && (!loopback || brokerUrl.protocol !== "http:"))
|
|
26
|
+
throw new Error("--dev requires a loopback HTTP broker");
|
|
27
|
+
let localBroker;
|
|
28
|
+
let server;
|
|
29
|
+
let store;
|
|
30
|
+
let http;
|
|
31
|
+
try {
|
|
32
|
+
if (dev) {
|
|
33
|
+
const { WsTunnelBuilder } = await import("@cyanmycelium/mcp-broker");
|
|
34
|
+
localBroker = new WsTunnelBuilder().withHost("127.0.0.1").withPort(Number(brokerUrl.port || 80)).build();
|
|
35
|
+
await localBroker.start();
|
|
36
|
+
console.error("[persistence] DEV: openGuard enabled, loopback only, no access policy. Use a separate data root.");
|
|
37
|
+
}
|
|
38
|
+
store = new SqlitePersistenceStore({ directory: process.env.MCP_PERSISTENCE_DATA ?? (dev ? "./data-dev" : "./data"), allowFileSyncOnly: process.env.MCP_PERSISTENCE_ALLOW_FILE_SYNC_ONLY === "1" });
|
|
39
|
+
const ws = new URL("/provider/persistence", brokerUrl);
|
|
40
|
+
ws.protocol = brokerUrl.protocol === "https:" ? "wss:" : "ws:";
|
|
41
|
+
const transport = new DirectTransport(ws.toString(), dev ? { aggregate: true } : { secret });
|
|
42
|
+
const guard = dev ? openGuard() : new BrokerAccessGuard(transport.broker);
|
|
43
|
+
server = new McpServerBuilder().withName("persistence").withTransport(transport).withGrammarResolver(() => `default:${process.env.MCP_PERSISTENCE_LOCALE === "fr" ? "fr" : "en"}`).register(new PersistenceBehavior(store, guard, { namespace: root })).build();
|
|
44
|
+
await server.start();
|
|
45
|
+
if (!dev) {
|
|
46
|
+
const declaration = await transport.broker.declare(buildPersistenceDeclaration({ version: "1", namespace: root }));
|
|
47
|
+
if (!declaration.accepted)
|
|
48
|
+
throw new Error("Broker refused the persistence declaration");
|
|
49
|
+
}
|
|
50
|
+
http = createArtifactTransferServer({ store, brokerMcpUrl: new URL("/persistence/mcp", brokerUrl).toString(), dev });
|
|
51
|
+
const port = integer(Number(process.env.MCP_PERSISTENCE_TRANSFER_PORT ?? 3001), 1, 65535);
|
|
52
|
+
await new Promise((resolve, reject) => { http.once("error", reject); http.listen(port, "127.0.0.1", resolve); });
|
|
53
|
+
console.error(`[persistence] ${dev ? "DEV" : "broker-authorized"} provider started; transfer endpoint on loopback:${port}`);
|
|
54
|
+
let stopping = false;
|
|
55
|
+
const stop = async () => {
|
|
56
|
+
if (stopping)
|
|
57
|
+
return;
|
|
58
|
+
stopping = true;
|
|
59
|
+
try {
|
|
60
|
+
await new Promise(resolve => http.close(() => resolve()));
|
|
61
|
+
await server?.stop?.();
|
|
62
|
+
await store?.closeAsync();
|
|
63
|
+
await localBroker?.stop();
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
console.error("[persistence] Shutdown failed");
|
|
67
|
+
process.exitCode = 1;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
process.once("SIGINT", () => { void stop(); });
|
|
71
|
+
process.once("SIGTERM", () => { void stop(); });
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
http?.close();
|
|
75
|
+
await server?.stop?.();
|
|
76
|
+
await store?.closeAsync();
|
|
77
|
+
await localBroker?.stop();
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
main().catch(error => { console.error(`[persistence] ${error instanceof Error && !error.message.includes("\\") ? error.message : "Startup failed"}`); process.exitCode = 1; });
|
|
82
|
+
//# sourceMappingURL=main.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/provider/main.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare class PersistenceResources {
|
|
2
|
+
readonly root: string;
|
|
3
|
+
constructor(root: string);
|
|
4
|
+
document(namespace: string, id: string): string;
|
|
5
|
+
artifact(namespace: string, id: string): string;
|
|
6
|
+
}
|
|
7
|
+
export declare function buildPersistenceDeclaration(input: {
|
|
8
|
+
version: string;
|
|
9
|
+
namespace: string;
|
|
10
|
+
}): {
|
|
11
|
+
version: string;
|
|
12
|
+
domain: string;
|
|
13
|
+
namespace: {
|
|
14
|
+
resource: string;
|
|
15
|
+
};
|
|
16
|
+
capabilities: string[];
|
|
17
|
+
resultsRequired: string[];
|
|
18
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { segment, text } from "../contract/validation.js";
|
|
2
|
+
export class PersistenceResources {
|
|
3
|
+
root;
|
|
4
|
+
constructor(root) {
|
|
5
|
+
this.root = root;
|
|
6
|
+
if (!root.startsWith("/") || root.split("/").slice(1).some(s => { try {
|
|
7
|
+
segment(s);
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return true;
|
|
12
|
+
} }))
|
|
13
|
+
throw new Error("Invalid broker resource root");
|
|
14
|
+
}
|
|
15
|
+
document(namespace, id) { return `${this.root}/namespaces/${segment(namespace)}/documents/${segment(id)}`; }
|
|
16
|
+
artifact(namespace, id) { return `${this.root}/namespaces/${segment(namespace)}/artifacts/${segment(id)}`; }
|
|
17
|
+
}
|
|
18
|
+
export function buildPersistenceDeclaration(input) {
|
|
19
|
+
new PersistenceResources(input.namespace);
|
|
20
|
+
text(input.version);
|
|
21
|
+
return { version: input.version, domain: "persistence", namespace: { resource: input.namespace }, capabilities: ["persistence.read", "persistence.write", "persistence.delete", "persistence.admin"], resultsRequired: ["persistence.write", "persistence.delete", "persistence.admin"] };
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=declaration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"declaration.js","sourceRoot":"","sources":["../../src/server/declaration.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,2BAA2B,CAAC;AAE1D,MAAM,OAAO,oBAAoB;IACR;IAArB,YAAqB,IAAY;QAAZ,SAAI,GAAJ,IAAI,CAAQ;QAC7B,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC;YAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YAAC,OAAO,KAAK,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,OAAO,IAAI,CAAC;QAAC,CAAC,CAAC,CAAC,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IACnL,CAAC;IACD,QAAQ,CAAC,SAAiB,EAAE,EAAU,IAAY,OAAO,GAAG,IAAI,CAAC,IAAI,eAAe,OAAO,CAAC,SAAS,CAAC,cAAc,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACpI,QAAQ,CAAC,SAAiB,EAAE,EAAU,IAAY,OAAO,GAAG,IAAI,CAAC,IAAI,eAAe,OAAO,CAAC,SAAS,CAAC,cAAc,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;CACvI;AACD,MAAM,UAAU,2BAA2B,CAAC,KAA6C;IACrF,IAAI,oBAAoB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC/D,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,SAAS,EAAE,EAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,EAAE,EAAE,YAAY,EAAE,CAAC,kBAAkB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,mBAAmB,CAAC,EAAE,eAAe,EAAE,CAAC,mBAAmB,EAAE,oBAAoB,EAAE,mBAAmB,CAAC,EAAE,CAAC;AAC9R,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { McpBehavior, McpGrammar, type McpResource, type McpResourceTemplate, type McpTool } from "@cyanmycelium/mcp-core";
|
|
2
|
+
import type { IAccessGuard } from "@cyanmycelium/mcp-uns";
|
|
3
|
+
import type { IPersistenceStore } from "../contract/persistence.store.js";
|
|
4
|
+
import type { IStoreContext } from "../contract/persistence.types.js";
|
|
5
|
+
/** Broker caller references are request-scoped, not stable user ids. Keys are shared per namespace. */
|
|
6
|
+
export declare const MCP_STORE_CONTEXT: IStoreContext;
|
|
7
|
+
export declare const CAPABILITIES_URI = "persistence://capabilities";
|
|
8
|
+
export declare class PersistenceBehavior extends McpBehavior {
|
|
9
|
+
constructor(store: IPersistenceStore, guard: IAccessGuard, options: {
|
|
10
|
+
namespace: string;
|
|
11
|
+
});
|
|
12
|
+
protected _buildResources(): McpResource[];
|
|
13
|
+
protected _buildTemplate(): McpResourceTemplate[];
|
|
14
|
+
protected _buildGrammars(): Map<string, McpGrammar>;
|
|
15
|
+
protected _buildTools(): McpTool[];
|
|
16
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { McpAdapterBase, McpBehavior, McpGrammar } from "@cyanmycelium/mcp-core";
|
|
2
|
+
import { PersistenceError } from "../contract/errors.js";
|
|
3
|
+
import { fail, segment } from "../contract/validation.js";
|
|
4
|
+
import { PersistenceResources } from "./declaration.js";
|
|
5
|
+
import { PERSISTENCE_TOOLS, PERSISTENCE_RESOURCE_TEMPLATES, PERSISTENCE_TOOL_DESCRIPTIONS as EN } from "../contract/persistence.protocol.js";
|
|
6
|
+
/** Broker caller references are request-scoped, not stable user ids. Keys are shared per namespace. */
|
|
7
|
+
export const MCP_STORE_CONTEXT = Object.freeze({ subject: "broker-namespace" });
|
|
8
|
+
export const CAPABILITIES_URI = "persistence://capabilities";
|
|
9
|
+
const FR = {
|
|
10
|
+
capabilities: "Lire les limites du protocole et les garanties de durabilité.",
|
|
11
|
+
get: "Lire la tête d'un document ou une révision immuable.", put: "Créer ou modifier avec expectedRevision et une clé d'idempotence.",
|
|
12
|
+
list: "Lister les documents autorisés avec pagination bornée.", listRevisions: "Lister les révisions immuables d'un document autorisé.",
|
|
13
|
+
delete: "Ajouter une suppression logique en conservant l'historique et les fichiers.", purge: "Purger définitivement une révision ou un artefact sans référence après rétention.",
|
|
14
|
+
beginArtifact: "Réserver un transfert. Les octets passent par le point HTTP authentifié.",
|
|
15
|
+
commitArtifact: "Vérifier et publier atomiquement un transfert terminé.", abortArtifact: "Annuler un transfert inactif.",
|
|
16
|
+
getArtifact: "Lire les métadonnées ; les octets passent par le point HTTP authentifié.",
|
|
17
|
+
uploadAccess: "Autoriser un flux de transfert et lire ses métadonnées cibles.",
|
|
18
|
+
};
|
|
19
|
+
class PersistenceAdapter extends McpAdapterBase {
|
|
20
|
+
store;
|
|
21
|
+
guard;
|
|
22
|
+
paths;
|
|
23
|
+
constructor(store, guard, root) {
|
|
24
|
+
super("persistence");
|
|
25
|
+
this.store = store;
|
|
26
|
+
this.guard = guard;
|
|
27
|
+
this.paths = new PersistenceResources(root);
|
|
28
|
+
}
|
|
29
|
+
check(capability, kind, key) {
|
|
30
|
+
return { capability: `persistence.${capability}`, resource: `persistence:${kind}:${segment(key.namespace)}/${segment(key.id)}`, resourcePath: this.paths[kind](key.namespace, key.id) };
|
|
31
|
+
}
|
|
32
|
+
async decisions(checks, request) {
|
|
33
|
+
const decisions = await this.guard.authorizeAsync(checks, request);
|
|
34
|
+
if (decisions.length !== checks.length)
|
|
35
|
+
fail("policy_denied", "No complete authorization decision");
|
|
36
|
+
return decisions;
|
|
37
|
+
}
|
|
38
|
+
async allowed(checks, request) {
|
|
39
|
+
const decisions = await this.decisions(checks, request);
|
|
40
|
+
if (decisions.some(d => !d.allowed || d.constraints)) {
|
|
41
|
+
for (const d of decisions)
|
|
42
|
+
if (d.allowed)
|
|
43
|
+
this.guard.report(d, "refused", "policy_denied");
|
|
44
|
+
fail("policy_denied", "Access refused");
|
|
45
|
+
}
|
|
46
|
+
return decisions;
|
|
47
|
+
}
|
|
48
|
+
async mutation(checks, request, action) {
|
|
49
|
+
const decisions = await this.allowed(checks, request);
|
|
50
|
+
try {
|
|
51
|
+
const result = await action();
|
|
52
|
+
for (const d of decisions)
|
|
53
|
+
this.guard.report(d, "success");
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
for (const d of decisions)
|
|
58
|
+
this.guard.report(d, "failure", error instanceof PersistenceError ? error.code : "store_unavailable");
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
async upload(args, request) {
|
|
63
|
+
const namespace = segment(args.namespace), uploadId = segment(args.uploadId);
|
|
64
|
+
let upload;
|
|
65
|
+
try {
|
|
66
|
+
upload = await this.store.inspectUploadAsync(namespace, uploadId, MCP_STORE_CONTEXT);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
await this.allowed([this.check("write", "artifact", { namespace, id: "_new" })], request);
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
return upload;
|
|
73
|
+
}
|
|
74
|
+
async invoke(name, args, request) {
|
|
75
|
+
if (name === "capabilities")
|
|
76
|
+
return this.store.getCapabilitiesAsync();
|
|
77
|
+
const namespace = segment(args.namespace);
|
|
78
|
+
const context = MCP_STORE_CONTEXT;
|
|
79
|
+
switch (name) {
|
|
80
|
+
case "list": {
|
|
81
|
+
const page = await this.store.listAsync(args, context);
|
|
82
|
+
const decisions = await this.decisions(page.items.map(d => this.check("read", "document", d)), request);
|
|
83
|
+
return { ...page, items: page.items.filter((_, i) => decisions[i]?.allowed && !decisions[i]?.constraints) };
|
|
84
|
+
}
|
|
85
|
+
case "get":
|
|
86
|
+
case "listRevisions": {
|
|
87
|
+
const key = { namespace, id: segment(args.id) };
|
|
88
|
+
await this.allowed([this.check("read", "document", key)], request);
|
|
89
|
+
return name === "get" ? this.store.getAsync(args, context)
|
|
90
|
+
: this.store.listRevisionsAsync(args, context);
|
|
91
|
+
}
|
|
92
|
+
case "put": {
|
|
93
|
+
const input = args;
|
|
94
|
+
if (!Array.isArray(input.references))
|
|
95
|
+
fail("invalid_request", "Expected references array");
|
|
96
|
+
const checks = [this.check("write", "document", { namespace, id: segment(args.id) })];
|
|
97
|
+
const caps = await this.store.getCapabilitiesAsync();
|
|
98
|
+
if (input.references.length > caps.limits.maxReferences)
|
|
99
|
+
fail("invalid_request", "Too many references");
|
|
100
|
+
for (const ref of input.references) {
|
|
101
|
+
if (!ref || (ref.type !== "document" && ref.type !== "artifact"))
|
|
102
|
+
fail("invalid_request", "Invalid reference");
|
|
103
|
+
checks.push(this.check("read", ref.type, ref));
|
|
104
|
+
}
|
|
105
|
+
return this.mutation(checks, request, () => this.store.putAsync(input, context));
|
|
106
|
+
}
|
|
107
|
+
case "delete": return this.mutation([this.check("delete", "document", { namespace, id: segment(args.id) })], request, () => this.store.deleteAsync(args, context));
|
|
108
|
+
case "purge": {
|
|
109
|
+
const input = args;
|
|
110
|
+
if (!input.target || (input.target.type !== "document" && input.target.type !== "artifact"))
|
|
111
|
+
fail("invalid_request", "Invalid purge target");
|
|
112
|
+
return this.mutation([this.check("admin", input.target.type, { namespace, id: segment(input.target.id) })], request, () => this.store.purgeAsync(input, context));
|
|
113
|
+
}
|
|
114
|
+
case "beginArtifact": return this.mutation([this.check("write", "artifact", { namespace, id: "_new" })], request, () => this.store.beginArtifactAsync(args, context));
|
|
115
|
+
case "uploadAccess":
|
|
116
|
+
case "commitArtifact":
|
|
117
|
+
case "abortArtifact": {
|
|
118
|
+
const upload = await this.upload(args, request);
|
|
119
|
+
const checks = [this.check("write", "artifact", { namespace, id: upload.artifactId })];
|
|
120
|
+
if (name === "uploadAccess")
|
|
121
|
+
return this.mutation(checks, request, async () => upload);
|
|
122
|
+
return this.mutation(checks, request, () => name === "commitArtifact"
|
|
123
|
+
? this.store.commitArtifactAsync(args, context) : this.store.abortArtifactAsync(args, context));
|
|
124
|
+
}
|
|
125
|
+
case "getArtifact": {
|
|
126
|
+
const key = { namespace, id: segment(args.id) };
|
|
127
|
+
await this.allowed([this.check("read", "artifact", key)], request);
|
|
128
|
+
return this.store.getArtifactAsync(key, context);
|
|
129
|
+
}
|
|
130
|
+
default: fail("invalid_request", "Unknown persistence tool");
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
async executeToolAsync(_uri, tool, args, request) {
|
|
134
|
+
try {
|
|
135
|
+
const definition = PERSISTENCE_TOOLS.find(t => t.name === tool);
|
|
136
|
+
if (!definition)
|
|
137
|
+
fail("invalid_request", "Unknown persistence tool");
|
|
138
|
+
const schema = definition.inputSchema;
|
|
139
|
+
if (Object.keys(args).some(k => !Object.hasOwn(schema.properties, k)) || schema.required.some(k => !Object.hasOwn(args, k)))
|
|
140
|
+
fail("invalid_request", "Unknown or missing tool argument");
|
|
141
|
+
const payload = (await this.invoke(tool.replace(/^persistence\./, ""), args, request)) ?? { ok: true };
|
|
142
|
+
return { content: [{ type: "text", text: JSON.stringify(payload) }], structuredContent: payload };
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
const code = error instanceof PersistenceError ? error.code : "store_unavailable";
|
|
146
|
+
const payload = { error: { code, message: error instanceof PersistenceError ? error.message : "Persistence operation failed" } };
|
|
147
|
+
return { isError: true, content: [{ type: "text", text: JSON.stringify(payload) }], structuredContent: payload };
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
async readResourceAsync(uri, request) {
|
|
151
|
+
if (uri === CAPABILITIES_URI)
|
|
152
|
+
return { uri, mimeType: "application/json", text: JSON.stringify(await this.store.getCapabilitiesAsync()) };
|
|
153
|
+
const match = /^persistence:\/\/(documents|artifacts)\/([^/]+)\/([^/]+)(?:\/revisions\/(\d+))?$/.exec(uri);
|
|
154
|
+
if (!match || (match[1] === "artifacts" && match[4]))
|
|
155
|
+
return undefined;
|
|
156
|
+
const args = { namespace: decodeURIComponent(match[2]), id: decodeURIComponent(match[3]), ...(match[4] ? { revision: Number(match[4]) } : {}) };
|
|
157
|
+
return { uri, mimeType: "application/json", text: JSON.stringify(await this.invoke(match[1] === "documents" ? "get" : "getArtifact", args, request)) };
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
export class PersistenceBehavior extends McpBehavior {
|
|
161
|
+
constructor(store, guard, options) { super(new PersistenceAdapter(store, guard, options.namespace), { namespace: "persistence" }); }
|
|
162
|
+
_buildResources() { return [{ uri: CAPABILITIES_URI, name: "Persistence capabilities", mimeType: "application/json", description: EN.capabilities }]; }
|
|
163
|
+
_buildTemplate() {
|
|
164
|
+
return structuredClone(PERSISTENCE_RESOURCE_TEMPLATES);
|
|
165
|
+
}
|
|
166
|
+
_buildGrammars() {
|
|
167
|
+
return new Map([["default:en", EN], ["default:fr", FR]].map(([key, descriptions]) => [key, McpGrammar.fromJSON({ tools: Object.fromEntries(Object.entries(descriptions).map(([name, description]) => [`persistence.${name}`, { description }])) })]));
|
|
168
|
+
}
|
|
169
|
+
_buildTools() {
|
|
170
|
+
return structuredClone(PERSISTENCE_TOOLS);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=persistence.behavior.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persistence.behavior.js","sourceRoot":"","sources":["../../src/server/persistence.behavior.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { IPersistenceStore } from "../contract/persistence.store.js";
|
|
2
|
+
import type { IArtifact, IBeginArtifact, IDeleteDocument, IDocument, IDocumentKey, IFinishArtifact, IListDocuments, IPage, IPageRequest, IPersistenceCapabilities, IPurge, IPutDocument, IStoreContext, IUpload } from "../contract/persistence.types.js";
|
|
3
|
+
export interface ISlotClient {
|
|
4
|
+
callTool(name: string, args: Record<string, unknown>): Promise<{
|
|
5
|
+
content?: readonly unknown[];
|
|
6
|
+
structuredContent?: unknown;
|
|
7
|
+
isError?: boolean;
|
|
8
|
+
}>;
|
|
9
|
+
}
|
|
10
|
+
export declare function slotPayload(result: Awaited<ReturnType<ISlotClient["callTool"]>>): unknown;
|
|
11
|
+
export interface ITransferClientOptions {
|
|
12
|
+
baseUrl: string;
|
|
13
|
+
/** The same bearer credentials used by the MCP client. Never sent to an arbitrary redirected URL. */
|
|
14
|
+
headers?: () => Record<string, string>;
|
|
15
|
+
}
|
|
16
|
+
export declare class PersistenceSlotStore implements IPersistenceStore {
|
|
17
|
+
readonly id: string;
|
|
18
|
+
private readonly client;
|
|
19
|
+
private readonly transfer?;
|
|
20
|
+
constructor(id: string, client: ISlotClient, transfer?: ITransferClientOptions | undefined);
|
|
21
|
+
private call;
|
|
22
|
+
getCapabilitiesAsync(): Promise<IPersistenceCapabilities>;
|
|
23
|
+
getAsync(r: IDocumentKey & {
|
|
24
|
+
revision?: number;
|
|
25
|
+
}, c: IStoreContext): Promise<IDocument>;
|
|
26
|
+
putAsync(r: IPutDocument, c: IStoreContext): Promise<IDocument>;
|
|
27
|
+
listAsync(r: IListDocuments, c: IStoreContext): Promise<IPage<IDocument>>;
|
|
28
|
+
listRevisionsAsync(r: IDocumentKey & IPageRequest, c: IStoreContext): Promise<IPage<IDocument>>;
|
|
29
|
+
deleteAsync(r: IDeleteDocument, c: IStoreContext): Promise<IDocument>;
|
|
30
|
+
purgeAsync(r: IPurge, c: IStoreContext): Promise<void>;
|
|
31
|
+
beginArtifactAsync(r: IBeginArtifact, c: IStoreContext): Promise<IUpload>;
|
|
32
|
+
inspectUploadAsync(namespace: string, uploadId: string, c: IStoreContext): Promise<IUpload>;
|
|
33
|
+
commitArtifactAsync(r: IFinishArtifact, c: IStoreContext): Promise<IArtifact>;
|
|
34
|
+
abortArtifactAsync(r: IFinishArtifact, c: IStoreContext): Promise<void>;
|
|
35
|
+
getArtifactAsync(r: IDocumentKey, c: IStoreContext): Promise<IArtifact>;
|
|
36
|
+
private response;
|
|
37
|
+
writeArtifactAsync(r: {
|
|
38
|
+
namespace: string;
|
|
39
|
+
uploadId: string;
|
|
40
|
+
bytes: AsyncIterable<Uint8Array>;
|
|
41
|
+
}, c: IStoreContext): Promise<void>;
|
|
42
|
+
readArtifactAsync(r: IDocumentKey, c: IStoreContext): Promise<AsyncIterable<Uint8Array>>;
|
|
43
|
+
/** Caller owns the connected MCP client. Context.subject is never sent over the wire. */
|
|
44
|
+
closeAsync(): Promise<void>;
|
|
45
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { PersistenceError } from "../contract/errors.js";
|
|
2
|
+
import { fail, segment } from "../contract/validation.js";
|
|
3
|
+
export function slotPayload(result) {
|
|
4
|
+
let payload = result.structuredContent;
|
|
5
|
+
if (payload === undefined) {
|
|
6
|
+
const block = result.content?.find(b => typeof b === "object" && b !== null && b.type === "text");
|
|
7
|
+
try {
|
|
8
|
+
payload = JSON.parse(block?.text ?? "null");
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
fail("integrity_error", "Malformed persistence response");
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
if (result.isError) {
|
|
15
|
+
const error = payload?.error;
|
|
16
|
+
throw new PersistenceError((error?.code ?? "store_unavailable"), error?.message ?? "Persistence operation failed");
|
|
17
|
+
}
|
|
18
|
+
return payload;
|
|
19
|
+
}
|
|
20
|
+
export class PersistenceSlotStore {
|
|
21
|
+
id;
|
|
22
|
+
client;
|
|
23
|
+
transfer;
|
|
24
|
+
constructor(id, client, transfer) {
|
|
25
|
+
this.id = id;
|
|
26
|
+
this.client = client;
|
|
27
|
+
this.transfer = transfer;
|
|
28
|
+
if (transfer) {
|
|
29
|
+
const url = new URL(transfer.baseUrl);
|
|
30
|
+
if (url.username || url.password || url.search || url.hash || (url.protocol !== "https:" && !(url.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname))))
|
|
31
|
+
fail("invalid_request", "Transfer endpoint requires HTTPS or loopback HTTP");
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
async call(method, request, context) {
|
|
35
|
+
context?.signal?.throwIfAborted();
|
|
36
|
+
return slotPayload(await this.client.callTool(`persistence.${method}`, { ...request }));
|
|
37
|
+
}
|
|
38
|
+
getCapabilitiesAsync() { return this.call("capabilities", {}); }
|
|
39
|
+
getAsync(r, c) { return this.call("get", { namespace: r.namespace, id: r.id, ...(r.revision === undefined ? {} : { revision: r.revision }) }, c); }
|
|
40
|
+
putAsync(r, c) { return this.call("put", r, c); }
|
|
41
|
+
listAsync(r, c) { return this.call("list", r, c); }
|
|
42
|
+
listRevisionsAsync(r, c) { return this.call("listRevisions", { namespace: r.namespace, id: r.id, ...(r.limit === undefined ? {} : { limit: r.limit }), ...(r.cursor === undefined ? {} : { cursor: r.cursor }) }, c); }
|
|
43
|
+
deleteAsync(r, c) { return this.call("delete", r, c); }
|
|
44
|
+
purgeAsync(r, c) { return this.call("purge", r, c); }
|
|
45
|
+
beginArtifactAsync(r, c) { return this.call("beginArtifact", r, c); }
|
|
46
|
+
inspectUploadAsync(namespace, uploadId, c) { return this.call("uploadAccess", { namespace, uploadId }, c); }
|
|
47
|
+
commitArtifactAsync(r, c) { return this.call("commitArtifact", r, c); }
|
|
48
|
+
abortArtifactAsync(r, c) { return this.call("abortArtifact", r, c); }
|
|
49
|
+
getArtifactAsync(r, c) { return this.call("getArtifact", { namespace: r.namespace, id: r.id }, c); }
|
|
50
|
+
async response(path, init) {
|
|
51
|
+
if (!this.transfer)
|
|
52
|
+
fail("unsupported_format", "Configure the HTTP transfer endpoint");
|
|
53
|
+
const response = await fetch(`${this.transfer.baseUrl.replace(/\/$/, "")}${path}`, { ...init, headers: { ...this.transfer.headers?.(), ...init.headers }, redirect: "error" });
|
|
54
|
+
if (!response.ok) {
|
|
55
|
+
let body = {};
|
|
56
|
+
try {
|
|
57
|
+
body = await response.json();
|
|
58
|
+
}
|
|
59
|
+
catch { /* A proxy may return a non-JSON failure. */ }
|
|
60
|
+
throw new PersistenceError(body.error?.code ?? (response.status === 403 || response.status === 401 ? "policy_denied" : "store_unavailable"), "Artifact transfer failed");
|
|
61
|
+
}
|
|
62
|
+
return response;
|
|
63
|
+
}
|
|
64
|
+
async writeArtifactAsync(r, c) {
|
|
65
|
+
c.signal?.throwIfAborted();
|
|
66
|
+
const iterator = r.bytes[Symbol.asyncIterator]();
|
|
67
|
+
const stream = new ReadableStream({ async pull(controller) { const next = await iterator.next(); if (next.done)
|
|
68
|
+
controller.close();
|
|
69
|
+
else
|
|
70
|
+
controller.enqueue(next.value); }, async cancel() { await iterator.return?.(); } });
|
|
71
|
+
await this.response(`/uploads/${segment(r.namespace)}/${segment(r.uploadId)}`, { method: "PUT", body: stream, signal: c.signal, duplex: "half" });
|
|
72
|
+
}
|
|
73
|
+
async readArtifactAsync(r, c) {
|
|
74
|
+
const response = await this.response(`/artifacts/${segment(r.namespace)}/${segment(r.id)}`, { signal: c.signal });
|
|
75
|
+
if (!response.body)
|
|
76
|
+
fail("transfer_incomplete", "Missing artifact response body");
|
|
77
|
+
const body = response.body;
|
|
78
|
+
return (async function* () { const reader = body.getReader(); try {
|
|
79
|
+
while (true) {
|
|
80
|
+
const chunk = await reader.read();
|
|
81
|
+
if (chunk.done)
|
|
82
|
+
break;
|
|
83
|
+
yield chunk.value;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
finally {
|
|
87
|
+
await reader.cancel();
|
|
88
|
+
reader.releaseLock();
|
|
89
|
+
} })();
|
|
90
|
+
}
|
|
91
|
+
/** Caller owns the connected MCP client. Context.subject is never sent over the wire. */
|
|
92
|
+
async closeAsync() { }
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=persistence.slot.store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persistence.slot.store.js","sourceRoot":"","sources":["../../src/server/persistence.slot.store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { IPersistenceStore } from "../contract/persistence.store.js";
|
|
2
|
+
import type { IArtifact, IBeginArtifact, IDeleteDocument, IDocument, IDocumentKey, IFinishArtifact, IListDocuments, IPage, IPageRequest, IPersistenceCapabilities, IPurge, IPutDocument, IStoreContext, IUpload } from "../contract/persistence.types.js";
|
|
3
|
+
declare const DEFAULTS: {
|
|
4
|
+
maxDocumentBytes: number;
|
|
5
|
+
maxArtifactBytes: number;
|
|
6
|
+
maxReferences: number;
|
|
7
|
+
maxPageSize: number;
|
|
8
|
+
maxNamespaceBytes: number;
|
|
9
|
+
idempotencyRetentionSeconds: number;
|
|
10
|
+
};
|
|
11
|
+
export interface ISqlitePersistenceOptions {
|
|
12
|
+
directory: string;
|
|
13
|
+
limits?: Partial<typeof DEFAULTS>;
|
|
14
|
+
retentionMs?: number;
|
|
15
|
+
/** Windows cannot fsync directories through Node. Opt in explicitly to file-sync durability. */
|
|
16
|
+
allowFileSyncOnly?: boolean;
|
|
17
|
+
}
|
|
18
|
+
/** One provider process owns one local data root. SQLite serializes all metadata mutations. */
|
|
19
|
+
export declare class SqlitePersistenceStore implements IPersistenceStore {
|
|
20
|
+
readonly id = "sqlite-files";
|
|
21
|
+
readonly directory: string;
|
|
22
|
+
private readonly db;
|
|
23
|
+
private readonly limits;
|
|
24
|
+
private readonly cursorKey;
|
|
25
|
+
private readonly retentionMs;
|
|
26
|
+
private readonly fileSyncOnly;
|
|
27
|
+
private readonly active;
|
|
28
|
+
private readonly readers;
|
|
29
|
+
private closed;
|
|
30
|
+
constructor(options: ISqlitePersistenceOptions);
|
|
31
|
+
private safe;
|
|
32
|
+
private syncDirectory;
|
|
33
|
+
private writeDurable;
|
|
34
|
+
private check;
|
|
35
|
+
private key;
|
|
36
|
+
private quota;
|
|
37
|
+
private mutation;
|
|
38
|
+
getCapabilitiesAsync(): Promise<IPersistenceCapabilities>;
|
|
39
|
+
private document;
|
|
40
|
+
getAsync(request: IDocumentKey & {
|
|
41
|
+
revision?: number;
|
|
42
|
+
}, context: IStoreContext): Promise<IDocument>;
|
|
43
|
+
private insert;
|
|
44
|
+
putAsync(request: IPutDocument, context: IStoreContext): Promise<IDocument>;
|
|
45
|
+
private page;
|
|
46
|
+
private pageAfter;
|
|
47
|
+
private pageLimit;
|
|
48
|
+
listAsync(request: IListDocuments, context: IStoreContext): Promise<IPage<IDocument>>;
|
|
49
|
+
listRevisionsAsync(request: IDocumentKey & IPageRequest, context: IStoreContext): Promise<IPage<IDocument>>;
|
|
50
|
+
deleteAsync(request: IDeleteDocument, context: IStoreContext): Promise<IDocument>;
|
|
51
|
+
beginArtifactAsync(request: IBeginArtifact, context: IStoreContext): Promise<IUpload>;
|
|
52
|
+
private upload;
|
|
53
|
+
inspectUploadAsync(namespace: string, uploadId: string, context: IStoreContext): Promise<IUpload>;
|
|
54
|
+
writeArtifactAsync(request: {
|
|
55
|
+
namespace: string;
|
|
56
|
+
uploadId: string;
|
|
57
|
+
bytes: AsyncIterable<Uint8Array>;
|
|
58
|
+
}, context: IStoreContext): Promise<void>;
|
|
59
|
+
commitArtifactAsync(request: IFinishArtifact, context: IStoreContext): Promise<IArtifact>;
|
|
60
|
+
abortArtifactAsync(request: IFinishArtifact, context: IStoreContext): Promise<void>;
|
|
61
|
+
private artifact;
|
|
62
|
+
getArtifactAsync(request: IDocumentKey, context: IStoreContext): Promise<IArtifact>;
|
|
63
|
+
readArtifactAsync(request: IDocumentKey, context: IStoreContext): Promise<AsyncIterable<Uint8Array>>;
|
|
64
|
+
private verifyFile;
|
|
65
|
+
purgeAsync(request: IPurge, context: IStoreContext): Promise<void>;
|
|
66
|
+
private collectGarbage;
|
|
67
|
+
private expireUploads;
|
|
68
|
+
private collectOrphans;
|
|
69
|
+
private recover;
|
|
70
|
+
closeAsync(): Promise<void>;
|
|
71
|
+
}
|
|
72
|
+
export {};
|