@stratabook/mcp 0.1.3 → 0.1.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/dist/src/cli.js CHANGED
@@ -3,7 +3,7 @@ import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js
3
3
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
4
  import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
5
5
  import { DEFAULT_API_BASE } from "@stratabook/sdk";
6
- import { STRATA_AGENT_HARNESS } from "./generated-harness.js";
6
+ import { STRATA_ACTION_GRAPH, STRATA_AGENT_HARNESS, } from "./generated-harness.js";
7
7
  import { createStrataMcpServer, probeStrataMcpReadiness } from "./server.js";
8
8
  import { SERVER_VERSION } from "./version.js";
9
9
  function parse(argv) {
@@ -60,7 +60,9 @@ Options:
60
60
  --host HOST HTTP bind host (default: localhost)
61
61
  --port N HTTP port (default: 8787)
62
62
 
63
- This server is read-only. It accepts no wallet, private key, or session key.
63
+ This server exposes capability-gated quote and execution operations. The external
64
+ agent owner controls permission and signing. Strata accepts public keys,
65
+ signatures, and signed transactions, never private keys or seed phrases.
64
66
  `);
65
67
  }
66
68
  async function runStdio(options) {
@@ -100,6 +102,12 @@ async function runHttp(options) {
100
102
  .set("Cache-Control", "public, max-age=300")
101
103
  .json(STRATA_AGENT_HARNESS);
102
104
  });
105
+ app.get("/.well-known/strata-action-graph.json", (_request, response) => {
106
+ response
107
+ .status(200)
108
+ .set("Cache-Control", "public, max-age=300")
109
+ .json(STRATA_ACTION_GRAPH);
110
+ });
103
111
  app.post("/mcp", async (request, response) => {
104
112
  let runtime;
105
113
  let transport;
@@ -3,24 +3,25 @@ export declare const STRATA_AGENT_HARNESS: {
3
3
  readonly harness_version: "1.0";
4
4
  readonly contract_version: "1.1";
5
5
  readonly name: "Strata Agent Harness";
6
- readonly summary: "A capability-gated workflow for agents that explore Strata markets and request validated Sonar quotes.";
6
+ readonly summary: "A capability-gated workflow and executable action graph for agents that discover, quote, prepare, externally sign, and submit Strata operations.";
7
7
  readonly entrypoints: {
8
8
  readonly documentation: "https://stratabook.org/docs/agent-harness/";
9
9
  readonly capabilities: "https://api.stratabook.app/sonar/capabilities";
10
10
  readonly markets: "https://api.stratabook.app/sonar/markets";
11
+ readonly action_graph: "https://api.stratabook.app/sonar/action-graph";
11
12
  readonly mcp: "https://api.stratabook.app/mcp";
12
13
  readonly manifest: "https://api.stratabook.app/.well-known/strata-agent.json";
13
14
  };
14
15
  readonly interfaces: {
15
- readonly mcp_tool_order: readonly ["strata_capabilities", "strata_markets", "strata_quote"];
16
- readonly terminal: readonly ["npx -y @stratabook/sdk capabilities --json", "npx -y @stratabook/sdk markets --json", "npx -y @stratabook/sdk quote --market SOL/USDC --side sell --amount-atoms 10000000 --json"];
16
+ readonly mcp_tool_order: readonly ["strata_capabilities", "strata_action_graph", "strata_markets", "strata_quote", "strata_execution_challenge", "strata_execution_prepare", "strata_execution_submit"];
17
+ readonly terminal: readonly ["npx -y @stratabook/sdk capabilities --json", "npx -y @stratabook/sdk action-graph --json", "npx -y @stratabook/sdk markets --json", "npx -y @stratabook/sdk quote --market SOL/USDC --side sell --amount-atoms 10000000 --json"];
17
18
  };
18
19
  readonly workflow: readonly [{
19
20
  readonly id: "discover_capabilities";
20
21
  readonly instruction: "Read the live capability catalog before every objective. Never infer permission from documentation, package support, or an earlier session.";
21
22
  }, {
22
23
  readonly id: "establish_mode";
23
- readonly instruction: "State whether the available session is read-only or exposes a separately authorized prepare or submit capability. Read access never implies permission to move funds.";
24
+ readonly instruction: "Read the action graph and identify which prepare and submit nodes are live. The external agent owner configures its permissions and signer authority; static documentation never enables a Strata operation.";
24
25
  }, {
25
26
  readonly id: "understand_objective";
26
27
  readonly instruction: "Resolve the user's market, side, amount, and tolerance. Ask before proceeding when any economically meaningful input is ambiguous.";
@@ -32,7 +33,7 @@ export declare const STRATA_AGENT_HARNESS: {
32
33
  readonly instruction: "Represent token amounts as unsigned base-10 atomic strings. Never pass settlement amounts through floating-point arithmetic.";
33
34
  }, {
34
35
  readonly id: "request_quote";
35
- readonly instruction: "Request a fresh Sonar quote with an explicit side, exact input atoms, and user-approved execution tolerance.";
36
+ readonly instruction: "Request a fresh Sonar quote with an explicit side, exact input atoms, and execution tolerance supplied by the external agent.";
36
37
  }, {
37
38
  readonly id: "validate_quote";
38
39
  readonly instruction: "Verify the quote binds to the selected market, side, and input. Check labelled fees, minimum output, price impact, server time, and expiry.";
@@ -41,13 +42,158 @@ export declare const STRATA_AGENT_HARNESS: {
41
42
  readonly instruction: "Report consumed input, expected output, minimum output, fees by asset side, price impact, and remaining validity without inventing private route composition.";
42
43
  }, {
43
44
  readonly id: "authorize_writes";
44
- readonly instruction: "If write capabilities are ever exposed, keep prepare and submit separate, require the configured approval, verify immutable economics, and use idempotency.";
45
+ readonly instruction: "When prepare and submit are exposed, keep signing external to Strata: request canonical authorization bytes, sign them with the owner-configured signer, verify the prepared transaction preserves the quote, then submit the externally signed transaction with idempotency.";
45
46
  }, {
46
47
  readonly id: "monitor_outcome";
47
48
  readonly instruction: "After an authorized submission, report the durable receipt or explicit failure. Never claim completion from preparation, signing, or an unconfirmed request.";
48
49
  }];
49
- readonly stop_conditions: readonly ["The required live capability is disabled or absent.", "The market is paused, unavailable, or has no reviewed operation path.", "Market, side, amount, decimals, tolerance, or approval is ambiguous.", "The contract version is unsupported or a response contains unknown fields.", "A quote is expired or its market, side, amount, fee, minimum-output, or time binding is inconsistent.", "A requested operation exceeds the exposed tool, account, or policy scope.", "A user asks the agent to receive or expose wallet secrets, private keys, seed phrases, session keys, or production credentials."];
50
- readonly safety_rules: readonly ["Never request or accept wallet secrets, private keys, seed phrases, session keys, or production credentials in a prompt.", "Never call undocumented endpoints or reconstruct private Sonar behavior.", "Never silently widen slippage, refresh changed economics, substitute a market, or retry a non-retryable failure.", "Treat capability removal, revocation, expiry, and emergency disable as immediate stop signals.", "The current MCP and terminal tools are read-only unless the live catalog and callable tool list explicitly prove otherwise."];
50
+ readonly stop_conditions: readonly ["The required live capability is disabled or absent.", "The market is paused, unavailable, or has no reviewed operation path.", "Market, side, amount, decimals, tolerance, or signer authority is unavailable or ambiguous.", "The contract version is unsupported or a response contains unknown fields.", "A quote is expired or its market, side, amount, fee, minimum-output, or time binding is inconsistent.", "A requested operation exceeds the exposed tool, account, or policy scope.", "A user asks the agent to receive or expose wallet secrets, private keys, seed phrases, session keys, or production credentials."];
51
+ readonly safety_rules: readonly ["Never request or accept wallet secrets, private keys, seed phrases, session keys, or production credentials in a prompt.", "Never call undocumented endpoints or reconstruct private Sonar behavior.", "Never silently widen slippage, refresh changed economics, substitute a market, or retry a non-retryable failure.", "Treat capability removal, revocation, expiry, and emergency disable as immediate stop signals.", "Capability and action-graph availability are authoritative for Strata operations; permission and signer policy remain controlled by the external agent owner."];
51
52
  };
52
53
  export declare const STRATA_AGENT_HARNESS_URI = "strata://agent-harness/v1";
53
- export declare const STRATA_AGENT_HARNESS_INSTRUCTIONS = "Strata Agent Harness 1.0. Start every objective with strata_capabilities, then strata_markets. Read strata://agent-harness/v1 for the complete workflow. Resolve the market, side, exact input atoms, and tolerance before strata_quote. Treat amounts as unsigned base-10 token atoms; check quote bindings, labelled fees, minimum output, and expiry. Stop on ambiguity, unavailable capabilities, paused markets, unsupported contracts, inconsistent bindings, expiry, or missing approval. Never request wallet secrets, private keys, seed phrases, session keys, or production credentials. Current MCP tools are read-only unless the live catalog and callable tool list explicitly prove otherwise.";
54
+ export declare const STRATA_ACTION_GRAPH: {
55
+ readonly schema_version: 1;
56
+ readonly graph_version: "1.0";
57
+ readonly contract_version: "1.1";
58
+ readonly entry_node: "discover_capabilities";
59
+ readonly authority: {
60
+ readonly permission_source: "external_agent_owner";
61
+ readonly signing_location: "external";
62
+ readonly accepts_private_keys: false;
63
+ };
64
+ readonly nodes: readonly [{
65
+ readonly id: "discover_capabilities";
66
+ readonly kind: "discovery";
67
+ readonly summary: "Read the live capabilities that currently expose Strata operations.";
68
+ readonly required_capabilities: readonly [];
69
+ readonly available: true;
70
+ readonly operation: {
71
+ readonly method: "GET";
72
+ readonly path: "/sonar/capabilities";
73
+ readonly mcp_tool: "strata_capabilities";
74
+ };
75
+ }, {
76
+ readonly id: "discover_markets";
77
+ readonly kind: "discovery";
78
+ readonly summary: "Discover ready markets, token decimals, and public operation paths.";
79
+ readonly required_capabilities: readonly ["markets.read"];
80
+ readonly available: true;
81
+ readonly operation: {
82
+ readonly method: "GET";
83
+ readonly path: "/sonar/markets";
84
+ readonly mcp_tool: "strata_markets";
85
+ };
86
+ }, {
87
+ readonly id: "discover_action_graph";
88
+ readonly kind: "discovery";
89
+ readonly summary: "Read the executable topology, live node availability, external signing steps, and transition conditions.";
90
+ readonly required_capabilities: readonly [];
91
+ readonly available: true;
92
+ readonly operation: {
93
+ readonly method: "GET";
94
+ readonly path: "/sonar/action-graph";
95
+ readonly mcp_tool: "strata_action_graph";
96
+ };
97
+ }, {
98
+ readonly id: "request_quote";
99
+ readonly kind: "read";
100
+ readonly summary: "Request economics bound to a market, side, exact input atoms, and tolerance.";
101
+ readonly required_capabilities: readonly ["quotes.read"];
102
+ readonly available: true;
103
+ readonly operation: {
104
+ readonly method: "POST";
105
+ readonly path: "/sonar/markets/{market}/quote";
106
+ readonly mcp_tool: "strata_quote";
107
+ };
108
+ }, {
109
+ readonly id: "request_execution_challenge";
110
+ readonly kind: "prepare";
111
+ readonly summary: "Request canonical authorization bytes for an unexpired quote and external signer.";
112
+ readonly required_capabilities: readonly ["trade.prepare"];
113
+ readonly available: true;
114
+ readonly operation: {
115
+ readonly method: "POST";
116
+ readonly path: "/sonar/markets/{market}/execution/challenge";
117
+ readonly mcp_tool: "strata_execution_challenge";
118
+ };
119
+ }, {
120
+ readonly id: "sign_authorization";
121
+ readonly kind: "external_signature";
122
+ readonly summary: "The agent owner's configured signer signs the returned authorization bytes externally.";
123
+ readonly required_capabilities: readonly [];
124
+ readonly available: true;
125
+ }, {
126
+ readonly id: "prepare_execution";
127
+ readonly kind: "prepare";
128
+ readonly summary: "Exchange the authorization signature for a quote-bound partially signed transaction.";
129
+ readonly required_capabilities: readonly ["trade.prepare"];
130
+ readonly available: true;
131
+ readonly operation: {
132
+ readonly method: "POST";
133
+ readonly path: "/sonar/markets/{market}/execution/prepare";
134
+ readonly mcp_tool: "strata_execution_prepare";
135
+ };
136
+ }, {
137
+ readonly id: "sign_transaction";
138
+ readonly kind: "external_signature";
139
+ readonly summary: "The external signer verifies and fills its signature slot without sending key material to Strata.";
140
+ readonly required_capabilities: readonly [];
141
+ readonly available: true;
142
+ }, {
143
+ readonly id: "submit_execution";
144
+ readonly kind: "submit";
145
+ readonly summary: "Submit the signed transaction with an idempotency key.";
146
+ readonly required_capabilities: readonly ["trade.submit"];
147
+ readonly available: true;
148
+ readonly operation: {
149
+ readonly method: "POST";
150
+ readonly path: "/sonar/markets/{market}/execution/submit";
151
+ readonly mcp_tool: "strata_execution_submit";
152
+ };
153
+ }, {
154
+ readonly id: "receive_receipt";
155
+ readonly kind: "receipt";
156
+ readonly summary: "Receive the execution ID, Solana signature, and submitted status.";
157
+ readonly required_capabilities: readonly [];
158
+ readonly available: true;
159
+ }];
160
+ readonly edges: readonly [{
161
+ readonly from: "discover_capabilities";
162
+ readonly to: "discover_action_graph";
163
+ readonly condition: "the returned contract version is supported";
164
+ }, {
165
+ readonly from: "discover_action_graph";
166
+ readonly to: "discover_markets";
167
+ readonly condition: "markets.read is enabled";
168
+ }, {
169
+ readonly from: "discover_markets";
170
+ readonly to: "request_quote";
171
+ readonly condition: "quotes.read is enabled and the market is ready";
172
+ }, {
173
+ readonly from: "request_quote";
174
+ readonly to: "request_execution_challenge";
175
+ readonly condition: "trade.prepare is enabled and the quote is unexpired";
176
+ }, {
177
+ readonly from: "request_execution_challenge";
178
+ readonly to: "sign_authorization";
179
+ readonly condition: "the challenge bindings match the quote and signer";
180
+ }, {
181
+ readonly from: "sign_authorization";
182
+ readonly to: "prepare_execution";
183
+ readonly condition: "a valid external authorization signature is available";
184
+ }, {
185
+ readonly from: "prepare_execution";
186
+ readonly to: "sign_transaction";
187
+ readonly condition: "the prepared transaction preserves the signed bindings";
188
+ }, {
189
+ readonly from: "sign_transaction";
190
+ readonly to: "submit_execution";
191
+ readonly condition: "trade.submit is enabled and the signed transaction is unmodified";
192
+ }, {
193
+ readonly from: "submit_execution";
194
+ readonly to: "receive_receipt";
195
+ readonly condition: "the execution ID and idempotency key match";
196
+ }];
197
+ };
198
+ export declare const STRATA_ACTION_GRAPH_URI = "strata://action-graph/v1";
199
+ export declare const STRATA_AGENT_HARNESS_INSTRUCTIONS = "Strata Agent Harness 1.0. Start every objective with strata_capabilities, then strata_action_graph, then strata_markets. Read strata://agent-harness/v1 and strata://action-graph/v1. The external agent owner controls permission and signer authority. Strata accepts public keys, detached signatures, and signed transactions, never private keys or seed phrases. Resolve the market, side, exact input atoms, and tolerance before strata_quote. Treat amounts as unsigned base-10 token atoms; check quote bindings, labelled fees, minimum output, and expiry. To execute: request a challenge, sign its canonical authorization bytes externally, prepare, verify and sign the returned transaction externally, then submit with idempotency. Stop on ambiguity, unavailable capabilities, paused markets, unsupported contracts, inconsistent bindings, expiry, or missing signer authority.";
@@ -4,22 +4,28 @@ export const STRATA_AGENT_HARNESS = {
4
4
  "harness_version": "1.0",
5
5
  "contract_version": "1.1",
6
6
  "name": "Strata Agent Harness",
7
- "summary": "A capability-gated workflow for agents that explore Strata markets and request validated Sonar quotes.",
7
+ "summary": "A capability-gated workflow and executable action graph for agents that discover, quote, prepare, externally sign, and submit Strata operations.",
8
8
  "entrypoints": {
9
9
  "documentation": "https://stratabook.org/docs/agent-harness/",
10
10
  "capabilities": "https://api.stratabook.app/sonar/capabilities",
11
11
  "markets": "https://api.stratabook.app/sonar/markets",
12
+ "action_graph": "https://api.stratabook.app/sonar/action-graph",
12
13
  "mcp": "https://api.stratabook.app/mcp",
13
14
  "manifest": "https://api.stratabook.app/.well-known/strata-agent.json"
14
15
  },
15
16
  "interfaces": {
16
17
  "mcp_tool_order": [
17
18
  "strata_capabilities",
19
+ "strata_action_graph",
18
20
  "strata_markets",
19
- "strata_quote"
21
+ "strata_quote",
22
+ "strata_execution_challenge",
23
+ "strata_execution_prepare",
24
+ "strata_execution_submit"
20
25
  ],
21
26
  "terminal": [
22
27
  "npx -y @stratabook/sdk capabilities --json",
28
+ "npx -y @stratabook/sdk action-graph --json",
23
29
  "npx -y @stratabook/sdk markets --json",
24
30
  "npx -y @stratabook/sdk quote --market SOL/USDC --side sell --amount-atoms 10000000 --json"
25
31
  ]
@@ -31,7 +37,7 @@ export const STRATA_AGENT_HARNESS = {
31
37
  },
32
38
  {
33
39
  "id": "establish_mode",
34
- "instruction": "State whether the available session is read-only or exposes a separately authorized prepare or submit capability. Read access never implies permission to move funds."
40
+ "instruction": "Read the action graph and identify which prepare and submit nodes are live. The external agent owner configures its permissions and signer authority; static documentation never enables a Strata operation."
35
41
  },
36
42
  {
37
43
  "id": "understand_objective",
@@ -47,7 +53,7 @@ export const STRATA_AGENT_HARNESS = {
47
53
  },
48
54
  {
49
55
  "id": "request_quote",
50
- "instruction": "Request a fresh Sonar quote with an explicit side, exact input atoms, and user-approved execution tolerance."
56
+ "instruction": "Request a fresh Sonar quote with an explicit side, exact input atoms, and execution tolerance supplied by the external agent."
51
57
  },
52
58
  {
53
59
  "id": "validate_quote",
@@ -59,7 +65,7 @@ export const STRATA_AGENT_HARNESS = {
59
65
  },
60
66
  {
61
67
  "id": "authorize_writes",
62
- "instruction": "If write capabilities are ever exposed, keep prepare and submit separate, require the configured approval, verify immutable economics, and use idempotency."
68
+ "instruction": "When prepare and submit are exposed, keep signing external to Strata: request canonical authorization bytes, sign them with the owner-configured signer, verify the prepared transaction preserves the quote, then submit the externally signed transaction with idempotency."
63
69
  },
64
70
  {
65
71
  "id": "monitor_outcome",
@@ -69,7 +75,7 @@ export const STRATA_AGENT_HARNESS = {
69
75
  "stop_conditions": [
70
76
  "The required live capability is disabled or absent.",
71
77
  "The market is paused, unavailable, or has no reviewed operation path.",
72
- "Market, side, amount, decimals, tolerance, or approval is ambiguous.",
78
+ "Market, side, amount, decimals, tolerance, or signer authority is unavailable or ambiguous.",
73
79
  "The contract version is unsupported or a response contains unknown fields.",
74
80
  "A quote is expired or its market, side, amount, fee, minimum-output, or time binding is inconsistent.",
75
81
  "A requested operation exceeds the exposed tool, account, or policy scope.",
@@ -80,8 +86,184 @@ export const STRATA_AGENT_HARNESS = {
80
86
  "Never call undocumented endpoints or reconstruct private Sonar behavior.",
81
87
  "Never silently widen slippage, refresh changed economics, substitute a market, or retry a non-retryable failure.",
82
88
  "Treat capability removal, revocation, expiry, and emergency disable as immediate stop signals.",
83
- "The current MCP and terminal tools are read-only unless the live catalog and callable tool list explicitly prove otherwise."
89
+ "Capability and action-graph availability are authoritative for Strata operations; permission and signer policy remain controlled by the external agent owner."
84
90
  ]
85
91
  };
86
92
  export const STRATA_AGENT_HARNESS_URI = "strata://agent-harness/v1";
87
- export const STRATA_AGENT_HARNESS_INSTRUCTIONS = "Strata Agent Harness 1.0. Start every objective with strata_capabilities, then strata_markets. Read strata://agent-harness/v1 for the complete workflow. Resolve the market, side, exact input atoms, and tolerance before strata_quote. Treat amounts as unsigned base-10 token atoms; check quote bindings, labelled fees, minimum output, and expiry. Stop on ambiguity, unavailable capabilities, paused markets, unsupported contracts, inconsistent bindings, expiry, or missing approval. Never request wallet secrets, private keys, seed phrases, session keys, or production credentials. Current MCP tools are read-only unless the live catalog and callable tool list explicitly prove otherwise.";
93
+ export const STRATA_ACTION_GRAPH = {
94
+ "schema_version": 1,
95
+ "graph_version": "1.0",
96
+ "contract_version": "1.1",
97
+ "entry_node": "discover_capabilities",
98
+ "authority": {
99
+ "permission_source": "external_agent_owner",
100
+ "signing_location": "external",
101
+ "accepts_private_keys": false
102
+ },
103
+ "nodes": [
104
+ {
105
+ "id": "discover_capabilities",
106
+ "kind": "discovery",
107
+ "summary": "Read the live capabilities that currently expose Strata operations.",
108
+ "required_capabilities": [],
109
+ "available": true,
110
+ "operation": {
111
+ "method": "GET",
112
+ "path": "/sonar/capabilities",
113
+ "mcp_tool": "strata_capabilities"
114
+ }
115
+ },
116
+ {
117
+ "id": "discover_markets",
118
+ "kind": "discovery",
119
+ "summary": "Discover ready markets, token decimals, and public operation paths.",
120
+ "required_capabilities": [
121
+ "markets.read"
122
+ ],
123
+ "available": true,
124
+ "operation": {
125
+ "method": "GET",
126
+ "path": "/sonar/markets",
127
+ "mcp_tool": "strata_markets"
128
+ }
129
+ },
130
+ {
131
+ "id": "discover_action_graph",
132
+ "kind": "discovery",
133
+ "summary": "Read the executable topology, live node availability, external signing steps, and transition conditions.",
134
+ "required_capabilities": [],
135
+ "available": true,
136
+ "operation": {
137
+ "method": "GET",
138
+ "path": "/sonar/action-graph",
139
+ "mcp_tool": "strata_action_graph"
140
+ }
141
+ },
142
+ {
143
+ "id": "request_quote",
144
+ "kind": "read",
145
+ "summary": "Request economics bound to a market, side, exact input atoms, and tolerance.",
146
+ "required_capabilities": [
147
+ "quotes.read"
148
+ ],
149
+ "available": true,
150
+ "operation": {
151
+ "method": "POST",
152
+ "path": "/sonar/markets/{market}/quote",
153
+ "mcp_tool": "strata_quote"
154
+ }
155
+ },
156
+ {
157
+ "id": "request_execution_challenge",
158
+ "kind": "prepare",
159
+ "summary": "Request canonical authorization bytes for an unexpired quote and external signer.",
160
+ "required_capabilities": [
161
+ "trade.prepare"
162
+ ],
163
+ "available": true,
164
+ "operation": {
165
+ "method": "POST",
166
+ "path": "/sonar/markets/{market}/execution/challenge",
167
+ "mcp_tool": "strata_execution_challenge"
168
+ }
169
+ },
170
+ {
171
+ "id": "sign_authorization",
172
+ "kind": "external_signature",
173
+ "summary": "The agent owner's configured signer signs the returned authorization bytes externally.",
174
+ "required_capabilities": [],
175
+ "available": true
176
+ },
177
+ {
178
+ "id": "prepare_execution",
179
+ "kind": "prepare",
180
+ "summary": "Exchange the authorization signature for a quote-bound partially signed transaction.",
181
+ "required_capabilities": [
182
+ "trade.prepare"
183
+ ],
184
+ "available": true,
185
+ "operation": {
186
+ "method": "POST",
187
+ "path": "/sonar/markets/{market}/execution/prepare",
188
+ "mcp_tool": "strata_execution_prepare"
189
+ }
190
+ },
191
+ {
192
+ "id": "sign_transaction",
193
+ "kind": "external_signature",
194
+ "summary": "The external signer verifies and fills its signature slot without sending key material to Strata.",
195
+ "required_capabilities": [],
196
+ "available": true
197
+ },
198
+ {
199
+ "id": "submit_execution",
200
+ "kind": "submit",
201
+ "summary": "Submit the signed transaction with an idempotency key.",
202
+ "required_capabilities": [
203
+ "trade.submit"
204
+ ],
205
+ "available": true,
206
+ "operation": {
207
+ "method": "POST",
208
+ "path": "/sonar/markets/{market}/execution/submit",
209
+ "mcp_tool": "strata_execution_submit"
210
+ }
211
+ },
212
+ {
213
+ "id": "receive_receipt",
214
+ "kind": "receipt",
215
+ "summary": "Receive the execution ID, Solana signature, and submitted status.",
216
+ "required_capabilities": [],
217
+ "available": true
218
+ }
219
+ ],
220
+ "edges": [
221
+ {
222
+ "from": "discover_capabilities",
223
+ "to": "discover_action_graph",
224
+ "condition": "the returned contract version is supported"
225
+ },
226
+ {
227
+ "from": "discover_action_graph",
228
+ "to": "discover_markets",
229
+ "condition": "markets.read is enabled"
230
+ },
231
+ {
232
+ "from": "discover_markets",
233
+ "to": "request_quote",
234
+ "condition": "quotes.read is enabled and the market is ready"
235
+ },
236
+ {
237
+ "from": "request_quote",
238
+ "to": "request_execution_challenge",
239
+ "condition": "trade.prepare is enabled and the quote is unexpired"
240
+ },
241
+ {
242
+ "from": "request_execution_challenge",
243
+ "to": "sign_authorization",
244
+ "condition": "the challenge bindings match the quote and signer"
245
+ },
246
+ {
247
+ "from": "sign_authorization",
248
+ "to": "prepare_execution",
249
+ "condition": "a valid external authorization signature is available"
250
+ },
251
+ {
252
+ "from": "prepare_execution",
253
+ "to": "sign_transaction",
254
+ "condition": "the prepared transaction preserves the signed bindings"
255
+ },
256
+ {
257
+ "from": "sign_transaction",
258
+ "to": "submit_execution",
259
+ "condition": "trade.submit is enabled and the signed transaction is unmodified"
260
+ },
261
+ {
262
+ "from": "submit_execution",
263
+ "to": "receive_receipt",
264
+ "condition": "the execution ID and idempotency key match"
265
+ }
266
+ ]
267
+ };
268
+ export const STRATA_ACTION_GRAPH_URI = "strata://action-graph/v1";
269
+ export const STRATA_AGENT_HARNESS_INSTRUCTIONS = "Strata Agent Harness 1.0. Start every objective with strata_capabilities, then strata_action_graph, then strata_markets. Read strata://agent-harness/v1 and strata://action-graph/v1. The external agent owner controls permission and signer authority. Strata accepts public keys, detached signatures, and signed transactions, never private keys or seed phrases. Resolve the market, side, exact input atoms, and tolerance before strata_quote. Treat amounts as unsigned base-10 token atoms; check quote bindings, labelled fees, minimum output, and expiry. To execute: request a challenge, sign its canonical authorization bytes externally, prepare, verify and sign the returned transaction externally, then submit with idempotency. Stop on ambiguity, unavailable capabilities, paused markets, unsupported contracts, inconsistent bindings, expiry, or missing signer authority.";
@@ -1,2 +1,2 @@
1
1
  export { capabilityAvailable, createStrataMcpServer, probeStrataMcpReadiness, type StrataMcpOptions, type StrataMcpReadiness, type StrataMcpRuntime, } from "./server.js";
2
- export { STRATA_AGENT_HARNESS, STRATA_AGENT_HARNESS_INSTRUCTIONS, STRATA_AGENT_HARNESS_URI, } from "./generated-harness.js";
2
+ export { STRATA_AGENT_HARNESS, STRATA_AGENT_HARNESS_INSTRUCTIONS, STRATA_AGENT_HARNESS_URI, STRATA_ACTION_GRAPH, STRATA_ACTION_GRAPH_URI, } from "./generated-harness.js";
package/dist/src/index.js CHANGED
@@ -1,2 +1,2 @@
1
1
  export { capabilityAvailable, createStrataMcpServer, probeStrataMcpReadiness, } from "./server.js";
2
- export { STRATA_AGENT_HARNESS, STRATA_AGENT_HARNESS_INSTRUCTIONS, STRATA_AGENT_HARNESS_URI, } from "./generated-harness.js";
2
+ export { STRATA_AGENT_HARNESS, STRATA_AGENT_HARNESS_INSTRUCTIONS, STRATA_AGENT_HARNESS_URI, STRATA_ACTION_GRAPH, STRATA_ACTION_GRAPH_URI, } from "./generated-harness.js";
@@ -1,15 +1,15 @@
1
1
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
2
  import { DEFAULT_SLIPPAGE_BPS, StrataApiError, StrataClient, } from "@stratabook/sdk";
3
3
  import * as z from "zod/v4";
4
- import { STRATA_AGENT_HARNESS, STRATA_AGENT_HARNESS_INSTRUCTIONS, STRATA_AGENT_HARNESS_URI, } from "./generated-harness.js";
4
+ import { STRATA_AGENT_HARNESS, STRATA_AGENT_HARNESS_INSTRUCTIONS, STRATA_AGENT_HARNESS_URI, STRATA_ACTION_GRAPH_URI, } from "./generated-harness.js";
5
5
  import { SERVER_VERSION } from "./version.js";
6
6
  const REFRESH_INTERVAL_MS = 5_000;
7
7
  export function capabilityAvailable(catalog, id) {
8
8
  return catalog.capabilities.some((capability) => capability.id === id
9
9
  && capability.default_enabled
10
10
  && capability.public_sdk
11
- && capability.risk === "read"
12
- && capability.mcp_exposure === "read");
11
+ && capability.mcp_exposure !== "none"
12
+ && capability.risk === capability.mcp_exposure);
13
13
  }
14
14
  function strataClient(options) {
15
15
  return options.client
@@ -56,9 +56,22 @@ export async function createStrataMcpServer(options = {}) {
56
56
  },
57
57
  ],
58
58
  }));
59
+ server.registerResource("strata_action_graph", STRATA_ACTION_GRAPH_URI, {
60
+ title: "Strata Action Graph",
61
+ description: "Live executable topology for discovery, quoting, external signing, and submission.",
62
+ mimeType: "application/json",
63
+ }, async () => ({
64
+ contents: [
65
+ {
66
+ uri: STRATA_ACTION_GRAPH_URI,
67
+ mimeType: "application/json",
68
+ text: JSON.stringify(await client.actionGraph()),
69
+ },
70
+ ],
71
+ }));
59
72
  server.registerPrompt("strata_start", {
60
73
  title: "Start a Strata objective",
61
- description: "Apply the Strata Agent Harness to a concrete read-only objective.",
74
+ description: "Apply the Strata Agent Harness to a concrete objective.",
62
75
  argsSchema: {
63
76
  objective: z
64
77
  .string()
@@ -88,6 +101,16 @@ export async function createStrataMcpServer(options = {}) {
88
101
  openWorldHint: true,
89
102
  },
90
103
  }, async () => toolResult(await client.capabilities(), "Current Strata capabilities."));
104
+ server.registerTool("strata_action_graph", {
105
+ title: "Strata action graph",
106
+ description: "Discover live operations, required capabilities, transition conditions, and external signing boundaries.",
107
+ annotations: {
108
+ readOnlyHint: true,
109
+ destructiveHint: false,
110
+ idempotentHint: true,
111
+ openWorldHint: true,
112
+ },
113
+ }, async () => toolResult(await client.actionGraph(), "Current Strata action graph."));
91
114
  const markets = server.registerTool("strata_markets", {
92
115
  title: "Strata markets",
93
116
  description: "List Strata markets and their current Sonar quote availability.",
@@ -158,7 +181,117 @@ export async function createStrataMcpServer(options = {}) {
158
181
  + `for ${response.amount_out_atoms} output atoms; minimum `
159
182
  + `${response.minimum_output_atoms}; expires at ${response.expires_at_ms}.`);
160
183
  }));
161
- const handles = { markets, quote };
184
+ const executionChallenge = server.registerTool("strata_execution_challenge", {
185
+ title: "Strata execution challenge",
186
+ description: "Request canonical quote-bound authorization bytes for the external signer configured by the agent owner.",
187
+ inputSchema: {
188
+ market: z.string().min(1).max(128).describe("Market label or public market ID."),
189
+ quoteId: z.string().regex(/^sq_[0-9a-f]{32}$/).describe("Unexpired Sonar quote ID."),
190
+ ownerWallet: z.string().min(32).max(44).describe("Base58 owner wallet public key."),
191
+ sessionPublicKey: z
192
+ .string()
193
+ .min(32)
194
+ .max(44)
195
+ .describe("Base58 public key for the externally configured signer."),
196
+ accountSequence: z
197
+ .string()
198
+ .regex(/^[0-9]+$/)
199
+ .max(20)
200
+ .describe("Current Vault account sequence as an unsigned decimal string."),
201
+ },
202
+ annotations: {
203
+ readOnlyHint: false,
204
+ destructiveHint: false,
205
+ idempotentHint: false,
206
+ openWorldHint: true,
207
+ },
208
+ }, async ({ market, quoteId, ownerWallet, sessionPublicKey, accountSequence }) => guardedTool(client, "trade.prepare", async () => {
209
+ const request = {
210
+ market,
211
+ quoteId,
212
+ ownerWallet,
213
+ sessionPublicKey,
214
+ accountSequence,
215
+ };
216
+ const response = await client.executionChallenge(request);
217
+ return toolResult(response, `Authorization challenge ${response.challenge_id}; expires at ${response.expires_at_ms}.`);
218
+ }));
219
+ const executionPrepare = server.registerTool("strata_execution_prepare", {
220
+ title: "Prepare Strata execution",
221
+ description: "Exchange an externally signed authorization challenge for a quote-bound partially signed transaction.",
222
+ inputSchema: {
223
+ market: z.string().min(1).max(128).describe("Market label or public market ID."),
224
+ challengeId: z
225
+ .string()
226
+ .regex(/^sc_[0-9a-f]{32}$/)
227
+ .describe("Execution challenge ID returned by Strata."),
228
+ authorizationSignature: z
229
+ .string()
230
+ .min(1)
231
+ .max(128)
232
+ .regex(/^[1-9A-HJ-NP-Za-km-z]+$/)
233
+ .describe("Base58 Ed25519 signature made externally over the challenge payload."),
234
+ },
235
+ annotations: {
236
+ readOnlyHint: false,
237
+ destructiveHint: false,
238
+ idempotentHint: false,
239
+ openWorldHint: true,
240
+ },
241
+ }, async ({ market, challengeId, authorizationSignature }) => guardedTool(client, "trade.prepare", async () => {
242
+ const request = {
243
+ market,
244
+ challengeId,
245
+ authorizationSignature,
246
+ };
247
+ const response = await client.executionPrepare(request);
248
+ return toolResult(response, `Prepared execution ${response.execution_id}; externally verify and sign before ${response.expires_at_ms}.`);
249
+ }));
250
+ const executionSubmit = server.registerTool("strata_execution_submit", {
251
+ title: "Submit Strata execution",
252
+ description: "Submit an externally signed prepared transaction with an idempotency key.",
253
+ inputSchema: {
254
+ market: z.string().min(1).max(128).describe("Market label or public market ID."),
255
+ executionId: z
256
+ .string()
257
+ .regex(/^se_[0-9a-f]{32}$/)
258
+ .describe("Prepared execution ID returned by Strata."),
259
+ signedTransactionBase64: z
260
+ .string()
261
+ .min(4)
262
+ .max(8_192)
263
+ .regex(/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/)
264
+ .describe("The externally signed Solana transaction in canonical base64."),
265
+ idempotencyKey: z
266
+ .string()
267
+ .min(1)
268
+ .max(64)
269
+ .regex(/^[A-Za-z0-9._-]+$/)
270
+ .describe("Stable retry key for exactly this execution."),
271
+ },
272
+ annotations: {
273
+ readOnlyHint: false,
274
+ destructiveHint: true,
275
+ idempotentHint: true,
276
+ openWorldHint: true,
277
+ },
278
+ }, async ({ market, executionId, signedTransactionBase64, idempotencyKey }) => guardedTool(client, "trade.submit", async () => {
279
+ const request = {
280
+ market,
281
+ executionId,
282
+ signedTransactionBase64,
283
+ idempotencyKey,
284
+ };
285
+ const response = await client.executionSubmit(request);
286
+ return toolResult(response, `Submitted execution ${response.execution_id} as ${response.signature}.`);
287
+ }));
288
+ const handles = {
289
+ markets,
290
+ quote,
291
+ executionChallenge,
292
+ executionPrepare,
293
+ executionSubmit,
294
+ };
162
295
  applyCapabilityCatalog(handles, initialCatalog);
163
296
  let closed = false;
164
297
  const refresh = async () => {
@@ -185,6 +318,9 @@ export async function createStrataMcpServer(options = {}) {
185
318
  function applyCapabilityCatalog(handles, catalog) {
186
319
  setToolEnabled(handles.markets, capabilityAvailable(catalog, "markets.read"));
187
320
  setToolEnabled(handles.quote, capabilityAvailable(catalog, "quotes.read"));
321
+ setToolEnabled(handles.executionChallenge, capabilityAvailable(catalog, "trade.prepare"));
322
+ setToolEnabled(handles.executionPrepare, capabilityAvailable(catalog, "trade.prepare"));
323
+ setToolEnabled(handles.executionSubmit, capabilityAvailable(catalog, "trade.submit"));
188
324
  }
189
325
  function setToolEnabled(tool, enabled) {
190
326
  if (enabled)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stratabook/mcp",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Connect AI agents to Strata markets and Sonar quotes with MCP.",
5
5
  "type": "module",
6
6
  "license": "MIT OR Apache-2.0",
@@ -44,7 +44,7 @@
44
44
  },
45
45
  "dependencies": {
46
46
  "@modelcontextprotocol/sdk": "1.30.0",
47
- "@stratabook/sdk": "0.1.2",
47
+ "@stratabook/sdk": "0.1.3",
48
48
  "zod": "^3.25.76"
49
49
  },
50
50
  "devDependencies": {