@synapsor/runner 0.1.0-alpha.7 → 0.1.0-alpha.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -171,6 +171,12 @@ HTTP defaults to `127.0.0.1:8765`, requires bearer auth by default, and should
171
171
  use private networking, TLS, and rate limits before being exposed beyond a
172
172
  local machine.
173
173
 
174
+ HTTP alpha scope: `serve-http` is a JSON-RPC endpoint for `tools/list`,
175
+ `tools/call`, and `resources/read`. It is not full MCP Streamable HTTP and does
176
+ not implement `initialize`/SSE. If an SDK HTTP MCP client expects that
177
+ handshake, use stdio mode or wrap the HTTP endpoint like the OpenAI HTTP
178
+ example.
179
+
174
180
  OpenAI Agents SDK examples:
175
181
 
176
182
  ```text
@@ -347,6 +353,13 @@ your application service already owns business writes, configure an
347
353
  `http_handler` or `command_handler` executor. Approval still happens outside
348
354
  MCP, and the handler returns an applied/conflict/failed receipt for replay.
349
355
 
356
+ For direct SQL writeback, set the writer env var named by the source
357
+ `write_url_env`, for example `SYNAPSOR_DATABASE_WRITE_URL`. Runner also creates
358
+ or writes `synapsor_writeback_receipts` for idempotency/replay, so the writer
359
+ needs permission for that receipt table or an administrator must pre-create and
360
+ grant it. Use app-owned handlers when you do not want Runner creating receipt
361
+ tables in your application schema.
362
+
350
363
  ## Command Name
351
364
 
352
365
  This package installs `synapsor-runner` as the OSS runner binary. The `synapsor`
package/dist/cli.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ import { type WritebackJob } from "@synapsor-runner/protocol";
2
3
  import { type SchemaInspection } from "@synapsor-runner/schema-inspector";
3
4
  export declare function main(argv: string[]): Promise<number>;
4
5
  type WizardAsk = (question: string, defaultValue?: string) => Promise<string>;
@@ -8,5 +9,6 @@ export declare function runInitWizard(args: string[], options?: {
8
9
  inspection?: SchemaInspection;
9
10
  stdout?: Pick<NodeJS.WriteStream, "write">;
10
11
  }): Promise<number>;
12
+ export declare function resolveSqlWriteDatabaseUrl(job: WritebackJob, configPath: string, env: NodeJS.ProcessEnv): Promise<string>;
11
13
  export {};
12
14
  //# sourceMappingURL=cli.d.ts.map
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AA+BA,OAAO,EAOL,KAAK,gBAAgB,EAEtB,MAAM,mCAAmC,CAAC;AA4H3C,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA8C1D;AA0DD,KAAK,SAAS,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAE9E,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,GAAE;IACP,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;CACvC,GACL,OAAO,CAAC,MAAM,CAAC,CAiLjB"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AA8BA,OAAO,EAA6G,KAAK,YAAY,EAAwB,MAAM,2BAA2B,CAAC;AAC/L,OAAO,EAOL,KAAK,gBAAgB,EAEtB,MAAM,mCAAmC,CAAC;AA4H3C,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA8C1D;AA0DD,KAAK,SAAS,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAE9E,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,GAAE;IACP,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;CACvC,GACL,OAAO,CAAC,MAAM,CAAC,CAiLjB;AAsyCD,wBAAsB,0BAA0B,CAAC,GAAG,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAM/H"}
package/dist/runner.mjs CHANGED
@@ -2685,7 +2685,7 @@ function createMcpRuntime(config, options = {}) {
2685
2685
  }
2686
2686
  function createSynapsorMcpServer(runtime) {
2687
2687
  const server = new McpServer(
2688
- { name: "synapsor-runner", version: "0.1.0-alpha.7" },
2688
+ { name: "synapsor-runner", version: "0.1.0-alpha.8" },
2689
2689
  { capabilities: { tools: {}, resources: {} } }
2690
2690
  );
2691
2691
  if (runtime.config.mode === "cloud") {
@@ -3748,7 +3748,7 @@ function failed(job, config, code) {
3748
3748
  }
3749
3749
  var mysqlAdapter = {
3750
3750
  async doctor(config) {
3751
- if (!config.databaseUrl) return { ok: false, details: { error: "SYNAPSOR_DATABASE_URL required" } };
3751
+ if (!config.databaseUrl) return { ok: false, details: { error: "database URL required; local config apply reads source.write_url_env, legacy workers use SYNAPSOR_DATABASE_URL" } };
3752
3752
  const connection = await mysql2.createConnection({ uri: config.databaseUrl, dateStrings: true });
3753
3753
  try {
3754
3754
  const [rows] = await connection.query("SELECT VERSION() AS version");
@@ -3963,7 +3963,7 @@ function failed2(job, config, code) {
3963
3963
  }
3964
3964
  var postgresAdapter = {
3965
3965
  async doctor(config) {
3966
- if (!config.databaseUrl) return { ok: false, details: { error: "SYNAPSOR_DATABASE_URL required" } };
3966
+ if (!config.databaseUrl) return { ok: false, details: { error: "database URL required; local config apply reads source.write_url_env, legacy workers use SYNAPSOR_DATABASE_URL" } };
3967
3967
  const pool = new Pool2({ connectionString: config.databaseUrl });
3968
3968
  const client = await pool.connect();
3969
3969
  try {
@@ -7386,12 +7386,13 @@ async function apply(args) {
7386
7386
  }
7387
7387
  await verifyLocalWritebackAuthority(job, configPath, storePath);
7388
7388
  }
7389
+ const databaseUrl = configPath ? await resolveSqlWriteDatabaseUrl(job, configPath, process2.env) : process2.env.SYNAPSOR_DATABASE_URL || "";
7389
7390
  const config = {
7390
7391
  controlPlaneUrl: process2.env.SYNAPSOR_CONTROL_PLANE_URL || "http://localhost:8000",
7391
7392
  runnerToken: process2.env.SYNAPSOR_RUNNER_TOKEN || "local-dry-run-token",
7392
7393
  runnerId: process2.env.SYNAPSOR_RUNNER_ID || "local-runner",
7393
7394
  sourceId: process2.env.SYNAPSOR_SOURCE_ID || job.source_id,
7394
- databaseUrl: process2.env.SYNAPSOR_DATABASE_URL || "",
7395
+ databaseUrl,
7395
7396
  engine: job.engine,
7396
7397
  pollIntervalMs: Number(process2.env.SYNAPSOR_POLL_INTERVAL_MS || "5000"),
7397
7398
  logLevel: process2.env.SYNAPSOR_LOG_LEVEL || "info",
@@ -7468,12 +7469,13 @@ async function applyProposal(args, proposalId) {
7468
7469
  async function applySqlJob(job, configPath, storePath, dryRun, env = process2.env) {
7469
7470
  const parsedJob = parseWritebackJob(job);
7470
7471
  await verifyLocalWritebackAuthority(parsedJob, configPath, storePath);
7472
+ const databaseUrl = await resolveSqlWriteDatabaseUrl(parsedJob, configPath, env);
7471
7473
  const config = {
7472
7474
  controlPlaneUrl: env.SYNAPSOR_CONTROL_PLANE_URL || "http://localhost:8000",
7473
7475
  runnerToken: env.SYNAPSOR_RUNNER_TOKEN || "local-dry-run-token",
7474
7476
  runnerId: env.SYNAPSOR_RUNNER_ID || "local-runner",
7475
7477
  sourceId: env.SYNAPSOR_SOURCE_ID || parsedJob.source_id,
7476
- databaseUrl: env.SYNAPSOR_DATABASE_URL || "",
7478
+ databaseUrl,
7477
7479
  engine: parsedJob.engine,
7478
7480
  pollIntervalMs: Number(env.SYNAPSOR_POLL_INTERVAL_MS || "5000"),
7479
7481
  logLevel: env.SYNAPSOR_LOG_LEVEL || "info",
@@ -7491,6 +7493,13 @@ async function applySqlJob(job, configPath, storePath, dryRun, env = process2.en
7491
7493
  }
7492
7494
  return result;
7493
7495
  }
7496
+ async function resolveSqlWriteDatabaseUrl(job, configPath, env) {
7497
+ const config = JSON.parse(await fs3.readFile(configPath, "utf8"));
7498
+ const source = config.sources?.[job.source_id];
7499
+ const writeUrlEnv = source?.write_url_env;
7500
+ if (writeUrlEnv && env[writeUrlEnv]) return env[writeUrlEnv] ?? "";
7501
+ return env.SYNAPSOR_DATABASE_URL || "";
7502
+ }
7494
7503
  function sourceNeedsSqlWriteback(config, sourceName) {
7495
7504
  return (config.capabilities ?? []).some((capability) => {
7496
7505
  if (capability.kind !== "proposal" || capability.source !== sourceName) return false;
@@ -7977,7 +7986,7 @@ async function cloudConnect(args) {
7977
7986
  return 1;
7978
7987
  }
7979
7988
  const runnerId = String(parsed.cloud.runner_id || process2.env.SYNAPSOR_RUNNER_ID || "synapsor_runner_local").trim();
7980
- const runnerVersion = String(parsed.cloud.runner_version || process2.env.npm_package_version || "0.1.0-alpha.7").trim();
7989
+ const runnerVersion = String(parsed.cloud.runner_version || process2.env.npm_package_version || "0.1.0-alpha.8").trim();
7981
7990
  const engines = normalizeEngines(parsed.cloud.engines);
7982
7991
  const capabilities = normalizeCapabilities(parsed.cloud.capabilities);
7983
7992
  const client = new ControlPlaneClient({
@@ -11435,7 +11444,7 @@ function starterCloudConfig() {
11435
11444
  base_url_env: "SYNAPSOR_CLOUD_BASE_URL",
11436
11445
  runner_token_env: "SYNAPSOR_RUNNER_TOKEN",
11437
11446
  runner_id: "synapsor_runner_local",
11438
- runner_version: "0.1.0-alpha.7",
11447
+ runner_version: "0.1.0-alpha.8",
11439
11448
  project_id: "token_scope",
11440
11449
  adapter_id: "mcp.your_adapter",
11441
11450
  source_id: "src_replace_me",
@@ -11560,7 +11569,10 @@ Start the stdio MCP server for local MCP clients such as Claude Desktop, Cursor,
11560
11569
  export SYNAPSOR_RUNNER_HTTP_TOKEN=...
11561
11570
  ${cmd} mcp serve-http --config ./synapsor.runner.json --store ./.synapsor/local.db [--host 127.0.0.1] [--port 8765] [--auth-token-env SYNAPSOR_RUNNER_HTTP_TOKEN]
11562
11571
 
11563
- Start the HTTP MCP server for app/server deployments. Bearer auth is required by default.
11572
+ Start the HTTP JSON-RPC MCP endpoint for app/server deployments. Bearer auth is required by default.
11573
+
11574
+ Alpha scope: supports POST /mcp methods tools/list, tools/call, and resources/read.
11575
+ It does not implement full MCP Streamable HTTP initialize/SSE sessions.
11564
11576
 
11565
11577
  Security:
11566
11578
  - Defaults to 127.0.0.1:8765.
@@ -11714,5 +11726,6 @@ function formatCliErrorHint(message) {
11714
11726
  }
11715
11727
  export {
11716
11728
  main,
11729
+ resolveSqlWriteDatabaseUrl,
11717
11730
  runInitWizard
11718
11731
  };
@@ -368,10 +368,14 @@ Apply through the trusted worker path with a separate writer credential:
368
368
  ```bash
