@synapsor/runner 1.5.3 → 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 +44 -2
- package/README.md +20 -12
- package/dist/cli.d.ts.map +1 -1
- package/dist/runner.mjs +2332 -501
- package/dist/runtime.mjs +788 -148
- package/dist/shadow.mjs +101 -1
- package/docs/capability-authoring.md +6 -1
- package/docs/cloud-mode.md +18 -0
- package/docs/database-enforced-scope.md +8 -0
- package/docs/dsl-reference.md +45 -4
- package/docs/getting-started-own-database.md +6 -3
- package/docs/guarded-crud-writeback.md +10 -1
- package/docs/http-mcp.md +222 -207
- package/docs/limitations.md +9 -2
- package/docs/local-mode.md +5 -2
- package/docs/mcp-client-setup.md +24 -11
- package/docs/mcp-clients.md +10 -4
- package/docs/openai-agents-sdk.md +16 -2
- package/docs/production.md +72 -7
- package/docs/release-notes.md +44 -3
- 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 +38 -3
- package/docs/store-lifecycle.md +93 -5
- 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-plan-credit/README.md +6 -1
- package/examples/support-plan-credit/mcp-client-examples/generic-streamable-http.json +4 -1
- package/examples/support-plan-credit/mcp-client-examples/openai-agents-streamable-http.ts +4 -0
- package/examples/support-plan-credit/synapsor.contract.json +0 -3
- package/package.json +1 -1
- package/schemas/synapsor.runner.schema.json +80 -0
package/docs/store-lifecycle.md
CHANGED
|
@@ -33,20 +33,108 @@ sqlite3 -readonly ./.synapsor/local.db '.tables'
|
|
|
33
33
|
Do not mutate the database directly. Its internal tables may change between
|
|
34
34
|
releases and are not a public storage API; use Runner commands for automation.
|
|
35
35
|
|
|
36
|
-
## Inspect
|
|
36
|
+
## Inspect one complete lifecycle
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
Start with no id:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
synapsor-runner lifecycle --store ./.synapsor/local.db
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`lifecycle`, `lifecycle show`, and `lifecycle show latest` are exact aliases.
|
|
45
|
+
They choose the newest proposal deterministically by `created_at` descending,
|
|
46
|
+
then proposal id as the tie-breaker. The default view answers:
|
|
47
|
+
|
|
48
|
+
- what capability and business object the model requested;
|
|
49
|
+
- which trusted tenant and principal scoped it;
|
|
50
|
+
- approval state and progress;
|
|
51
|
+
- whether a writeback job or intent exists;
|
|
52
|
+
- the latest guarded outcome and whether the source changed;
|
|
53
|
+
- replay and Cloud-link status; and
|
|
54
|
+
- the next safe read-only or operator command.
|
|
55
|
+
|
|
56
|
+
Use `--details` for one causal proposal-to-receipt/replay timeline, or `--json`
|
|
57
|
+
for one stable `synapsor.lifecycle-view.v1` JSON document:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
synapsor-runner lifecycle --details --store ./.synapsor/local.db
|
|
61
|
+
synapsor-runner lifecycle --json --store ./.synapsor/local.db
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The JSON is a domain view, not a dump of internal SQLite/PostgreSQL tables.
|
|
65
|
+
Absent stages are represented explicitly as empty arrays or `null`; Runner
|
|
66
|
+
does not fabricate a job, receipt, replay, or Cloud synchronization.
|
|
67
|
+
|
|
68
|
+
### Browse and filter without copying ids
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
synapsor-runner lifecycle list --limit 20 --store ./.synapsor/local.db
|
|
72
|
+
synapsor-runner lifecycle show --object invoice:INV-3001 --details --store ./.synapsor/local.db
|
|
73
|
+
synapsor-runner lifecycle list --tenant acme --capability billing.propose_late_fee_waiver
|
|
74
|
+
synapsor-runner lifecycle show --principal support-agent-17 --status applied
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
List/show support tenant, principal, capability, business object, status/state,
|
|
78
|
+
and time-window filters. Filtered `show` selects the newest match and reports
|
|
79
|
+
the total match count; use `lifecycle list` to browse all matches. List JSON
|
|
80
|
+
uses `synapsor.lifecycle-list.v1`.
|
|
81
|
+
|
|
82
|
+
### Start from any handle you already have
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
synapsor-runner lifecycle show wrp_... --details
|
|
86
|
+
synapsor-runner lifecycle show ev_... --details
|
|
87
|
+
synapsor-runner lifecycle show replay_... --details
|
|
88
|
+
synapsor-runner lifecycle show wbj_... --details
|
|
89
|
+
synapsor-runner lifecycle show wbi:wbj_... --details
|
|
90
|
+
synapsor-runner lifecycle show receipt:42 --details
|
|
91
|
+
synapsor-runner lifecycle show audit:17 --details
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Runner resolves proposal, evidence, replay, writeback-job, writeback-intent,
|
|
95
|
+
receipt, and query-audit handles to the owning proposal. Numeric receipt and
|
|
96
|
+
query-audit ids require the `receipt:` or `audit:` namespace; a bare number is
|
|
97
|
+
rejected rather than guessed.
|
|
98
|
+
|
|
99
|
+
Lifecycle inspection is read-only. It does not contact the source database or
|
|
100
|
+
Cloud, create a writeback job, acquire a worker lease, approve, apply, reconcile,
|
|
101
|
+
retry, or synchronize anything. It applies the same tenant/principal visibility
|
|
102
|
+
rules and secret/kept-out-field protections as the focused views.
|
|
103
|
+
|
|
104
|
+
### Shared PostgreSQL runtime store
|
|
105
|
+
|
|
106
|
+
For `storage.shared_postgres.mode = "runtime_store"`, pass the reviewed config:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
synapsor-runner lifecycle --config ./synapsor.runner.json
|
|
110
|
+
synapsor-runner lifecycle show --object invoice:INV-3001 --details \
|
|
111
|
+
--config ./synapsor.runner.json
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Runner reuses the existing bounded read bridge to the authoritative shared
|
|
115
|
+
ledger. It does not create or synchronize a persistent local mirror during
|
|
116
|
+
inspection. Connection failures fail safely; the command never falls back to an
|
|
117
|
+
unrelated local store.
|
|
118
|
+
|
|
119
|
+
## Focused inspection commands
|
|
120
|
+
|
|
121
|
+
The existing commands remain useful when you need one record type:
|
|
122
|
+
|
|
123
|
+
| Question | Focused command |
|
|
39
124
|
| --- | --- |
|
|
40
|
-
| What did the model propose? | `synapsor-runner proposals show
|
|
125
|
+
| What did the model propose? | `synapsor-runner proposals show latest --details` |
|
|
41
126
|
| What data supported it? | `synapsor-runner evidence list --proposal <proposal-id>` then `evidence show <evidence-id> --details` |
|
|
42
127
|
| What query was run? | `synapsor-runner query-audit list --proposal <proposal-id>` |
|
|
43
|
-
| Who approved or rejected it? | `synapsor-runner proposals show <proposal-id> --details` |
|
|
44
128
|
| Did guarded writeback apply? | `synapsor-runner receipts list --proposal <proposal-id>` |
|
|
45
|
-
| What
|
|
129
|
+
| What replay snapshot exists? | `synapsor-runner replay show latest --details` |
|
|
46
130
|
| What happened to one object? | `synapsor-runner activity search --object invoice:INV-3001` |
|
|
47
131
|
| What are the latest events? | `synapsor-runner events tail` |
|
|
48
132
|
| How large is the store? | `synapsor-runner store stats --store ./.synapsor/local.db` |
|
|
49
133
|
|
|
134
|
+
`proposals writeback-job` is intentionally absent from inspection examples:
|
|
135
|
+
it materializes a job and is therefore an operator mutation, not a read-only
|
|
136
|
+
view.
|
|
137
|
+
|
|
50
138
|
## Server leases
|
|
51
139
|
|
|
52
140
|
MCP server modes write a small lease file next to the store:
|
|
@@ -40,7 +40,7 @@ OpenAI Agents Streamable HTTP example smoke passed.
|
|
|
40
40
|
export DATABASE_URL="<postgres-or-mysql-read-url>"
|
|
41
41
|
export SYNAPSOR_TENANT_ID="acme"
|
|
42
42
|
export SYNAPSOR_PRINCIPAL="openai_agent_demo"
|
|
43
|
-
export SYNAPSOR_RUNNER_HTTP_TOKEN="
|
|
43
|
+
export SYNAPSOR_RUNNER_HTTP_TOKEN="$(node -e 'process.stdout.write(require("node:crypto").randomBytes(32).toString("base64url"))')"
|
|
44
44
|
|
|
45
45
|
npx -y -p @synapsor/runner synapsor-runner mcp serve-streamable-http \
|
|
46
46
|
--config ./synapsor.runner.json \
|
|
@@ -49,6 +49,10 @@ npx -y -p @synapsor/runner synapsor-runner mcp serve-streamable-http \
|
|
|
49
49
|
--alias-mode openai
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
+
The operator must provision that same opaque value to the authorized client.
|
|
53
|
+
It is endpoint access for this loopback/single-service example, not user or
|
|
54
|
+
tenant identity. Do not put it in source code or the client config.
|
|
55
|
+
|
|
52
56
|
## Terminal 2: Run The Agent
|
|
53
57
|
|
|
54
58
|
```bash
|
|
@@ -58,7 +62,7 @@ pip install -r requirements.txt
|
|
|
58
62
|
|
|
59
63
|
export OPENAI_API_KEY="..."
|
|
60
64
|
export SYNAPSOR_RUNNER_HTTP_URL="http://127.0.0.1:8766/mcp"
|
|
61
|
-
|
|
65
|
+
read -rsp "Provisioned Synapsor endpoint token: " SYNAPSOR_MCP_ACCESS_TOKEN; printf '\n'; export SYNAPSOR_MCP_ACCESS_TOKEN
|
|
62
66
|
export SYNAPSOR_INVOICE_ID="INV-3001"
|
|
63
67
|
|
|
64
68
|
python agent.py
|
|
@@ -74,5 +78,7 @@ Expected behavior:
|
|
|
74
78
|
- no SQL/write/approval tool is exposed to the model;
|
|
75
79
|
- evidence/query audit are saved in the local Runner store.
|
|
76
80
|
|
|
77
|
-
For production-like deployment,
|
|
78
|
-
|
|
81
|
+
For production-like deployment, non-loopback HTTP requires Runner TLS or an
|
|
82
|
+
explicitly trusted TLS proxy. A shared user/tenant service uses a short-lived
|
|
83
|
+
signed access token from an external identity provider rather than distributing
|
|
84
|
+
one opaque token. See [HTTP MCP](../../docs/http-mcp.md).
|
|
@@ -13,14 +13,14 @@ except ImportError as exc:
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
async def main() -> None:
|
|
16
|
-
required = ["OPENAI_API_KEY", "SYNAPSOR_RUNNER_HTTP_URL", "
|
|
16
|
+
required = ["OPENAI_API_KEY", "SYNAPSOR_RUNNER_HTTP_URL", "SYNAPSOR_MCP_ACCESS_TOKEN"]
|
|
17
17
|
missing = [name for name in required if not os.environ.get(name)]
|
|
18
18
|
if missing:
|
|
19
19
|
raise SystemExit(f"Missing required environment variables: {', '.join(missing)}")
|
|
20
20
|
|
|
21
21
|
invoice_id = os.environ.get("SYNAPSOR_INVOICE_ID", "INV-3001")
|
|
22
22
|
mcp_url = os.environ["SYNAPSOR_RUNNER_HTTP_URL"]
|
|
23
|
-
token = os.environ["
|
|
23
|
+
token = os.environ["SYNAPSOR_MCP_ACCESS_TOKEN"]
|
|
24
24
|
|
|
25
25
|
async with MCPServerStreamableHttp(
|
|
26
26
|
params={
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
FROM node:22-bookworm-slim
|
|
2
2
|
|
|
3
|
+
RUN apt-get update \
|
|
4
|
+
&& apt-get install -y --no-install-recommends openssl \
|
|
5
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
6
|
+
|
|
3
7
|
RUN corepack enable && corepack prepare pnpm@10.14.0 --activate
|
|
4
8
|
|
|
5
9
|
WORKDIR /app
|
|
6
10
|
COPY . .
|
|
7
11
|
RUN corepack pnpm install --frozen-lockfile \
|
|
8
|
-
&& corepack pnpm build:runner-package
|
|
12
|
+
&& corepack pnpm build:runner-package \
|
|
13
|
+
&& chmod +x examples/runner-fleet/start-tls-runner.sh
|
|
9
14
|
|
|
10
|
-
ENTRYPOINT ["
|
|
15
|
+
ENTRYPOINT ["examples/runner-fleet/start-tls-runner.sh"]
|
|
11
16
|
CMD ["mcp", "serve", "--transport", "streamable-http", "--host", "0.0.0.0", "--port", "8766", "--config", "/config/synapsor.runner.json"]
|
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
This synthetic fixture starts Postgres, MySQL, and two stateless Streamable
|
|
4
4
|
HTTP Runner services. Both Runners share one bounded Postgres runtime ledger.
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
Each container generates a one-day self-signed certificate at startup so the
|
|
6
|
+
non-loopback Runner listener exercises direct TLS rather than insecure HTTP.
|
|
7
|
+
The committed database passwords and HS256 key are disposable local-demo
|
|
8
|
+
values. Never reuse them outside this fixture; production should use a trusted
|
|
9
|
+
certificate and asymmetric identity-provider tokens.
|
|
7
10
|
|
|
8
11
|
From the repository root:
|
|
9
12
|
|
|
@@ -16,9 +19,9 @@ docker compose --profile fleet -f examples/runner-fleet/docker-compose.yml ps
|
|
|
16
19
|
Check both instances:
|
|
17
20
|
|
|
18
21
|
```bash
|
|
19
|
-
curl --fail
|
|
20
|
-
curl --fail
|
|
21
|
-
curl --fail
|
|
22
|
+
curl --fail --insecure https://127.0.0.1:8871/healthz
|
|
23
|
+
curl --fail --insecure https://127.0.0.1:8871/readyz
|
|
24
|
+
curl --fail --insecure https://127.0.0.1:8872/readyz
|
|
22
25
|
```
|
|
23
26
|
|
|
24
27
|
The MCP endpoint requires a claim-bearing development JWT. Generate one for
|
|
@@ -28,8 +31,9 @@ the fixture only:
|
|
|
28
31
|
node examples/runner-fleet/mint-dev-token.mjs acme local-agent
|
|
29
32
|
```
|
|
30
33
|
|
|
31
|
-
|
|
32
|
-
|
|
34
|
+
`--insecure` is acceptable only for this synthetic self-signed fixture. The
|
|
35
|
+
production path should use a trusted TLS chain and `jwt_asymmetric` with an
|
|
36
|
+
explicit RS256/ES256 allowlist plus a trusted JWKS URL or public PEM. See
|
|
33
37
|
[Running A Runner Fleet](../../docs/running-a-runner-fleet.md).
|
|
34
38
|
|
|
35
39
|
Run the stronger automated verification instead of treating a green Compose
|
|
@@ -46,11 +46,11 @@ services:
|
|
|
46
46
|
SYNAPSOR_SESSION_JWT_SECRET: synthetic-fleet-session-secret-change-before-use-0001
|
|
47
47
|
SYNAPSOR_METRICS_TOKEN: synthetic-fleet-metrics-token-change-before-use
|
|
48
48
|
ports:
|
|
49
|
-
- "8871:8766"
|
|
49
|
+
- "127.0.0.1:8871:8766"
|
|
50
50
|
volumes:
|
|
51
51
|
- ./synapsor.runner.json:/config/synapsor.runner.json:ro
|
|
52
52
|
healthcheck:
|
|
53
|
-
test: ["CMD", "node
|
|
53
|
+
test: ["CMD-SHELL", "NODE_TLS_REJECT_UNAUTHORIZED=0 node -e \"fetch('https://127.0.0.1:8766/readyz').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\""]
|
|
54
54
|
interval: 2s
|
|
55
55
|
timeout: 5s
|
|
56
56
|
retries: 30
|
|
@@ -66,11 +66,11 @@ services:
|
|
|
66
66
|
condition: service_healthy
|
|
67
67
|
environment: *runner_environment
|
|
68
68
|
ports:
|
|
69
|
-
- "8872:8766"
|
|
69
|
+
- "127.0.0.1:8872:8766"
|
|
70
70
|
volumes:
|
|
71
71
|
- ./synapsor.runner.json:/config/synapsor.runner.json:ro
|
|
72
72
|
healthcheck:
|
|
73
|
-
test: ["CMD", "node
|
|
73
|
+
test: ["CMD-SHELL", "NODE_TLS_REJECT_UNAUTHORIZED=0 node -e \"fetch('https://127.0.0.1:8766/readyz').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\""]
|
|
74
74
|
interval: 2s
|
|
75
75
|
timeout: 5s
|
|
76
76
|
retries: 30
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
tls_dir="${SYNAPSOR_FLEET_TLS_DIR:-/tmp/synapsor-runner-tls}"
|
|
5
|
+
mkdir -p "$tls_dir"
|
|
6
|
+
chmod 700 "$tls_dir"
|
|
7
|
+
|
|
8
|
+
openssl req -x509 -newkey rsa:2048 -sha256 -nodes -days 1 \
|
|
9
|
+
-subj "/CN=localhost" \
|
|
10
|
+
-addext "subjectAltName=DNS:localhost,IP:127.0.0.1" \
|
|
11
|
+
-keyout "$tls_dir/server.key" \
|
|
12
|
+
-out "$tls_dir/server.crt" \
|
|
13
|
+
>/dev/null 2>&1
|
|
14
|
+
chmod 600 "$tls_dir/server.key" "$tls_dir/server.crt"
|
|
15
|
+
|
|
16
|
+
export SYNAPSOR_FLEET_TLS_CERT_PEM="$(<"$tls_dir/server.crt")"
|
|
17
|
+
export SYNAPSOR_FLEET_TLS_KEY_PEM="$(<"$tls_dir/server.key")"
|
|
18
|
+
|
|
19
|
+
exec node apps/runner/dist/cli.js "$@" \
|
|
20
|
+
--tls-cert-env SYNAPSOR_FLEET_TLS_CERT_PEM \
|
|
21
|
+
--tls-key-env SYNAPSOR_FLEET_TLS_KEY_PEM
|
|
@@ -36,11 +36,37 @@
|
|
|
36
36
|
"provider": "jwt_hs256",
|
|
37
37
|
"secret_env": "SYNAPSOR_SESSION_JWT_SECRET",
|
|
38
38
|
"issuer": "https://fleet.example.invalid",
|
|
39
|
-
"audience": "
|
|
39
|
+
"audience": "https://runner-fleet.example.invalid/mcp",
|
|
40
40
|
"tenant_claim": "tenant_id",
|
|
41
41
|
"principal_claim": "sub",
|
|
42
42
|
"clock_skew_seconds": 10
|
|
43
43
|
},
|
|
44
|
+
"http_security": {
|
|
45
|
+
"deployment": "shared",
|
|
46
|
+
"oauth_resource": {
|
|
47
|
+
"resource": "https://runner-fleet.example.invalid/mcp",
|
|
48
|
+
"authorization_servers": ["https://fleet.example.invalid"],
|
|
49
|
+
"resource_name": "Synthetic Synapsor Runner fleet"
|
|
50
|
+
},
|
|
51
|
+
"allowed_hosts": [
|
|
52
|
+
"127.0.0.1:8766",
|
|
53
|
+
"127.0.0.1:8871",
|
|
54
|
+
"127.0.0.1:8872",
|
|
55
|
+
"localhost:8766",
|
|
56
|
+
"localhost:8871",
|
|
57
|
+
"localhost:8872"
|
|
58
|
+
],
|
|
59
|
+
"limits": {
|
|
60
|
+
"max_request_bytes": 65536,
|
|
61
|
+
"max_header_bytes": 8192,
|
|
62
|
+
"max_sessions": 100,
|
|
63
|
+
"session_idle_timeout_seconds": 120,
|
|
64
|
+
"request_timeout_ms": 15000,
|
|
65
|
+
"headers_timeout_ms": 5000,
|
|
66
|
+
"keep_alive_timeout_ms": 5000,
|
|
67
|
+
"max_connections": 200
|
|
68
|
+
}
|
|
69
|
+
},
|
|
44
70
|
"rate_limits": {
|
|
45
71
|
"enabled": true,
|
|
46
72
|
"default": { "requests": 20, "window_seconds": 60 },
|
|
@@ -252,13 +252,16 @@ verification gate.
|
|
|
252
252
|
For Streamable HTTP, run:
|
|
253
253
|
|
|
254
254
|
```bash
|
|
255
|
+
export SYNAPSOR_RUNNER_HTTP_TOKEN="$(node -e 'process.stdout.write(require("node:crypto").randomBytes(32).toString("base64url"))')"
|
|
256
|
+
|
|
255
257
|
synapsor-runner mcp serve \
|
|
256
258
|
--transport streamable-http \
|
|
257
259
|
--alias-mode openai \
|
|
258
260
|
--host 127.0.0.1 \
|
|
259
261
|
--port 8766 \
|
|
260
262
|
--config examples/support-plan-credit/synapsor.runner.json \
|
|
261
|
-
--store ./tmp/support-plan-credit/local.db
|
|
263
|
+
--store ./tmp/support-plan-credit/local.db \
|
|
264
|
+
--auth-token-env SYNAPSOR_RUNNER_HTTP_TOKEN
|
|
262
265
|
```
|
|
263
266
|
|
|
264
267
|
The OpenAI client receives `support__inspect_customer` and
|
|
@@ -266,6 +269,8 @@ The OpenAI client receives `support__inspect_customer` and
|
|
|
266
269
|
tool metadata and results. For Claude, Cursor, or generic MCP clients, omit
|
|
267
270
|
`--alias-mode openai` to expose `support.inspect_customer` and
|
|
268
271
|
`support.propose_plan_credit`. Approval and apply remain outside MCP.
|
|
272
|
+
The HTTP client reads the same opaque endpoint token from its protected
|
|
273
|
+
environment; no token value belongs in the checked-in recipe.
|
|
269
274
|
|
|
270
275
|
## How The Policy Is Governed
|
|
271
276
|
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { Agent, MCPServerStreamableHttp, run } from "@openai/agents";
|
|
2
2
|
|
|
3
3
|
// Start Runner with --alias-mode openai so model-visible tool names are valid OpenAI function names.
|
|
4
|
+
const token = process.env.SYNAPSOR_RUNNER_HTTP_TOKEN;
|
|
5
|
+
if (!token) throw new Error("set SYNAPSOR_RUNNER_HTTP_TOKEN in the launching environment");
|
|
6
|
+
|
|
4
7
|
const synapsor = new MCPServerStreamableHttp({
|
|
5
8
|
name: "Synapsor Runner",
|
|
6
9
|
url: "http://127.0.0.1:8766/mcp",
|
|
10
|
+
requestInit: { headers: { Authorization: `Bearer ${token}` } },
|
|
7
11
|
});
|
|
8
12
|
|
|
9
13
|
await synapsor.connect();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synapsor/runner",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.4",
|
|
4
4
|
"description": "Stop giving AI agents execute_sql; expose reviewed Postgres/MySQL MCP actions with proposals, approval, writeback, and replay.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -293,6 +293,80 @@
|
|
|
293
293
|
"max_response_bytes": { "type": "integer", "minimum": 1024, "maximum": 10485760 }
|
|
294
294
|
}
|
|
295
295
|
},
|
|
296
|
+
"http_security": {
|
|
297
|
+
"description": "Runner-only deployment security for networked MCP. Credential values remain in environment or secret-manager wiring and never enter portable contracts.",
|
|
298
|
+
"type": "object",
|
|
299
|
+
"additionalProperties": false,
|
|
300
|
+
"properties": {
|
|
301
|
+
"deployment": {
|
|
302
|
+
"description": "Trust topology. shared requires signed per-session http_claims identity; single_tenant may use one opaque service token.",
|
|
303
|
+
"enum": ["loopback", "single_tenant", "shared"]
|
|
304
|
+
},
|
|
305
|
+
"channel": {
|
|
306
|
+
"description": "How a remote listener is protected in transit. insecure_http_break_glass is unsafe and still requires authentication.",
|
|
307
|
+
"enum": ["direct_tls", "trusted_tls_proxy", "insecure_http_break_glass"]
|
|
308
|
+
},
|
|
309
|
+
"static_token": {
|
|
310
|
+
"description": "Environment-variable names for the current opaque endpoint token and at most one previous rotation token.",
|
|
311
|
+
"type": "object",
|
|
312
|
+
"additionalProperties": false,
|
|
313
|
+
"properties": {
|
|
314
|
+
"active_env": { "$ref": "#/$defs/env_name" },
|
|
315
|
+
"previous_env": { "$ref": "#/$defs/env_name" }
|
|
316
|
+
}
|
|
317
|
+
},
|
|
318
|
+
"oauth_resource": {
|
|
319
|
+
"description": "RFC 9728 metadata for Runner as an OAuth protected resource. The external authorization server issues tokens; Runner only verifies them.",
|
|
320
|
+
"type": "object",
|
|
321
|
+
"additionalProperties": false,
|
|
322
|
+
"required": ["resource", "authorization_servers"],
|
|
323
|
+
"properties": {
|
|
324
|
+
"resource": { "type": "string", "pattern": "^https://" },
|
|
325
|
+
"authorization_servers": {
|
|
326
|
+
"type": "array",
|
|
327
|
+
"minItems": 1,
|
|
328
|
+
"maxItems": 8,
|
|
329
|
+
"uniqueItems": true,
|
|
330
|
+
"items": { "type": "string", "pattern": "^https://" }
|
|
331
|
+
},
|
|
332
|
+
"scopes_supported": { "type": "array", "minItems": 1, "maxItems": 64, "uniqueItems": true, "items": { "$ref": "#/$defs/oauth_scope" } },
|
|
333
|
+
"required_scopes": { "type": "array", "minItems": 1, "maxItems": 64, "uniqueItems": true, "items": { "$ref": "#/$defs/oauth_scope" } },
|
|
334
|
+
"resource_name": { "type": "string", "minLength": 1, "maxLength": 128 },
|
|
335
|
+
"resource_documentation": { "type": "string", "pattern": "^https://" }
|
|
336
|
+
}
|
|
337
|
+
},
|
|
338
|
+
"allowed_origins": {
|
|
339
|
+
"description": "Exact browser origins accepted on HTTP MCP requests. Native clients may omit Origin. Wildcards are forbidden.",
|
|
340
|
+
"type": "array",
|
|
341
|
+
"maxItems": 32,
|
|
342
|
+
"uniqueItems": true,
|
|
343
|
+
"items": { "type": "string", "pattern": "^https?://[^/*]+(?::[0-9]+)?$" }
|
|
344
|
+
},
|
|
345
|
+
"allowed_hosts": {
|
|
346
|
+
"description": "Exact HTTP Host authorities accepted by the direct listener or trusted proxy. Forwarded host headers are never authority.",
|
|
347
|
+
"type": "array",
|
|
348
|
+
"minItems": 1,
|
|
349
|
+
"maxItems": 32,
|
|
350
|
+
"uniqueItems": true,
|
|
351
|
+
"items": { "type": "string", "minLength": 1, "maxLength": 255, "pattern": "^(?:\\[[0-9A-Fa-f:.]+\\]|[A-Za-z0-9.-]+)(?::[0-9]{1,5})?$" }
|
|
352
|
+
},
|
|
353
|
+
"limits": {
|
|
354
|
+
"description": "Bounded HTTP request, header, connection, and session resource limits.",
|
|
355
|
+
"type": "object",
|
|
356
|
+
"additionalProperties": false,
|
|
357
|
+
"properties": {
|
|
358
|
+
"max_request_bytes": { "type": "integer", "minimum": 1024, "maximum": 16777216 },
|
|
359
|
+
"max_header_bytes": { "type": "integer", "minimum": 4096, "maximum": 65536 },
|
|
360
|
+
"max_sessions": { "type": "integer", "minimum": 1, "maximum": 100000 },
|
|
361
|
+
"session_idle_timeout_seconds": { "type": "integer", "minimum": 10, "maximum": 86400 },
|
|
362
|
+
"request_timeout_ms": { "type": "integer", "minimum": 1000, "maximum": 300000 },
|
|
363
|
+
"headers_timeout_ms": { "type": "integer", "minimum": 1000, "maximum": 120000 },
|
|
364
|
+
"keep_alive_timeout_ms": { "type": "integer", "minimum": 1000, "maximum": 120000 },
|
|
365
|
+
"max_connections": { "type": "integer", "minimum": 1, "maximum": 100000 }
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
},
|
|
296
370
|
"cloud": {
|
|
297
371
|
"type": "object",
|
|
298
372
|
"additionalProperties": false,
|
|
@@ -347,6 +421,12 @@
|
|
|
347
421
|
"type": "string",
|
|
348
422
|
"pattern": "^[A-Z_][A-Z0-9_]*$"
|
|
349
423
|
},
|
|
424
|
+
"oauth_scope": {
|
|
425
|
+
"type": "string",
|
|
426
|
+
"minLength": 1,
|
|
427
|
+
"maxLength": 128,
|
|
428
|
+
"pattern": "^[!#-\\[\\]-~]+$"
|
|
429
|
+
},
|
|
350
430
|
"identifier": {
|
|
351
431
|
"type": "string",
|
|
352
432
|
"pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
|