@synapsor/runner 1.5.0 → 1.5.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 +134 -3
- package/README.md +108 -113
- package/dist/authoring.d.ts +23 -0
- package/dist/authoring.d.ts.map +1 -0
- package/dist/authoring.mjs +1318 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +4 -5
- package/dist/local-ui.d.ts +14 -0
- package/dist/local-ui.d.ts.map +1 -1
- package/dist/runner.mjs +12334 -5256
- package/dist/runtime.mjs +817 -149
- package/dist/shadow.d.ts +36 -0
- package/dist/shadow.d.ts.map +1 -0
- package/dist/shadow.mjs +5362 -0
- package/docs/README.md +25 -2
- package/docs/alternatives.md +122 -0
- package/docs/capability-authoring.md +49 -1
- package/docs/client-recipes.md +218 -0
- package/docs/cloud-mode.md +18 -0
- package/docs/contract-testing.md +9 -7
- package/docs/cursor-plugin.md +78 -0
- package/docs/database-enforced-scope.md +8 -0
- package/docs/dsl-reference.md +45 -4
- package/docs/effect-regression.md +39 -2
- package/docs/fresh-developer-usability.md +110 -0
- package/docs/getting-started-own-database.md +102 -5
- package/docs/guarded-crud-writeback.md +10 -1
- package/docs/host-compatibility.md +59 -0
- package/docs/http-mcp.md +222 -207
- package/docs/limitations.md +9 -2
- package/docs/local-mode.md +11 -7
- package/docs/mcp-audit.md +166 -2
- package/docs/mcp-client-setup.md +28 -11
- package/docs/mcp-clients.md +43 -8
- package/docs/openai-agents-sdk.md +16 -2
- package/docs/oss-vs-cloud.md +3 -0
- package/docs/production.md +72 -7
- package/docs/release-notes.md +131 -4
- package/docs/runner-bundles.md +7 -2
- package/docs/runner-config-reference.md +96 -6
- package/docs/running-a-runner-fleet.md +42 -13
- package/docs/security-boundary.md +58 -8
- package/docs/shadow-studies.md +47 -4
- package/docs/store-lifecycle.md +93 -5
- package/docs/troubleshooting-first-run.md +46 -0
- package/examples/openai-agents-http/README.md +10 -4
- package/examples/openai-agents-http/agent.py +2 -2
- package/examples/runner-fleet/Dockerfile +7 -2
- package/examples/runner-fleet/README.md +11 -7
- package/examples/runner-fleet/docker-compose.yml +4 -4
- package/examples/runner-fleet/mint-dev-token.mjs +1 -1
- package/examples/runner-fleet/start-tls-runner.sh +21 -0
- package/examples/runner-fleet/synapsor.runner.json +27 -1
- package/examples/support-billing-agent/README.md +18 -0
- package/examples/support-billing-agent/app/README.md +6 -0
- package/examples/support-billing-agent/app/contract.ts +28 -0
- package/examples/support-billing-agent/app/effect-adapter.mjs +23 -0
- package/examples/support-billing-agent/app/record-shadow-outcomes.mjs +44 -0
- package/examples/support-billing-agent/scripts/run-evaluation.sh +6 -5
- package/examples/support-plan-credit/README.md +54 -3
- package/examples/support-plan-credit/mcp-client-examples/README.md +23 -0
- package/examples/support-plan-credit/mcp-client-examples/claude-code.sh +34 -0
- package/examples/support-plan-credit/mcp-client-examples/codex.config.toml +24 -0
- package/examples/support-plan-credit/mcp-client-examples/generic-stdio.mjs +35 -0
- package/examples/support-plan-credit/mcp-client-examples/generic-streamable-http.json +4 -1
- package/examples/support-plan-credit/mcp-client-examples/generic-streamable-http.mjs +31 -0
- package/examples/support-plan-credit/mcp-client-examples/google-adk.py +40 -0
- package/examples/support-plan-credit/mcp-client-examples/langchain.mjs +29 -0
- package/examples/support-plan-credit/mcp-client-examples/llamaindex.py +36 -0
- package/examples/support-plan-credit/mcp-client-examples/openai-agents-stdio.ts +1 -1
- package/examples/support-plan-credit/mcp-client-examples/openai-agents-streamable-http.ts +5 -1
- package/examples/support-plan-credit/mcp-client-examples/vscode.mcp.json +20 -0
- package/examples/support-plan-credit/synapsor/actions/support.propose_plan_credit.contract-tests.generated.json +221 -0
- package/examples/support-plan-credit/synapsor/actions/support.propose_plan_credit.ts +34 -0
- package/examples/support-plan-credit/synapsor.contract.json +0 -3
- package/fixtures/mcp-audit/README.md +14 -0
- package/fixtures/mcp-audit/cursor-bypass-config.json +38 -0
- package/fixtures/mcp-audit/dangerous-tools-list.json +33 -0
- package/fixtures/mcp-audit/reviewed-proposal-tools-list.json +60 -0
- package/package.json +18 -3
- package/schemas/mcp-audit-report.schema.json +100 -1
- package/schemas/synapsor.contract-tests.schema.json +1 -1
- package/schemas/synapsor.runner.schema.json +80 -0
package/docs/mcp-audit.md
CHANGED
|
@@ -8,7 +8,10 @@ available for users who look for the command under the MCP namespace.
|
|
|
8
8
|
From a source checkout, use `./bin/synapsor-runner ...` if the global binary is not
|
|
9
9
|
linked yet.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Static mode does not launch configured MCP servers or call business tools. It
|
|
12
|
+
only inspects names, descriptions, input schemas, output schemas, annotations,
|
|
13
|
+
and examples when those are present. An explicitly consented live check calls
|
|
14
|
+
only `initialize` and `tools/list` on one named server.
|
|
12
15
|
|
|
13
16
|
Every report includes this disclaimer:
|
|
14
17
|
|
|
@@ -86,6 +89,36 @@ Markdown output for issues, PRs, or security review notes:
|
|
|
86
89
|
npx -y -p @synapsor/runner synapsor-runner audit --example dangerous-db-mcp --format markdown
|
|
87
90
|
```
|
|
88
91
|
|
|
92
|
+
Inspect a project-scoped Cursor configuration without launching anything:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
npx -y -p @synapsor/runner synapsor-runner audit \
|
|
96
|
+
--mcp-config ./.cursor/mcp.json \
|
|
97
|
+
--format markdown
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Static client-config output marks every server without supplied tool metadata
|
|
101
|
+
as `requires_operator_verification`. To query one reviewed stdio command, name
|
|
102
|
+
that exact server and give explicit consent:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
npx -y -p @synapsor/runner synapsor-runner audit \
|
|
106
|
+
--mcp-config ./.cursor/mcp.json \
|
|
107
|
+
--live-server synapsor \
|
|
108
|
+
--yes \
|
|
109
|
+
--format json
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Runner does not use a shell and refuses unresolved interpolation. For Cursor's
|
|
113
|
+
documented `${workspaceFolder}` token, a config under `.cursor/mcp.json`
|
|
114
|
+
resolves against the project root. Live mode executes no business, approval,
|
|
115
|
+
apply, commit, or revert tool. It cannot prove the selected server is secure.
|
|
116
|
+
|
|
117
|
+
The bypass check matters after installing Runner: another model-visible MCP
|
|
118
|
+
server may still expose `execute_sql` or a direct write. Synapsor cannot govern
|
|
119
|
+
calls routed around Runner. Audit reports the server and observed tool names,
|
|
120
|
+
but never removes or rewrites unrelated MCP configuration automatically.
|
|
121
|
+
|
|
89
122
|
During local development, the repo-local wrapper can run the same command:
|
|
90
123
|
|
|
91
124
|
```bash
|
|
@@ -104,6 +137,19 @@ npx -y -p @synapsor/runner synapsor-runner audit generate \
|
|
|
104
137
|
--output ./synapsor-audit-candidates
|
|
105
138
|
```
|
|
106
139
|
|
|
140
|
+
Open the same blocked candidate directly in the secured local review
|
|
141
|
+
workbench:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
npx -y -p @synapsor/runner synapsor-runner audit generate \
|
|
145
|
+
./tools-list.json \
|
|
146
|
+
--output ./synapsor-audit-candidates \
|
|
147
|
+
--open-ui
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
This does not activate the candidate. The generated Runner config has no source
|
|
151
|
+
and every proposal writeback is `none`.
|
|
152
|
+
|
|
107
153
|
The generator uses the same parser and findings as `audit`. It writes:
|
|
108
154
|
|
|
109
155
|
- a canonical `@synapsor/spec` contract;
|
|
@@ -147,7 +193,33 @@ The audit accepts common exported shapes:
|
|
|
147
193
|
|
|
148
194
|
It also scans nested `adapter`, `mcpServers`, and `servers` blocks when they include tool metadata.
|
|
149
195
|
|
|
150
|
-
For live targets, the audit
|
|
196
|
+
For live stdio targets, the audit performs MCP `initialize`, then calls only
|
|
197
|
+
JSON-RPC `tools/list`. Remote URL mode calls `tools/list`. It does not call
|
|
198
|
+
business tools, approval tools, commit tools, or writeback tools.
|
|
199
|
+
|
|
200
|
+
Checked-in deterministic fixtures live under
|
|
201
|
+
[`fixtures/mcp-audit`](../fixtures/mcp-audit). The repository's
|
|
202
|
+
[`mcp-audit` GitHub Actions workflow](https://github.com/Synapsor/Synapsor-Runner/blob/main/.github/workflows/mcp-audit.yml)
|
|
203
|
+
builds the package, proves the dangerous fixture is detected, emits SARIF for
|
|
204
|
+
the reviewed proposal fixture, validates the SARIF shape, and uploads the
|
|
205
|
+
artifacts. Code-scanning upload runs only outside pull requests so forks do not
|
|
206
|
+
receive write authority.
|
|
207
|
+
|
|
208
|
+
## Model-authority map
|
|
209
|
+
|
|
210
|
+
Every text, JSON, Markdown, and SARIF report records structural evidence for:
|
|
211
|
+
|
|
212
|
+
- semantic reads and semantic proposals;
|
|
213
|
+
- direct writes and raw SQL/query authority;
|
|
214
|
+
- arbitrary identifier and model-controlled trust inputs;
|
|
215
|
+
- model-visible approval/apply/commit/revert authority;
|
|
216
|
+
- structured output and observable conflict/idempotency signals;
|
|
217
|
+
- controls that require an operator or sit outside static audit visibility.
|
|
218
|
+
|
|
219
|
+
Statuses are `observed`, `not_observed`, `requires_operator_verification`, or
|
|
220
|
+
`outside_static_audit_visibility`. These are evidence labels, not a numerical
|
|
221
|
+
security score. `not_observed` means only that the supplied metadata did not
|
|
222
|
+
show the authority. It is not proof of absence at runtime.
|
|
151
223
|
|
|
152
224
|
## Findings
|
|
153
225
|
|
|
@@ -164,6 +236,85 @@ The audit flags database-commit risks such as:
|
|
|
164
236
|
- ambiguous read/write tool boundaries;
|
|
165
237
|
- missing business descriptions, annotations, or fixture examples.
|
|
166
238
|
|
|
239
|
+
### Finding remediation index
|
|
240
|
+
|
|
241
|
+
The report carries one stable remediation URL for every finding. These anchors
|
|
242
|
+
are intentionally durable for JSON, Markdown, SARIF, pull requests, and code
|
|
243
|
+
scanning.
|
|
244
|
+
|
|
245
|
+
<a id="finding-generic-sql-tool"></a>
|
|
246
|
+
<a id="finding-write-tool-accepts-arbitrary-sql"></a>
|
|
247
|
+
<a id="finding-arbitrary-identifier-input"></a>
|
|
248
|
+
<a id="finding-arbitrary-predicate-input"></a>
|
|
249
|
+
|
|
250
|
+
#### Raw SQL, arbitrary identifiers, and free-form predicates
|
|
251
|
+
|
|
252
|
+
Replace generic SQL/query tools and model-selected schemas, tables, databases,
|
|
253
|
+
columns, filters, predicates, or WHERE clauses with a reviewed semantic
|
|
254
|
+
capability. Fixed identifiers and row-selection rules belong in the contract;
|
|
255
|
+
model inputs carry bounded business values only.
|
|
256
|
+
|
|
257
|
+
<a id="finding-model-controlled-trust-scope"></a>
|
|
258
|
+
|
|
259
|
+
#### Model-controlled trust scope
|
|
260
|
+
|
|
261
|
+
Bind tenant, principal, source, allowed fields, approval identity, and conflict
|
|
262
|
+
authority from verified context outside model arguments. Retain database RLS,
|
|
263
|
+
restricted views, and least-privilege roles underneath Runner.
|
|
264
|
+
|
|
265
|
+
<a id="finding-model-callable-commit-or-approval"></a>
|
|
266
|
+
<a id="finding-write-without-proposal-boundary"></a>
|
|
267
|
+
<a id="finding-mcp-bypass-direct-authority"></a>
|
|
268
|
+
|
|
269
|
+
#### Missing review boundary or bypass
|
|
270
|
+
|
|
271
|
+
Expose an immutable proposal rather than direct mutation. Keep activation,
|
|
272
|
+
approval, apply, commit, and revert outside MCP. Disable or independently
|
|
273
|
+
constrain another model-visible server that bypasses Runner; Synapsor cannot
|
|
274
|
+
govern calls made through that server.
|
|
275
|
+
|
|
276
|
+
<a id="finding-no-idempotency-field"></a>
|
|
277
|
+
<a id="finding-no-conflict-guard"></a>
|
|
278
|
+
<a id="finding-ambiguous-read-write-tool"></a>
|
|
279
|
+
|
|
280
|
+
#### Retry, stale-state, and mixed-authority gaps
|
|
281
|
+
|
|
282
|
+
Separate reads from proposals and require stable operation identity,
|
|
283
|
+
idempotency receipts, an exact conflict/version guard, and an affected-row
|
|
284
|
+
bound before trusted writeback.
|
|
285
|
+
|
|
286
|
+
<a id="finding-no-structured-output-schema"></a>
|
|
287
|
+
|
|
288
|
+
#### Missing structured output
|
|
289
|
+
|
|
290
|
+
Publish typed results that distinguish reads, pending proposals, conflicts,
|
|
291
|
+
failures, receipts, evidence, replay, and retry guidance without parsing prose.
|
|
292
|
+
|
|
293
|
+
<a id="finding-missing-business-description"></a>
|
|
294
|
+
<a id="finding-missing-risk-annotations"></a>
|
|
295
|
+
<a id="finding-missing-test-fixture"></a>
|
|
296
|
+
|
|
297
|
+
#### Reviewability gaps
|
|
298
|
+
|
|
299
|
+
Add a reviewer-readable business description, honest read/destructive hints,
|
|
300
|
+
and a non-production fixture. Annotations are vocabulary for clients, not an
|
|
301
|
+
enforcement boundary.
|
|
302
|
+
|
|
303
|
+
<a id="finding-mcp-server-tool-surface-unverified"></a>
|
|
304
|
+
|
|
305
|
+
#### Unverified configured server
|
|
306
|
+
|
|
307
|
+
Export that server's `tools/list`, or run the exact named `--live-server` check
|
|
308
|
+
after reviewing its configured command. Static client configuration does not
|
|
309
|
+
reveal the actual tool catalog.
|
|
310
|
+
|
|
311
|
+
<a id="finding-no-tools-found"></a>
|
|
312
|
+
|
|
313
|
+
#### No tools found
|
|
314
|
+
|
|
315
|
+
Provide an exported `tools/list` response, a supported manifest, a Runner
|
|
316
|
+
config, or an explicitly consented live target.
|
|
317
|
+
|
|
167
318
|
## Recommended target shape
|
|
168
319
|
|
|
169
320
|
A safer model-facing database MCP tool should look like a reviewed semantic proposal capability:
|
|
@@ -205,6 +356,19 @@ A safer model-facing database MCP tool should look like a reviewed semantic prop
|
|
|
205
356
|
|
|
206
357
|
Trusted values such as tenant, principal, source, allowed columns, approval identity, row-version guard, and database credentials must come from Synapsor/runner context, not from model-facing arguments.
|
|
207
358
|
|
|
359
|
+
To turn an identified business write into a disabled reviewed action, continue
|
|
360
|
+
with the Safe Action Composer:
|
|
361
|
+
|
|
362
|
+
```bash
|
|
363
|
+
synapsor-runner start \
|
|
364
|
+
--action refund_order \
|
|
365
|
+
--description "Propose one reviewed order refund"
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
The generated TypeScript action remains disabled. A coding agent may complete
|
|
369
|
+
and validate it; only a human can activate its exact digest in the secured
|
|
370
|
+
localhost Workbench.
|
|
371
|
+
|
|
208
372
|
## Related Fixture Benchmark
|
|
209
373
|
|
|
210
374
|
`synapsor-runner benchmark mcp-efficiency` compares a fixed generic database
|
package/docs/mcp-client-setup.md
CHANGED
|
@@ -11,6 +11,10 @@ or SDK. The simplest local-client contract is stdio. Standard HTTP MCP is
|
|
|
11
11
|
available through Streamable HTTP when your agent connects to a long-running
|
|
12
12
|
Runner service.
|
|
13
13
|
|
|
14
|
+
The checked [Client And Framework Recipes](client-recipes.md) use one shared
|
|
15
|
+
`support.propose_plan_credit` flow and distinguish host evidence from standard
|
|
16
|
+
MCP protocol evidence.
|
|
17
|
+
|
|
14
18
|
Proposal tools also advertise a standard display-only
|
|
15
19
|
[MCP App](mcp-apps.md). Supporting hosts discover it from tool metadata;
|
|
16
20
|
other clients keep the same text/JSON proposal result. Approval and apply
|
|
@@ -45,10 +49,13 @@ developer path. Streamable HTTP implements MCP initialize/session behavior over
|
|
|
45
49
|
an authenticated `/mcp` endpoint. The JSON-RPC bridge is intentionally smaller
|
|
46
50
|
and does not implement MCP initialize/session behavior.
|
|
47
51
|
|
|
48
|
-
HTTP requires
|
|
52
|
+
HTTP requires Bearer authentication by default. `Bearer` is the HTTP
|
|
53
|
+
presentation scheme; for this loopback example it carries one opaque random
|
|
54
|
+
endpoint token, not a user identity or JWT. The operator generates it and
|
|
55
|
+
provisions the same environment value to Runner and the authorized client:
|
|
49
56
|
|
|
50
57
|
```bash
|
|
51
|
-
export SYNAPSOR_RUNNER_HTTP_TOKEN="
|
|
58
|
+
export SYNAPSOR_RUNNER_HTTP_TOKEN="$(node -e 'process.stdout.write(require("node:crypto").randomBytes(32).toString("base64url"))')"
|
|
52
59
|
|
|
53
60
|
npx -y -p @synapsor/runner synapsor-runner mcp serve-streamable-http \
|
|
54
61
|
--config ./synapsor.runner.json \
|
|
@@ -84,8 +91,10 @@ npx -y -p @synapsor/runner synapsor-runner tools preview \
|
|
|
84
91
|
--alias-mode openai
|
|
85
92
|
```
|
|
86
93
|
|
|
87
|
-
|
|
88
|
-
|
|
94
|
+
Do not distribute one opaque token to unrelated users or tenants. A
|
|
95
|
+
non-loopback service also needs direct TLS or an explicitly trusted TLS proxy;
|
|
96
|
+
a shared service uses short-lived signed JWTs issued by your identity provider,
|
|
97
|
+
with tenant/principal bound from verified claims. Details: [HTTP MCP](http-mcp.md).
|
|
89
98
|
|
|
90
99
|
## Generate A Client Snippet
|
|
91
100
|
|
|
@@ -138,8 +147,10 @@ npx -y -p @synapsor/runner synapsor-runner mcp configure \
|
|
|
138
147
|
When the destination already exists, Synapsor Runner creates a timestamped
|
|
139
148
|
backup before writing. Noninteractive scripts must add `--yes`.
|
|
140
149
|
|
|
141
|
-
The command writes only
|
|
142
|
-
|
|
150
|
+
The command writes only command arguments and, for HTTP clients, credential
|
|
151
|
+
environment references plus external authorization metadata. It never writes
|
|
152
|
+
database URLs, passwords, token values, client secrets, or refresh tokens into
|
|
153
|
+
the generated client config.
|
|
143
154
|
|
|
144
155
|
No separate Apps flag is required. A compatible host discovers
|
|
145
156
|
`ui://synapsor/proposal-review.html` from proposal-tool metadata. The app can
|
|
@@ -161,8 +172,6 @@ the current `latest` release.
|
|
|
161
172
|
For standard app/server HTTP MCP mode:
|
|
162
173
|
|
|
163
174
|
```bash
|
|
164
|
-
export SYNAPSOR_RUNNER_HTTP_TOKEN="dev-local-token"
|
|
165
|
-
|
|
166
175
|
npx -y -p @synapsor/runner synapsor-runner mcp serve-streamable-http \
|
|
167
176
|
--config ./examples/mcp-postgres-billing/synapsor.runner.json \
|
|
168
177
|
--store ./.synapsor/local.db \
|
|
@@ -170,6 +179,8 @@ npx -y -p @synapsor/runner synapsor-runner mcp serve-streamable-http \
|
|
|
170
179
|
```
|
|
171
180
|
|
|
172
181
|
For the smaller JSON-RPC bridge, use `synapsor-runner mcp serve-http` instead.
|
|
182
|
+
The bridge is not standard Streamable HTTP and cannot provide claim-bound MCP
|
|
183
|
+
sessions, so do not use it for a shared identity deployment.
|
|
173
184
|
|
|
174
185
|
## Generic stdio Client
|
|
175
186
|
|
|
@@ -191,9 +202,9 @@ For the smaller JSON-RPC bridge, use `synapsor-runner mcp serve-http` instead.
|
|
|
191
202
|
"./.synapsor/local.db"
|
|
192
203
|
],
|
|
193
204
|
"env": {
|
|
194
|
-
"BILLING_POSTGRES_READ_URL": "
|
|
195
|
-
"SYNAPSOR_TENANT_ID": "
|
|
196
|
-
"SYNAPSOR_PRINCIPAL": "
|
|
205
|
+
"BILLING_POSTGRES_READ_URL": "${BILLING_POSTGRES_READ_URL}",
|
|
206
|
+
"SYNAPSOR_TENANT_ID": "${SYNAPSOR_TENANT_ID}",
|
|
207
|
+
"SYNAPSOR_PRINCIPAL": "${SYNAPSOR_PRINCIPAL}"
|
|
197
208
|
}
|
|
198
209
|
}
|
|
199
210
|
}
|
|
@@ -261,6 +272,12 @@ examples/mcp-client-configs/vscode.json
|
|
|
261
272
|
|
|
262
273
|
Each example uses the same stdio command/args/env structure. Replace the placeholder environment variables in your client settings or shell environment.
|
|
263
274
|
|
|
275
|
+
These checked-in desktop examples use stdio, which is the recommended local
|
|
276
|
+
path for Claude Desktop, Cursor, and VS Code. The OpenAI Agents SDK recipe is
|
|
277
|
+
syntax-checked, and the HTTP endpoint is interoperability-tested with the
|
|
278
|
+
official MCP TypeScript client; repository CI does not claim to exercise an
|
|
279
|
+
identity-provider login inside every third-party host.
|
|
280
|
+
|
|
264
281
|
Do not add a write database URL to the MCP server environment unless you are intentionally running a local review/writeback demo. For normal read/proposal tool calls, use the read URL and trusted context values only.
|
|
265
282
|
|
|
266
283
|
Before documenting a client UI as officially tested, verify:
|
package/docs/mcp-clients.md
CHANGED
|
@@ -15,6 +15,11 @@ The complete copy-paste templates live in:
|
|
|
15
15
|
- every local `synapsor-runner contract bundle` output;
|
|
16
16
|
- every downloadable Synapsor Cloud runner bundle.
|
|
17
17
|
|
|
18
|
+
For one shared proposal call across Claude Code, Codex, VS Code, OpenAI Agents,
|
|
19
|
+
LangChain/LangGraph, Google ADK, LlamaIndex, and generic MCP clients, see
|
|
20
|
+
[Client And Framework Recipes](client-recipes.md). Each recipe states whether
|
|
21
|
+
it is host-tested, configuration-tested, protocol-tested, or recipe-only.
|
|
22
|
+
|
|
18
23
|
Before connecting a client, validate the local boundary:
|
|
19
24
|
|
|
20
25
|
```bash
|
|
@@ -62,15 +67,39 @@ repository file.
|
|
|
62
67
|
|
|
63
68
|
### Cursor
|
|
64
69
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
70
|
+
Prefer Runner's owned project lifecycle for one repository:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
synapsor-runner mcp install cursor --project --dry-run \
|
|
74
|
+
--config ./synapsor.runner.json \
|
|
75
|
+
--store ./.synapsor/local.db
|
|
76
|
+
synapsor-runner mcp install cursor --project --yes \
|
|
77
|
+
--config ./synapsor.runner.json \
|
|
78
|
+
--store ./.synapsor/local.db
|
|
79
|
+
synapsor-runner mcp status cursor --project --check-launch
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Runner previews the merge, backs up an existing `.cursor/mcp.json`, preserves
|
|
83
|
+
other MCP servers/settings, writes an exact-version `npx` invocation, and
|
|
84
|
+
tracks only its own entry with an integrity marker. Repeating install is
|
|
85
|
+
idempotent. `mcp uninstall cursor --project --yes` removes only that intact,
|
|
86
|
+
Runner-owned entry and also creates a backup.
|
|
87
|
+
|
|
88
|
+
For global setup, merge `cursor-global.mcp.json` through Cursor's MCP settings
|
|
89
|
+
and replace every `<absolute-path-to-bundle>` marker. Restart the MCP server
|
|
90
|
+
from Cursor settings after editing.
|
|
69
91
|
|
|
70
92
|
The model-facing list should contain only the contract's inspect/propose tools.
|
|
71
93
|
If Cursor reports a missing config or store, use absolute paths and rerun
|
|
72
94
|
`tools preview` from the same working directory.
|
|
73
95
|
|
|
96
|
+
Cursor can be configured to auto-run model-facing tools. Synapsor therefore
|
|
97
|
+
never exposes approval, apply, revert, policy activation, trusted identity, or
|
|
98
|
+
credentials as MCP tools. Inline MCP App review is not assumed for Cursor; use
|
|
99
|
+
the secured localhost workbench or operator CLI. No Add to Cursor deep link is
|
|
100
|
+
generated because Runner has not verified a currently documented generic
|
|
101
|
+
payload for this server. See [Host Compatibility](host-compatibility.md).
|
|
102
|
+
|
|
74
103
|
### OpenAI Agents SDK
|
|
75
104
|
|
|
76
105
|
Install the SDK in your agent project and run either TypeScript template:
|
|
@@ -86,19 +115,25 @@ metadata preserves the canonical dotted Synapsor capability name.
|
|
|
86
115
|
## Streamable HTTP
|
|
87
116
|
|
|
88
117
|
```bash
|
|
118
|
+
export SYNAPSOR_RUNNER_HTTP_TOKEN="$(node -e 'process.stdout.write(require("node:crypto").randomBytes(32).toString("base64url"))')"
|
|
119
|
+
|
|
89
120
|
synapsor-runner mcp serve \
|
|
90
121
|
--transport streamable-http \
|
|
91
122
|
--alias-mode openai \
|
|
92
123
|
--host 127.0.0.1 \
|
|
93
124
|
--port 8766 \
|
|
94
125
|
--config ./synapsor.runner.json \
|
|
95
|
-
--store ./.synapsor/local.db
|
|
126
|
+
--store ./.synapsor/local.db \
|
|
127
|
+
--auth-token-env SYNAPSOR_RUNNER_HTTP_TOKEN
|
|
96
128
|
```
|
|
97
129
|
|
|
98
130
|
Connect a standard Streamable HTTP MCP client to
|
|
99
|
-
`http://127.0.0.1:8766/mcp
|
|
100
|
-
|
|
101
|
-
|
|
131
|
+
`http://127.0.0.1:8766/mcp` with `Authorization: Bearer` loaded from the same
|
|
132
|
+
protected environment value. Keep it on loopback for local development. A
|
|
133
|
+
non-loopback listener refuses to bind without direct TLS, an explicitly trusted
|
|
134
|
+
TLS proxy, or authenticated emergency break glass. Shared deployments require
|
|
135
|
+
identity-provider-issued signed claims. Follow [HTTP MCP](http-mcp.md) and the
|
|
136
|
+
[production guide](production.md).
|
|
102
137
|
|
|
103
138
|
Use `--alias-mode openai` for the OpenAI Agents SDK. Omit it for clients that
|
|
104
139
|
accept canonical dotted names, or use `--alias-mode both` only during a planned
|
|
@@ -8,7 +8,7 @@ surface.
|
|
|
8
8
|
## Start Runner
|
|
9
9
|
|
|
10
10
|
```bash
|
|
11
|
-
export SYNAPSOR_RUNNER_HTTP_TOKEN="
|
|
11
|
+
export SYNAPSOR_RUNNER_HTTP_TOKEN="$(node -e 'process.stdout.write(require("node:crypto").randomBytes(32).toString("base64url"))')"
|
|
12
12
|
|
|
13
13
|
npx -y -p @synapsor/runner synapsor-runner mcp serve-streamable-http \
|
|
14
14
|
--config ./synapsor.runner.json \
|
|
@@ -17,6 +17,11 @@ npx -y -p @synapsor/runner synapsor-runner mcp serve-streamable-http \
|
|
|
17
17
|
--alias-mode openai
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
+
For this loopback/single-service example, the operator provisions that same
|
|
21
|
+
opaque value to the Runner process and the Python client through protected
|
|
22
|
+
environment injection. HTTP `Bearer` describes how the credential is sent; it
|
|
23
|
+
does not make the opaque value a JWT, and Runner does not issue it.
|
|
24
|
+
|
|
20
25
|
`--alias-mode openai` is important because OpenAI function/tool names cannot
|
|
21
26
|
contain dots. Runner exposes names such as `billing__inspect_invoice` to the
|
|
22
27
|
model and maps calls back to canonical Synapsor capability names such as
|
|
@@ -28,7 +33,8 @@ model and maps calls back to canonical Synapsor capability names such as
|
|
|
28
33
|
npx -y -p @synapsor/runner synapsor-runner mcp client-config \
|
|
29
34
|
--client openai-agents \
|
|
30
35
|
--config ./synapsor.runner.json \
|
|
31
|
-
--store ./.synapsor/local.db
|
|
36
|
+
--store ./.synapsor/local.db \
|
|
37
|
+
--client-access-token-env SYNAPSOR_RUNNER_HTTP_TOKEN
|
|
32
38
|
```
|
|
33
39
|
|
|
34
40
|
The generated output includes:
|
|
@@ -41,6 +47,14 @@ The generated output includes:
|
|
|
41
47
|
It does not include database URLs, passwords, write credentials, API keys, or
|
|
42
48
|
bearer token values.
|
|
43
49
|
|
|
50
|
+
For a shared deployment, configure `http_claims`, asymmetric `session_auth`, and
|
|
51
|
+
`http_security.oauth_resource`, then use a separate env name such as
|
|
52
|
+
`SYNAPSOR_MCP_ACCESS_TOKEN`. Your configured identity provider issues that
|
|
53
|
+
short-lived token for the protected-resource audience; Runner validates it on
|
|
54
|
+
every request but never stores end-user passwords or issues/refreshes tokens.
|
|
55
|
+
The generated client URL is the configured HTTPS protected resource. See
|
|
56
|
+
[HTTP MCP](http-mcp.md) for the complete profile and TLS/proxy requirements.
|
|
57
|
+
|
|
44
58
|
## Sanity Check
|
|
45
59
|
|
|
46
60
|
Before giving the agent a real task, ask it to inspect one known object and
|
package/docs/oss-vs-cloud.md
CHANGED
|
@@ -22,6 +22,7 @@ runtime stay local.
|
|
|
22
22
|
| Contract source | Local files reviewed in Git | Shared registry with immutable versions and digests |
|
|
23
23
|
| Trusted context | Local environment/session bindings | Registered bindings plus deployment-specific Cloud session context |
|
|
24
24
|
| Capabilities | Local semantic MCP tools | Registry, version history, and capability inspection |
|
|
25
|
+
| Safe Action activation | Explicit digest-confirmed local Workbench activation after a source-unchanged staging Data PR | Governed Cloud activation and immutable registry version; local coding agents still cannot activate |
|
|
25
26
|
| Evidence and replay | Local SQLite ledger by default; optional shared Postgres runtime store | Redacted shared chronology and references; full evidence payload stays local by default |
|
|
26
27
|
| Approval | Local CLI or localhost UI | Human-authenticated shared approval inbox; unavailable to MCP/Runner tokens |
|
|
27
28
|
| Writeback | Guarded one-row CRUD, fixed/frozen bounded sets, or app-owned executor | Durable approval/job/lease coordination; the local Runner rechecks and executes |
|
|
@@ -36,6 +37,8 @@ runtime stay local.
|
|
|
36
37
|
- direct access to Postgres or MySQL;
|
|
37
38
|
- the process that executes guarded writeback;
|
|
38
39
|
- local development ledgers when Cloud linkage is not enabled.
|
|
40
|
+
- local disabled Safe Action drafts, project agent instructions, and source
|
|
41
|
+
database preview/writeback execution.
|
|
39
42
|
|
|
40
43
|
Cloud contract registration does not require uploading database credentials or
|
|
41
44
|
business rows. A Runner bundle contains the normalized contract, placeholder
|
package/docs/production.md
CHANGED
|
@@ -421,6 +421,36 @@ synapsor-runner activity search --proposal wrp_... --store ./.synapsor/local.db
|
|
|
421
421
|
|
|
422
422
|
## Deployment Recipes
|
|
423
423
|
|
|
424
|
+
### Networked MCP boundary
|
|
425
|
+
|
|
426
|
+
Prefer stdio when one local client can launch Runner. For Streamable HTTP,
|
|
427
|
+
choose the deployment profile before binding:
|
|
428
|
+
|
|
429
|
+
- loopback: authenticated opaque endpoint token by default;
|
|
430
|
+
- remote single-tenant: direct TLS or an explicitly trusted TLS proxy, plus one
|
|
431
|
+
high-entropy rotated service token;
|
|
432
|
+
- shared multi-user/tenant: direct TLS or trusted proxy, asymmetric signed JWT
|
|
433
|
+
sessions, exact issuer/audience/resource, verified tenant/principal claims,
|
|
434
|
+
and RFC 9728 protected-resource metadata.
|
|
435
|
+
|
|
436
|
+
An opaque token is generated by the operator and provisioned to server and
|
|
437
|
+
authorized client through environment/secret-manager injection. Runner does not
|
|
438
|
+
issue it. In a shared deployment, the configured external identity provider
|
|
439
|
+
issues short-lived access tokens; Runner verifies them but does not store user
|
|
440
|
+
passwords or issue refresh tokens. See [HTTP MCP](http-mcp.md) before exposing a
|
|
441
|
+
listener outside loopback.
|
|
442
|
+
|
|
443
|
+
Run the transport-specific doctor check before serving:
|
|
444
|
+
|
|
445
|
+
```bash
|
|
446
|
+
synapsor-runner doctor \
|
|
447
|
+
--config ./synapsor.runner.json \
|
|
448
|
+
--transport streamable-http \
|
|
449
|
+
--host 0.0.0.0 \
|
|
450
|
+
--trusted-tls-proxy \
|
|
451
|
+
--auth-token-env SYNAPSOR_RUNNER_HTTP_TOKEN
|
|
452
|
+
```
|
|
453
|
+
|
|
424
454
|
### Docker Compose Shape
|
|
425
455
|
|
|
426
456
|
Use Compose to run the MCP server next to your app and database network. Keep
|
|
@@ -436,14 +466,20 @@ export SYNAPSOR_SECRET_MAP='{
|
|
|
436
466
|
}'
|
|
437
467
|
|
|
438
468
|
synapsor-runner mcp serve-streamable-http \
|
|
469
|
+
--host 0.0.0.0 \
|
|
439
470
|
--config ./synapsor.runner.json \
|
|
440
471
|
--store ./.synapsor/local.db \
|
|
472
|
+
--trusted-tls-proxy \
|
|
473
|
+
--auth-token-env SYNAPSOR_RUNNER_HTTP_TOKEN \
|
|
441
474
|
--secrets-provider aws-secretsmanager-cli \
|
|
442
475
|
--secret-map-env SYNAPSOR_SECRET_MAP
|
|
443
476
|
```
|
|
444
477
|
|
|
445
478
|
The AWS provider shells out to `aws secretsmanager get-secret-value`; the runner
|
|
446
|
-
logs only how many target env vars were loaded or skipped.
|
|
479
|
+
logs only how many target env vars were loaded or skipped. This command assumes
|
|
480
|
+
`http_security.deployment: single_tenant`, an exact `allowed_hosts` list, and a
|
|
481
|
+
TLS proxy on a private hop. Use asymmetric claim-bound identity instead for a
|
|
482
|
+
shared user/tenant service.
|
|
447
483
|
|
|
448
484
|
```yaml
|
|
449
485
|
services:
|
|
@@ -453,22 +489,30 @@ services:
|
|
|
453
489
|
command: >
|
|
454
490
|
sh -lc "npm install -g @synapsor/runner &&
|
|
455
491
|
synapsor-runner up --review --config /config/synapsor.runner.json
|
|
456
|
-
--store /data/local.db --host 0.0.0.0 --port 8766
|
|
492
|
+
--store /data/local.db --host 0.0.0.0 --port 8766
|
|
493
|
+
--trusted-tls-proxy --auth-token-env SYNAPSOR_RUNNER_HTTP_TOKEN"
|
|
457
494
|
environment:
|
|
458
495
|
SYNAPSOR_DATABASE_READ_URL: ${SYNAPSOR_DATABASE_READ_URL}
|
|
459
496
|
SYNAPSOR_DATABASE_WRITE_URL: ${SYNAPSOR_DATABASE_WRITE_URL}
|
|
460
497
|
SYNAPSOR_TENANT_ID: ${SYNAPSOR_TENANT_ID}
|
|
461
498
|
SYNAPSOR_PRINCIPAL: ${SYNAPSOR_PRINCIPAL}
|
|
499
|
+
SYNAPSOR_RUNNER_HTTP_TOKEN: ${SYNAPSOR_RUNNER_HTTP_TOKEN}
|
|
462
500
|
volumes:
|
|
463
501
|
- ./synapsor.runner.json:/config/synapsor.runner.json:ro
|
|
464
502
|
- synapsor-runner-data:/data
|
|
465
|
-
|
|
466
|
-
- "8766
|
|
503
|
+
expose:
|
|
504
|
+
- "8766"
|
|
467
505
|
|
|
468
506
|
volumes:
|
|
469
507
|
synapsor-runner-data:
|
|
470
508
|
```
|
|
471
509
|
|
|
510
|
+
This shape deliberately does not publish the Runner port to the host. Put a
|
|
511
|
+
TLS-terminating proxy on the same private container network, publish only that
|
|
512
|
+
proxy, preserve the reviewed external Host, and prevent direct client access to
|
|
513
|
+
Runner. If Runner itself owns TLS, replace `--trusted-tls-proxy` with protected
|
|
514
|
+
`--tls-cert-env`/`--tls-key-env` PEM references.
|
|
515
|
+
|
|
472
516
|
### systemd Shape
|
|
473
517
|
|
|
474
518
|
```ini
|
|
@@ -491,10 +535,20 @@ PrivateTmp=true
|
|
|
491
535
|
WantedBy=multi-user.target
|
|
492
536
|
```
|
|
493
537
|
|
|
494
|
-
Put database credentials
|
|
495
|
-
manager, not in
|
|
538
|
+
Put database credentials and the random loopback endpoint token in
|
|
539
|
+
`/etc/synapsor-runner.env` or your system secret manager, not in
|
|
540
|
+
`synapsor.runner.json`. The systemd command binds loopback, so a local trusted
|
|
541
|
+
proxy may connect to it without exposing cleartext Bearer traffic on the
|
|
542
|
+
network.
|
|
496
543
|
|
|
497
|
-
## TLS And SSL
|
|
544
|
+
## TLS, mTLS, And Database SSL
|
|
545
|
+
|
|
546
|
+
For MCP HTTP, Runner-owned TLS reads certificate/key PEM only from named
|
|
547
|
+
environment variables. Optional mTLS verifies client certificates against an
|
|
548
|
+
explicit CA and supplements Bearer authentication; it does not replace
|
|
549
|
+
per-session tenant/principal identity in a shared service. A trusted proxy must
|
|
550
|
+
be protected from direct bypass and must not inject forwarded tenant/principal
|
|
551
|
+
headers as authority.
|
|
498
552
|
|
|
499
553
|
For staging or production-like databases:
|
|
500
554
|
|
|
@@ -507,6 +561,17 @@ For staging or production-like databases:
|
|
|
507
561
|
For disposable local Docker fixtures, `sslmode=disable` is acceptable when the
|
|
508
562
|
database is bound to loopback and contains only test data.
|
|
509
563
|
|
|
564
|
+
Rotate credentials independently:
|
|
565
|
+
|
|
566
|
+
- opaque endpoint token: active plus at most one previous env during rollout;
|
|
567
|
+
- HS256 session key: active plus one previous key, only for controlled use;
|
|
568
|
+
- asymmetric JWT key: publish a new `kid`, honor bounded JWKS cache/cooldown,
|
|
569
|
+
then retire the old public key after clients rotate;
|
|
570
|
+
- TLS certificate and mTLS client CA: roll protected PEM material and restart
|
|
571
|
+
instances without changing tenant identity;
|
|
572
|
+
- database and handler credentials: rotate their separate env/secret-manager
|
|
573
|
+
entries without reusing an MCP or Cloud credential.
|
|
574
|
+
|
|
510
575
|
## Health And Doctor
|
|
511
576
|
|
|
512
577
|
Run these before exposing tools to an agent:
|