369
369
  export SYNAPSOR_DATABASE_WRITE_URL="<postgres-or-mysql-write-url>"
370
370
  SYNAPSOR_ENGINE=postgres \
371
- SYNAPSOR_DATABASE_URL="$SYNAPSOR_DATABASE_WRITE_URL" \
372
371
  npx -y -p @synapsor/runner@alpha synapsor-runner apply --job job.json --config synapsor.runner.json --store ./.synapsor/local.db
373
372
  ```
374
373
 
374
+ For `apply --job ... --config ...`, Runner reads the write credential from the
375
+ source `write_url_env` in `synapsor.runner.json`, such as
376
+ `SYNAPSOR_DATABASE_WRITE_URL`. `SYNAPSOR_DATABASE_URL` is accepted only as a
377
+ legacy fallback for direct worker flows that do not pass a local config.
378
+
375
379
  If your application/API should own the business write, use an `http_handler`
376
380
  executor instead of direct SQL writeback. Handler URLs and bearer tokens come
377
381
  from environment variables, and the handler receives a structured proposal/job
package/docs/http-mcp.md CHANGED
@@ -6,6 +6,13 @@ needs to connect to a long-running Synapsor Runner service.
6
6
  Use stdio MCP when a local MCP client such as Claude Desktop, Cursor, or a
7
7
  local agent tool can launch Synapsor Runner directly.
8
8
 
9
+ Current alpha scope: `serve-http` exposes a small authenticated JSON-RPC
10
+ endpoint at `POST /mcp` for `tools/list`, `tools/call`, and `resources/read`.
11
+ It is not the full MCP Streamable HTTP transport and does not implement an
12
+ `initialize`/SSE session handshake. If your SDK expects full HTTP MCP
13
+ initialization, use stdio mode or wrap this endpoint with a thin tool/function
14
+ adapter like the OpenAI HTTP example.
15
+
9
16
  ## Start The HTTP Server
10
17
 
11
18
  ```bash
