synartesis 0.2.2 → 0.2.4
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/CHANGELOG.md +38 -0
- package/README.md +38 -2
- package/dist/{chunk-YMZNQZWT.js → chunk-GD6PRYZZ.js} +14 -1
- package/dist/chunk-GD6PRYZZ.js.map +1 -0
- package/dist/cli.js +27 -6
- package/dist/cli.js.map +1 -1
- package/dist/proxy.js +22 -4
- package/dist/proxy.js.map +1 -1
- package/manifests/github.yaml +15 -0
- package/package.json +4 -1
- package/dist/chunk-YMZNQZWT.js.map +0 -1
- package/dist/demo-agent.js +0 -67
- package/dist/demo-agent.js.map +0 -1
- package/dist/toy-crm.js +0 -293
- package/dist/toy-crm.js.map +0 -1
- package/manifests/toy-crm.yaml +0 -66
package/dist/proxy.js
CHANGED
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
runRead,
|
|
20
20
|
toPayload,
|
|
21
21
|
verifyAgainstServers
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-GD6PRYZZ.js";
|
|
23
23
|
import {
|
|
24
24
|
SnapshotError,
|
|
25
25
|
UpstreamError,
|
|
@@ -109,6 +109,17 @@ function isInitialize(body) {
|
|
|
109
109
|
}
|
|
110
110
|
async function serveHttp(options) {
|
|
111
111
|
const sessions = /* @__PURE__ */ new Map();
|
|
112
|
+
const sweep = setInterval(() => {
|
|
113
|
+
const deadline = Date.now() - options.idleSeconds * 1e3;
|
|
114
|
+
for (const [id, live] of sessions) {
|
|
115
|
+
if (live.lastSeen < deadline) {
|
|
116
|
+
sessions.delete(id);
|
|
117
|
+
options.log.info({ session: id }, "http session swept after going quiet");
|
|
118
|
+
void live.transport.close().catch(() => void 0);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}, Math.max(1e3, options.idleSeconds * 1e3 / 4));
|
|
122
|
+
sweep.unref();
|
|
112
123
|
const server = createServer((req, res) => {
|
|
113
124
|
void (async () => {
|
|
114
125
|
try {
|
|
@@ -126,6 +137,7 @@ async function serveHttp(options) {
|
|
|
126
137
|
const sessionId = req.headers["mcp-session-id"];
|
|
127
138
|
const existing = typeof sessionId === "string" ? sessions.get(sessionId) : void 0;
|
|
128
139
|
if (existing !== void 0) {
|
|
140
|
+
existing.lastSeen = Date.now();
|
|
129
141
|
await writeResponse(res, await existing.transport.handleRequest(toRequest(req, raw, origin)));
|
|
130
142
|
return;
|
|
131
143
|
}
|
|
@@ -138,7 +150,7 @@ async function serveHttp(options) {
|
|
|
138
150
|
const transport = new WebStandardStreamableHTTPServerTransport({
|
|
139
151
|
sessionIdGenerator: () => randomUUID(),
|
|
140
152
|
onsessioninitialized: (id) => {
|
|
141
|
-
sessions.set(id, { transport, proxy });
|
|
153
|
+
sessions.set(id, { transport, proxy, lastSeen: Date.now() });
|
|
142
154
|
options.log.info({ session: id }, "http session opened");
|
|
143
155
|
}
|
|
144
156
|
});
|
|
@@ -174,6 +186,7 @@ async function serveHttp(options) {
|
|
|
174
186
|
return {
|
|
175
187
|
port,
|
|
176
188
|
close: async () => {
|
|
189
|
+
clearInterval(sweep);
|
|
177
190
|
for (const { transport } of sessions.values()) {
|
|
178
191
|
await transport.close().catch(() => void 0);
|
|
179
192
|
}
|
|
@@ -952,7 +965,7 @@ function parseArgv(argv) {
|
|
|
952
965
|
const at = argv.indexOf(flag);
|
|
953
966
|
return at === -1 ? void 0 : argv[at + 1];
|
|
954
967
|
};
|
|
955
|
-
const known = ["--manifest", "--journal", "--gate-timeout", "--log-level", "--http", "--http-host", "--token"];
|
|
968
|
+
const known = ["--manifest", "--journal", "--gate-timeout", "--log-level", "--http", "--http-host", "--http-idle", "--token"];
|
|
956
969
|
const unknown = argv.find((token) => token.startsWith("--") && !known.includes(token));
|
|
957
970
|
if (unknown !== void 0) {
|
|
958
971
|
throw new Error(`unknown flag ${unknown}; expected one of ${known.join(", ")}`);
|
|
@@ -979,7 +992,12 @@ function parseArgv(argv) {
|
|
|
979
992
|
"--http needs --token, or SYNARTESIS_TOKEN, of at least 16 characters: this serves write access over a socket"
|
|
980
993
|
);
|
|
981
994
|
}
|
|
982
|
-
|
|
995
|
+
const rawIdle = read("--http-idle");
|
|
996
|
+
const idleSeconds = rawIdle === void 0 ? 1800 : Number(rawIdle);
|
|
997
|
+
if (!Number.isFinite(idleSeconds) || idleSeconds <= 0) {
|
|
998
|
+
throw new Error("--http-idle needs a positive number of seconds");
|
|
999
|
+
}
|
|
1000
|
+
http = { port, host: read("--http-host") ?? "127.0.0.1", token, idleSeconds };
|
|
983
1001
|
}
|
|
984
1002
|
const manifest = findManifest(read("--manifest"));
|
|
985
1003
|
return {
|
package/dist/proxy.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/proxy/stdio.ts","../src/proxy/http.ts","../src/gate/gate.ts","../src/logging.ts","../src/proxy/proxy.ts","../src/gate/heuristic.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * better-sqlite3 requires Node 22, and on Node 20 it does not fail politely:\n * it segfaults the moment a database is opened. Saying so is better than\n * letting somebody meet exit code 139.\n */\nconst NODE_MAJOR = Number(process.versions.node.split(\".\")[0]);\nif (NODE_MAJOR < 22) {\n process.stderr.write(\n `synartesis: needs Node 22 or newer, and this is ${process.version}.\\n`,\n );\n process.exit(2);\n}\n\nimport { resolve } from \"node:path\";\n\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\n\nimport { serveHttp } from \"./http.js\";\n\nimport { describe } from \"../errors.js\";\nimport { DEFAULT_GATE_TIMEOUT_MS } from \"../gate/gate.js\";\nimport { cliCommandFrom } from \"../invocation.js\";\nimport { findJournal, findManifest } from \"../locate.js\";\nimport { createLogger, isLogLevel, LOG_LEVELS, type LogLevel } from \"../logging.js\";\nimport { mark } from \"../style.js\";\nimport { openJournal } from \"../journal/journal.js\";\nimport { loadManifest } from \"../manifest/load.js\";\nimport { verifyAgainstServers } from \"../manifest/verify.js\";\nimport { createProxyServer } from \"./proxy.js\";\nimport { connectStdioUpstream, type Upstream } from \"./upstream.js\";\n\n/**\n * The manifest is the configuration (D3): it already declares every server and\n * how to start it, so there is nothing left for flags to say.\n *\n * synartesis-proxy [--manifest synartesis.yaml] [--journal .synartesis/journal.db]\n * [--gate-timeout <seconds>] [--log-level <level>]\n */\ninterface Argv {\n readonly manifest: string;\n readonly journal: string;\n readonly gateTimeoutMs: number;\n /** Whether --gate-timeout was actually typed, as against defaulted. */\n readonly gateTimeoutGiven: boolean;\n /** Serve over http instead of stdio, for a client that will not start one. */\n readonly http?: { readonly port: number; readonly host: string; readonly token: string };\n readonly logLevel: LogLevel;\n}\n\nfunction parseArgv(argv: readonly string[]): Argv {\n const read = (flag: string): string | undefined => {\n const at = argv.indexOf(flag);\n return at === -1 ? undefined : argv[at + 1];\n };\n const known = [\"--manifest\", \"--journal\", \"--gate-timeout\", \"--log-level\", \"--http\", \"--http-host\", \"--token\"];\n const unknown = argv.find((token) => token.startsWith(\"--\") && !known.includes(token));\n if (unknown !== undefined) {\n throw new Error(`unknown flag ${unknown}; expected one of ${known.join(\", \")}`);\n }\n\n const rawTimeout = read(\"--gate-timeout\");\n const seconds = rawTimeout === undefined ? undefined : Number(rawTimeout);\n if (seconds !== undefined && (!Number.isFinite(seconds) || seconds <= 0)) {\n throw new Error(\"--gate-timeout needs a positive number of seconds\");\n }\n\n const level = read(\"--log-level\") ?? \"info\";\n if (!isLogLevel(level)) {\n throw new Error(`--log-level must be one of ${LOG_LEVELS.join(\", \")}`);\n }\n\n const httpPort = read(\"--http\");\n let http: Argv[\"http\"];\n if (httpPort !== undefined) {\n const port = Number(httpPort);\n if (!Number.isInteger(port) || port < 1 || port > 65535) {\n throw new Error(\"--http needs a port number\");\n }\n // Refused rather than defaulted. What is served here can write through\n // every server in the policy, and a default of \"no auth\" is the kind of\n // convenience that ends up on someone's public tunnel.\n const token = read(\"--token\") ?? process.env[\"SYNARTESIS_TOKEN\"];\n if (token === undefined || token.length < 16) {\n throw new Error(\n \"--http needs --token, or SYNARTESIS_TOKEN, of at least 16 characters: this serves write access over a socket\",\n );\n }\n http = { port, host: read(\"--http-host\") ?? \"127.0.0.1\", token };\n }\n\n const manifest = findManifest(read(\"--manifest\"));\n return {\n manifest,\n journal: findJournal(read(\"--journal\"), manifest),\n gateTimeoutMs: seconds === undefined ? DEFAULT_GATE_TIMEOUT_MS : seconds * 1000,\n gateTimeoutGiven: seconds !== undefined,\n ...(http === undefined ? {} : { http }),\n logLevel: level,\n };\n}\n\nasync function main(): Promise<void> {\n const argv = parseArgv(process.argv.slice(2));\n const log = createLogger(argv.logLevel);\n if (argv.gateTimeoutGiven) {\n // Accepted, validated, threaded through, and read by nothing: this proxy\n // refuses a held call straight away rather than holding the connection\n // open, so there is no wait for a timeout to cut short. Saying so is\n // better than a flag that quietly does nothing, and better than rejecting\n // one that earlier versions took.\n log.warn(\n \"--gate-timeout has no effect: a held call is refused immediately and the agent makes it again once you approve\",\n );\n }\n // Only on a real terminal. A client collecting our stderr into a log file\n // wants the structured records and nothing else.\n if (process.stderr.isTTY) {\n process.stderr.write(mark());\n }\n // Loaded before anything is spawned: never start with a broken policy.\n const manifest = loadManifest(argv.manifest);\n const journal = openJournal(argv.journal);\n\n const upstreams: Upstream[] = [];\n for (const [name, spec] of Object.entries(manifest.servers)) {\n upstreams.push(\n await connectStdioUpstream({\n name,\n command: spec.command,\n args: spec.args,\n ...(spec.env === undefined ? {} : { env: spec.env }),\n }),\n );\n }\n\n // Never serve a request under a policy that calls tools the servers do not\n // have: at run time that is indistinguishable from a missing resource.\n await verifyAgainstServers(upstreams, manifest);\n\n log.info(\n {\n manifest: argv.manifest,\n journal: argv.journal,\n servers: upstreams.map((upstream) => upstream.name),\n policies: manifest.tools.length,\n },\n \"proxy ready\",\n );\n\n const build = (): ReturnType<typeof createProxyServer> =>\n createProxyServer({\n upstreams,\n manifest,\n journal,\n gateTimeoutMs: argv.gateTimeoutMs,\n logger: log,\n // Absolute, because whoever approves may be in any directory at all.\n approveHint: (actionId: string): string =>\n `${cliCommandFrom(import.meta.url)} approve ${actionId.slice(0, 8)} --journal ${resolve(argv.journal)}`,\n });\n\n if (argv.http !== undefined) {\n // One server, many sessions. Each session is a connection and a connection\n // is a run, so each gets a proxy of its own; the upstreams and the journal\n // are shared, which is what makes them one story.\n const served = await serveHttp({\n ...argv.http,\n create: build,\n log: {\n info: (data, message) => {\n log.info(data, message);\n },\n warn: (message) => {\n log.warn(message);\n },\n },\n });\n const stop = (): void => {\n void (async (): Promise<void> => {\n await served.close();\n for (const upstream of upstreams) {\n await upstream.close();\n }\n journal.close();\n process.exit(0);\n })();\n };\n process.on(\"SIGINT\", stop);\n process.on(\"SIGTERM\", stop);\n return;\n }\n\n const proxy = build();\n\n let shuttingDown = false;\n const shutdown = (code: number): void => {\n if (shuttingDown) {\n return;\n }\n shuttingDown = true;\n void (async (): Promise<void> => {\n // Let in-flight calls settle before tearing the connection down. An\n // aborted write leaves the journal unable to say whether it applied.\n await Promise.race([\n proxy.whenIdle(),\n new Promise<void>((resolve) => setTimeout(resolve, 5000).unref()),\n ]);\n await proxy.server.close();\n for (const upstream of upstreams) {\n await upstream.close();\n }\n journal.close();\n process.exit(code);\n })();\n };\n\n process.on(\"SIGINT\", () => {\n shutdown(0);\n });\n process.on(\"SIGTERM\", () => {\n shutdown(0);\n });\n\n // StdioServerTransport only reports a close that we initiate; it never\n // reacts to the parent closing the pipe. Without these listeners the proxy\n // survives its own client, holding every upstream child open until whoever\n // spawned us escalates to a signal.\n // The pipe closing means no more requests are coming, not that the ones\n // already delivered can be dropped. The transport hands only a few buffered\n // frames to handlers per turn of the event loop, so wait until the proxy has\n // been quiet for several consecutive turns rather than yielding a fixed\n // number of times, which is guesswork. The cap stops a wedged upstream from\n // holding the process open.\n const pipeClosed = (): void => {\n const giveUpAt = Date.now() + 5000;\n let quiet = 0;\n const settle = (): void => {\n quiet = proxy.busy() ? 0 : quiet + 1;\n if (quiet >= 10 || Date.now() > giveUpAt) {\n shutdown(0);\n return;\n }\n setImmediate(settle);\n };\n setImmediate(settle);\n };\n process.stdin.on(\"end\", pipeClosed);\n process.stdin.on(\"close\", pipeClosed);\n\n const inner = proxy.server.server;\n const onclose = inner.onclose;\n inner.onclose = (): void => {\n onclose?.();\n shutdown(0);\n };\n\n await proxy.server.connect(new StdioServerTransport());\n}\n\ntry {\n await main();\n} catch (error: unknown) {\n // stdout carries protocol frames only; diagnostics must not corrupt it.\n process.stderr.write(`synartesis: ${describe(error)}\\n`);\n process.exit(1);\n}\n","import { createServer, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport { randomUUID, timingSafeEqual } from \"node:crypto\";\n\nimport { WebStandardStreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js\";\n\nimport type { ProxyServer } from \"./proxy.js\";\n\n/**\n * Serving the proxy over HTTP, for clients that will not start a process.\n *\n * ChatGPT's connectors are the reason this exists: they take a remote https\n * endpoint and nothing else, so stdio -- which every other client speaks -- is\n * not an option there.\n *\n * What is served is an undo layer with write access to real systems, so this\n * refuses to run without a token and binds to the loopback interface unless\n * told otherwise. Reaching it from the internet is a tunnel in front of it,\n * deliberately: that is a decision someone should have to make out loud.\n */\nexport interface HttpOptions {\n readonly port: number;\n readonly host: string;\n readonly token: string;\n /** A fresh proxy per session, since a run belongs to one client's connection. */\n readonly create: () => ProxyServer;\n readonly log: {\n info: (data: Record<string, unknown>, message: string) => void;\n warn: (message: string) => void;\n };\n}\n\nexport interface HttpServer {\n readonly port: number;\n close(): Promise<void>;\n}\n\n\n/**\n * Node's request and response, in the shapes the sdk's transport speaks.\n *\n * The node-native transport in this sdk declares onclose as a getter/setter\n * pair typed `(() => void) | undefined`, which an exactOptionalPropertyTypes\n * project cannot accept without an assertion. The web-standard one declares it\n * plainly, so it is used instead and the twenty lines below are the price.\n */\nfunction toRequest(req: IncomingMessage, body: Buffer, origin: string): Request {\n const headers = new Headers();\n for (const [key, value] of Object.entries(req.headers)) {\n if (typeof value === \"string\") {\n headers.set(key, value);\n } else if (Array.isArray(value)) {\n for (const one of value) {\n headers.append(key, one);\n }\n }\n }\n const method = req.method ?? \"GET\";\n return new Request(new URL(req.url ?? \"/\", origin), {\n method,\n headers,\n // A GET or HEAD may not carry one, and node sends an empty buffer anyway.\n ...(method === \"GET\" || method === \"HEAD\" ? {} : { body }),\n });\n}\n\nasync function writeResponse(res: ServerResponse, response: Response): Promise<void> {\n const headers: Record<string, string> = {};\n response.headers.forEach((value, key) => {\n headers[key] = value;\n });\n res.writeHead(response.status, headers);\n if (response.body === null) {\n res.end();\n return;\n }\n // Streamed rather than buffered: this is how an SSE reply stays live.\n for await (const chunk of response.body) {\n res.write(Buffer.from(chunk));\n }\n res.end();\n}\n\n/** Constant time, so a wrong token cannot be found one character at a time. */\nfunction tokenMatches(given: string, expected: string): boolean {\n const a = Buffer.from(given);\n const b = Buffer.from(expected);\n return a.length === b.length && timingSafeEqual(a, b);\n}\n\nfunction bearer(req: IncomingMessage): string | undefined {\n const header = req.headers.authorization;\n if (typeof header !== \"string\") {\n return undefined;\n }\n const match = /^Bearer[ ]+(.+)$/i.exec(header.trim());\n return match?.[1];\n}\n\nfunction refuse(res: ServerResponse, status: number, message: string): void {\n res.writeHead(status, {\n \"content-type\": \"application/json\",\n // Told the same way twice: the header is what a client acts on, the body\n // is what a person reads in a terminal.\n ...(status === 401 ? { \"www-authenticate\": 'Bearer realm=\"synartesis\"' } : {}),\n });\n res.end(JSON.stringify({ error: message }));\n}\n\nasync function readRaw(req: IncomingMessage): Promise<Buffer> {\n const chunks: Buffer[] = [];\n let size = 0;\n for await (const chunk of req) {\n const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk));\n size += buffer.length;\n // A cap, because this listens on a socket: an unbounded body is a way to\n // exhaust memory without ever authenticating.\n if (size > 8 * 1024 * 1024) {\n throw new Error(\"request body too large\");\n }\n chunks.push(buffer);\n }\n return Buffer.concat(chunks);\n}\n\nfunction isInitialize(body: unknown): boolean {\n const one = (message: unknown): boolean =>\n typeof message === \"object\" &&\n message !== null &&\n \"method\" in message &&\n message.method === \"initialize\";\n return Array.isArray(body) ? body.some(one) : one(body);\n}\n\nexport async function serveHttp(options: HttpOptions): Promise<HttpServer> {\n const sessions = new Map<string, { transport: WebStandardStreamableHTTPServerTransport; proxy: ProxyServer }>();\n\n const server = createServer((req, res) => {\n void (async (): Promise<void> => {\n try {\n const token = bearer(req);\n if (token === undefined || !tokenMatches(token, options.token)) {\n // Before anything is parsed or routed. An unauthenticated request\n // must not be able to reach the proxy, the journal or an upstream.\n refuse(res, 401, \"a bearer token is required\");\n return;\n }\n if (req.url !== undefined && !req.url.startsWith(\"/mcp\")) {\n refuse(res, 404, \"the endpoint is /mcp\");\n return;\n }\n\n const origin = `http://${options.host}:${String(options.port)}`;\n const raw = await readRaw(req);\n const sessionId = req.headers[\"mcp-session-id\"];\n const existing = typeof sessionId === \"string\" ? sessions.get(sessionId) : undefined;\n if (existing !== undefined) {\n await writeResponse(res, await existing.transport.handleRequest(toRequest(req, raw, origin)));\n return;\n }\n\n const body: unknown =\n req.method === \"POST\" && raw.length > 0 ? JSON.parse(raw.toString(\"utf8\")) : undefined;\n if (req.method !== \"POST\" || !isInitialize(body)) {\n refuse(res, 400, \"no such session; start one with an initialize request\");\n return;\n }\n\n // A session is a connection, and a connection is a run: each one gets\n // its own proxy so its actions are journalled as one story.\n const proxy = options.create();\n const transport = new WebStandardStreamableHTTPServerTransport({\n sessionIdGenerator: () => randomUUID(),\n onsessioninitialized: (id: string) => {\n sessions.set(id, { transport, proxy });\n options.log.info({ session: id }, \"http session opened\");\n },\n });\n await proxy.server.connect(transport);\n transport.onclose = (): void => {\n const id = transport.sessionId;\n if (id !== undefined) {\n sessions.delete(id);\n }\n };\n await writeResponse(res, await transport.handleRequest(toRequest(req, raw, origin)));\n } catch (error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n if (!res.headersSent) {\n refuse(res, 400, message);\n } else {\n res.end();\n }\n }\n })();\n });\n\n await new Promise<void>((resolve) => {\n server.listen(options.port, options.host, resolve);\n });\n const address = server.address();\n const port = typeof address === \"object\" && address !== null ? address.port : options.port;\n\n if (options.host !== \"127.0.0.1\" && options.host !== \"localhost\") {\n options.log.warn(\n `listening on ${options.host}, which is not loopback: anything that can reach this port and holds the token can write through your servers`,\n );\n }\n options.log.info({ host: options.host, port, endpoint: \"/mcp\" }, \"http proxy ready\");\n\n return {\n port,\n close: async (): Promise<void> => {\n for (const { transport } of sessions.values()) {\n await transport.close().catch(() => undefined);\n }\n sessions.clear();\n await new Promise<void>((resolve) => {\n server.close(() => {\n resolve();\n });\n });\n },\n };\n}\n","import type { Journal } from \"../journal/journal.js\";\n\nexport interface GateRequest {\n readonly actionId: string;\n readonly runId: string;\n readonly seq: number;\n readonly server: string;\n readonly tool: string;\n readonly args: unknown;\n /** Why this is being asked about, in the words the agent is given. */\n readonly why: string;\n readonly signal: AbortSignal;\n}\n\nexport type GateDecision =\n | { readonly approved: true; readonly by: string }\n | {\n readonly approved: false;\n readonly by?: string;\n readonly reason: string;\n /**\n * Nobody has refused; the request is simply waiting for a person. The\n * agent should tell its user how to approve and then try again.\n */\n readonly awaiting?: boolean;\n };\n\nexport interface Gate {\n decide(request: GateRequest): Promise<GateDecision>;\n}\n\nexport const DEFAULT_GATE_TIMEOUT_MS = 300_000;\n\n/**\n * Records the request and refuses immediately, rather than holding the call\n * open until someone answers.\n *\n * Holding it open cannot work against a real client. Measured against Claude\n * Code: a suspended call sat for the full five minutes while the client had\n * long since reported it as failed, and any approval in that gap would have\n * sent something the agent had already said it had not sent. Every useful\n * window for a person to notice, open a terminal and decide is longer than a\n * client will wait, so the two cannot be reconciled by choosing a better\n * timeout. Refusing at once and letting the agent retry removes the conflict\n * instead of tuning it.\n */\n/**\n * `approveHint` builds the command a person on this machine would actually\n * run, journal path and all. A hint that omits an argument the caller needs is\n * an instruction that fails the moment somebody follows it.\n */\nexport type ApproveHint = (actionId: string) => string;\n\nconst DEFAULT_HINT: ApproveHint = (actionId) => `synartesis approve ${actionId.slice(0, 8)}`;\n\nexport function createRetryGate(journal: Journal, approveHint: ApproveHint = DEFAULT_HINT): Gate {\n return {\n decide(request: GateRequest): Promise<GateDecision> {\n journal.markGated(request.actionId, request.why);\n return Promise.resolve({\n approved: false,\n awaiting: true,\n reason:\n \"it is waiting for a person to approve it. Ask them to run: \" +\n approveHint(request.actionId) +\n \" --- then make this exact call again.\",\n });\n },\n };\n}\n\nexport interface JournalGateOptions {\n readonly timeoutMs?: number;\n readonly pollMs?: number;\n /** Where the operator is told that something is waiting. */\n readonly notify?: (request: GateRequest) => void;\n}\n\n/**\n * Approval arrives out of band, through the journal, rather than from a prompt\n * on stdin.\n *\n * The proxy speaks MCP over stdin and stdout: that pipe carries protocol\n * frames, so there is nothing to prompt on. A prompt written to the\n * controlling terminal would work only when one exists, which rules out every\n * desktop client. The journal is already a transactional, WAL-mode, multi\n * process store, so `synartesis approve` in any other terminal is the natural\n * channel, and it behaves identically wherever the proxy was launched from.\n */\nexport function createJournalGate(journal: Journal, options: JournalGateOptions = {}): Gate {\n const timeoutMs = options.timeoutMs ?? DEFAULT_GATE_TIMEOUT_MS;\n const pollMs = options.pollMs ?? 100;\n const notify = options.notify ?? ((): void => undefined);\n\n return {\n async decide(request: GateRequest): Promise<GateDecision> {\n journal.markGated(request.actionId, request.why);\n notify(request);\n\n const deadline = Date.now() + timeoutMs;\n for (;;) {\n const action = journal.getAction(request.actionId);\n if (action === undefined) {\n return { approved: false, reason: \"the journal entry disappeared while awaiting approval\" };\n }\n if (action.status !== \"gated\") {\n return action.status === \"denied\"\n ? {\n approved: false,\n ...(action.approvedBy === undefined ? {} : { by: action.approvedBy }),\n reason: action.error ?? \"denied\",\n }\n : { approved: true, by: action.approvedBy ?? \"unknown\" };\n }\n\n if (request.signal.aborted) {\n journal.deny(request.actionId, undefined, \"the client disconnected before a decision\");\n return { approved: false, reason: \"the client disconnected before a decision\" };\n }\n if (Date.now() >= deadline) {\n // Deny by default (3.4): silence is not consent.\n const reason = `no answer within ${String(Math.round(timeoutMs / 1000))}s, so it was denied`;\n journal.deny(request.actionId, undefined, reason);\n return { approved: false, reason };\n }\n\n await new Promise<void>((resolve) => setTimeout(resolve, pollMs).unref());\n }\n },\n };\n}\n","import pino, { type Logger } from \"pino\";\n\nexport type { Logger };\n\nexport const LOG_LEVELS = [\"trace\", \"debug\", \"info\", \"warn\", \"error\", \"silent\"] as const;\nexport type LogLevel = (typeof LOG_LEVELS)[number];\n\nexport function isLogLevel(value: string): value is LogLevel {\n return LOG_LEVELS.some((level) => level === value);\n}\n\n/**\n * Always fd 2. stdout carries MCP protocol frames, and a single stray log line\n * on it corrupts the session for every client. Synchronous so that the last\n * lines before an exit are not lost, which is exactly when they matter.\n */\nexport function createLogger(level: LogLevel): Logger {\n return pino(\n { level, base: { name: \"synartesis\" } },\n pino.destination({ dest: 2, sync: true }),\n );\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport {\n CallToolRequestSchema,\n CompleteRequestSchema,\n ErrorCode,\n GetPromptRequestSchema,\n ListPromptsRequestSchema,\n ListResourceTemplatesRequestSchema,\n ListResourcesRequestSchema,\n ListToolsRequestSchema,\n McpError,\n ReadResourceRequestSchema,\n SetLevelRequestSchema,\n SubscribeRequestSchema,\n UnsubscribeRequestSchema,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport type {\n Implementation,\n Request,\n ServerCapabilities,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { z } from \"zod\";\n\nimport { SnapshotError, UpstreamError, describe } from \"../errors.js\";\nimport { createRetryGate, type ApproveHint, type Gate } from \"../gate/gate.js\";\nimport { shouldGateOnWrite } from \"../gate/heuristic.js\";\nimport type { Journal } from \"../journal/journal.js\";\nimport type { Logger } from \"../logging.js\";\nimport {\n createPolicyResolver,\n type PolicyResolver,\n} from \"../manifest/match.js\";\nimport { qualify, type Manifest } from \"../manifest/types.js\";\nimport { createRouter, type Router } from \"./routing.js\";\nimport {\n observeState,\n planInverse,\n isDisconnected,\n mayHaveArrived,\n planRead,\n refusal,\n runRead,\n toPayload,\n type ResolvedRead,\n} from \"./snapshot.js\";\nimport type { Upstream } from \"./upstream.js\";\n\nexport interface ProxyOptions {\n readonly upstreams: readonly Upstream[];\n readonly manifest: Manifest;\n readonly journal: Journal;\n /** Defaults to out-of-band approval through the journal. */\n readonly gate?: Gate;\n readonly gateTimeoutMs?: number;\n readonly logger?: Logger;\n /** Builds the exact command a person here would run to approve an action. */\n readonly approveHint?: ApproveHint;\n}\n\nexport interface ProxyServer {\n readonly server: McpServer;\n /** Resolves with the run id once the client session is initialized. */\n readonly ready: Promise<string>;\n /** Resolves when no tool call is in flight, so shutdown can drain first. */\n whenIdle(): Promise<void>;\n /** The open run, once the session has initialized. */\n readonly runId: string | undefined;\n /** Whether any forwarded request is currently in flight. */\n busy(): boolean;\n}\n\ntype Passthrough = { [key: string]: unknown };\n\n/**\n * How long an approval stays usable. Long enough to survive a client restart\n * and a person walking away from their desk, short enough that a decision made\n * this morning cannot quietly authorise the same call tomorrow.\n */\nconst APPROVAL_WINDOW_MS = 60 * 60 * 1000;\n\n/**\n * Results are read through loose schemas. The SDK's typed schemas strip fields\n * they do not know about, which would quietly erase any metadata an upstream\n * added; only the names this proxy has to rewrite are described here.\n */\nconst PassthroughResult = z.looseObject({});\nconst ToolList = z.looseObject({\n tools: z.array(z.looseObject({ name: z.string() })),\n nextCursor: z.string().optional(),\n});\nconst PromptList = z.looseObject({\n prompts: z.array(z.looseObject({ name: z.string() })),\n nextCursor: z.string().optional(),\n});\nconst ResourceList = z.looseObject({\n resources: z.array(z.looseObject({ uri: z.string() })),\n nextCursor: z.string().optional(),\n});\nconst TemplateList = z.looseObject({\n resourceTemplates: z.array(z.looseObject({ uriTemplate: z.string() })),\n nextCursor: z.string().optional(),\n});\n\nfunction unwrap(error: McpError): string {\n const prefix = `MCP error ${String(error.code)}: `;\n return error.message.startsWith(prefix)\n ? error.message.slice(prefix.length)\n : error.message;\n}\n\nfunction rethrow(server: string, operation: string, error: unknown): never {\n if (error instanceof McpError) {\n throw new McpError(error.code, unwrap(error), error.data);\n }\n throw new UpstreamError(server, operation, error);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * The client sees one logical server, so it must be told about anything any\n * upstream can do. Sub-objects are merged rather than replaced so that, for\n * example, one server's resources.subscribe survives another's resources {}.\n */\nfunction mergeCapabilities(\n all: readonly ServerCapabilities[],\n): ServerCapabilities {\n const merged: Record<string, unknown> = {};\n for (const capabilities of all) {\n for (const [key, value] of Object.entries(capabilities)) {\n const existing = merged[key];\n merged[key] =\n isRecord(existing) && isRecord(value)\n ? { ...existing, ...value }\n : value;\n }\n }\n return merged;\n}\n\nfunction identityFor(router: Router): Implementation {\n const only = router.upstreams[0];\n if (!router.prefixed && only !== undefined) {\n const upstream = only.client.getServerVersion();\n if (upstream !== undefined) {\n return upstream;\n }\n }\n // With several servers behind it there is no single identity to mirror.\n return { name: \"synartesis\", version: \"0.0.0\" };\n}\n\n/**\n * Told to the agent at connect time. Without it a gated call is just an opaque\n * failure, and the person watching has no idea why their agent stopped or what\n * they are supposed to do about it. With it, the agent explains itself.\n */\nconst SYNARTESIS_INSTRUCTIONS = [\n \"These tools are guarded by Synartesis, which records every change so it can be undone later.\",\n \"\",\n \"Some actions cannot be undone. Those are held until a person approves them, and the call\",\n \"will fail with a message beginning \\\"Synartesis is holding this call for approval\\\".\",\n \"When that happens:\",\n \" 1. Tell the user plainly that you are asking Synartesis for approval, and what for.\",\n \" 2. Give them the exact `synartesis approve ...` command from the error.\",\n \" 3. Once they say they have approved it, make the same call again. It will go through.\",\n \"Do not try to work around a held call by using a different tool to achieve the same thing.\",\n].join(\"\\n\");\n\nfunction instructionsFor(router: Router): string {\n const sections = router.upstreams\n .map((upstream) => ({\n name: upstream.name,\n text: upstream.client.getInstructions(),\n }))\n .filter(\n (section): section is { name: string; text: string } => section.text !== undefined,\n );\n\n const upstream = router.prefixed\n ? sections.map((section) => `Tools prefixed ${section.name}__:\\n${section.text}`).join(\"\\n\\n\")\n : (sections[0]?.text ?? \"\");\n\n return upstream === \"\" ? SYNARTESIS_INSTRUCTIONS : `${SYNARTESIS_INSTRUCTIONS}\\n\\n${upstream}`;\n}\n\n/** Walks every page so that aggregation across servers is never partial. */\nasync function drain<T>(\n fetch: (\n cursor: string | undefined,\n ) => Promise<{ items: T[]; nextCursor: string | undefined }>,\n): Promise<T[]> {\n const collected: T[] = [];\n let cursor: string | undefined;\n do {\n const page = await fetch(cursor);\n collected.push(...page.items);\n cursor = page.nextCursor;\n } while (cursor !== undefined);\n return collected;\n}\n\nexport function createProxyServer(options: ProxyOptions): ProxyServer {\n const { upstreams, manifest, journal } = options;\n const router = createRouter(upstreams, manifest);\n const policies: PolicyResolver = createPolicyResolver(manifest);\n\n const log = options.logger;\n\n const gate = options.gate ?? createRetryGate(journal, options.approveHint);\n\n const capabilities = mergeCapabilities(\n upstreams.map((upstream) => upstream.client.getServerCapabilities() ?? {}),\n );\n const instructions = instructionsFor(router);\n\n const wrapper = new McpServer(identityFor(router), { capabilities, instructions });\n const server = wrapper.server;\n\n let runId: string | undefined;\n let resolveReady: (id: string) => void = () => undefined;\n const ready = new Promise<string>((resolve) => {\n resolveReady = resolve;\n });\n\n let inflight = 0;\n const idle: (() => void)[] = [];\n const enter = (): void => {\n inflight += 1;\n };\n /**\n * Every decrement goes through here, including the one that parks a call at\n * the gate. A decrement that reached zero without waking the waiters would\n * leave a shutdown draining for ever against a counter that is already idle.\n */\n const leave = (): void => {\n inflight -= 1;\n if (inflight === 0) {\n for (const resolve of idle.splice(0)) {\n resolve();\n }\n }\n };\n const whenIdle = async (): Promise<void> => {\n if (inflight === 0) {\n return;\n }\n await new Promise<void>((resolve) => idle.push(resolve));\n };\n\n // A client that pipelines notifications/initialized ahead of the initialize\n // response can reach oninitialized before its own identity is recorded, so\n // the label is filled in at the first opportunity rather than once.\n let labelled = false;\n const ensureLabel = (): void => {\n if (labelled || runId === undefined) {\n return;\n }\n const name = server.getClientVersion()?.name;\n if (name !== undefined) {\n journal.setRunLabel(runId, name);\n labelled = true;\n }\n };\n\n const supports = (\n upstream: Upstream,\n key: keyof ServerCapabilities,\n ): boolean => upstream.client.getServerCapabilities()?.[key] !== undefined;\n\n const ask = async (\n upstream: Upstream,\n request: Request,\n signal: AbortSignal,\n ): Promise<Passthrough> => {\n try {\n return await upstream.client.request(request, PassthroughResult, {\n signal,\n });\n } catch (error: unknown) {\n return rethrow(upstream.name, request.method, error);\n }\n };\n\n // --- resource ownership -------------------------------------------------\n // A resource uri is an opaque identifier the client hands back verbatim, so\n // unlike a tool name it cannot be namespaced. Ownership therefore has to be\n // discovered from what each server advertises.\n let owners: Map<string, string> | undefined;\n let schemes: Map<string, string> | undefined;\n let conflict: string | undefined;\n\n const refreshResources = async (signal: AbortSignal): Promise<void> => {\n const nextOwners = new Map<string, string>();\n const nextSchemes = new Map<string, string>();\n let nextConflict: string | undefined;\n\n for (const upstream of router.upstreams) {\n if (!supports(upstream, \"resources\")) {\n continue;\n }\n const resources = await drain(async (cursor) => {\n const raw = await ask(\n upstream,\n {\n method: \"resources/list\",\n params: cursor === undefined ? {} : { cursor },\n },\n signal,\n );\n const page = ResourceList.parse(raw);\n return { items: page.resources, nextCursor: page.nextCursor };\n });\n for (const resource of resources) {\n const existing = nextOwners.get(resource.uri);\n if (existing !== undefined && existing !== upstream.name) {\n nextConflict ??= `resource ${resource.uri} is advertised by both ${existing} and ${upstream.name}; a uri cannot be namespaced, so one of them must stop exposing it`;\n }\n nextOwners.set(resource.uri, existing ?? upstream.name);\n const scheme = resource.uri.split(\":\")[0] ?? \"\";\n if (scheme !== \"\" && !nextSchemes.has(scheme)) {\n nextSchemes.set(scheme, upstream.name);\n }\n }\n\n const templates = await drain(async (cursor) => {\n const raw = await ask(\n upstream,\n {\n method: \"resources/templates/list\",\n params: cursor === undefined ? {} : { cursor },\n },\n signal,\n );\n const page = TemplateList.parse(raw);\n return { items: page.resourceTemplates, nextCursor: page.nextCursor };\n });\n for (const template of templates) {\n const scheme = template.uriTemplate.split(\":\")[0] ?? \"\";\n if (scheme !== \"\" && !nextSchemes.has(scheme)) {\n nextSchemes.set(scheme, upstream.name);\n }\n }\n }\n\n owners = nextOwners;\n schemes = nextSchemes;\n conflict = nextConflict;\n };\n\n const ensureResources = async (signal: AbortSignal): Promise<void> => {\n if (owners === undefined) {\n await refreshResources(signal);\n }\n if (conflict !== undefined) {\n throw new McpError(ErrorCode.InternalError, conflict);\n }\n };\n\n const ownerOf = async (\n uri: string,\n signal: AbortSignal,\n ): Promise<Upstream> => {\n await ensureResources(signal);\n const direct = owners?.get(uri);\n const scheme = uri.split(\":\")[0] ?? \"\";\n const name = direct ?? schemes?.get(scheme);\n const upstream = name === undefined ? undefined : router.byName(name);\n if (upstream === undefined) {\n throw new McpError(\n ErrorCode.InvalidParams,\n `no configured server provides ${uri}`,\n );\n }\n return upstream;\n };\n\n // --- handlers -----------------------------------------------------------\n if (capabilities.tools !== undefined) {\n server.setRequestHandler(\n ListToolsRequestSchema,\n async (_request, extra) => {\n const tools: Passthrough[] = [];\n for (const upstream of router.upstreams) {\n if (!supports(upstream, \"tools\")) {\n continue;\n }\n const items = await drain(async (cursor) => {\n const raw = await ask(\n upstream,\n {\n method: \"tools/list\",\n params: cursor === undefined ? {} : { cursor },\n },\n extra.signal,\n );\n const page = ToolList.parse(raw);\n return { items: page.tools, nextCursor: page.nextCursor };\n });\n for (const tool of items) {\n tools.push({\n ...tool,\n name: router.expose(upstream.name, tool.name),\n });\n }\n }\n // Pagination is flattened: a cursor would have to encode a position\n // across several independent servers, and the client gains nothing.\n return { tools };\n },\n );\n\n server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {\n if (runId === undefined) {\n throw new UpstreamError(\"proxy\", \"tools/call\", \"no active run\");\n }\n // Captured: narrowing does not survive into the closures below.\n const activeRun = runId;\n ensureLabel();\n const route = router.route(request.params.name);\n if (route === undefined) {\n throw new McpError(\n ErrorCode.InvalidParams,\n `no configured server provides tool ${request.params.name}`,\n );\n }\n\n const { policy } = policies.resolve(qualify(route.upstream.name, route.tool));\n const args = request.params.arguments ?? {};\n // Counted from here, not from the forward call: the pre-read is part of\n // the action, and a shutdown that aborts it blocks a legitimate write.\n enter();\n try {\n const wantsGate =\n policy.gate === \"always\" || (policy.gate === \"on_write\" && shouldGateOnWrite(args));\n\n // A retry after an out-of-band approval reuses the row that was\n // approved, so the approval ends up on the action that actually ran\n // rather than on an abandoned twin of it.\n const granted = wantsGate\n ? journal.findApproval({\n server: route.upstream.name,\n tool: route.tool,\n args,\n notBefore: new Date(Date.now() - APPROVAL_WINDOW_MS).toISOString(),\n })\n : undefined;\n\n // An approval granted in an earlier session cannot simply be adopted:\n // the action belongs to the run happening now, or undoing this run\n // would not include it.\n const inherited =\n granted !== undefined && granted.runId !== activeRun ? granted : undefined;\n\n // Nobody has answered yet and the agent is asking again. Reusing the\n // row it is already waiting on keeps one call to one decision, which\n // is what `synartesis gates` and `approve` both assume.\n const waiting =\n granted === undefined && wantsGate\n ? journal.findGated({\n runId: activeRun,\n server: route.upstream.name,\n tool: route.tool,\n args,\n })\n : undefined;\n\n const reusable = waiting ?? (inherited === undefined ? granted : undefined);\n const pending =\n reusable === undefined\n ? journal.recordPending({\n runId: activeRun,\n server: route.upstream.name,\n tool: route.tool,\n args,\n class: policy.class,\n })\n : {\n actionId: reusable.id,\n seq: reusable.seq,\n idempotencyKey: reusable.idempotencyKey,\n };\n\n if (inherited !== undefined) {\n journal.adoptApproval(pending.actionId, inherited);\n } else if (granted !== undefined && waiting === undefined) {\n // Reusing the approved row itself: from here its outcome stops being\n // known, so it stops being `approved`.\n journal.markInFlight(granted.id);\n }\n if (granted !== undefined) {\n log?.info(\n { action: pending.actionId, by: granted.approvedBy, from: granted.runId },\n \"proceeding on a standing approval\",\n );\n }\n\n const decide = async (why: string): Promise<void> => {\n // Parked, not working: a suspended call must not hold up shutdown,\n // and the drain exists to let real work finish.\n leave();\n let decision;\n try {\n decision = await gate.decide({\n actionId: pending.actionId,\n runId: activeRun,\n seq: pending.seq,\n server: route.upstream.name,\n tool: route.tool,\n args,\n why,\n signal: extra.signal,\n });\n } finally {\n enter();\n }\n log?.info(\n { action: pending.actionId, approved: decision.approved },\n decision.approved ? \"approved\" : \"denied\",\n );\n // An approval that lands after the client has given up would send\n // a real email that the agent has already reported as not sent.\n // Nobody is waiting for the result, so the safe reading of an\n // approval nobody can hear is that it did not happen.\n if (decision.approved && extra.signal.aborted) {\n journal.settleAsDenied(\n pending.actionId,\n decision.by,\n \"approved, but the client had already stopped waiting, so it was not sent\",\n );\n throw new McpError(\n ErrorCode.InvalidRequest,\n `synartesis blocked ${request.params.name}: it was approved after the client stopped waiting, so it was not sent. Ask the agent to try again.`,\n );\n }\n if (!decision.approved) {\n if (decision.awaiting === true) {\n log?.warn(\n {\n action: pending.actionId,\n tool: `${route.upstream.name}.${route.tool}`,\n approve: options.approveHint?.(pending.actionId) ?? pending.actionId,\n },\n \"awaiting approval\",\n );\n throw new McpError(\n ErrorCode.InvalidRequest,\n `Synartesis is holding this call for approval, because ${why}. ${decision.reason}`,\n );\n }\n const who = decision.by === undefined ? \"\" : ` by ${decision.by}`;\n throw new McpError(\n ErrorCode.InvalidRequest,\n `synartesis blocked ${request.params.name}: ${why} and was denied${who}. ${decision.reason}`,\n );\n }\n };\n\n // D4/3.4: a policy gate suspends before anything is read or written, so\n // a gated action never even looks at the resource.\n // decide() throws on refusal, so getting past this means approved.\n const askedAlready = wantsGate;\n if (wantsGate && granted === undefined) {\n await decide(\"this action cannot be undone\");\n }\n\n // The pre-read happens before the write goes out, and a failure stops\n // the write entirely: a reversible action without a snapshot is\n // silently irreversible, which is worse than the action not happening.\n let snapshot: unknown;\n let verify: ResolvedRead | undefined;\n let missingPriorState: string | undefined;\n if (policy.snapshot !== undefined) {\n try {\n verify = planRead(policy.snapshot, { args });\n snapshot = await runRead(router, verify, extra.signal);\n journal.attachSnapshot(pending.actionId, snapshot);\n } catch (error: unknown) {\n const reason = describe(error);\n if (error instanceof SnapshotError && error.absent) {\n // Nothing exists here yet, so this call creates rather than\n // replaces and there is nothing to put back. It is an\n // irreversible action wearing a reversible policy. Refusing\n // outright would mean an agent could never create anything, so\n // it falls through to the same question the gate asks.\n missingPriorState = reason;\n verify = undefined;\n } else {\n journal.markFailed(pending.actionId, reason);\n log?.error(\n { seq: pending.seq, tool: route.tool, reason },\n \"write blocked: snapshot failed\",\n );\n throw new McpError(\n ErrorCode.InternalError,\n `synartesis blocked ${request.params.name}: ${reason}`,\n );\n }\n }\n }\n\n if (missingPriorState !== undefined && !askedAlready) {\n // An approval granted out of band counts here too. It was only ever\n // looked up for a policy that asked to be gated, so a write whose\n // prior state was missing -- an agent creating a file, the commonest\n // thing an agent does -- asked, was approved, and asked again, and\n // no number of approvals ever let it through. The instructions this\n // proxy sends to every agent promise the opposite.\n const standing = journal.findApproval({\n server: route.upstream.name,\n tool: route.tool,\n args,\n notBefore: new Date(Date.now() - APPROVAL_WINDOW_MS).toISOString(),\n });\n if (standing === undefined) {\n // Not \"nothing exists here\": every tool-level error on a pre-read\n // arrives here, so a file that exists and merely could not be read\n // came out as one that was not there. The person approving an\n // unundoable write was shown absence and given no way to learn\n // otherwise until after they had allowed it. Say what happened and\n // hand over the server's own words.\n await decide(\n `nothing was captured to restore, so this cannot be undone — the read said: ${missingPriorState}`,\n );\n } else {\n // Moved onto the row that actually runs, which also spends it: an\n // approval answers one call, not every call that looks like it.\n journal.adoptApproval(pending.actionId, standing);\n log?.info(\n { action: pending.actionId, by: standing.approvedBy, from: standing.runId },\n \"proceeding on a standing approval\",\n );\n }\n }\n\n const forwarded: Request = {\n method: \"tools/call\",\n params: { ...request.params, name: route.tool },\n };\n\n try {\n const result = await route.upstream.client.request(forwarded, PassthroughResult, {\n signal: extra.signal,\n });\n\n // The server understood the call and did not do it. Recording that\n // as an action would be worse than not recording it at all: an\n // inverse resolved from a refusal is a compensating call for\n // something that never happened, and undo would faithfully carry it\n // out. The agent still sees the refusal exactly as sent.\n const refused = refusal(result);\n if (refused !== undefined) {\n journal.markFailed(pending.actionId, `the upstream refused the call: ${refused}`);\n log?.debug(\n { seq: pending.seq, tool: route.tool, reason: refused },\n \"refused by the upstream\",\n );\n return result;\n }\n\n const context = { args, snapshot, result: toPayload(result) };\n const warnings: string[] = [];\n if (missingPriorState !== undefined) {\n warnings.push(\n `no prior state existed, so there is nothing to restore: ${missingPriorState}`,\n );\n }\n\n // Resolved now rather than at rollback time (D5).\n let inverse: unknown;\n if (policy.inverse !== undefined && missingPriorState === undefined) {\n try {\n inverse = planInverse(policy.inverse, context);\n } catch (error: unknown) {\n warnings.push(`inverse could not be resolved: ${describe(error)}`);\n }\n }\n\n // Best effort: the write has already applied, so a failed post-read\n // cannot undo it. Phase 4 fails closed when the post-state is\n // missing. A resource that is now absent is a captured post-state,\n // not a missing one.\n let postSnapshot: unknown;\n if (verify !== undefined) {\n try {\n postSnapshot = await observeState(router, verify, extra.signal);\n } catch (error: unknown) {\n warnings.push(`post-state could not be captured: ${describe(error)}`);\n }\n }\n\n if (warnings.length > 0) {\n log?.warn({ seq: pending.seq, tool: route.tool, warnings }, \"applied with reservations\");\n }\n log?.debug(\n { seq: pending.seq, server: route.upstream.name, tool: route.tool, class: policy.class },\n \"applied\",\n );\n journal.markApplied(pending.actionId, {\n result,\n ...(inverse === undefined ? {} : { inverse }),\n ...(verify === undefined ? {} : { verify }),\n ...(postSnapshot === undefined ? {} : { postSnapshot }),\n ...(warnings.length === 0 ? {} : { warning: warnings.join(\"; \") }),\n });\n return result;\n } catch (error: unknown) {\n const disconnected = isDisconnected(error);\n if (extra.signal.aborted || mayHaveArrived(error)) {\n // A transport that closed while a reply was still owed says\n // nothing about whether the call arrived. Recording that as failed\n // asserts it did not, and undo would then step over an action that\n // may well have applied. Having had no connection to write to at\n // all is the other case, and that one really did not happen.\n journal.markUnknown(pending.actionId, describe(error));\n } else {\n journal.markFailed(pending.actionId, describe(error));\n }\n if (disconnected && route.upstream.reconnect !== undefined) {\n // Not to retry this call -- a write must never be sent twice on a\n // guess -- but so the rest of the session is not lost with it.\n await route.upstream.reconnect().catch(() => undefined);\n }\n return rethrow(route.upstream.name, \"tools/call\", error);\n }\n } finally {\n leave();\n }\n });\n }\n\n if (capabilities.resources !== undefined) {\n server.setRequestHandler(\n ListResourcesRequestSchema,\n async (_request, extra) => {\n await refreshResources(extra.signal);\n await ensureResources(extra.signal);\n const resources: Passthrough[] = [];\n for (const upstream of router.upstreams) {\n if (!supports(upstream, \"resources\")) {\n continue;\n }\n const items = await drain(async (cursor) => {\n const raw = await ask(\n upstream,\n {\n method: \"resources/list\",\n params: cursor === undefined ? {} : { cursor },\n },\n extra.signal,\n );\n const page = ResourceList.parse(raw);\n return { items: page.resources, nextCursor: page.nextCursor };\n });\n resources.push(...items);\n }\n return { resources };\n },\n );\n\n server.setRequestHandler(\n ListResourceTemplatesRequestSchema,\n async (_request, extra) => {\n const resourceTemplates: Passthrough[] = [];\n for (const upstream of router.upstreams) {\n if (!supports(upstream, \"resources\")) {\n continue;\n }\n const items = await drain(async (cursor) => {\n const raw = await ask(\n upstream,\n {\n method: \"resources/templates/list\",\n params: cursor === undefined ? {} : { cursor },\n },\n extra.signal,\n );\n const page = TemplateList.parse(raw);\n return {\n items: page.resourceTemplates,\n nextCursor: page.nextCursor,\n };\n });\n resourceTemplates.push(...items);\n }\n return { resourceTemplates };\n },\n );\n\n server.setRequestHandler(\n ReadResourceRequestSchema,\n async (request, extra) => {\n const upstream = await ownerOf(request.params.uri, extra.signal);\n return ask(upstream, request, extra.signal);\n },\n );\n\n if (capabilities.resources.subscribe === true) {\n for (const schema of [SubscribeRequestSchema, UnsubscribeRequestSchema]) {\n server.setRequestHandler(schema, async (request, extra) => {\n const upstream = await ownerOf(request.params.uri, extra.signal);\n return ask(upstream, request, extra.signal);\n });\n }\n }\n }\n\n if (capabilities.prompts !== undefined) {\n server.setRequestHandler(\n ListPromptsRequestSchema,\n async (_request, extra) => {\n const prompts: Passthrough[] = [];\n for (const upstream of router.upstreams) {\n if (!supports(upstream, \"prompts\")) {\n continue;\n }\n const items = await drain(async (cursor) => {\n const raw = await ask(\n upstream,\n {\n method: \"prompts/list\",\n params: cursor === undefined ? {} : { cursor },\n },\n extra.signal,\n );\n const page = PromptList.parse(raw);\n return { items: page.prompts, nextCursor: page.nextCursor };\n });\n for (const prompt of items) {\n prompts.push({\n ...prompt,\n name: router.expose(upstream.name, prompt.name),\n });\n }\n }\n return { prompts };\n },\n );\n\n server.setRequestHandler(GetPromptRequestSchema, async (request, extra) => {\n const route = router.route(request.params.name);\n if (route === undefined) {\n throw new McpError(\n ErrorCode.InvalidParams,\n `no configured server provides prompt ${request.params.name}`,\n );\n }\n return ask(\n route.upstream,\n {\n method: \"prompts/get\",\n params: { ...request.params, name: route.tool },\n },\n extra.signal,\n );\n });\n }\n\n if (capabilities.completions !== undefined) {\n server.setRequestHandler(CompleteRequestSchema, async (request, extra) => {\n const reference = request.params.ref;\n if (reference.type === \"ref/prompt\") {\n const route = router.route(reference.name);\n if (route === undefined) {\n throw new McpError(\n ErrorCode.InvalidParams,\n `unknown prompt ${reference.name}`,\n );\n }\n return ask(\n route.upstream,\n {\n method: \"completion/complete\",\n params: {\n ...request.params,\n ref: { ...reference, name: route.tool },\n },\n },\n extra.signal,\n );\n }\n const upstream = await ownerOf(reference.uri, extra.signal);\n return ask(upstream, request, extra.signal);\n });\n }\n\n if (capabilities.logging !== undefined) {\n server.setRequestHandler(SetLevelRequestSchema, async (request, extra) => {\n // Broadcast: the client is configuring one logical server.\n for (const upstream of router.upstreams) {\n if (supports(upstream, \"logging\")) {\n await ask(upstream, request, extra.signal);\n }\n }\n return {};\n });\n }\n\n // --- lifecycle ----------------------------------------------------------\n let connected = false;\n for (const upstream of router.upstreams) {\n upstream.client.fallbackNotificationHandler = async (\n notification,\n ): Promise<void> => {\n if (notification.method.endsWith(\"list_changed\")) {\n owners = undefined;\n schemes = undefined;\n conflict = undefined;\n }\n if (connected) {\n await server.notification(notification);\n }\n };\n }\n\n server.oninitialized = (): void => {\n connected = true;\n const name = server.getClientVersion()?.name;\n const id = journal.beginRun(name);\n runId = id;\n labelled = name !== undefined;\n resolveReady(id);\n };\n\n const previousOnClose = server.onclose;\n server.onclose = (): void => {\n connected = false;\n if (runId !== undefined) {\n journal.endRun(runId, \"complete\");\n runId = undefined;\n }\n previousOnClose?.();\n };\n\n return {\n server: wrapper,\n ready,\n whenIdle,\n busy: (): boolean => inflight > 0,\n get runId(): string | undefined {\n return runId;\n },\n };\n}\n","/**\n * The `on_write` heuristic for tools whose destructiveness cannot be decided\n * statically, such as a raw SQL runner.\n *\n * This is a heuristic and is documented as one. It exists because the\n * alternative for `postgres.query` is to gate every SELECT, which no operator\n * would tolerate for long. Anything it cannot confidently read as a read is\n * gated (D4): failing to recognise a statement is not evidence that it is safe.\n * `always` remains the correct choice wherever certainty matters.\n */\nconst READ_ONLY = /^(select|with|show|explain|describe|desc|values|table)\\b/;\n\nfunction isReadOnlyStatement(text: string): boolean {\n const stripped = text\n .replace(/--[^\\n]*/g, \" \")\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, \" \")\n .trim();\n if (!READ_ONLY.test(stripped.toLowerCase())) {\n return false;\n }\n // More than one statement means the leading SELECT says nothing about what\n // follows it.\n return stripped.replace(/;\\s*$/, \"\").indexOf(\";\") === -1;\n}\n\nexport function shouldGateOnWrite(args: unknown): boolean {\n if (typeof args !== \"object\" || args === null) {\n return true;\n }\n const strings = Object.values(args).filter(\n (value): value is string => typeof value === \"string\",\n );\n if (strings.length === 0) {\n return true;\n }\n return !strings.every(isReadOnlyStatement);\n}\n"],"mappings":"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","names":["resolve","upstream","resolve","resolve"]}
|
|
1
|
+
{"version":3,"sources":["../src/proxy/stdio.ts","../src/proxy/http.ts","../src/gate/gate.ts","../src/logging.ts","../src/proxy/proxy.ts","../src/gate/heuristic.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * better-sqlite3 requires Node 22, and on Node 20 it does not fail politely:\n * it segfaults the moment a database is opened. Saying so is better than\n * letting somebody meet exit code 139.\n */\nconst NODE_MAJOR = Number(process.versions.node.split(\".\")[0]);\nif (NODE_MAJOR < 22) {\n process.stderr.write(\n `synartesis: needs Node 22 or newer, and this is ${process.version}.\\n`,\n );\n process.exit(2);\n}\n\nimport { resolve } from \"node:path\";\n\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\n\nimport { serveHttp } from \"./http.js\";\n\nimport { describe } from \"../errors.js\";\nimport { DEFAULT_GATE_TIMEOUT_MS } from \"../gate/gate.js\";\nimport { cliCommandFrom } from \"../invocation.js\";\nimport { findJournal, findManifest } from \"../locate.js\";\nimport { createLogger, isLogLevel, LOG_LEVELS, type LogLevel } from \"../logging.js\";\nimport { mark } from \"../style.js\";\nimport { openJournal } from \"../journal/journal.js\";\nimport { loadManifest } from \"../manifest/load.js\";\nimport { verifyAgainstServers } from \"../manifest/verify.js\";\nimport { createProxyServer } from \"./proxy.js\";\nimport { connectStdioUpstream, type Upstream } from \"./upstream.js\";\n\n/**\n * The manifest is the configuration (D3): it already declares every server and\n * how to start it, so there is nothing left for flags to say.\n *\n * synartesis-proxy [--manifest synartesis.yaml] [--journal .synartesis/journal.db]\n * [--gate-timeout <seconds>] [--log-level <level>]\n */\ninterface Argv {\n readonly manifest: string;\n readonly journal: string;\n readonly gateTimeoutMs: number;\n /** Whether --gate-timeout was actually typed, as against defaulted. */\n readonly gateTimeoutGiven: boolean;\n /** Serve over http instead of stdio, for a client that will not start one. */\n readonly http?: {\n readonly port: number;\n readonly host: string;\n readonly token: string;\n readonly idleSeconds: number;\n };\n readonly logLevel: LogLevel;\n}\n\nfunction parseArgv(argv: readonly string[]): Argv {\n const read = (flag: string): string | undefined => {\n const at = argv.indexOf(flag);\n return at === -1 ? undefined : argv[at + 1];\n };\n const known = [\"--manifest\", \"--journal\", \"--gate-timeout\", \"--log-level\", \"--http\", \"--http-host\", \"--http-idle\", \"--token\"];\n const unknown = argv.find((token) => token.startsWith(\"--\") && !known.includes(token));\n if (unknown !== undefined) {\n throw new Error(`unknown flag ${unknown}; expected one of ${known.join(\", \")}`);\n }\n\n const rawTimeout = read(\"--gate-timeout\");\n const seconds = rawTimeout === undefined ? undefined : Number(rawTimeout);\n if (seconds !== undefined && (!Number.isFinite(seconds) || seconds <= 0)) {\n throw new Error(\"--gate-timeout needs a positive number of seconds\");\n }\n\n const level = read(\"--log-level\") ?? \"info\";\n if (!isLogLevel(level)) {\n throw new Error(`--log-level must be one of ${LOG_LEVELS.join(\", \")}`);\n }\n\n const httpPort = read(\"--http\");\n let http: Argv[\"http\"];\n if (httpPort !== undefined) {\n const port = Number(httpPort);\n if (!Number.isInteger(port) || port < 1 || port > 65535) {\n throw new Error(\"--http needs a port number\");\n }\n // Refused rather than defaulted. What is served here can write through\n // every server in the policy, and a default of \"no auth\" is the kind of\n // convenience that ends up on someone's public tunnel.\n const token = read(\"--token\") ?? process.env[\"SYNARTESIS_TOKEN\"];\n if (token === undefined || token.length < 16) {\n throw new Error(\n \"--http needs --token, or SYNARTESIS_TOKEN, of at least 16 characters: this serves write access over a socket\",\n );\n }\n const rawIdle = read(\"--http-idle\");\n const idleSeconds = rawIdle === undefined ? 1800 : Number(rawIdle);\n if (!Number.isFinite(idleSeconds) || idleSeconds <= 0) {\n throw new Error(\"--http-idle needs a positive number of seconds\");\n }\n http = { port, host: read(\"--http-host\") ?? \"127.0.0.1\", token, idleSeconds };\n }\n\n const manifest = findManifest(read(\"--manifest\"));\n return {\n manifest,\n journal: findJournal(read(\"--journal\"), manifest),\n gateTimeoutMs: seconds === undefined ? DEFAULT_GATE_TIMEOUT_MS : seconds * 1000,\n gateTimeoutGiven: seconds !== undefined,\n ...(http === undefined ? {} : { http }),\n logLevel: level,\n };\n}\n\nasync function main(): Promise<void> {\n const argv = parseArgv(process.argv.slice(2));\n const log = createLogger(argv.logLevel);\n if (argv.gateTimeoutGiven) {\n // Accepted, validated, threaded through, and read by nothing: this proxy\n // refuses a held call straight away rather than holding the connection\n // open, so there is no wait for a timeout to cut short. Saying so is\n // better than a flag that quietly does nothing, and better than rejecting\n // one that earlier versions took.\n log.warn(\n \"--gate-timeout has no effect: a held call is refused immediately and the agent makes it again once you approve\",\n );\n }\n // Only on a real terminal. A client collecting our stderr into a log file\n // wants the structured records and nothing else.\n if (process.stderr.isTTY) {\n process.stderr.write(mark());\n }\n // Loaded before anything is spawned: never start with a broken policy.\n const manifest = loadManifest(argv.manifest);\n const journal = openJournal(argv.journal);\n\n const upstreams: Upstream[] = [];\n for (const [name, spec] of Object.entries(manifest.servers)) {\n upstreams.push(\n await connectStdioUpstream({\n name,\n command: spec.command,\n args: spec.args,\n ...(spec.env === undefined ? {} : { env: spec.env }),\n }),\n );\n }\n\n // Never serve a request under a policy that calls tools the servers do not\n // have: at run time that is indistinguishable from a missing resource.\n await verifyAgainstServers(upstreams, manifest);\n\n log.info(\n {\n manifest: argv.manifest,\n journal: argv.journal,\n servers: upstreams.map((upstream) => upstream.name),\n policies: manifest.tools.length,\n },\n \"proxy ready\",\n );\n\n const build = (): ReturnType<typeof createProxyServer> =>\n createProxyServer({\n upstreams,\n manifest,\n journal,\n gateTimeoutMs: argv.gateTimeoutMs,\n logger: log,\n // Absolute, because whoever approves may be in any directory at all.\n approveHint: (actionId: string): string =>\n `${cliCommandFrom(import.meta.url)} approve ${actionId.slice(0, 8)} --journal ${resolve(argv.journal)}`,\n });\n\n if (argv.http !== undefined) {\n // One server, many sessions. Each session is a connection and a connection\n // is a run, so each gets a proxy of its own; the upstreams and the journal\n // are shared, which is what makes them one story.\n const served = await serveHttp({\n ...argv.http,\n create: build,\n log: {\n info: (data, message) => {\n log.info(data, message);\n },\n warn: (message) => {\n log.warn(message);\n },\n },\n });\n const stop = (): void => {\n void (async (): Promise<void> => {\n await served.close();\n for (const upstream of upstreams) {\n await upstream.close();\n }\n journal.close();\n process.exit(0);\n })();\n };\n process.on(\"SIGINT\", stop);\n process.on(\"SIGTERM\", stop);\n return;\n }\n\n const proxy = build();\n\n let shuttingDown = false;\n const shutdown = (code: number): void => {\n if (shuttingDown) {\n return;\n }\n shuttingDown = true;\n void (async (): Promise<void> => {\n // Let in-flight calls settle before tearing the connection down. An\n // aborted write leaves the journal unable to say whether it applied.\n await Promise.race([\n proxy.whenIdle(),\n new Promise<void>((resolve) => setTimeout(resolve, 5000).unref()),\n ]);\n await proxy.server.close();\n for (const upstream of upstreams) {\n await upstream.close();\n }\n journal.close();\n process.exit(code);\n })();\n };\n\n process.on(\"SIGINT\", () => {\n shutdown(0);\n });\n process.on(\"SIGTERM\", () => {\n shutdown(0);\n });\n\n // StdioServerTransport only reports a close that we initiate; it never\n // reacts to the parent closing the pipe. Without these listeners the proxy\n // survives its own client, holding every upstream child open until whoever\n // spawned us escalates to a signal.\n // The pipe closing means no more requests are coming, not that the ones\n // already delivered can be dropped. The transport hands only a few buffered\n // frames to handlers per turn of the event loop, so wait until the proxy has\n // been quiet for several consecutive turns rather than yielding a fixed\n // number of times, which is guesswork. The cap stops a wedged upstream from\n // holding the process open.\n const pipeClosed = (): void => {\n const giveUpAt = Date.now() + 5000;\n let quiet = 0;\n const settle = (): void => {\n quiet = proxy.busy() ? 0 : quiet + 1;\n if (quiet >= 10 || Date.now() > giveUpAt) {\n shutdown(0);\n return;\n }\n setImmediate(settle);\n };\n setImmediate(settle);\n };\n process.stdin.on(\"end\", pipeClosed);\n process.stdin.on(\"close\", pipeClosed);\n\n const inner = proxy.server.server;\n const onclose = inner.onclose;\n inner.onclose = (): void => {\n onclose?.();\n shutdown(0);\n };\n\n await proxy.server.connect(new StdioServerTransport());\n}\n\ntry {\n await main();\n} catch (error: unknown) {\n // stdout carries protocol frames only; diagnostics must not corrupt it.\n process.stderr.write(`synartesis: ${describe(error)}\\n`);\n process.exit(1);\n}\n","import { createServer, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport { randomUUID, timingSafeEqual } from \"node:crypto\";\n\nimport { WebStandardStreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js\";\n\nimport type { ProxyServer } from \"./proxy.js\";\n\n/**\n * Serving the proxy over HTTP, for clients that will not start a process.\n *\n * ChatGPT's connectors are the reason this exists: they take a remote https\n * endpoint and nothing else, so stdio -- which every other client speaks -- is\n * not an option there.\n *\n * What is served is an undo layer with write access to real systems, so this\n * refuses to run without a token and binds to the loopback interface unless\n * told otherwise. Reaching it from the internet is a tunnel in front of it,\n * deliberately: that is a decision someone should have to make out loud.\n */\nexport interface HttpOptions {\n readonly port: number;\n readonly host: string;\n readonly token: string;\n /** Seconds a session may sit untouched before it is closed. */\n readonly idleSeconds: number;\n /** A fresh proxy per session, since a run belongs to one client's connection. */\n readonly create: () => ProxyServer;\n readonly log: {\n info: (data: Record<string, unknown>, message: string) => void;\n warn: (message: string) => void;\n };\n}\n\nexport interface HttpServer {\n readonly port: number;\n close(): Promise<void>;\n}\n\n\n/**\n * Node's request and response, in the shapes the sdk's transport speaks.\n *\n * The node-native transport in this sdk declares onclose as a getter/setter\n * pair typed `(() => void) | undefined`, which an exactOptionalPropertyTypes\n * project cannot accept without an assertion. The web-standard one declares it\n * plainly, so it is used instead and the twenty lines below are the price.\n */\nfunction toRequest(req: IncomingMessage, body: Buffer, origin: string): Request {\n const headers = new Headers();\n for (const [key, value] of Object.entries(req.headers)) {\n if (typeof value === \"string\") {\n headers.set(key, value);\n } else if (Array.isArray(value)) {\n for (const one of value) {\n headers.append(key, one);\n }\n }\n }\n const method = req.method ?? \"GET\";\n return new Request(new URL(req.url ?? \"/\", origin), {\n method,\n headers,\n // A GET or HEAD may not carry one, and node sends an empty buffer anyway.\n ...(method === \"GET\" || method === \"HEAD\" ? {} : { body }),\n });\n}\n\nasync function writeResponse(res: ServerResponse, response: Response): Promise<void> {\n const headers: Record<string, string> = {};\n response.headers.forEach((value, key) => {\n headers[key] = value;\n });\n res.writeHead(response.status, headers);\n if (response.body === null) {\n res.end();\n return;\n }\n // Streamed rather than buffered: this is how an SSE reply stays live.\n for await (const chunk of response.body) {\n res.write(Buffer.from(chunk));\n }\n res.end();\n}\n\n/** Constant time, so a wrong token cannot be found one character at a time. */\nfunction tokenMatches(given: string, expected: string): boolean {\n const a = Buffer.from(given);\n const b = Buffer.from(expected);\n return a.length === b.length && timingSafeEqual(a, b);\n}\n\nfunction bearer(req: IncomingMessage): string | undefined {\n const header = req.headers.authorization;\n if (typeof header !== \"string\") {\n return undefined;\n }\n const match = /^Bearer[ ]+(.+)$/i.exec(header.trim());\n return match?.[1];\n}\n\nfunction refuse(res: ServerResponse, status: number, message: string): void {\n res.writeHead(status, {\n \"content-type\": \"application/json\",\n // Told the same way twice: the header is what a client acts on, the body\n // is what a person reads in a terminal.\n ...(status === 401 ? { \"www-authenticate\": 'Bearer realm=\"synartesis\"' } : {}),\n });\n res.end(JSON.stringify({ error: message }));\n}\n\nasync function readRaw(req: IncomingMessage): Promise<Buffer> {\n const chunks: Buffer[] = [];\n let size = 0;\n for await (const chunk of req) {\n const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk));\n size += buffer.length;\n // A cap, because this listens on a socket: an unbounded body is a way to\n // exhaust memory without ever authenticating.\n if (size > 8 * 1024 * 1024) {\n throw new Error(\"request body too large\");\n }\n chunks.push(buffer);\n }\n return Buffer.concat(chunks);\n}\n\nfunction isInitialize(body: unknown): boolean {\n const one = (message: unknown): boolean =>\n typeof message === \"object\" &&\n message !== null &&\n \"method\" in message &&\n message.method === \"initialize\";\n return Array.isArray(body) ? body.some(one) : one(body);\n}\n\nexport async function serveHttp(options: HttpOptions): Promise<HttpServer> {\n interface Live {\n readonly transport: WebStandardStreamableHTTPServerTransport;\n readonly proxy: ProxyServer;\n lastSeen: number;\n }\n const sessions = new Map<string, Live>();\n\n // A client that drops without closing -- a network blip, a connector that\n // gives up -- used to leave its session, and the proxy and upstream handles\n // behind it, in this map for the life of the process. unref'd so an idle\n // server still exits when nothing else is holding it open.\n const sweep = setInterval(() => {\n const deadline = Date.now() - options.idleSeconds * 1000;\n for (const [id, live] of sessions) {\n if (live.lastSeen < deadline) {\n sessions.delete(id);\n options.log.info({ session: id }, \"http session swept after going quiet\");\n void live.transport.close().catch(() => undefined);\n }\n }\n }, Math.max(1000, (options.idleSeconds * 1000) / 4));\n sweep.unref();\n\n const server = createServer((req, res) => {\n void (async (): Promise<void> => {\n try {\n const token = bearer(req);\n if (token === undefined || !tokenMatches(token, options.token)) {\n // Before anything is parsed or routed. An unauthenticated request\n // must not be able to reach the proxy, the journal or an upstream.\n refuse(res, 401, \"a bearer token is required\");\n return;\n }\n if (req.url !== undefined && !req.url.startsWith(\"/mcp\")) {\n refuse(res, 404, \"the endpoint is /mcp\");\n return;\n }\n\n const origin = `http://${options.host}:${String(options.port)}`;\n const raw = await readRaw(req);\n const sessionId = req.headers[\"mcp-session-id\"];\n const existing = typeof sessionId === \"string\" ? sessions.get(sessionId) : undefined;\n if (existing !== undefined) {\n existing.lastSeen = Date.now();\n await writeResponse(res, await existing.transport.handleRequest(toRequest(req, raw, origin)));\n return;\n }\n\n const body: unknown =\n req.method === \"POST\" && raw.length > 0 ? JSON.parse(raw.toString(\"utf8\")) : undefined;\n if (req.method !== \"POST\" || !isInitialize(body)) {\n refuse(res, 400, \"no such session; start one with an initialize request\");\n return;\n }\n\n // A session is a connection, and a connection is a run: each one gets\n // its own proxy so its actions are journalled as one story.\n const proxy = options.create();\n const transport = new WebStandardStreamableHTTPServerTransport({\n sessionIdGenerator: () => randomUUID(),\n onsessioninitialized: (id: string) => {\n sessions.set(id, { transport, proxy, lastSeen: Date.now() });\n options.log.info({ session: id }, \"http session opened\");\n },\n });\n await proxy.server.connect(transport);\n transport.onclose = (): void => {\n const id = transport.sessionId;\n if (id !== undefined) {\n sessions.delete(id);\n }\n };\n await writeResponse(res, await transport.handleRequest(toRequest(req, raw, origin)));\n } catch (error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n if (!res.headersSent) {\n refuse(res, 400, message);\n } else {\n res.end();\n }\n }\n })();\n });\n\n await new Promise<void>((resolve) => {\n server.listen(options.port, options.host, resolve);\n });\n const address = server.address();\n const port = typeof address === \"object\" && address !== null ? address.port : options.port;\n\n if (options.host !== \"127.0.0.1\" && options.host !== \"localhost\") {\n options.log.warn(\n `listening on ${options.host}, which is not loopback: anything that can reach this port and holds the token can write through your servers`,\n );\n }\n options.log.info({ host: options.host, port, endpoint: \"/mcp\" }, \"http proxy ready\");\n\n return {\n port,\n close: async (): Promise<void> => {\n clearInterval(sweep);\n for (const { transport } of sessions.values()) {\n await transport.close().catch(() => undefined);\n }\n sessions.clear();\n await new Promise<void>((resolve) => {\n server.close(() => {\n resolve();\n });\n });\n },\n };\n}\n","import type { Journal } from \"../journal/journal.js\";\n\nexport interface GateRequest {\n readonly actionId: string;\n readonly runId: string;\n readonly seq: number;\n readonly server: string;\n readonly tool: string;\n readonly args: unknown;\n /** Why this is being asked about, in the words the agent is given. */\n readonly why: string;\n readonly signal: AbortSignal;\n}\n\nexport type GateDecision =\n | { readonly approved: true; readonly by: string }\n | {\n readonly approved: false;\n readonly by?: string;\n readonly reason: string;\n /**\n * Nobody has refused; the request is simply waiting for a person. The\n * agent should tell its user how to approve and then try again.\n */\n readonly awaiting?: boolean;\n };\n\nexport interface Gate {\n decide(request: GateRequest): Promise<GateDecision>;\n}\n\nexport const DEFAULT_GATE_TIMEOUT_MS = 300_000;\n\n/**\n * Records the request and refuses immediately, rather than holding the call\n * open until someone answers.\n *\n * Holding it open cannot work against a real client. Measured against Claude\n * Code: a suspended call sat for the full five minutes while the client had\n * long since reported it as failed, and any approval in that gap would have\n * sent something the agent had already said it had not sent. Every useful\n * window for a person to notice, open a terminal and decide is longer than a\n * client will wait, so the two cannot be reconciled by choosing a better\n * timeout. Refusing at once and letting the agent retry removes the conflict\n * instead of tuning it.\n */\n/**\n * `approveHint` builds the command a person on this machine would actually\n * run, journal path and all. A hint that omits an argument the caller needs is\n * an instruction that fails the moment somebody follows it.\n */\nexport type ApproveHint = (actionId: string) => string;\n\nconst DEFAULT_HINT: ApproveHint = (actionId) => `synartesis approve ${actionId.slice(0, 8)}`;\n\nexport function createRetryGate(journal: Journal, approveHint: ApproveHint = DEFAULT_HINT): Gate {\n return {\n decide(request: GateRequest): Promise<GateDecision> {\n journal.markGated(request.actionId, request.why);\n return Promise.resolve({\n approved: false,\n awaiting: true,\n reason:\n \"it is waiting for a person to approve it. Ask them to run: \" +\n approveHint(request.actionId) +\n \" --- then make this exact call again.\",\n });\n },\n };\n}\n\nexport interface JournalGateOptions {\n readonly timeoutMs?: number;\n readonly pollMs?: number;\n /** Where the operator is told that something is waiting. */\n readonly notify?: (request: GateRequest) => void;\n}\n\n/**\n * Approval arrives out of band, through the journal, rather than from a prompt\n * on stdin.\n *\n * The proxy speaks MCP over stdin and stdout: that pipe carries protocol\n * frames, so there is nothing to prompt on. A prompt written to the\n * controlling terminal would work only when one exists, which rules out every\n * desktop client. The journal is already a transactional, WAL-mode, multi\n * process store, so `synartesis approve` in any other terminal is the natural\n * channel, and it behaves identically wherever the proxy was launched from.\n */\nexport function createJournalGate(journal: Journal, options: JournalGateOptions = {}): Gate {\n const timeoutMs = options.timeoutMs ?? DEFAULT_GATE_TIMEOUT_MS;\n const pollMs = options.pollMs ?? 100;\n const notify = options.notify ?? ((): void => undefined);\n\n return {\n async decide(request: GateRequest): Promise<GateDecision> {\n journal.markGated(request.actionId, request.why);\n notify(request);\n\n const deadline = Date.now() + timeoutMs;\n for (;;) {\n const action = journal.getAction(request.actionId);\n if (action === undefined) {\n return { approved: false, reason: \"the journal entry disappeared while awaiting approval\" };\n }\n if (action.status !== \"gated\") {\n return action.status === \"denied\"\n ? {\n approved: false,\n ...(action.approvedBy === undefined ? {} : { by: action.approvedBy }),\n reason: action.error ?? \"denied\",\n }\n : { approved: true, by: action.approvedBy ?? \"unknown\" };\n }\n\n if (request.signal.aborted) {\n journal.deny(request.actionId, undefined, \"the client disconnected before a decision\");\n return { approved: false, reason: \"the client disconnected before a decision\" };\n }\n if (Date.now() >= deadline) {\n // Deny by default (3.4): silence is not consent.\n const reason = `no answer within ${String(Math.round(timeoutMs / 1000))}s, so it was denied`;\n journal.deny(request.actionId, undefined, reason);\n return { approved: false, reason };\n }\n\n await new Promise<void>((resolve) => setTimeout(resolve, pollMs).unref());\n }\n },\n };\n}\n","import pino, { type Logger } from \"pino\";\n\nexport type { Logger };\n\nexport const LOG_LEVELS = [\"trace\", \"debug\", \"info\", \"warn\", \"error\", \"silent\"] as const;\nexport type LogLevel = (typeof LOG_LEVELS)[number];\n\nexport function isLogLevel(value: string): value is LogLevel {\n return LOG_LEVELS.some((level) => level === value);\n}\n\n/**\n * Always fd 2. stdout carries MCP protocol frames, and a single stray log line\n * on it corrupts the session for every client. Synchronous so that the last\n * lines before an exit are not lost, which is exactly when they matter.\n */\nexport function createLogger(level: LogLevel): Logger {\n return pino(\n { level, base: { name: \"synartesis\" } },\n pino.destination({ dest: 2, sync: true }),\n );\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport {\n CallToolRequestSchema,\n CompleteRequestSchema,\n ErrorCode,\n GetPromptRequestSchema,\n ListPromptsRequestSchema,\n ListResourceTemplatesRequestSchema,\n ListResourcesRequestSchema,\n ListToolsRequestSchema,\n McpError,\n ReadResourceRequestSchema,\n SetLevelRequestSchema,\n SubscribeRequestSchema,\n UnsubscribeRequestSchema,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport type {\n Implementation,\n Request,\n ServerCapabilities,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { z } from \"zod\";\n\nimport { SnapshotError, UpstreamError, describe } from \"../errors.js\";\nimport { createRetryGate, type ApproveHint, type Gate } from \"../gate/gate.js\";\nimport { shouldGateOnWrite } from \"../gate/heuristic.js\";\nimport type { Journal } from \"../journal/journal.js\";\nimport type { Logger } from \"../logging.js\";\nimport {\n createPolicyResolver,\n type PolicyResolver,\n} from \"../manifest/match.js\";\nimport { qualify, type Manifest } from \"../manifest/types.js\";\nimport { createRouter, type Router } from \"./routing.js\";\nimport {\n observeState,\n planInverse,\n isDisconnected,\n mayHaveArrived,\n planRead,\n refusal,\n runRead,\n toPayload,\n type ResolvedRead,\n} from \"./snapshot.js\";\nimport type { Upstream } from \"./upstream.js\";\n\nexport interface ProxyOptions {\n readonly upstreams: readonly Upstream[];\n readonly manifest: Manifest;\n readonly journal: Journal;\n /** Defaults to out-of-band approval through the journal. */\n readonly gate?: Gate;\n readonly gateTimeoutMs?: number;\n readonly logger?: Logger;\n /** Builds the exact command a person here would run to approve an action. */\n readonly approveHint?: ApproveHint;\n}\n\nexport interface ProxyServer {\n readonly server: McpServer;\n /** Resolves with the run id once the client session is initialized. */\n readonly ready: Promise<string>;\n /** Resolves when no tool call is in flight, so shutdown can drain first. */\n whenIdle(): Promise<void>;\n /** The open run, once the session has initialized. */\n readonly runId: string | undefined;\n /** Whether any forwarded request is currently in flight. */\n busy(): boolean;\n}\n\ntype Passthrough = { [key: string]: unknown };\n\n/**\n * How long an approval stays usable. Long enough to survive a client restart\n * and a person walking away from their desk, short enough that a decision made\n * this morning cannot quietly authorise the same call tomorrow.\n */\nconst APPROVAL_WINDOW_MS = 60 * 60 * 1000;\n\n/**\n * Results are read through loose schemas. The SDK's typed schemas strip fields\n * they do not know about, which would quietly erase any metadata an upstream\n * added; only the names this proxy has to rewrite are described here.\n */\nconst PassthroughResult = z.looseObject({});\nconst ToolList = z.looseObject({\n tools: z.array(z.looseObject({ name: z.string() })),\n nextCursor: z.string().optional(),\n});\nconst PromptList = z.looseObject({\n prompts: z.array(z.looseObject({ name: z.string() })),\n nextCursor: z.string().optional(),\n});\nconst ResourceList = z.looseObject({\n resources: z.array(z.looseObject({ uri: z.string() })),\n nextCursor: z.string().optional(),\n});\nconst TemplateList = z.looseObject({\n resourceTemplates: z.array(z.looseObject({ uriTemplate: z.string() })),\n nextCursor: z.string().optional(),\n});\n\nfunction unwrap(error: McpError): string {\n const prefix = `MCP error ${String(error.code)}: `;\n return error.message.startsWith(prefix)\n ? error.message.slice(prefix.length)\n : error.message;\n}\n\nfunction rethrow(server: string, operation: string, error: unknown): never {\n if (error instanceof McpError) {\n throw new McpError(error.code, unwrap(error), error.data);\n }\n throw new UpstreamError(server, operation, error);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * The client sees one logical server, so it must be told about anything any\n * upstream can do. Sub-objects are merged rather than replaced so that, for\n * example, one server's resources.subscribe survives another's resources {}.\n */\nfunction mergeCapabilities(\n all: readonly ServerCapabilities[],\n): ServerCapabilities {\n const merged: Record<string, unknown> = {};\n for (const capabilities of all) {\n for (const [key, value] of Object.entries(capabilities)) {\n const existing = merged[key];\n merged[key] =\n isRecord(existing) && isRecord(value)\n ? { ...existing, ...value }\n : value;\n }\n }\n return merged;\n}\n\nfunction identityFor(router: Router): Implementation {\n const only = router.upstreams[0];\n if (!router.prefixed && only !== undefined) {\n const upstream = only.client.getServerVersion();\n if (upstream !== undefined) {\n return upstream;\n }\n }\n // With several servers behind it there is no single identity to mirror.\n return { name: \"synartesis\", version: \"0.0.0\" };\n}\n\n/**\n * Told to the agent at connect time. Without it a gated call is just an opaque\n * failure, and the person watching has no idea why their agent stopped or what\n * they are supposed to do about it. With it, the agent explains itself.\n */\nconst SYNARTESIS_INSTRUCTIONS = [\n \"These tools are guarded by Synartesis, which records every change so it can be undone later.\",\n \"\",\n \"Some actions cannot be undone. Those are held until a person approves them, and the call\",\n \"will fail with a message beginning \\\"Synartesis is holding this call for approval\\\".\",\n \"When that happens:\",\n \" 1. Tell the user plainly that you are asking Synartesis for approval, and what for.\",\n \" 2. Give them the exact `synartesis approve ...` command from the error.\",\n \" 3. Once they say they have approved it, make the same call again. It will go through.\",\n \"Do not try to work around a held call by using a different tool to achieve the same thing.\",\n].join(\"\\n\");\n\nfunction instructionsFor(router: Router): string {\n const sections = router.upstreams\n .map((upstream) => ({\n name: upstream.name,\n text: upstream.client.getInstructions(),\n }))\n .filter(\n (section): section is { name: string; text: string } => section.text !== undefined,\n );\n\n const upstream = router.prefixed\n ? sections.map((section) => `Tools prefixed ${section.name}__:\\n${section.text}`).join(\"\\n\\n\")\n : (sections[0]?.text ?? \"\");\n\n return upstream === \"\" ? SYNARTESIS_INSTRUCTIONS : `${SYNARTESIS_INSTRUCTIONS}\\n\\n${upstream}`;\n}\n\n/** Walks every page so that aggregation across servers is never partial. */\nasync function drain<T>(\n fetch: (\n cursor: string | undefined,\n ) => Promise<{ items: T[]; nextCursor: string | undefined }>,\n): Promise<T[]> {\n const collected: T[] = [];\n let cursor: string | undefined;\n do {\n const page = await fetch(cursor);\n collected.push(...page.items);\n cursor = page.nextCursor;\n } while (cursor !== undefined);\n return collected;\n}\n\nexport function createProxyServer(options: ProxyOptions): ProxyServer {\n const { upstreams, manifest, journal } = options;\n const router = createRouter(upstreams, manifest);\n const policies: PolicyResolver = createPolicyResolver(manifest);\n\n const log = options.logger;\n\n const gate = options.gate ?? createRetryGate(journal, options.approveHint);\n\n const capabilities = mergeCapabilities(\n upstreams.map((upstream) => upstream.client.getServerCapabilities() ?? {}),\n );\n const instructions = instructionsFor(router);\n\n const wrapper = new McpServer(identityFor(router), { capabilities, instructions });\n const server = wrapper.server;\n\n let runId: string | undefined;\n let resolveReady: (id: string) => void = () => undefined;\n const ready = new Promise<string>((resolve) => {\n resolveReady = resolve;\n });\n\n let inflight = 0;\n const idle: (() => void)[] = [];\n const enter = (): void => {\n inflight += 1;\n };\n /**\n * Every decrement goes through here, including the one that parks a call at\n * the gate. A decrement that reached zero without waking the waiters would\n * leave a shutdown draining for ever against a counter that is already idle.\n */\n const leave = (): void => {\n inflight -= 1;\n if (inflight === 0) {\n for (const resolve of idle.splice(0)) {\n resolve();\n }\n }\n };\n const whenIdle = async (): Promise<void> => {\n if (inflight === 0) {\n return;\n }\n await new Promise<void>((resolve) => idle.push(resolve));\n };\n\n // A client that pipelines notifications/initialized ahead of the initialize\n // response can reach oninitialized before its own identity is recorded, so\n // the label is filled in at the first opportunity rather than once.\n let labelled = false;\n const ensureLabel = (): void => {\n if (labelled || runId === undefined) {\n return;\n }\n const name = server.getClientVersion()?.name;\n if (name !== undefined) {\n journal.setRunLabel(runId, name);\n labelled = true;\n }\n };\n\n const supports = (\n upstream: Upstream,\n key: keyof ServerCapabilities,\n ): boolean => upstream.client.getServerCapabilities()?.[key] !== undefined;\n\n const ask = async (\n upstream: Upstream,\n request: Request,\n signal: AbortSignal,\n ): Promise<Passthrough> => {\n try {\n return await upstream.client.request(request, PassthroughResult, {\n signal,\n });\n } catch (error: unknown) {\n return rethrow(upstream.name, request.method, error);\n }\n };\n\n // --- resource ownership -------------------------------------------------\n // A resource uri is an opaque identifier the client hands back verbatim, so\n // unlike a tool name it cannot be namespaced. Ownership therefore has to be\n // discovered from what each server advertises.\n let owners: Map<string, string> | undefined;\n let schemes: Map<string, string> | undefined;\n let conflict: string | undefined;\n\n const refreshResources = async (signal: AbortSignal): Promise<void> => {\n const nextOwners = new Map<string, string>();\n const nextSchemes = new Map<string, string>();\n let nextConflict: string | undefined;\n\n for (const upstream of router.upstreams) {\n if (!supports(upstream, \"resources\")) {\n continue;\n }\n const resources = await drain(async (cursor) => {\n const raw = await ask(\n upstream,\n {\n method: \"resources/list\",\n params: cursor === undefined ? {} : { cursor },\n },\n signal,\n );\n const page = ResourceList.parse(raw);\n return { items: page.resources, nextCursor: page.nextCursor };\n });\n for (const resource of resources) {\n const existing = nextOwners.get(resource.uri);\n if (existing !== undefined && existing !== upstream.name) {\n nextConflict ??= `resource ${resource.uri} is advertised by both ${existing} and ${upstream.name}; a uri cannot be namespaced, so one of them must stop exposing it`;\n }\n nextOwners.set(resource.uri, existing ?? upstream.name);\n const scheme = resource.uri.split(\":\")[0] ?? \"\";\n if (scheme !== \"\" && !nextSchemes.has(scheme)) {\n nextSchemes.set(scheme, upstream.name);\n }\n }\n\n const templates = await drain(async (cursor) => {\n const raw = await ask(\n upstream,\n {\n method: \"resources/templates/list\",\n params: cursor === undefined ? {} : { cursor },\n },\n signal,\n );\n const page = TemplateList.parse(raw);\n return { items: page.resourceTemplates, nextCursor: page.nextCursor };\n });\n for (const template of templates) {\n const scheme = template.uriTemplate.split(\":\")[0] ?? \"\";\n if (scheme !== \"\" && !nextSchemes.has(scheme)) {\n nextSchemes.set(scheme, upstream.name);\n }\n }\n }\n\n owners = nextOwners;\n schemes = nextSchemes;\n conflict = nextConflict;\n };\n\n const ensureResources = async (signal: AbortSignal): Promise<void> => {\n if (owners === undefined) {\n await refreshResources(signal);\n }\n if (conflict !== undefined) {\n throw new McpError(ErrorCode.InternalError, conflict);\n }\n };\n\n const ownerOf = async (\n uri: string,\n signal: AbortSignal,\n ): Promise<Upstream> => {\n await ensureResources(signal);\n const direct = owners?.get(uri);\n const scheme = uri.split(\":\")[0] ?? \"\";\n const name = direct ?? schemes?.get(scheme);\n const upstream = name === undefined ? undefined : router.byName(name);\n if (upstream === undefined) {\n throw new McpError(\n ErrorCode.InvalidParams,\n `no configured server provides ${uri}`,\n );\n }\n return upstream;\n };\n\n // --- handlers -----------------------------------------------------------\n if (capabilities.tools !== undefined) {\n server.setRequestHandler(\n ListToolsRequestSchema,\n async (_request, extra) => {\n const tools: Passthrough[] = [];\n for (const upstream of router.upstreams) {\n if (!supports(upstream, \"tools\")) {\n continue;\n }\n const items = await drain(async (cursor) => {\n const raw = await ask(\n upstream,\n {\n method: \"tools/list\",\n params: cursor === undefined ? {} : { cursor },\n },\n extra.signal,\n );\n const page = ToolList.parse(raw);\n return { items: page.tools, nextCursor: page.nextCursor };\n });\n for (const tool of items) {\n tools.push({\n ...tool,\n name: router.expose(upstream.name, tool.name),\n });\n }\n }\n // Pagination is flattened: a cursor would have to encode a position\n // across several independent servers, and the client gains nothing.\n return { tools };\n },\n );\n\n server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {\n if (runId === undefined) {\n throw new UpstreamError(\"proxy\", \"tools/call\", \"no active run\");\n }\n // Captured: narrowing does not survive into the closures below.\n const activeRun = runId;\n ensureLabel();\n const route = router.route(request.params.name);\n if (route === undefined) {\n throw new McpError(\n ErrorCode.InvalidParams,\n `no configured server provides tool ${request.params.name}`,\n );\n }\n\n const { policy } = policies.resolve(qualify(route.upstream.name, route.tool));\n const args = request.params.arguments ?? {};\n // Counted from here, not from the forward call: the pre-read is part of\n // the action, and a shutdown that aborts it blocks a legitimate write.\n enter();\n try {\n const wantsGate =\n policy.gate === \"always\" || (policy.gate === \"on_write\" && shouldGateOnWrite(args));\n\n // A retry after an out-of-band approval reuses the row that was\n // approved, so the approval ends up on the action that actually ran\n // rather than on an abandoned twin of it.\n const granted = wantsGate\n ? journal.findApproval({\n server: route.upstream.name,\n tool: route.tool,\n args,\n notBefore: new Date(Date.now() - APPROVAL_WINDOW_MS).toISOString(),\n })\n : undefined;\n\n // An approval granted in an earlier session cannot simply be adopted:\n // the action belongs to the run happening now, or undoing this run\n // would not include it.\n const inherited =\n granted !== undefined && granted.runId !== activeRun ? granted : undefined;\n\n // Nobody has answered yet and the agent is asking again. Reusing the\n // row it is already waiting on keeps one call to one decision, which\n // is what `synartesis gates` and `approve` both assume.\n const waiting =\n granted === undefined && wantsGate\n ? journal.findGated({\n runId: activeRun,\n server: route.upstream.name,\n tool: route.tool,\n args,\n })\n : undefined;\n\n const reusable = waiting ?? (inherited === undefined ? granted : undefined);\n const pending =\n reusable === undefined\n ? journal.recordPending({\n runId: activeRun,\n server: route.upstream.name,\n tool: route.tool,\n args,\n class: policy.class,\n })\n : {\n actionId: reusable.id,\n seq: reusable.seq,\n idempotencyKey: reusable.idempotencyKey,\n };\n\n if (inherited !== undefined) {\n journal.adoptApproval(pending.actionId, inherited);\n } else if (granted !== undefined && waiting === undefined) {\n // Reusing the approved row itself: from here its outcome stops being\n // known, so it stops being `approved`.\n journal.markInFlight(granted.id);\n }\n if (granted !== undefined) {\n log?.info(\n { action: pending.actionId, by: granted.approvedBy, from: granted.runId },\n \"proceeding on a standing approval\",\n );\n }\n\n const decide = async (why: string): Promise<void> => {\n // Parked, not working: a suspended call must not hold up shutdown,\n // and the drain exists to let real work finish.\n leave();\n let decision;\n try {\n decision = await gate.decide({\n actionId: pending.actionId,\n runId: activeRun,\n seq: pending.seq,\n server: route.upstream.name,\n tool: route.tool,\n args,\n why,\n signal: extra.signal,\n });\n } finally {\n enter();\n }\n log?.info(\n { action: pending.actionId, approved: decision.approved },\n decision.approved ? \"approved\" : \"denied\",\n );\n // An approval that lands after the client has given up would send\n // a real email that the agent has already reported as not sent.\n // Nobody is waiting for the result, so the safe reading of an\n // approval nobody can hear is that it did not happen.\n if (decision.approved && extra.signal.aborted) {\n journal.settleAsDenied(\n pending.actionId,\n decision.by,\n \"approved, but the client had already stopped waiting, so it was not sent\",\n );\n throw new McpError(\n ErrorCode.InvalidRequest,\n `synartesis blocked ${request.params.name}: it was approved after the client stopped waiting, so it was not sent. Ask the agent to try again.`,\n );\n }\n if (!decision.approved) {\n if (decision.awaiting === true) {\n log?.warn(\n {\n action: pending.actionId,\n tool: `${route.upstream.name}.${route.tool}`,\n approve: options.approveHint?.(pending.actionId) ?? pending.actionId,\n },\n \"awaiting approval\",\n );\n throw new McpError(\n ErrorCode.InvalidRequest,\n `Synartesis is holding this call for approval, because ${why}. ${decision.reason}`,\n );\n }\n const who = decision.by === undefined ? \"\" : ` by ${decision.by}`;\n throw new McpError(\n ErrorCode.InvalidRequest,\n `synartesis blocked ${request.params.name}: ${why} and was denied${who}. ${decision.reason}`,\n );\n }\n };\n\n // D4/3.4: a policy gate suspends before anything is read or written, so\n // a gated action never even looks at the resource.\n // decide() throws on refusal, so getting past this means approved.\n const askedAlready = wantsGate;\n if (wantsGate && granted === undefined) {\n await decide(\"this action cannot be undone\");\n }\n\n // The pre-read happens before the write goes out, and a failure stops\n // the write entirely: a reversible action without a snapshot is\n // silently irreversible, which is worse than the action not happening.\n let snapshot: unknown;\n let verify: ResolvedRead | undefined;\n let missingPriorState: string | undefined;\n if (policy.snapshot !== undefined) {\n try {\n verify = planRead(policy.snapshot, { args });\n snapshot = await runRead(router, verify, extra.signal);\n journal.attachSnapshot(pending.actionId, snapshot);\n } catch (error: unknown) {\n const reason = describe(error);\n if (error instanceof SnapshotError && error.absent) {\n // Nothing exists here yet, so this call creates rather than\n // replaces and there is nothing to put back. It is an\n // irreversible action wearing a reversible policy. Refusing\n // outright would mean an agent could never create anything, so\n // it falls through to the same question the gate asks.\n missingPriorState = reason;\n verify = undefined;\n } else {\n journal.markFailed(pending.actionId, reason);\n log?.error(\n { seq: pending.seq, tool: route.tool, reason },\n \"write blocked: snapshot failed\",\n );\n throw new McpError(\n ErrorCode.InternalError,\n `synartesis blocked ${request.params.name}: ${reason}`,\n );\n }\n }\n }\n\n if (missingPriorState !== undefined && !askedAlready) {\n // An approval granted out of band counts here too. It was only ever\n // looked up for a policy that asked to be gated, so a write whose\n // prior state was missing -- an agent creating a file, the commonest\n // thing an agent does -- asked, was approved, and asked again, and\n // no number of approvals ever let it through. The instructions this\n // proxy sends to every agent promise the opposite.\n const standing = journal.findApproval({\n server: route.upstream.name,\n tool: route.tool,\n args,\n notBefore: new Date(Date.now() - APPROVAL_WINDOW_MS).toISOString(),\n });\n if (standing === undefined) {\n // Not \"nothing exists here\": every tool-level error on a pre-read\n // arrives here, so a file that exists and merely could not be read\n // came out as one that was not there. The person approving an\n // unundoable write was shown absence and given no way to learn\n // otherwise until after they had allowed it. Say what happened and\n // hand over the server's own words.\n await decide(\n `nothing was captured to restore, so this cannot be undone — the read said: ${missingPriorState}`,\n );\n } else {\n // Moved onto the row that actually runs, which also spends it: an\n // approval answers one call, not every call that looks like it.\n journal.adoptApproval(pending.actionId, standing);\n log?.info(\n { action: pending.actionId, by: standing.approvedBy, from: standing.runId },\n \"proceeding on a standing approval\",\n );\n }\n }\n\n const forwarded: Request = {\n method: \"tools/call\",\n params: { ...request.params, name: route.tool },\n };\n\n try {\n const result = await route.upstream.client.request(forwarded, PassthroughResult, {\n signal: extra.signal,\n });\n\n // The server understood the call and did not do it. Recording that\n // as an action would be worse than not recording it at all: an\n // inverse resolved from a refusal is a compensating call for\n // something that never happened, and undo would faithfully carry it\n // out. The agent still sees the refusal exactly as sent.\n const refused = refusal(result);\n if (refused !== undefined) {\n journal.markFailed(pending.actionId, `the upstream refused the call: ${refused}`);\n log?.debug(\n { seq: pending.seq, tool: route.tool, reason: refused },\n \"refused by the upstream\",\n );\n return result;\n }\n\n const context = { args, snapshot, result: toPayload(result) };\n const warnings: string[] = [];\n if (missingPriorState !== undefined) {\n warnings.push(\n `no prior state existed, so there is nothing to restore: ${missingPriorState}`,\n );\n }\n\n // Resolved now rather than at rollback time (D5).\n let inverse: unknown;\n if (policy.inverse !== undefined && missingPriorState === undefined) {\n try {\n inverse = planInverse(policy.inverse, context);\n } catch (error: unknown) {\n warnings.push(`inverse could not be resolved: ${describe(error)}`);\n }\n }\n\n // Best effort: the write has already applied, so a failed post-read\n // cannot undo it. Phase 4 fails closed when the post-state is\n // missing. A resource that is now absent is a captured post-state,\n // not a missing one.\n let postSnapshot: unknown;\n if (verify !== undefined) {\n try {\n postSnapshot = await observeState(router, verify, extra.signal);\n } catch (error: unknown) {\n warnings.push(`post-state could not be captured: ${describe(error)}`);\n }\n }\n\n if (warnings.length > 0) {\n log?.warn({ seq: pending.seq, tool: route.tool, warnings }, \"applied with reservations\");\n }\n log?.debug(\n { seq: pending.seq, server: route.upstream.name, tool: route.tool, class: policy.class },\n \"applied\",\n );\n journal.markApplied(pending.actionId, {\n result,\n ...(inverse === undefined ? {} : { inverse }),\n ...(verify === undefined ? {} : { verify }),\n ...(postSnapshot === undefined ? {} : { postSnapshot }),\n ...(warnings.length === 0 ? {} : { warning: warnings.join(\"; \") }),\n });\n return result;\n } catch (error: unknown) {\n const disconnected = isDisconnected(error);\n if (extra.signal.aborted || mayHaveArrived(error)) {\n // A transport that closed while a reply was still owed says\n // nothing about whether the call arrived. Recording that as failed\n // asserts it did not, and undo would then step over an action that\n // may well have applied. Having had no connection to write to at\n // all is the other case, and that one really did not happen.\n journal.markUnknown(pending.actionId, describe(error));\n } else {\n journal.markFailed(pending.actionId, describe(error));\n }\n if (disconnected && route.upstream.reconnect !== undefined) {\n // Not to retry this call -- a write must never be sent twice on a\n // guess -- but so the rest of the session is not lost with it.\n await route.upstream.reconnect().catch(() => undefined);\n }\n return rethrow(route.upstream.name, \"tools/call\", error);\n }\n } finally {\n leave();\n }\n });\n }\n\n if (capabilities.resources !== undefined) {\n server.setRequestHandler(\n ListResourcesRequestSchema,\n async (_request, extra) => {\n await refreshResources(extra.signal);\n await ensureResources(extra.signal);\n const resources: Passthrough[] = [];\n for (const upstream of router.upstreams) {\n if (!supports(upstream, \"resources\")) {\n continue;\n }\n const items = await drain(async (cursor) => {\n const raw = await ask(\n upstream,\n {\n method: \"resources/list\",\n params: cursor === undefined ? {} : { cursor },\n },\n extra.signal,\n );\n const page = ResourceList.parse(raw);\n return { items: page.resources, nextCursor: page.nextCursor };\n });\n resources.push(...items);\n }\n return { resources };\n },\n );\n\n server.setRequestHandler(\n ListResourceTemplatesRequestSchema,\n async (_request, extra) => {\n const resourceTemplates: Passthrough[] = [];\n for (const upstream of router.upstreams) {\n if (!supports(upstream, \"resources\")) {\n continue;\n }\n const items = await drain(async (cursor) => {\n const raw = await ask(\n upstream,\n {\n method: \"resources/templates/list\",\n params: cursor === undefined ? {} : { cursor },\n },\n extra.signal,\n );\n const page = TemplateList.parse(raw);\n return {\n items: page.resourceTemplates,\n nextCursor: page.nextCursor,\n };\n });\n resourceTemplates.push(...items);\n }\n return { resourceTemplates };\n },\n );\n\n server.setRequestHandler(\n ReadResourceRequestSchema,\n async (request, extra) => {\n const upstream = await ownerOf(request.params.uri, extra.signal);\n return ask(upstream, request, extra.signal);\n },\n );\n\n if (capabilities.resources.subscribe === true) {\n for (const schema of [SubscribeRequestSchema, UnsubscribeRequestSchema]) {\n server.setRequestHandler(schema, async (request, extra) => {\n const upstream = await ownerOf(request.params.uri, extra.signal);\n return ask(upstream, request, extra.signal);\n });\n }\n }\n }\n\n if (capabilities.prompts !== undefined) {\n server.setRequestHandler(\n ListPromptsRequestSchema,\n async (_request, extra) => {\n const prompts: Passthrough[] = [];\n for (const upstream of router.upstreams) {\n if (!supports(upstream, \"prompts\")) {\n continue;\n }\n const items = await drain(async (cursor) => {\n const raw = await ask(\n upstream,\n {\n method: \"prompts/list\",\n params: cursor === undefined ? {} : { cursor },\n },\n extra.signal,\n );\n const page = PromptList.parse(raw);\n return { items: page.prompts, nextCursor: page.nextCursor };\n });\n for (const prompt of items) {\n prompts.push({\n ...prompt,\n name: router.expose(upstream.name, prompt.name),\n });\n }\n }\n return { prompts };\n },\n );\n\n server.setRequestHandler(GetPromptRequestSchema, async (request, extra) => {\n const route = router.route(request.params.name);\n if (route === undefined) {\n throw new McpError(\n ErrorCode.InvalidParams,\n `no configured server provides prompt ${request.params.name}`,\n );\n }\n return ask(\n route.upstream,\n {\n method: \"prompts/get\",\n params: { ...request.params, name: route.tool },\n },\n extra.signal,\n );\n });\n }\n\n if (capabilities.completions !== undefined) {\n server.setRequestHandler(CompleteRequestSchema, async (request, extra) => {\n const reference = request.params.ref;\n if (reference.type === \"ref/prompt\") {\n const route = router.route(reference.name);\n if (route === undefined) {\n throw new McpError(\n ErrorCode.InvalidParams,\n `unknown prompt ${reference.name}`,\n );\n }\n return ask(\n route.upstream,\n {\n method: \"completion/complete\",\n params: {\n ...request.params,\n ref: { ...reference, name: route.tool },\n },\n },\n extra.signal,\n );\n }\n const upstream = await ownerOf(reference.uri, extra.signal);\n return ask(upstream, request, extra.signal);\n });\n }\n\n if (capabilities.logging !== undefined) {\n server.setRequestHandler(SetLevelRequestSchema, async (request, extra) => {\n // Broadcast: the client is configuring one logical server.\n for (const upstream of router.upstreams) {\n if (supports(upstream, \"logging\")) {\n await ask(upstream, request, extra.signal);\n }\n }\n return {};\n });\n }\n\n // --- lifecycle ----------------------------------------------------------\n let connected = false;\n for (const upstream of router.upstreams) {\n upstream.client.fallbackNotificationHandler = async (\n notification,\n ): Promise<void> => {\n if (notification.method.endsWith(\"list_changed\")) {\n owners = undefined;\n schemes = undefined;\n conflict = undefined;\n }\n if (connected) {\n await server.notification(notification);\n }\n };\n }\n\n server.oninitialized = (): void => {\n connected = true;\n const name = server.getClientVersion()?.name;\n const id = journal.beginRun(name);\n runId = id;\n labelled = name !== undefined;\n resolveReady(id);\n };\n\n const previousOnClose = server.onclose;\n server.onclose = (): void => {\n connected = false;\n if (runId !== undefined) {\n journal.endRun(runId, \"complete\");\n runId = undefined;\n }\n previousOnClose?.();\n };\n\n return {\n server: wrapper,\n ready,\n whenIdle,\n busy: (): boolean => inflight > 0,\n get runId(): string | undefined {\n return runId;\n },\n };\n}\n","/**\n * The `on_write` heuristic for tools whose destructiveness cannot be decided\n * statically, such as a raw SQL runner.\n *\n * This is a heuristic and is documented as one. It exists because the\n * alternative for `postgres.query` is to gate every SELECT, which no operator\n * would tolerate for long. Anything it cannot confidently read as a read is\n * gated (D4): failing to recognise a statement is not evidence that it is safe.\n * `always` remains the correct choice wherever certainty matters.\n */\nconst READ_ONLY = /^(select|with|show|explain|describe|desc|values|table)\\b/;\n\nfunction isReadOnlyStatement(text: string): boolean {\n const stripped = text\n .replace(/--[^\\n]*/g, \" \")\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, \" \")\n .trim();\n if (!READ_ONLY.test(stripped.toLowerCase())) {\n return false;\n }\n // More than one statement means the leading SELECT says nothing about what\n // follows it.\n return stripped.replace(/;\\s*$/, \"\").indexOf(\";\") === -1;\n}\n\nexport function shouldGateOnWrite(args: unknown): boolean {\n if (typeof args !== \"object\" || args === null) {\n return true;\n }\n const strings = Object.values(args).filter(\n (value): value is string => typeof value === \"string\",\n );\n if (strings.length === 0) {\n return true;\n }\n return !strings.every(isReadOnlyStatement);\n}\n"],"mappings":"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","names":["resolve","upstream","resolve","resolve"]}
|
package/manifests/github.yaml
CHANGED
|
@@ -54,6 +54,11 @@ tools:
|
|
|
54
54
|
owner: "$.owner"
|
|
55
55
|
repo: "$.repo"
|
|
56
56
|
issue_number: "$.issue_number"
|
|
57
|
+
# What GitHub says when the thing is not there. Anything else the
|
|
58
|
+
# pre-read reports -- a permissions change, a rate limit -- is a failed
|
|
59
|
+
# snapshot rather than absence, and the write is refused instead of being
|
|
60
|
+
# offered for approval as a creation.
|
|
61
|
+
absent_when: ["Not Found", "404"]
|
|
57
62
|
inverse:
|
|
58
63
|
tool: "github.update_issue"
|
|
59
64
|
args:
|
|
@@ -83,6 +88,11 @@ tools:
|
|
|
83
88
|
owner: "$.owner"
|
|
84
89
|
repo: "$.repo"
|
|
85
90
|
pull_number: "$.pull_number"
|
|
91
|
+
# What GitHub says when the thing is not there. Anything else the
|
|
92
|
+
# pre-read reports -- a permissions change, a rate limit -- is a failed
|
|
93
|
+
# snapshot rather than absence, and the write is refused instead of being
|
|
94
|
+
# offered for approval as a creation.
|
|
95
|
+
absent_when: ["Not Found", "404"]
|
|
86
96
|
inverse:
|
|
87
97
|
tool: "github.update_pull_request"
|
|
88
98
|
args:
|
|
@@ -143,6 +153,11 @@ tools:
|
|
|
143
153
|
repo: "$.repo"
|
|
144
154
|
path: "$.path"
|
|
145
155
|
ref: "$.branch"
|
|
156
|
+
# What GitHub says when the thing is not there. Anything else the
|
|
157
|
+
# pre-read reports -- a permissions change, a rate limit -- is a failed
|
|
158
|
+
# snapshot rather than absence, and the write is refused instead of being
|
|
159
|
+
# offered for approval as a creation.
|
|
160
|
+
absent_when: ["Not Found", "404"]
|
|
146
161
|
inverse:
|
|
147
162
|
tool: "github.create_or_update_file"
|
|
148
163
|
args:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "synartesis",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "An undo layer for AI agents.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -28,7 +28,10 @@
|
|
|
28
28
|
},
|
|
29
29
|
"files": [
|
|
30
30
|
"dist",
|
|
31
|
+
"!dist/toy-crm.*",
|
|
32
|
+
"!dist/demo-agent.*",
|
|
31
33
|
"manifests",
|
|
34
|
+
"!manifests/toy-crm.yaml",
|
|
32
35
|
"README.md",
|
|
33
36
|
"CHANGELOG.md",
|
|
34
37
|
"LICENSE"
|