@stratabook/mcp 0.1.5 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,178 +1,85 @@
1
- <p align="center">
2
- <img src="./assets/readme-hero.svg" alt="Strata — The deepest book in DeFi." width="100%" />
3
- </p>
1
+ # Strata MCP
4
2
 
5
- <h1 align="center">Strata MCP</h1>
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
- <p align="center">
8
- Put live Strata markets and Sonar pricing inside any MCP-compatible agent.
9
- </p>
7
+ ## Local stdio
10
8
 
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
9
+ ```sh
10
+ npx -y @stratabook/mcp
11
+ ```
26
12
 
27
- Add Strata as a Streamable HTTP server:
13
+ Example client configuration:
28
14
 
29
15
  ```json
30
16
  {
31
17
  "mcpServers": {
32
18
  "strata": {
33
- "type": "streamable-http",
34
- "url": "https://api.stratabook.app/mcp"
19
+ "command": "npx",
20
+ "args": ["-y", "@stratabook/mcp"]
35
21
  }
36
22
  }
37
23
  }
38
24
  ```
39
25
 
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:
66
-
67
- ```sh
68
- npx -y @modelcontextprotocol/inspector --cli \
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"'
76
- ```
77
-
78
- The response is structured data, ready for terminals, scripts, and agents.
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.
26
+ The tools currently available are:
116
27
 
117
- ### Execution tolerance
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
118
38
 
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.
39
+ Every initialization response carries the compact Strata Agent Harness. The
40
+ server also publishes the complete harness as the
41
+ `strata://agent-harness/v1` resource and provides a `strata_start` prompt for
42
+ applying it to one concrete objective.
43
+ The live executable topology is also available as
44
+ `strata://action-graph/v1`.
123
45
 
124
- ## Hosted or local
46
+ The tool list follows the live public policy. Every call rechecks that policy,
47
+ so a disabled capability stops immediately even if a client cached an older
48
+ tool list.
125
49
 
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 |
50
+ ## Hosted Streamable HTTP
132
51
 
133
- Local stdio configuration:
52
+ The managed public endpoint is:
134
53
 
135
- ```json
136
- {
137
- "mcpServers": {
138
- "strata": {
139
- "command": "npx",
140
- "args": ["-y", "@stratabook/mcp"]
141
- }
142
- }
143
- }
54
+ ```text
55
+ https://api.stratabook.app/mcp
144
56
  ```
145
57
 
146
- Node.js 20+ is required for the local package.
147
-
148
- ## Self-host Streamable HTTP
58
+ For a self-hosted or development process:
149
59
 
150
60
  ```sh