@@ -196,5 +203,6 @@ examples/openai-agents-stdio/
196
203
  The stdio example uses the MCP client integration from the OpenAI Agents SDK
197
204
  when available. The HTTP example uses a minimal JSON-RPC client wrapped as an
198
205
  OpenAI function tool because native HTTP MCP client support can vary by SDK
199
- version. The boundary is the same: the agent calls a semantic Synapsor tool,
200
- not raw SQL.
206
+ version and Runner's HTTP alpha endpoint is intentionally limited to JSON-RPC
207
+ tool/resource calls. The boundary is the same: the agent calls a semantic
208
+ Synapsor tool, not raw SQL.
@@ -158,11 +158,15 @@ npx -y -p @synapsor/runner@alpha synapsor-runner proposals writeback-job wrp_123
158
158
  The generated job uses the public `synapsor.writeback-job.v1` protocol and can be applied by the guarded worker:
159
159
 
160
160
  ```bash
161
+ export SYNAPSOR_DATABASE_WRITE_URL="postgresql://writer:<password>@localhost:5432/app"
161
162
  SYNAPSOR_ENGINE=postgres \
162
- SYNAPSOR_DATABASE_URL="postgresql://writer:<password>@localhost:5432/app" \
163
163
  npx -y -p @synapsor/runner@alpha synapsor-runner apply --job job.json --config synapsor.runner.json --store ./.synapsor/local.db
164
164
  ```
