@stratabook/mcp 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +59 -151
- package/dist/src/generated-harness.d.ts +98 -4
- package/dist/src/generated-harness.js +125 -4
- package/dist/src/server.d.ts +2 -1
- package/dist/src/server.js +149 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,136 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
<img src="./assets/readme-hero.svg" alt="Strata — The deepest book in DeFi." width="100%" />
|
|
3
|
-
</p>
|
|
1
|
+
# Strata MCP
|
|
4
2
|
|
|
5
|
-
|
|
3
|
+
Official capability-gated MCP access to Strata and Sonar. The server is a thin adapter
|
|
4
|
+
over `@stratabook/sdk`: it follows the live capability catalog and contains no
|
|
5
|
+
private execution logic.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
Put live Strata markets and Sonar pricing inside any MCP-compatible agent.
|
|
9
|
-
</p>
|
|
10
|
-
|
|
11
|
-
<p align="center">
|
|
12
|
-
<a href="https://stratabook.org/docs/agent-mcp">Documentation</a>
|
|
13
|
-
·
|
|
14
|
-
<a href="https://github.com/alsk1992/strata-sdk-ts">TypeScript</a>
|
|
15
|
-
·
|
|
16
|
-
<a href="https://github.com/alsk1992/strata-agent-skills">Agent Skills</a>
|
|
17
|
-
·
|
|
18
|
-
<a href="https://stratabook.app">Strata</a>
|
|
19
|
-
</p>
|
|
20
|
-
|
|
21
|
-
One hosted connection gives an agent current market availability and
|
|
22
|
-
decision-ready quotes from Sonar—Strata's unified liquidity and matching
|
|
23
|
-
system. No local daemon is required.
|
|
24
|
-
|
|
25
|
-
## Connect
|
|
26
|
-
|
|
27
|
-
Add Strata as a Streamable HTTP server:
|
|
28
|
-
|
|
29
|
-
```json
|
|
30
|
-
{
|
|
31
|
-
"mcpServers": {
|
|
32
|
-
"strata": {
|
|
33
|
-
"type": "streamable-http",
|
|
34
|
-
"url": "https://api.stratabook.app/mcp"
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
That is the complete hosted setup. Once connected, the client discovers the
|
|
41
|
-
Strata tools currently available to it.
|
|
42
|
-
|
|
43
|
-
## See Strata answer from a terminal
|
|
44
|
-
|
|
45
|
-
Use the official MCP Inspector (Node.js 22.7.5+) to list the hosted tools:
|
|
46
|
-
|
|
47
|
-
```sh
|
|
48
|
-
npx -y @modelcontextprotocol/inspector --cli \
|
|
49
|
-
https://api.stratabook.app/mcp \
|
|
50
|
-
--transport http \
|
|
51
|
-
--method tools/list
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
Call Strata directly:
|
|
55
|
-
|
|
56
|
-
```sh
|
|
57
|
-
npx -y @modelcontextprotocol/inspector --cli \
|
|
58
|
-
https://api.stratabook.app/mcp \
|
|
59
|
-
--transport http \
|
|
60
|
-
--method tools/call \
|
|
61
|
-
--tool-name strata_markets \
|
|
62
|
-
--tool-arg includePaused=false
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
Request a live Sonar quote through the same connection:
|
|
7
|
+
## Local stdio
|
|
66
8
|
|
|
67
9
|
```sh
|
|
68
|
-
npx -y @
|
|
69
|
-
https://api.stratabook.app/mcp \
|
|
70
|
-
--transport http \
|
|
71
|
-
--method tools/call \
|
|
72
|
-
--tool-name strata_quote \
|
|
73
|
-
--tool-arg market=SOL/USDC \
|
|
74
|
-
--tool-arg side=sell \
|
|
75
|
-
--tool-arg 'amountInAtoms="10000000"'
|
|
10
|
+
npx -y @stratabook/mcp
|
|
76
11
|
```
|
|
77
12
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
## What lands in the agent
|
|
81
|
-
|
|
82
|
-
| Tool | Result |
|
|
83
|
-
| --- | --- |
|
|
84
|
-
| `strata_capabilities` | The Strata features available in the current session |
|
|
85
|
-
| `strata_markets` | Markets, token decimals, and current Sonar quote readiness |
|
|
86
|
-
| `strata_quote` | Expected output, consumed input, fees, minimum output, price impact, and expiry |
|
|
87
|
-
|
|
88
|
-
### A Sonar quote call
|
|
89
|
-
|
|
90
|
-
```json
|
|
91
|
-
{
|
|
92
|
-
"market": "SOL/USDC",
|
|
93
|
-
"side": "sell",
|
|
94
|
-
"amountInAtoms": "10000000"
|
|
95
|
-
}
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
The result gives an agent the economics it needs to reason clearly:
|
|
99
|
-
|
|
100
|
-
```json
|
|
101
|
-
{
|
|
102
|
-
"provider": "Sonar",
|
|
103
|
-
"amount_in_consumed_atoms": "10000000",
|
|
104
|
-
"amount_out_atoms": "1990000",
|
|
105
|
-
"minimum_output_atoms": "1990000",
|
|
106
|
-
"output_fee_atoms": "995",
|
|
107
|
-
"reference_price": "199.1",
|
|
108
|
-
"price_impact_pct": "0.0005"
|
|
109
|
-
}
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
The values above use the repository's versioned example fixture. Live quotes
|
|
113
|
-
also include a unique quote ID and authoritative expiry.
|
|
114
|
-
|
|
115
|
-
Sonar handles the market. Your agent works with one economic result.
|
|
116
|
-
|
|
117
|
-
### Execution tolerance
|
|
118
|
-
|
|
119
|
-
Quotes default to exact output: `minimum_output_atoms` equals
|
|
120
|
-
`amount_out_atoms`. An agent may explicitly provide `slippageBps` when its task
|
|
121
|
-
accepts a lower minimum output. This is an execution safeguard, not an estimate
|
|
122
|
-
of market depth; `price_impact_pct` reports price impact separately.
|
|
123
|
-
|
|
124
|
-
## Hosted or local
|
|
125
|
-
|
|
126
|
-
| | Hosted Streamable HTTP | Local stdio |
|
|
127
|
-
| --- | --- | --- |
|
|
128
|
-
| Start with | `https://api.stratabook.app/mcp` | `npx -y @stratabook/mcp` |
|
|
129
|
-
| Best for | Agents with remote MCP support | Desktop clients and local toolchains |
|
|
130
|
-
| You operate | Nothing | The local Node.js process |
|
|
131
|
-
| Strata market data | Live | Live |
|
|
132
|
-
|
|
133
|
-
Local stdio configuration:
|
|
13
|
+
Example client configuration:
|
|
134
14
|
|
|
135
15
|
```json
|
|
136
16
|
{
|
|
@@ -143,36 +23,64 @@ Local stdio configuration:
|
|
|
143
23
|
}
|
|
144
24
|
```
|
|
145
25
|
|
|
146
|
-
|
|
26
|
+
The tools currently available are:
|
|
27
|
+
|
|
28
|
+
- `strata_capabilities`
|
|
29
|
+
- `strata_action_graph`
|
|
30
|
+
- `strata_markets`, when `markets.read` is enabled for MCP
|
|
31
|
+
- `strata_quote`, when `quotes.read` is enabled for MCP
|
|
32
|
+
- `strata_execution_challenge`, when `trade.prepare` is enabled for MCP
|
|
33
|
+
- `strata_execution_prepare`, when `trade.prepare` is enabled for MCP
|
|
34
|
+
- `strata_execution_submit`, when `trade.submit` is enabled for MCP
|
|
35
|
+
- `strata_order_challenge`, when `orders.prepare` is enabled for MCP
|
|
36
|
+
- `strata_order_prepare`, when `orders.prepare` is enabled for MCP
|
|
37
|
+
- `strata_order_submit`, when `orders.submit` is enabled for MCP
|
|
38
|
+
- `strata_order_status`, when `orders.submit` is enabled for MCP
|
|
39
|
+
|
|
40
|
+
Every initialization response carries the compact Strata Agent Harness. The
|
|
41
|
+
server also publishes the complete harness as the
|
|
42
|
+
`strata://agent-harness/v1` resource and provides a `strata_start` prompt for
|
|
43
|
+
applying it to one concrete objective.
|
|
44
|
+
The live executable topology is also available as
|
|
45
|
+
`strata://action-graph/v1`.
|
|
46
|
+
|
|
47
|
+
The tool list follows the live public policy. Every call rechecks that policy,
|
|
48
|
+
so a disabled capability stops immediately even if a client cached an older
|
|
49
|
+
tool list.
|
|
50
|
+
|
|
51
|
+
## Hosted Streamable HTTP
|
|
52
|
+
|
|
53
|
+
The managed public endpoint is:
|
|
54
|
+
|
|
55
|
+
```text
|
|
56
|
+
https://api.stratabook.app/mcp
|
|
57
|
+
```
|
|
147
58
|
|
|
148
|
-
|
|
59
|
+
For a self-hosted or development process:
|
|
149
60
|
|
|
150
61
|
```sh
|
|
151
|
-
|
|
152
|
-
--transport http \
|
|
153
|
-
--host 127.0.0.1 \
|
|
154
|
-
--port 8787
|
|
62
|
+
strata-mcp --transport http --port 8787
|
|
155
63
|
```
|
|
156
64
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
## Built for exact automation
|
|
161
|
-
|
|
162
|
-
- Token values stay as atomic-unit decimal strings.
|
|
163
|
-
- Quote expiry and minimum output remain explicit fields.
|
|
164
|
-
- The tool set follows what Strata currently makes available.
|
|
165
|
-
- Errors include stable codes and retryability hints.
|
|
65
|
+
Place TLS and request limiting in front of `/mcp`. Loopback is the default bind;
|
|
66
|
+
the official MCP HTTP helper enforces Host validation for local installations.
|
|
166
67
|
|
|
167
|
-
`
|
|
168
|
-
|
|
68
|
+
`GET /health` is a readiness check, not a shallow process-liveness response. It
|
|
69
|
+
validates the live capability catalog against the bundled public contract and
|
|
70
|
+
agent harness. A stale SDK or incompatible contract therefore returns `503` and
|
|
71
|
+
blocks release activation. The same process serves the reviewed discovery
|
|
72
|
+
manifest at `/.well-known/strata-agent.json` and the graph at
|
|
73
|
+
`/.well-known/strata-action-graph.json`.
|
|
169
74
|
|
|
170
|
-
##
|
|
75
|
+
## Safety
|
|
171
76
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
-
|
|
175
|
-
|
|
176
|
-
|
|
77
|
+
The external agent owner decides what its agent may do and configures its
|
|
78
|
+
signer. MCP can request authorization bytes, prepare quote-bound trades or
|
|
79
|
+
resting-order controls, and submit the externally signed result. It accepts
|
|
80
|
+
public keys, detached signatures, and signed transactions, never private keys,
|
|
81
|
+
seed phrases, or wallet secrets. Amounts are token atoms encoded as base-10
|
|
82
|
+
strings.
|
|
177
83
|
|
|
178
|
-
|
|
84
|
+
Quotes default to zero execution tolerance. An agent can request a non-zero
|
|
85
|
+
`slippageBps` explicitly when its task accepts a lower minimum output; price
|
|
86
|
+
impact remains a separate measure of current market depth.
|
|
@@ -15,7 +15,7 @@ export declare const STRATA_AGENT_HARNESS: {
|
|
|
15
15
|
readonly manifest: "https://api.stratabook.app/.well-known/strata-agent.json";
|
|
16
16
|
};
|
|
17
17
|
readonly interfaces: {
|
|
18
|
-
readonly mcp_tool_order: readonly ["strata_capabilities", "strata_action_graph", "strata_markets", "strata_quote", "strata_execution_challenge", "strata_execution_prepare", "strata_execution_submit"];
|
|
18
|
+
readonly mcp_tool_order: readonly ["strata_capabilities", "strata_action_graph", "strata_markets", "strata_quote", "strata_execution_challenge", "strata_execution_prepare", "strata_execution_submit", "strata_order_challenge", "strata_order_prepare", "strata_order_submit", "strata_order_status"];
|
|
19
19
|
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"];
|
|
20
20
|
};
|
|
21
21
|
readonly workflow: readonly [{
|
|
@@ -50,10 +50,10 @@ export declare const STRATA_AGENT_HARNESS: {
|
|
|
50
50
|
readonly instruction: "Report consumed input, expected output, minimum output, fees by asset side, price impact, and remaining validity.";
|
|
51
51
|
}, {
|
|
52
52
|
readonly id: "authorize_writes";
|
|
53
|
-
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.";
|
|
53
|
+
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 or exact opaque order set, then submit the externally signed transaction with idempotency. Resting-order control uses place, cancel, or cancel-all and cancel-all is atomically bounded to six orders per call.";
|
|
54
54
|
}, {
|
|
55
55
|
readonly id: "monitor_outcome";
|
|
56
|
-
readonly instruction: "After an authorized submission, report the durable receipt or explicit failure. Never claim completion from preparation, signing, or an unconfirmed request.";
|
|
56
|
+
readonly instruction: "After an authorized submission, report the durable receipt or explicit failure. If the request times out or either process restarts, recover it with the same control ID and idempotency key. Never claim completion from preparation, signing, or an unconfirmed request.";
|
|
57
57
|
}];
|
|
58
58
|
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."];
|
|
59
59
|
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."];
|
|
@@ -270,6 +270,68 @@ export declare const STRATA_ACTION_GRAPH: {
|
|
|
270
270
|
readonly summary: "Receive the execution ID, Solana signature, and submitted status.";
|
|
271
271
|
readonly required_capabilities: readonly [];
|
|
272
272
|
readonly available: true;
|
|
273
|
+
}, {
|
|
274
|
+
readonly id: "request_order_challenge";
|
|
275
|
+
readonly kind: "prepare";
|
|
276
|
+
readonly summary: "Bind a product-level place, cancel, or cancel-all operation to canonical authorization bytes.";
|
|
277
|
+
readonly required_capabilities: readonly ["orders.prepare"];
|
|
278
|
+
readonly available: false;
|
|
279
|
+
readonly operation: {
|
|
280
|
+
readonly method: "POST";
|
|
281
|
+
readonly path: "/v2/markets/{market_id}/orders/challenge";
|
|
282
|
+
readonly mcp_tool: "strata_order_challenge";
|
|
283
|
+
};
|
|
284
|
+
}, {
|
|
285
|
+
readonly id: "sign_order_authorization";
|
|
286
|
+
readonly kind: "external_signature";
|
|
287
|
+
readonly summary: "The agent owner's configured session signer verifies the exact order set and signs externally.";
|
|
288
|
+
readonly required_capabilities: readonly [];
|
|
289
|
+
readonly available: true;
|
|
290
|
+
}, {
|
|
291
|
+
readonly id: "prepare_order_control";
|
|
292
|
+
readonly kind: "prepare";
|
|
293
|
+
readonly summary: "Exchange the order authorization signature for a partially signed transaction.";
|
|
294
|
+
readonly required_capabilities: readonly ["orders.prepare"];
|
|
295
|
+
readonly available: false;
|
|
296
|
+
readonly operation: {
|
|
297
|
+
readonly method: "POST";
|
|
298
|
+
readonly path: "/v2/markets/{market_id}/orders/prepare";
|
|
299
|
+
readonly mcp_tool: "strata_order_prepare";
|
|
300
|
+
};
|
|
301
|
+
}, {
|
|
302
|
+
readonly id: "sign_order_transaction";
|
|
303
|
+
readonly kind: "external_signature";
|
|
304
|
+
readonly summary: "The external session signer verifies and fills only its transaction signature slot.";
|
|
305
|
+
readonly required_capabilities: readonly [];
|
|
306
|
+
readonly available: true;
|
|
307
|
+
}, {
|
|
308
|
+
readonly id: "submit_order_control";
|
|
309
|
+
readonly kind: "submit";
|
|
310
|
+
readonly summary: "Submit the unchanged signed order transaction with an idempotency key.";
|
|
311
|
+
readonly required_capabilities: readonly ["orders.submit"];
|
|
312
|
+
readonly available: false;
|
|
313
|
+
readonly operation: {
|
|
314
|
+
readonly method: "POST";
|
|
315
|
+
readonly path: "/v2/markets/{market_id}/orders/submit";
|
|
316
|
+
readonly mcp_tool: "strata_order_submit";
|
|
317
|
+
};
|
|
318
|
+
}, {
|
|
319
|
+
readonly id: "receive_order_receipt";
|
|
320
|
+
readonly kind: "receipt";
|
|
321
|
+
readonly summary: "Receive the opaque order IDs, transaction signature, and submitted status.";
|
|
322
|
+
readonly required_capabilities: readonly [];
|
|
323
|
+
readonly available: true;
|
|
324
|
+
}, {
|
|
325
|
+
readonly id: "recover_order_status";
|
|
326
|
+
readonly kind: "read";
|
|
327
|
+
readonly summary: "Recover durable submitting, submitted, or failed status after a timeout or restart.";
|
|
328
|
+
readonly required_capabilities: readonly ["orders.submit"];
|
|
329
|
+
readonly available: false;
|
|
330
|
+
readonly operation: {
|
|
331
|
+
readonly method: "POST";
|
|
332
|
+
readonly path: "/v2/markets/{market_id}/orders/status";
|
|
333
|
+
readonly mcp_tool: "strata_order_status";
|
|
334
|
+
};
|
|
273
335
|
}];
|
|
274
336
|
readonly edges: readonly [{
|
|
275
337
|
readonly from: "discover_capabilities";
|
|
@@ -351,7 +413,39 @@ export declare const STRATA_ACTION_GRAPH: {
|
|
|
351
413
|
readonly from: "submit_execution";
|
|
352
414
|
readonly to: "receive_receipt";
|
|
353
415
|
readonly condition: "the execution ID and idempotency key match";
|
|
416
|
+
}, {
|
|
417
|
+
readonly from: "discover_platform_markets";
|
|
418
|
+
readonly to: "request_order_challenge";
|
|
419
|
+
readonly condition: "orders.prepare is enabled and the market accepts order control";
|
|
420
|
+
}, {
|
|
421
|
+
readonly from: "request_order_challenge";
|
|
422
|
+
readonly to: "sign_order_authorization";
|
|
423
|
+
readonly condition: "the action and exact opaque order set match owner intent";
|
|
424
|
+
}, {
|
|
425
|
+
readonly from: "sign_order_authorization";
|
|
426
|
+
readonly to: "prepare_order_control";
|
|
427
|
+
readonly condition: "a valid external authorization signature is available";
|
|
428
|
+
}, {
|
|
429
|
+
readonly from: "prepare_order_control";
|
|
430
|
+
readonly to: "sign_order_transaction";
|
|
431
|
+
readonly condition: "the prepared transaction preserves the signed order bindings";
|
|
432
|
+
}, {
|
|
433
|
+
readonly from: "sign_order_transaction";
|
|
434
|
+
readonly to: "submit_order_control";
|
|
435
|
+
readonly condition: "orders.submit is enabled and the signed transaction is unmodified";
|
|
436
|
+
}, {
|
|
437
|
+
readonly from: "submit_order_control";
|
|
438
|
+
readonly to: "receive_order_receipt";
|
|
439
|
+
readonly condition: "the control ID and idempotency key match";
|
|
440
|
+
}, {
|
|
441
|
+
readonly from: "submit_order_control";
|
|
442
|
+
readonly to: "recover_order_status";
|
|
443
|
+
readonly condition: "the submission result is ambiguous or either process restarted";
|
|
444
|
+
}, {
|
|
445
|
+
readonly from: "recover_order_status";
|
|
446
|
+
readonly to: "receive_order_receipt";
|
|
447
|
+
readonly condition: "durable status is submitted";
|
|
354
448
|
}];
|
|
355
449
|
};
|
|
356
450
|
export declare const STRATA_ACTION_GRAPH_URI = "strata://action-graph/v1";
|
|
357
|
-
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,
|
|
451
|
+
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 or control a resting order: request a challenge, verify its quote or exact opaque order bindings, sign canonical authorization bytes externally, prepare, verify and sign the returned transaction externally, then submit with idempotency. If order submission is ambiguous, recover durable status with the same control ID and idempotency key. Cancel-all is atomically bounded to six orders per call. Stop on ambiguity, unavailable capabilities, paused markets, unsupported contracts, inconsistent bindings, expiry, or missing signer authority.";
|
|
@@ -23,7 +23,11 @@ export const STRATA_AGENT_HARNESS = {
|
|
|
23
23
|
"strata_quote",
|
|
24
24
|
"strata_execution_challenge",
|
|
25
25
|
"strata_execution_prepare",
|
|
26
|
-
"strata_execution_submit"
|
|
26
|
+
"strata_execution_submit",
|
|
27
|
+
"strata_order_challenge",
|
|
28
|
+
"strata_order_prepare",
|
|
29
|
+
"strata_order_submit",
|
|
30
|
+
"strata_order_status"
|
|
27
31
|
],
|
|
28
32
|
"terminal": [
|
|
29
33
|
"npx -y @stratabook/sdk capabilities --json",
|
|
@@ -75,11 +79,11 @@ export const STRATA_AGENT_HARNESS = {
|
|
|
75
79
|
},
|
|
76
80
|
{
|
|
77
81
|
"id": "authorize_writes",
|
|
78
|
-
"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."
|
|
82
|
+
"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 or exact opaque order set, then submit the externally signed transaction with idempotency. Resting-order control uses place, cancel, or cancel-all and cancel-all is atomically bounded to six orders per call."
|
|
79
83
|
},
|
|
80
84
|
{
|
|
81
85
|
"id": "monitor_outcome",
|
|
82
|
-
"instruction": "After an authorized submission, report the durable receipt or explicit failure. Never claim completion from preparation, signing, or an unconfirmed request."
|
|
86
|
+
"instruction": "After an authorized submission, report the durable receipt or explicit failure. If the request times out or either process restarts, recover it with the same control ID and idempotency key. Never claim completion from preparation, signing, or an unconfirmed request."
|
|
83
87
|
}
|
|
84
88
|
],
|
|
85
89
|
"stop_conditions": [
|
|
@@ -360,6 +364,83 @@ export const STRATA_ACTION_GRAPH = {
|
|
|
360
364
|
"summary": "Receive the execution ID, Solana signature, and submitted status.",
|
|
361
365
|
"required_capabilities": [],
|
|
362
366
|
"available": true
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
"id": "request_order_challenge",
|
|
370
|
+
"kind": "prepare",
|
|
371
|
+
"summary": "Bind a product-level place, cancel, or cancel-all operation to canonical authorization bytes.",
|
|
372
|
+
"required_capabilities": [
|
|
373
|
+
"orders.prepare"
|
|
374
|
+
],
|
|
375
|
+
"available": false,
|
|
376
|
+
"operation": {
|
|
377
|
+
"method": "POST",
|
|
378
|
+
"path": "/v2/markets/{market_id}/orders/challenge",
|
|
379
|
+
"mcp_tool": "strata_order_challenge"
|
|
380
|
+
}
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
"id": "sign_order_authorization",
|
|
384
|
+
"kind": "external_signature",
|
|
385
|
+
"summary": "The agent owner's configured session signer verifies the exact order set and signs externally.",
|
|
386
|
+
"required_capabilities": [],
|
|
387
|
+
"available": true
|
|
388
|
+
},
|
|
389
|
+
{
|
|
390
|
+
"id": "prepare_order_control",
|
|
391
|
+
"kind": "prepare",
|
|
392
|
+
"summary": "Exchange the order authorization signature for a partially signed transaction.",
|
|
393
|
+
"required_capabilities": [
|
|
394
|
+
"orders.prepare"
|
|
395
|
+
],
|
|
396
|
+
"available": false,
|
|
397
|
+
"operation": {
|
|
398
|
+
"method": "POST",
|
|
399
|
+
"path": "/v2/markets/{market_id}/orders/prepare",
|
|
400
|
+
"mcp_tool": "strata_order_prepare"
|
|
401
|
+
}
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
"id": "sign_order_transaction",
|
|
405
|
+
"kind": "external_signature",
|
|
406
|
+
"summary": "The external session signer verifies and fills only its transaction signature slot.",
|
|
407
|
+
"required_capabilities": [],
|
|
408
|
+
"available": true
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
"id": "submit_order_control",
|
|
412
|
+
"kind": "submit",
|
|
413
|
+
"summary": "Submit the unchanged signed order transaction with an idempotency key.",
|
|
414
|
+
"required_capabilities": [
|
|
415
|
+
"orders.submit"
|
|
416
|
+
],
|
|
417
|
+
"available": false,
|
|
418
|
+
"operation": {
|
|
419
|
+
"method": "POST",
|
|
420
|
+
"path": "/v2/markets/{market_id}/orders/submit",
|
|
421
|
+
"mcp_tool": "strata_order_submit"
|
|
422
|
+
}
|
|
423
|
+
},
|
|
424
|
+
{
|
|
425
|
+
"id": "receive_order_receipt",
|
|
426
|
+
"kind": "receipt",
|
|
427
|
+
"summary": "Receive the opaque order IDs, transaction signature, and submitted status.",
|
|
428
|
+
"required_capabilities": [],
|
|
429
|
+
"available": true
|
|
430
|
+
},
|
|
431
|
+
{
|
|
432
|
+
"id": "recover_order_status",
|
|
433
|
+
"kind": "read",
|
|
434
|
+
"summary": "Recover durable submitting, submitted, or failed status after a timeout or restart.",
|
|
435
|
+
"required_capabilities": [
|
|
436
|
+
"orders.submit"
|
|
437
|
+
],
|
|
438
|
+
"available": false,
|
|
439
|
+
"operation": {
|
|
440
|
+
"method": "POST",
|
|
441
|
+
"path": "/v2/markets/{market_id}/orders/status",
|
|
442
|
+
"mcp_tool": "strata_order_status"
|
|
443
|
+
}
|
|
363
444
|
}
|
|
364
445
|
],
|
|
365
446
|
"edges": [
|
|
@@ -462,8 +543,48 @@ export const STRATA_ACTION_GRAPH = {
|
|
|
462
543
|
"from": "submit_execution",
|
|
463
544
|
"to": "receive_receipt",
|
|
464
545
|
"condition": "the execution ID and idempotency key match"
|
|
546
|
+
},
|
|
547
|
+
{
|
|
548
|
+
"from": "discover_platform_markets",
|
|
549
|
+
"to": "request_order_challenge",
|
|
550
|
+
"condition": "orders.prepare is enabled and the market accepts order control"
|
|
551
|
+
},
|
|
552
|
+
{
|
|
553
|
+
"from": "request_order_challenge",
|
|
554
|
+
"to": "sign_order_authorization",
|
|
555
|
+
"condition": "the action and exact opaque order set match owner intent"
|
|
556
|
+
},
|
|
557
|
+
{
|
|
558
|
+
"from": "sign_order_authorization",
|
|
559
|
+
"to": "prepare_order_control",
|
|
560
|
+
"condition": "a valid external authorization signature is available"
|
|
561
|
+
},
|
|
562
|
+
{
|
|
563
|
+
"from": "prepare_order_control",
|
|
564
|
+
"to": "sign_order_transaction",
|
|
565
|
+
"condition": "the prepared transaction preserves the signed order bindings"
|
|
566
|
+
},
|
|
567
|
+
{
|
|
568
|
+
"from": "sign_order_transaction",
|
|
569
|
+
"to": "submit_order_control",
|
|
570
|
+
"condition": "orders.submit is enabled and the signed transaction is unmodified"
|
|
571
|
+
},
|
|
572
|
+
{
|
|
573
|
+
"from": "submit_order_control",
|
|
574
|
+
"to": "receive_order_receipt",
|
|
575
|
+
"condition": "the control ID and idempotency key match"
|
|
576
|
+
},
|
|
577
|
+
{
|
|
578
|
+
"from": "submit_order_control",
|
|
579
|
+
"to": "recover_order_status",
|
|
580
|
+
"condition": "the submission result is ambiguous or either process restarted"
|
|
581
|
+
},
|
|
582
|
+
{
|
|
583
|
+
"from": "recover_order_status",
|
|
584
|
+
"to": "receive_order_receipt",
|
|
585
|
+
"condition": "durable status is submitted"
|
|
465
586
|
}
|
|
466
587
|
]
|
|
467
588
|
};
|
|
468
589
|
export const STRATA_ACTION_GRAPH_URI = "strata://action-graph/v1";
|
|
469
|
-
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,
|
|
590
|
+
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 or control a resting order: request a challenge, verify its quote or exact opaque order bindings, sign canonical authorization bytes externally, prepare, verify and sign the returned transaction externally, then submit with idempotency. If order submission is ambiguous, recover durable status with the same control ID and idempotency key. Cancel-all is atomically bounded to six orders per call. Stop on ambiguity, unavailable capabilities, paused markets, unsupported contracts, inconsistent bindings, expiry, or missing signer authority.";
|
package/dist/src/server.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
-
import { StrataClient, type CapabilityCatalog } from "@stratabook/sdk";
|
|
2
|
+
import { StrataClient, StrataPlatformClient, type CapabilityCatalog } from "@stratabook/sdk";
|
|
3
3
|
export interface StrataMcpOptions {
|
|
4
4
|
apiBase?: string;
|
|
5
5
|
timeoutMs?: number;
|
|
6
6
|
client?: StrataClient;
|
|
7
|
+
platformClient?: StrataPlatformClient;
|
|
7
8
|
}
|
|
8
9
|
export interface StrataMcpRuntime {
|
|
9
10
|
server: McpServer;
|
package/dist/src/server.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
-
import { DEFAULT_SLIPPAGE_BPS, StrataApiError, StrataClient, } from "@stratabook/sdk";
|
|
2
|
+
import { DEFAULT_SLIPPAGE_BPS, StrataApiError, StrataClient, StrataPlatformClient, } from "@stratabook/sdk";
|
|
3
3
|
import * as z from "zod/v4";
|
|
4
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";
|
|
@@ -33,6 +33,10 @@ export async function probeStrataMcpReadiness(options = {}) {
|
|
|
33
33
|
}
|
|
34
34
|
export async function createStrataMcpServer(options = {}) {
|
|
35
35
|
const client = strataClient(options);
|
|
36
|
+
const platformClient = options.platformClient ?? new StrataPlatformClient({
|
|
37
|
+
apiBase: options.apiBase,
|
|
38
|
+
timeoutMs: options.timeoutMs,
|
|
39
|
+
});
|
|
36
40
|
const initialCatalog = await client.capabilities();
|
|
37
41
|
if (initialCatalog.contract_version !== STRATA_AGENT_HARNESS.contract_version) {
|
|
38
42
|
throw new Error("agent harness and live contract versions differ");
|
|
@@ -285,12 +289,152 @@ export async function createStrataMcpServer(options = {}) {
|
|
|
285
289
|
const response = await client.executionSubmit(request);
|
|
286
290
|
return toolResult(response, `Submitted execution ${response.execution_id} as ${response.signature}.`);
|
|
287
291
|
}));
|
|
292
|
+
const orderChallenge = server.registerTool("strata_order_challenge", {
|
|
293
|
+
title: "Strata order challenge",
|
|
294
|
+
description: "Bind a product-level place, cancel, or cancel-all request to canonical bytes for the agent owner's external signer.",
|
|
295
|
+
inputSchema: {
|
|
296
|
+
marketId: z.string().regex(/^market_[0-9a-f]{32}$/),
|
|
297
|
+
action: z.enum(["place", "cancel", "cancel_all"]),
|
|
298
|
+
ownerWallet: z.string().min(32).max(44),
|
|
299
|
+
sessionPublicKey: z.string().min(32).max(44),
|
|
300
|
+
accountSequence: z.string().regex(/^[0-9]+$/).max(20).optional(),
|
|
301
|
+
clientOrderId: z.string().min(1).max(64).regex(/^[A-Za-z0-9._-]+$/).optional(),
|
|
302
|
+
side: z.enum(["buy", "sell"]).optional(),
|
|
303
|
+
orderType: z.enum(["good_until_cancelled", "post_only"]).optional(),
|
|
304
|
+
limitPriceAtoms: z.string().regex(/^[1-9][0-9]*$/).max(20).optional(),
|
|
305
|
+
sizeAtoms: z.string().regex(/^[1-9][0-9]*$/).max(20).optional(),
|
|
306
|
+
orderId: z.string().regex(/^order_[0-9a-f]{32}$/).optional(),
|
|
307
|
+
},
|
|
308
|
+
annotations: {
|
|
309
|
+
readOnlyHint: false,
|
|
310
|
+
destructiveHint: true,
|
|
311
|
+
idempotentHint: false,
|
|
312
|
+
openWorldHint: true,
|
|
313
|
+
},
|
|
314
|
+
}, async (args) => guardedTool(client, "orders.prepare", async () => {
|
|
315
|
+
let request;
|
|
316
|
+
if (args.action === "place") {
|
|
317
|
+
if (args.accountSequence === undefined
|
|
318
|
+
|| args.clientOrderId === undefined
|
|
319
|
+
|| args.side === undefined
|
|
320
|
+
|| args.orderType === undefined
|
|
321
|
+
|| args.limitPriceAtoms === undefined
|
|
322
|
+
|| args.sizeAtoms === undefined) {
|
|
323
|
+
return toolError("invalid_request", "Place requires accountSequence, clientOrderId, side, orderType, limitPriceAtoms, and sizeAtoms.", false);
|
|
324
|
+
}
|
|
325
|
+
request = {
|
|
326
|
+
action: "place",
|
|
327
|
+
ownerWallet: args.ownerWallet,
|
|
328
|
+
sessionPublicKey: args.sessionPublicKey,
|
|
329
|
+
accountSequence: args.accountSequence,
|
|
330
|
+
clientOrderId: args.clientOrderId,
|
|
331
|
+
side: args.side,
|
|
332
|
+
orderType: args.orderType,
|
|
333
|
+
limitPriceAtoms: args.limitPriceAtoms,
|
|
334
|
+
sizeAtoms: args.sizeAtoms,
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
else if (args.action === "cancel") {
|
|
338
|
+
if (args.orderId === undefined) {
|
|
339
|
+
return toolError("invalid_request", "Cancel requires orderId.", false);
|
|
340
|
+
}
|
|
341
|
+
request = {
|
|
342
|
+
action: "cancel",
|
|
343
|
+
ownerWallet: args.ownerWallet,
|
|
344
|
+
sessionPublicKey: args.sessionPublicKey,
|
|
345
|
+
orderId: args.orderId,
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
else {
|
|
349
|
+
request = {
|
|
350
|
+
action: "cancel_all",
|
|
351
|
+
ownerWallet: args.ownerWallet,
|
|
352
|
+
sessionPublicKey: args.sessionPublicKey,
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
const response = await platformClient.orders.challenge(args.marketId, request);
|
|
356
|
+
return toolResult(response, `Order challenge ${response.challenge_id} binds ${response.order_ids.length} opaque order ID(s); expires at ${response.expires_at_ms}.`);
|
|
357
|
+
}));
|
|
358
|
+
const orderPrepare = server.registerTool("strata_order_prepare", {
|
|
359
|
+
title: "Prepare Strata order control",
|
|
360
|
+
description: "Exchange an externally signed order challenge for an immutable partially signed transaction.",
|
|
361
|
+
inputSchema: {
|
|
362
|
+
marketId: z.string().regex(/^market_[0-9a-f]{32}$/),
|
|
363
|
+
challengeId: z.string().regex(/^oc_[0-9a-f]{32}$/),
|
|
364
|
+
authorizationSignature: z
|
|
365
|
+
.string()
|
|
366
|
+
.min(64)
|
|
367
|
+
.max(88)
|
|
368
|
+
.regex(/^[1-9A-HJ-NP-Za-km-z]+$/),
|
|
369
|
+
},
|
|
370
|
+
annotations: {
|
|
371
|
+
readOnlyHint: false,
|
|
372
|
+
destructiveHint: true,
|
|
373
|
+
idempotentHint: false,
|
|
374
|
+
openWorldHint: true,
|
|
375
|
+
},
|
|
376
|
+
}, async ({ marketId, challengeId, authorizationSignature }) => guardedTool(client, "orders.prepare", async () => {
|
|
377
|
+
const response = await platformClient.orders.prepare(marketId, {
|
|
378
|
+
challengeId,
|
|
379
|
+
authorizationSignature,
|
|
380
|
+
});
|
|
381
|
+
return toolResult(response, `Prepared ${response.action} control ${response.order_control_id}; externally verify and sign before ${response.expires_at_ms}.`);
|
|
382
|
+
}));
|
|
383
|
+
const orderSubmit = server.registerTool("strata_order_submit", {
|
|
384
|
+
title: "Submit Strata order control",
|
|
385
|
+
description: "Submit an externally signed order transaction with a stable retry key.",
|
|
386
|
+
inputSchema: {
|
|
387
|
+
marketId: z.string().regex(/^market_[0-9a-f]{32}$/),
|
|
388
|
+
orderControlId: z.string().regex(/^or_[0-9a-f]{32}$/),
|
|
389
|
+
signedTransactionBase64: z
|
|
390
|
+
.string()
|
|
391
|
+
.min(4)
|
|
392
|
+
.max(8_192)
|
|
393
|
+
.regex(/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/),
|
|
394
|
+
idempotencyKey: z.string().min(1).max(64).regex(/^[A-Za-z0-9._-]+$/),
|
|
395
|
+
},
|
|
396
|
+
annotations: {
|
|
397
|
+
readOnlyHint: false,
|
|
398
|
+
destructiveHint: true,
|
|
399
|
+
idempotentHint: true,
|
|
400
|
+
openWorldHint: true,
|
|
401
|
+
},
|
|
402
|
+
}, async ({ marketId, orderControlId, signedTransactionBase64, idempotencyKey }) => guardedTool(client, "orders.submit", async () => {
|
|
403
|
+
const response = await platformClient.orders.submit(marketId, {
|
|
404
|
+
orderControlId,
|
|
405
|
+
signedTransactionBase64,
|
|
406
|
+
idempotencyKey,
|
|
407
|
+
});
|
|
408
|
+
return toolResult(response, `Submitted ${response.action} control ${response.order_control_id} as ${response.signature}.`);
|
|
409
|
+
}));
|
|
410
|
+
const orderStatus = server.registerTool("strata_order_status", {
|
|
411
|
+
title: "Read Strata order-control status",
|
|
412
|
+
description: "Recover the durable result for an externally signed order submission after a timeout or restart.",
|
|
413
|
+
inputSchema: {
|
|
414
|
+
marketId: z.string().regex(/^market_[0-9a-f]{32}$/),
|
|
415
|
+
orderControlId: z.string().regex(/^or_[0-9a-f]{32}$/),
|
|
416
|
+
idempotencyKey: z.string().min(1).max(64).regex(/^[A-Za-z0-9._-]+$/),
|
|
417
|
+
},
|
|
418
|
+
annotations: {
|
|
419
|
+
readOnlyHint: true,
|
|
420
|
+
destructiveHint: false,
|
|
421
|
+
idempotentHint: true,
|
|
422
|
+
openWorldHint: true,
|
|
423
|
+
},
|
|
424
|
+
}, async ({ marketId, orderControlId, idempotencyKey }) => guardedTool(client, "orders.submit", async () => {
|
|
425
|
+
const response = await platformClient.orders.status(marketId, { orderControlId, idempotencyKey });
|
|
426
|
+
return toolResult(response, `Order control ${response.order_control_id} is ${response.status}.`);
|
|
427
|
+
}));
|
|
288
428
|
const handles = {
|
|
289
429
|
markets,
|
|
290
430
|
quote,
|
|
291
431
|
executionChallenge,
|
|
292
432
|
executionPrepare,
|
|
293
433
|
executionSubmit,
|
|
434
|
+
orderChallenge,
|
|
435
|
+
orderPrepare,
|
|
436
|
+
orderSubmit,
|
|
437
|
+
orderStatus,
|
|
294
438
|
};
|
|
295
439
|
applyCapabilityCatalog(handles, initialCatalog);
|
|
296
440
|
let closed = false;
|
|
@@ -321,6 +465,10 @@ function applyCapabilityCatalog(handles, catalog) {
|
|
|
321
465
|
setToolEnabled(handles.executionChallenge, capabilityAvailable(catalog, "trade.prepare"));
|
|
322
466
|
setToolEnabled(handles.executionPrepare, capabilityAvailable(catalog, "trade.prepare"));
|
|
323
467
|
setToolEnabled(handles.executionSubmit, capabilityAvailable(catalog, "trade.submit"));
|
|
468
|
+
setToolEnabled(handles.orderChallenge, capabilityAvailable(catalog, "orders.prepare"));
|
|
469
|
+
setToolEnabled(handles.orderPrepare, capabilityAvailable(catalog, "orders.prepare"));
|
|
470
|
+
setToolEnabled(handles.orderSubmit, capabilityAvailable(catalog, "orders.submit"));
|
|
471
|
+
setToolEnabled(handles.orderStatus, capabilityAvailable(catalog, "orders.submit"));
|
|
324
472
|
}
|
|
325
473
|
function setToolEnabled(tool, enabled) {
|
|
326
474
|
if (enabled)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stratabook/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
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.
|
|
47
|
+
"@stratabook/sdk": "0.1.6",
|
|
48
48
|
"zod": "^3.25.76"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|