151
- npx -y @stratabook/mcp \
152
- --transport http \
153
- --host 127.0.0.1 \
154
- --port 8787
61
+ strata-mcp --transport http --port 8787
155
62
  ```
156
63
 
157
- The server binds to loopback by default. Add TLS, authentication, and rate
158
- limiting before making a self-hosted instance remotely accessible.
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.
64
+ Place TLS and request limiting in front of `/mcp`. Loopback is the default bind;
65
+ the official MCP HTTP helper enforces Host validation for local installations.
166
66
 
167
- `0.1.x` provides market discovery and read-only Sonar quotes. It cannot prepare,
168
- sign, or submit transactions and never asks for wallet or private-key material.
67
+ `GET /health` is a readiness check, not a shallow process-liveness response. It
68
+ validates the live capability catalog against the bundled public contract and
69
+ agent harness. A stale SDK or incompatible contract therefore returns `503` and
70
+ blocks release activation. The same process serves the reviewed discovery
71
+ manifest at `/.well-known/strata-agent.json` and the graph at
72
+ `/.well-known/strata-action-graph.json`.
169
73
 
170
- ## Resources
74
+ ## Safety
171
75
 
172
- - [Agent quick start](https://stratabook.org/docs/hello-agents)
173
- - [MCP documentation](https://stratabook.org/docs/agent-mcp)
174
- - [TypeScript SDK](https://github.com/alsk1992/strata-sdk-ts)
175
- - [Issues and feature requests](https://github.com/alsk1992/strata-mcp/issues)
176
- - [Security policy](SECURITY.md)
76
+ The external agent owner decides what its agent may do and configures its
77
+ signer. MCP can request authorization bytes, prepare quote-bound trades or
78
+ resting-order controls, and submit the externally signed result. It accepts
79
+ public keys, detached signatures, and signed transactions, never private keys,
80
+ seed phrases, or wallet secrets. Amounts are token atoms encoded as base-10
81
+ strings.
177
82
 
178
- Licensed under either [Apache-2.0](LICENSE-APACHE) or [MIT](LICENSE-MIT).
83
+ Quotes default to zero execution tolerance. An agent can request a non-zero
84
+ `slippageBps` explicitly when its task accepts a lower minimum output; price
85
+ 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"];
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,7 +50,7 @@ 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
56
  readonly instruction: "After an authorized submission, report the durable receipt or explicit failure. Never claim completion from preparation, signing, or an unconfirmed request.";
@@ -270,6 +270,57 @@ 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;
273
324
  }];
274
325
  readonly edges: readonly [{
275
326
  readonly from: "discover_capabilities";
@@ -351,7 +402,31 @@ export declare const STRATA_ACTION_GRAPH: {
351
402
  readonly from: "submit_execution";
352
403
  readonly to: "receive_receipt";
353
404
  readonly condition: "the execution ID and idempotency key match";
405
+ }, {
406
+ readonly from: "discover_platform_markets";
407
+ readonly to: "request_order_challenge";
408
+ readonly condition: "orders.prepare is enabled and the market accepts order control";
409
+ }, {
410
+ readonly from: "request_order_challenge";
411
+ readonly to: "sign_order_authorization";
412
+ readonly condition: "the action and exact opaque order set match owner intent";
413
+ }, {
414
+ readonly from: "sign_order_authorization";
415
+ readonly to: "prepare_order_control";
416
+ readonly condition: "a valid external authorization signature is available";
417
+ }, {
418
+ readonly from: "prepare_order_control";
419
+ readonly to: "sign_order_transaction";
420
+ readonly condition: "the prepared transaction preserves the signed order bindings";
421
+ }, {
422
+ readonly from: "sign_order_transaction";
423
+ readonly to: "submit_order_control";
424
+ readonly condition: "orders.submit is enabled and the signed transaction is unmodified";
425
+ }, {
426
+ readonly from: "submit_order_control";
427
+ readonly to: "receive_order_receipt";
428
+ readonly condition: "the control ID and idempotency key match";
354
429
  }];
355
430
  };
356
431
  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, 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.";
432
+ 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. 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,10 @@ 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"
27
30
  ],
28
31
  "terminal": [
29
32
  "npx -y @stratabook/sdk capabilities --json",
@@ -75,7 +78,7 @@ export const STRATA_AGENT_HARNESS = {
75
78
  },
76
79
  {
77
80
  "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."
81
+ "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
82
  },
80
83
  {
81
84
  "id": "monitor_outcome",
@@ -360,6 +363,69 @@ export const STRATA_ACTION_GRAPH = {
360
363
  "summary": "Receive the execution ID, Solana signature, and submitted status.",
361
364
  "required_capabilities": [],
362
365
  "available": true
366
+ },
367
+ {
368
+ "id": "request_order_challenge",
369
+ "kind": "prepare",
370
+ "summary": "Bind a product-level place, cancel, or cancel-all operation to canonical authorization bytes.",
371
+ "required_capabilities": [
372
+ "orders.prepare"
373
+ ],
374
+ "available": false,
375
+ "operation": {
376
+ "method": "POST",
377
+ "path": "/v2/markets/{market_id}/orders/challenge",
378
+ "mcp_tool": "strata_order_challenge"
379
+ }
380
+ },
381
+ {
382
+ "id": "sign_order_authorization",
383
+ "kind": "external_signature",
384
+ "summary": "The agent owner's configured session signer verifies the exact order set and signs externally.",
385
+ "required_capabilities": [],
386
+ "available": true
387
+ },
388
+ {
389
+ "id": "prepare_order_control",
390
+ "kind": "prepare",
391
+ "summary": "Exchange the order authorization signature for a partially signed transaction.",
392
+ "required_capabilities": [
393
+ "orders.prepare"
394
+ ],
395
+ "available": false,
396
+ "operation": {
397
+ "method": "POST",
398
+ "path": "/v2/markets/{market_id}/orders/prepare",
399
+ "mcp_tool": "strata_order_prepare"
400
+ }
401
+ },
402
+ {
403
+ "id": "sign_order_transaction",
404
+ "kind": "external_signature",
405
+ "summary": "The external session signer verifies and fills only its transaction signature slot.",
406
+ "required_capabilities": [],
407
+ "available": true
408
+ },
409
+ {
410
+ "id": "submit_order_control",
411
+ "kind": "submit",
412
+ "summary": "Submit the unchanged signed order transaction with an idempotency key.",
413
+ "required_capabilities": [
414
+ "orders.submit"
415
+ ],
416
+ "available": false,
417
+ "operation": {
418
+ "method": "POST",
419
+ "path": "/v2/markets/{market_id}/orders/submit",
420
+ "mcp_tool": "strata_order_submit"
421
+ }
422
+ },
423
+ {
424
+ "id": "receive_order_receipt",
425
+ "kind": "receipt",
426
+ "summary": "Receive the opaque order IDs, transaction signature, and submitted status.",
427
+ "required_capabilities": [],
428
+ "available": true
363
429
  }
364
430
  ],
365
431
  "edges": [
@@ -462,8 +528,38 @@ export const STRATA_ACTION_GRAPH = {
462
528
  "from": "submit_execution",
463
529
  "to": "receive_receipt",
464
530
  "condition": "the execution ID and idempotency key match"
531
+ },
532
+ {
533
+ "from": "discover_platform_markets",
534
+ "to": "request_order_challenge",
535
+ "condition": "orders.prepare is enabled and the market accepts order control"
536
+ },
537
+ {
538
+ "from": "request_order_challenge",
539
+ "to": "sign_order_authorization",
540
+ "condition": "the action and exact opaque order set match owner intent"
541
+ },
542
+ {
543
+ "from": "sign_order_authorization",
544
+ "to": "prepare_order_control",
545
+ "condition": "a valid external authorization signature is available"
546
+ },
547
+ {
548
+ "from": "prepare_order_control",
549
+ "to": "sign_order_transaction",
550
+ "condition": "the prepared transaction preserves the signed order bindings"
551
+ },
552
+ {
553
+ "from": "sign_order_transaction",
554
+ "to": "submit_order_control",
555
+ "condition": "orders.submit is enabled and the signed transaction is unmodified"
556
+ },
557
+ {
558
+ "from": "submit_order_control",
559
+ "to": "receive_order_receipt",
560
+ "condition": "the control ID and idempotency key match"
465
561
  }
466
562
  ]
467
563
  };
468
564
  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, 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.";
565
+ 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. 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.";
@@ -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;
@@ -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,133 @@ 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
+ }));
288
410
  const handles = {
289
411
  markets,
290
412
  quote,
291
413
  executionChallenge,
292
414
  executionPrepare,
293
415
  executionSubmit,
416
+ orderChallenge,
417
+ orderPrepare,
418
+ orderSubmit,
294
419
  };
295
420
  applyCapabilityCatalog(handles, initialCatalog);
296
421
  let closed = false;
@@ -321,6 +446,9 @@ function applyCapabilityCatalog(handles, catalog) {
321
446
  setToolEnabled(handles.executionChallenge, capabilityAvailable(catalog, "trade.prepare"));
322
447
  setToolEnabled(handles.executionPrepare, capabilityAvailable(catalog, "trade.prepare"));
323
448
  setToolEnabled(handles.executionSubmit, capabilityAvailable(catalog, "trade.submit"));
449
+ setToolEnabled(handles.orderChallenge, capabilityAvailable(catalog, "orders.prepare"));
450
+ setToolEnabled(handles.orderPrepare, capabilityAvailable(catalog, "orders.prepare"));
451
+ setToolEnabled(handles.orderSubmit, capabilityAvailable(catalog, "orders.submit"));
324
452
  }
325
453
  function setToolEnabled(tool, enabled) {
326
454
  if (enabled)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stratabook/mcp",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
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.4",
47
+ "@stratabook/sdk": "0.1.5",
48
48
  "zod": "^3.25.76"
49
49
  },
50
50
  "devDependencies": {