165
165
 
166
+ When `--config` is passed, direct SQL writeback reads the writer connection from
167
+ the source `write_url_env` in that config. `SYNAPSOR_DATABASE_URL` is only a
168
+ legacy fallback for direct worker flows without a local runner config.
169
+
166
170
  Passing `--store` records the terminal `synapsor.execution-receipt.v1` locally. Replay then links the proposal, approval, writeback job, applied/conflict/failed receipt, evidence, and query audit.
167
171
 
168
172
  Reject:
@@ -38,6 +38,11 @@ Stdio keeps the MCP protocol on process stdin/stdout and is the simplest local
38
38
  developer path. HTTP uses JSON-RPC over an authenticated `/mcp` endpoint and is
39
39
  better for app/server deployments.
40
40
 
41
+ Important alpha limitation: HTTP mode is not full MCP Streamable HTTP. It does
42
+ not implement `initialize` or an SSE session handshake. Standard SDK HTTP MCP
43
+ clients that require initialization may fail. Use stdio for those clients, or
44
+ call Runner's HTTP JSON-RPC endpoint through a thin app/server wrapper.
45
+
41
46
  HTTP requires bearer auth by default:
42
47
 
43
48
  ```bash
@@ -65,6 +65,13 @@ outside the model-facing MCP server and verifies:
65
65
 
66
66
  If any authority check cannot be verified, the write fails closed.
67
67
 
68
+ For direct SQL writeback, the writer connection is the env var named by the
69
+ source `write_url_env` in `synapsor.runner.json`. Direct SQL writeback also
70
+ creates or writes `synapsor_writeback_receipts` for idempotency and replay, so
71
+ the writer needs permission for that receipt table or an administrator must
72
+ pre-create and grant it. If your database policy forbids Runner-managed receipt
73
+ tables, use an app-owned `http_handler` or `command_handler` executor instead.
74
+
68
75
  When a capability uses an `http_handler` or `command_handler` executor, the
69
76
  same approval boundary applies. The runner sends a structured proposal/job
70
77
  payload to the configured handler after approval. Handler URLs, commands, bearer
@@ -24,6 +24,38 @@ It applies one guarded `UPDATE` through the database adapter:
24
24
  Use this when the trusted runner is allowed to update the selected business row
25
25
  directly.
26
26
 
27
+ The source config controls which writer env var is used:
28
+
29
+ ```json
30
+ {
31
+ "sources": {
32
+ "local_postgres": {
33
+ "engine": "postgres",
34
+ "read_url_env": "SYNAPSOR_DATABASE_READ_URL",
35
+ "write_url_env": "SYNAPSOR_DATABASE_WRITE_URL"
36
+ }
37
+ }
38
+ }
39
+ ```
40
+
41
+ For `synapsor-runner apply --job ... --config ...`, set the env var named by
42
+ `write_url_env`. `SYNAPSOR_DATABASE_URL` is only a legacy fallback for direct
43
+ worker flows that do not pass a local config.
44
+
45
+ Direct SQL writeback also stores idempotency receipts in the source database.
46
+ By default it runs:
47
+
48
+ ```sql
49
+ CREATE TABLE IF NOT EXISTS synapsor_writeback_receipts (...);
50
+ ```
51
+
52
+ That means the writer needs permission to create and write that receipt table in
53
+ the target schema/database, or the table must be pre-created by an administrator
54
+ and granted to the writer. If you do not want Runner to create a table in the
55
+ application schema, create a dedicated schema/database for receipts where your
56
+ database policy allows it, or use `http_handler`/`command_handler` so your
57
+ application owns receipt storage and business writes.
58
+
27
59
  ## `http_handler`
28
60
 
29
61
  Use `http_handler` when your application/API should own business execution.
@@ -7,9 +7,11 @@ Use HTTP when your agent runs as an app/server and should connect to Runner
7
7
  over a local/private network endpoint instead of launching a stdio child
8
8
  process.
9
9
 
10
- Native HTTP MCP client support can vary by SDK version. This example is honest
11
- about that: it uses the OpenAI Agents SDK for the agent and wraps Synapsor's
12
- HTTP MCP JSON-RPC endpoint as an OpenAI function tool.
10
+ Runner's HTTP alpha endpoint is a small authenticated JSON-RPC surface for
11
+ `tools/list`, `tools/call`, and `resources/read`. It is not the full MCP
12
+ Streamable HTTP transport and does not implement `initialize`/SSE. This example
13
+ therefore uses the OpenAI Agents SDK for the agent and wraps Synapsor's HTTP
14
+ JSON-RPC endpoint as an OpenAI function tool.
13
15
 
14
16
  The model still sees a semantic action. It does not receive raw SQL, database
15
17
  URLs, write credentials, approval tools, or commit tools.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synapsor/runner",
3
- "version": "0.1.0-alpha.7",
3
+ "version": "0.1.0-alpha.8",
4
4
  "description": "Commit-safe MCP runner for Postgres and MySQL agents",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",