@stratabook/mcp 0.1.12 → 0.2.0

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,8 +1,8 @@
1
1
  # Strata MCP
2
2
 
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.
3
+ Official capability-gated MCP access to Strata and Sonar. The server delegates
4
+ to `@stratabook/sdk`: it follows the live capability catalog and contains no
5
+ separate quote or execution logic.
6
6
 
7
7
  ## Local stdio
8
8
 
@@ -27,11 +27,36 @@ The tools currently available are:
27
27
 
28
28
  - `strata_capabilities`
29
29
  - `strata_action_graph`
30
+ - `strata_platform_graph`
31
+ - `strata_status`
32
+ - `strata_candles`
33
+ - `strata_marks`
34
+ - `strata_twaps`
35
+ - `strata_twap_challenge`
36
+ - `strata_twap_cancel`
37
+ - `strata_twap_prepare`
38
+ - `strata_twap_submit`
39
+ - `strata_portfolio`
40
+ - `strata_portfolio_history`
41
+ - `strata_market_making_status`
42
+ - `strata_market_making_reputation`
43
+ - `strata_vault_status`
44
+ - `strata_vault_setup`, `strata_vault_deposit`, `strata_vault_withdraw`, `strata_vault_delegate`, `strata_vault_policy`, `strata_vault_pause` — prepare owner actions with Strata as sponsored fee payer
45
+ - `strata_vault_submit` — submit the owner-signed preparation; Strata pays and broadcasts
46
+ - `strata_vault_submission` — durable outcome of a submission
47
+ - `strata_rewards`
48
+ - `strata_referrals`
49
+ - `strata_referral_link` — prepare externally signable consent or submit the signed link
50
+ - `strata_referral_claim` — prepare externally signable consent or submit the signed claim
51
+ - `strata_bugs`
52
+ - `strata_bug_submit` — prepare externally signable bytes or submit the signed report
30
53
  - `strata_markets`, when `markets.read` is enabled for MCP
31
- - `strata_quote`, when `quotes.read` is enabled for MCP
54
+ - `strata_quote` and `strata_exact_output_quote` (spend X / receive at least Y), when market quotes are enabled for MCP
55
+ - `strata_swap_quote`, when catalog-asset swap quotes are enabled for MCP
32
56
  - `strata_execution_challenge`, when `trade.prepare` is enabled for MCP
33
57
  - `strata_execution_prepare`, when `trade.prepare` is enabled for MCP
34
58
  - `strata_execution_submit`, when `trade.submit` is enabled for MCP
59
+ - `strata_execution_status` — recover a durable immediate-execution receipt
35
60
  - `strata_order_challenge`, when `orders.prepare` is enabled for MCP
36
61
  - `strata_order_prepare`, when `orders.prepare` is enabled for MCP
37
62
  - `strata_order_submit`, when `orders.submit` is enabled for MCP
@@ -42,7 +67,8 @@ server also publishes the complete harness as the
42
67
  `strata://agent-harness/v1` resource and provides a `strata_start` prompt for
43
68
  applying it to one concrete objective.
44
69
  The live executable topology is also available as
45
- `strata://action-graph/v1`.
70
+ `strata://action-graph/v1`. The complete entity, operation, and workflow map is
71
+ available as `strata://platform-graph/v2`.
46
72
 
47
73
  The tool list follows the live public policy. Every call rechecks that policy,
48
74
  so a disabled capability stops immediately even if a client cached an older
@@ -75,13 +101,14 @@ manifest at `/.well-known/strata-agent.json` and the graph at
75
101
  ## Safety
76
102
 
77
103
  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
- atomic place, cancel, cancel-all, replace, or bounded batch order controls, and
104
+ signer. MCP can request authorization bytes, prepare quote-bound trades,
105
+ bounded TWAP placement or cancellation, or atomic place, cancel, cancel-all,
106
+ replace, or bounded batch order controls, and
80
107
  submit the externally signed result. It accepts
81
108
  public keys, detached signatures, and signed transactions, never private keys,
82
109
  seed phrases, or wallet secrets. Amounts are token atoms encoded as base-10
83
110
  strings.
84
111
 
85
- Quotes default to zero execution tolerance. An agent can request a non-zero
86
- `slippageBps` explicitly when its task accepts a lower minimum output; price
87
- impact remains a separate measure of current market depth.
112
+ Quotes default to zero tolerance. `maximumToleranceBps` is the agent's own
113
+ floor (the most it accepts below the quoted output); `price_impact_pct` is
114
+ measured from the book. They are unrelated, and every quote result states both.
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Session autonomy — the user-owned "how much may the agent finish by itself"
3
+ * slider, enforced inside the MCP server.
4
+ *
5
+ * The default is `ask`: the MCP prepares trades but never signs them, so the
6
+ * human signs every one. This is the calm default and it is unchanged from a
7
+ * server with no session key at all. A user who wants unattended, popup-free
8
+ * trading opts in by giving the MCP a Vault **session** secret key (capped and
9
+ * revocable on-chain) and raising the level:
10
+ *
11
+ * - `ask` — read + prepare only; the agent hands back an unsigned
12
+ * transaction for the human to sign. Never signs.
13
+ * - `limits` — signs and submits instantly, but only within an extra
14
+ * MCP-side ceiling (per-trade USD, per-day USD, allowed
15
+ * markets). Anything above stops and hands back a prepare.
16
+ * - `instant` — signs and submits instantly within the on-chain session
17
+ * caps (the owner's per-asset limits, tolerance, interval,
18
+ * expiry). Hyperliquid-style.
19
+ *
20
+ * Withdraw, policy, pause, and revoke are never on this slider — they always
21
+ * require the owner's wallet. The on-chain session caps are the hard ceiling;
22
+ * this slider is a softer layer above them. An agent can *read* the level
23
+ * (`strata_autonomy`) and *offer* to change it, but nothing an agent calls can
24
+ * raise its own autonomy: the only knob is the human's (env / Agents page).
25
+ */
26
+ import { StrataPlatformClient, type StrataSessionSigner } from "@stratabook/sdk";
27
+ export declare const AUTONOMY_LEVELS: readonly ["ask", "limits", "instant"];
28
+ export type AutonomyLevel = (typeof AUTONOMY_LEVELS)[number];
29
+ export interface AutonomyConfig {
30
+ readonly level: AutonomyLevel;
31
+ /** `limits` only: the most one trade may be, in USD. Undefined = no per-trade cap. */
32
+ readonly maxUsdPerTrade?: number;
33
+ /** `limits` only: the most all trades may total per UTC day, in USD. */
34
+ readonly maxUsdPerDay?: number;
35
+ /** `limits` only: opaque market IDs the agent may trade. Empty = every live market. */
36
+ readonly allowedMarketIds?: readonly string[];
37
+ }
38
+ export interface SessionAutonomy {
39
+ readonly signer: StrataSessionSigner;
40
+ readonly ownerWallet: string;
41
+ readonly config: AutonomyConfig;
42
+ readonly dailyBudget: DailyUsdBudget;
43
+ }
44
+ /** Parse the autonomy slider from a plain env bag; defaults to the calm `ask`. */
45
+ export declare function parseAutonomyConfig(env: Record<string, string | undefined>): AutonomyConfig;
46
+ /** Build the session-autonomy context from env, or null when no session key is set. */
47
+ export declare function sessionAutonomyFromEnv(env: Record<string, string | undefined>): Promise<SessionAutonomy | null>;
48
+ /** In-memory per-UTC-day USD ledger. Resets on day change and on process restart. */
49
+ export declare class DailyUsdBudget {
50
+ private day;
51
+ private spent;
52
+ private roll;
53
+ spentToday(nowMs: number): number;
54
+ record(usd: number, nowMs: number): void;
55
+ }
56
+ export type AutonomyDecision = {
57
+ readonly allow: true;
58
+ } | {
59
+ readonly allow: false;
60
+ readonly reason: string;
61
+ };
62
+ /**
63
+ * Decide whether a trade of `notionalUsd` on `marketId` may be signed now.
64
+ * `notionalUsd` null means the notional could not be established — treated as
65
+ * over budget under `limits` (fail closed), ignored under `instant`.
66
+ */
67
+ export declare function decideAutonomy(autonomy: SessionAutonomy, marketId: string, notionalUsd: number | null, nowMs: number): AutonomyDecision;
68
+ /** A single cached join of platform market_id → its decimals + label. */
69
+ interface MarketMeta {
70
+ readonly label: string;
71
+ readonly baseDecimals: number;
72
+ readonly quoteDecimals: number;
73
+ }
74
+ /**
75
+ * Resolve base/quote decimals for opaque platform market IDs by joining the
76
+ * platform market list (market_id ↔ label) with the Sonar market list
77
+ * (label ↔ decimals). Cached briefly; both are cheap public reads.
78
+ */
79
+ export declare class MarketMetaResolver {
80
+ private readonly platformClient;
81
+ private readonly sonarMarkets;
82
+ private readonly nowMs;
83
+ private byId;
84
+ private labelToId;
85
+ private fetchedAtMs;
86
+ constructor(platformClient: Pick<StrataPlatformClient, "markets">, sonarMarkets: () => Promise<ReadonlyArray<{
87
+ label: string;
88
+ base_decimals: number;
89
+ quote_decimals: number;
90
+ }>>, nowMs: () => number);
91
+ private load;
92
+ get(marketId: string): Promise<MarketMeta | null>;
93
+ /** Opaque platform market_id for a Sonar market label, or null if unknown. */
94
+ idForLabel(label: string): Promise<string | null>;
95
+ }
96
+ /**
97
+ * USD notional of an order/TWAP of `baseAtoms` base on `marketId`, from the
98
+ * current mark. Best effort: returns null (→ fail closed under `limits`) when
99
+ * decimals or a fresh mark are unavailable. Cancels pass `baseAtoms = 0n`.
100
+ */
101
+ export declare function estimateBaseNotionalUsd(resolver: MarketMetaResolver, markPriceAtomsPerBase: (marketId: string) => Promise<{
102
+ price_atoms_per_base_unit: string | null;
103
+ quote_decimals: number;
104
+ stale: boolean;
105
+ }>, marketId: string, baseAtoms: bigint): Promise<number | null>;
106
+ /** USD notional of a Sonar quote: the quote-asset side, exact from the quote. */
107
+ export declare function quoteNotionalUsd(side: "buy" | "sell", amountInAtoms: string, minimumOutputAtoms: string, quoteDecimals: number): number | null;
108
+ export {};
@@ -0,0 +1,230 @@
1
+ /**
2
+ * Session autonomy — the user-owned "how much may the agent finish by itself"
3
+ * slider, enforced inside the MCP server.
4
+ *
5
+ * The default is `ask`: the MCP prepares trades but never signs them, so the
6
+ * human signs every one. This is the calm default and it is unchanged from a
7
+ * server with no session key at all. A user who wants unattended, popup-free
8
+ * trading opts in by giving the MCP a Vault **session** secret key (capped and
9
+ * revocable on-chain) and raising the level:
10
+ *
11
+ * - `ask` — read + prepare only; the agent hands back an unsigned
12
+ * transaction for the human to sign. Never signs.
13
+ * - `limits` — signs and submits instantly, but only within an extra
14
+ * MCP-side ceiling (per-trade USD, per-day USD, allowed
15
+ * markets). Anything above stops and hands back a prepare.
16
+ * - `instant` — signs and submits instantly within the on-chain session
17
+ * caps (the owner's per-asset limits, tolerance, interval,
18
+ * expiry). Hyperliquid-style.
19
+ *
20
+ * Withdraw, policy, pause, and revoke are never on this slider — they always
21
+ * require the owner's wallet. The on-chain session caps are the hard ceiling;
22
+ * this slider is a softer layer above them. An agent can *read* the level
23
+ * (`strata_autonomy`) and *offer* to change it, but nothing an agent calls can
24
+ * raise its own autonomy: the only knob is the human's (env / Agents page).
25
+ */
26
+ import { StrataContractError, sessionSignerFromSecretKey, } from "@stratabook/sdk";
27
+ export const AUTONOMY_LEVELS = ["ask", "limits", "instant"];
28
+ function positiveNumber(raw) {
29
+ if (raw === undefined)
30
+ return undefined;
31
+ const value = Number(raw.trim());
32
+ return Number.isFinite(value) && value > 0 ? value : undefined;
33
+ }
34
+ /** Parse the autonomy slider from a plain env bag; defaults to the calm `ask`. */
35
+ export function parseAutonomyConfig(env) {
36
+ const raw = (env.STRATA_AUTONOMY ?? "ask").trim().toLowerCase();
37
+ const level = AUTONOMY_LEVELS.includes(raw)
38
+ ? raw
39
+ : "ask";
40
+ const maxUsdPerTrade = positiveNumber(env.STRATA_AUTONOMY_MAX_USD_PER_TRADE);
41
+ const maxUsdPerDay = positiveNumber(env.STRATA_AUTONOMY_MAX_USD_PER_DAY);
42
+ const allowedMarketIds = (env.STRATA_AUTONOMY_MARKETS ?? "")
43
+ .split(",")
44
+ .map((id) => id.trim())
45
+ .filter((id) => /^market_[0-9a-f]{32}$/.test(id));
46
+ return {
47
+ level,
48
+ ...(maxUsdPerTrade === undefined ? {} : { maxUsdPerTrade }),
49
+ ...(maxUsdPerDay === undefined ? {} : { maxUsdPerDay }),
50
+ ...(allowedMarketIds.length > 0 ? { allowedMarketIds } : {}),
51
+ };
52
+ }
53
+ /** Build the session-autonomy context from env, or null when no session key is set. */
54
+ export async function sessionAutonomyFromEnv(env) {
55
+ const secret = env.STRATA_SESSION_SECRET_KEY?.trim();
56
+ const ownerWallet = env.STRATA_OWNER_WALLET?.trim();
57
+ if (!secret)
58
+ return null;
59
+ if (!ownerWallet || !/^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(ownerWallet)) {
60
+ throw new StrataContractError("STRATA_SESSION_SECRET_KEY is set but STRATA_OWNER_WALLET is missing or invalid");
61
+ }
62
+ const expected = env.STRATA_SESSION_PUBLIC_KEY?.trim();
63
+ const signer = await sessionSignerFromSecretKey(secret, expected || undefined);
64
+ return {
65
+ signer,
66
+ ownerWallet,
67
+ config: parseAutonomyConfig(env),
68
+ dailyBudget: new DailyUsdBudget(),
69
+ };
70
+ }
71
+ /** In-memory per-UTC-day USD ledger. Resets on day change and on process restart. */
72
+ export class DailyUsdBudget {
73
+ day = "";
74
+ spent = 0;
75
+ roll(nowMs) {
76
+ const day = new Date(nowMs).toISOString().slice(0, 10);
77
+ if (day !== this.day) {
78
+ this.day = day;
79
+ this.spent = 0;
80
+ }
81
+ }
82
+ spentToday(nowMs) {
83
+ this.roll(nowMs);
84
+ return this.spent;
85
+ }
86
+ record(usd, nowMs) {
87
+ this.roll(nowMs);
88
+ this.spent += Math.max(0, usd);
89
+ }
90
+ }
91
+ /**
92
+ * Decide whether a trade of `notionalUsd` on `marketId` may be signed now.
93
+ * `notionalUsd` null means the notional could not be established — treated as
94
+ * over budget under `limits` (fail closed), ignored under `instant`.
95
+ */
96
+ export function decideAutonomy(autonomy, marketId, notionalUsd, nowMs) {
97
+ const { config } = autonomy;
98
+ if (config.level === "ask") {
99
+ return {
100
+ allow: false,
101
+ reason: "Autonomy is set to \"ask\": I prepared this trade but will not sign it. "
102
+ + "Sign the returned transaction yourself, or raise the slider to \"limits\" or \"instant\".",
103
+ };
104
+ }
105
+ if (config.level === "instant") {
106
+ return { allow: true };
107
+ }
108
+ // limits
109
+ if (config.allowedMarketIds && !config.allowedMarketIds.includes(marketId)) {
110
+ return {
111
+ allow: false,
112
+ reason: `Autonomy \"limits\" does not include this market. Allowed: ${config.allowedMarketIds.join(", ")}. `
113
+ + "Sign it yourself, add the market, or switch to \"instant\".",
114
+ };
115
+ }
116
+ if (notionalUsd === null) {
117
+ return {
118
+ allow: false,
119
+ reason: "Autonomy \"limits\" needs the trade's USD size to check the ceiling and I could not establish it, "
120
+ + "so I will not sign automatically. Sign the returned transaction yourself, or switch to \"instant\".",
121
+ };
122
+ }
123
+ if (config.maxUsdPerTrade !== undefined && notionalUsd > config.maxUsdPerTrade) {
124
+ return {
125
+ allow: false,
126
+ reason: `This trade is about $${notionalUsd.toFixed(2)}, over the per-trade limit of `
127
+ + `$${config.maxUsdPerTrade.toFixed(2)}. Sign it yourself, raise the limit, or switch to \"instant\".`,
128
+ };
129
+ }
130
+ if (config.maxUsdPerDay !== undefined) {
131
+ const remaining = config.maxUsdPerDay - autonomy.dailyBudget.spentToday(nowMs);
132
+ if (notionalUsd > remaining) {
133
+ return {
134
+ allow: false,
135
+ reason: `This trade is about $${notionalUsd.toFixed(2)} but only $${Math.max(0, remaining).toFixed(2)} `
136
+ + `of today's $${config.maxUsdPerDay.toFixed(2)} budget is left. Sign it yourself or raise the daily budget.`,
137
+ };
138
+ }
139
+ }
140
+ return { allow: true };
141
+ }
142
+ const MARKET_META_TTL_MS = 60_000;
143
+ /**
144
+ * Resolve base/quote decimals for opaque platform market IDs by joining the
145
+ * platform market list (market_id ↔ label) with the Sonar market list
146
+ * (label ↔ decimals). Cached briefly; both are cheap public reads.
147
+ */
148
+ export class MarketMetaResolver {
149
+ platformClient;
150
+ sonarMarkets;
151
+ nowMs;
152
+ byId = null;
153
+ labelToId = new Map();
154
+ fetchedAtMs = 0;
155
+ constructor(platformClient, sonarMarkets, nowMs) {
156
+ this.platformClient = platformClient;
157
+ this.sonarMarkets = sonarMarkets;
158
+ this.nowMs = nowMs;
159
+ }
160
+ async load() {
161
+ if (this.byId && this.nowMs() - this.fetchedAtMs < MARKET_META_TTL_MS) {
162
+ return this.byId;
163
+ }
164
+ const byLabel = new Map();
165
+ for (const market of await this.sonarMarkets()) {
166
+ byLabel.set(market.label, {
167
+ baseDecimals: market.base_decimals,
168
+ quoteDecimals: market.quote_decimals,
169
+ });
170
+ }
171
+ const meta = new Map();
172
+ const labelToId = new Map();
173
+ let cursor;
174
+ for (let page = 0; page < 20; page += 1) {
175
+ const response = await this.platformClient.markets.list(cursor === undefined ? { limit: 100 } : { limit: 100, cursor });
176
+ for (const market of response.markets) {
177
+ labelToId.set(market.label, market.market_id);
178
+ const decimals = byLabel.get(market.label);
179
+ if (decimals) {
180
+ meta.set(market.market_id, { label: market.label, ...decimals });
181
+ }
182
+ }
183
+ if (!response.page.has_more || response.page.next_cursor === null)
184
+ break;
185
+ cursor = response.page.next_cursor;
186
+ }
187
+ this.byId = meta;
188
+ this.labelToId = labelToId;
189
+ this.fetchedAtMs = this.nowMs();
190
+ return meta;
191
+ }
192
+ async get(marketId) {
193
+ return (await this.load()).get(marketId) ?? null;
194
+ }
195
+ /** Opaque platform market_id for a Sonar market label, or null if unknown. */
196
+ async idForLabel(label) {
197
+ await this.load();
198
+ return this.labelToId.get(label) ?? null;
199
+ }
200
+ }
201
+ /**
202
+ * USD notional of an order/TWAP of `baseAtoms` base on `marketId`, from the
203
+ * current mark. Best effort: returns null (→ fail closed under `limits`) when
204
+ * decimals or a fresh mark are unavailable. Cancels pass `baseAtoms = 0n`.
205
+ */
206
+ export async function estimateBaseNotionalUsd(resolver, markPriceAtomsPerBase, marketId, baseAtoms) {
207
+ if (baseAtoms <= 0n)
208
+ return 0;
209
+ const meta = await resolver.get(marketId);
210
+ if (!meta)
211
+ return null;
212
+ const mark = await markPriceAtomsPerBase(marketId);
213
+ if (mark.stale || mark.price_atoms_per_base_unit === null)
214
+ return null;
215
+ const price = Number(mark.price_atoms_per_base_unit);
216
+ if (!Number.isFinite(price) || price <= 0)
217
+ return null;
218
+ const baseWhole = Number(baseAtoms) / 10 ** meta.baseDecimals;
219
+ const usd = (baseWhole * price) / 10 ** mark.quote_decimals;
220
+ return Number.isFinite(usd) ? usd : null;
221
+ }
222
+ /** USD notional of a Sonar quote: the quote-asset side, exact from the quote. */
223
+ export function quoteNotionalUsd(side, amountInAtoms, minimumOutputAtoms, quoteDecimals) {
224
+ const quoteAtoms = side === "buy" ? amountInAtoms : minimumOutputAtoms;
225
+ const value = Number(quoteAtoms);
226
+ if (!Number.isFinite(value) || value < 0)
227
+ return null;
228
+ const usd = value / 10 ** quoteDecimals;
229
+ return Number.isFinite(usd) ? usd : null;
230
+ }
package/dist/src/cli.js CHANGED
@@ -5,6 +5,7 @@ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/
5
5
  import { DEFAULT_API_BASE } from "@stratabook/sdk";
6
6
  import { STRATA_ACTION_GRAPH, STRATA_AGENT_HARNESS, } from "./generated-harness.js";
7
7
  import { createStrataMcpServer, probeStrataMcpReadiness } from "./server.js";
8
+ import { sessionAutonomyFromEnv } from "./autonomy.js";
8
9
  import { SERVER_VERSION } from "./version.js";
9
10
  function parse(argv) {
10
11
  const values = new Map();
@@ -160,10 +161,16 @@ function safeError(error) {
160
161
  }
161
162
  async function main() {
162
163
  const options = parse(process.argv.slice(2));
163
- if (options.transport === "stdio")
164
- await runStdio(options);
164
+ const sessionAutonomy = await sessionAutonomyFromEnv(process.env);
165
+ const withSession = sessionAutonomy ? { ...options, sessionAutonomy } : options;
166
+ if (sessionAutonomy) {
167
+ process.stderr.write(`[strata-mcp] session autonomy: ${sessionAutonomy.config.level} `
168
+ + `(wallet ${sessionAutonomy.ownerWallet.slice(0, 6)}…, session ${sessionAutonomy.signer.publicKey.slice(0, 6)}…)\n`);
169
+ }
170
+ if (withSession.transport === "stdio")
171
+ await runStdio(withSession);
165
172
  else
166
- await runHttp(options);
173
+ await runHttp(withSession);
167
174
  }
168
175
  main().catch((error) => {
169
176
  process.stderr.write(`${error instanceof Error ? error.message : "Strata MCP failed to start."}\n`);
@@ -9,48 +9,86 @@ export declare const STRATA_AGENT_HARNESS: {
9
9
  readonly capabilities: "https://api.stratabook.app/sonar/capabilities";
10
10
  readonly markets: "https://api.stratabook.app/sonar/markets";
11
11
  readonly platform_capabilities: "https://api.stratabook.app/v2/capabilities";
12
+ readonly platform_action_graph: "https://api.stratabook.app/v2/action-graph";
13
+ readonly platform_status: "https://api.stratabook.app/v2/status";
12
14
  readonly platform_markets: "https://api.stratabook.app/v2/markets";
13
15
  readonly action_graph: "https://api.stratabook.app/sonar/action-graph";
14
16
  readonly mcp: "https://api.stratabook.app/mcp";
15
17
  readonly manifest: "https://api.stratabook.app/.well-known/strata-agent.json";
16
18
  };
17
19
  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", "strata_order_challenge", "strata_order_prepare", "strata_order_submit", "strata_order_status"];
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", "npx -y @stratabook/sdk order-slo --market-id MARKET_ID --owner-wallet OWNER_PUBLIC_KEY --json"];
20
+ readonly mcp_tool_order: readonly ["strata_capabilities", "strata_action_graph", "strata_platform_graph", "strata_status", "strata_markets", "strata_marks", "strata_candles", "strata_twaps", "strata_twap_challenge", "strata_twap_cancel", "strata_twap_prepare", "strata_twap_submit", "strata_portfolio", "strata_portfolio_history", "strata_market_making_status", "strata_market_making_reputation", "strata_vault_status", "strata_vault_setup", "strata_vault_deposit", "strata_vault_withdraw", "strata_vault_delegate", "strata_vault_policy", "strata_vault_pause", "strata_vault_submit", "strata_vault_submission", "strata_rewards", "strata_referrals", "strata_referral_link", "strata_referral_claim", "strata_bugs", "strata_bug_submit", "strata_quote", "strata_exact_output_quote", "strata_swap_quote", "strata_execution_challenge", "strata_execution_prepare", "strata_execution_submit", "strata_execution_status", "strata_order_challenge", "strata_order_prepare", "strata_order_submit", "strata_order_status"];
21
+ readonly terminal: readonly ["npx -y @stratabook/sdk capabilities --json", "npx -y @stratabook/sdk action-graph --json", "npx -y @stratabook/sdk platform-graph --json", "npx -y @stratabook/sdk platform-status --json", "npx -y @stratabook/sdk mark --market-id MARKET_ID --json", "npx -y @stratabook/sdk candles --market-id MARKET_ID --from-ms FROM_MS --to-ms TO_MS --resolution-seconds 300 --json", "npx -y @stratabook/sdk execution-status --market-id MARKET_ID --execution-id EXECUTION_ID --json", "npx -y @stratabook/sdk twaps --market-id MARKET_ID --wallet WALLET_PUBLIC_KEY --json", "npx -y @stratabook/sdk twap-challenge --market-id MARKET_ID --owner-wallet OWNER_PUBLIC_KEY --session-public-key SESSION_PUBLIC_KEY --side buy --total-size-atoms TOTAL_ATOMS --slices 10 --tolerance-bps 100 --interval-slots 100 --limit-price-atoms PRICE_ATOMS --json", "npx -y @stratabook/sdk twap-cancel --market-id MARKET_ID --owner-wallet OWNER_PUBLIC_KEY --session-public-key SESSION_PUBLIC_KEY --twap-id TWAP_ID --json", "npx -y @stratabook/sdk twap-prepare --market-id MARKET_ID --owner-wallet OWNER_PUBLIC_KEY --session-public-key SESSION_PUBLIC_KEY --side buy --total-size-atoms TOTAL_ATOMS --slices 10 --tolerance-bps 100 --interval-slots 100 --limit-price-atoms PRICE_ATOMS --json", "npx -y @stratabook/sdk twap-submit --market-id MARKET_ID --twap-control-id CONTROL_ID --signed-transaction-base64 TRANSACTION --idempotency-key KEY --json", "npx -y @stratabook/sdk account --wallet WALLET_PUBLIC_KEY --json", "npx -y @stratabook/sdk portfolio-history --wallet WALLET_PUBLIC_KEY --range 24h --json", "npx -y @stratabook/sdk maker-status --market-id MARKET_ID --wallet WALLET_PUBLIC_KEY --json", "npx -y @stratabook/sdk maker-reputation --market-id MARKET_ID --wallet WALLET_PUBLIC_KEY --json", "npx -y @stratabook/sdk vault-status --wallet WALLET_PUBLIC_KEY --session-public-key SESSION_PUBLIC_KEY --json", "npx -y @stratabook/sdk session-keygen --json", "npx -y @stratabook/sdk vault-setup --wallet WALLET_PUBLIC_KEY --session-public-key SESSION_PUBLIC_KEY --json", "npx -y @stratabook/sdk vault-deposit --wallet WALLET_PUBLIC_KEY --market-id MARKET_ID --asset-id ASSET_ID --amount-atoms AMOUNT --session-public-key SESSION_PUBLIC_KEY --json", "npx -y @stratabook/sdk vault-withdraw --wallet WALLET_PUBLIC_KEY --market-id MARKET_ID --asset-id ASSET_ID --destination-wallet DESTINATION_WALLET --amount-atoms AMOUNT --json", "npx -y @stratabook/sdk vault-delegate --wallet WALLET_PUBLIC_KEY --session-public-key SESSION_PUBLIC_KEY --action revoke --json", "npx -y @stratabook/sdk vault-policy --wallet WALLET_PUBLIC_KEY --mode restricted --allowed-wallets DESTINATION_WALLET --json", "npx -y @stratabook/sdk vault-pause --wallet WALLET_PUBLIC_KEY --paused true --json", "npx -y @stratabook/sdk rewards --wallet WALLET_PUBLIC_KEY --json", "npx -y @stratabook/sdk referrals --wallet WALLET_PUBLIC_KEY --json", "npx -y @stratabook/sdk referral-link --wallet WALLET_PUBLIC_KEY --code REFERRAL_CODE --json", "npx -y @stratabook/sdk referral-claim --wallet WALLET_PUBLIC_KEY --json", "npx -y @stratabook/sdk bugs --wallet WALLET_PUBLIC_KEY --json", "npx -y @stratabook/sdk bug-payload --message REPORT_TEXT --json", "npx -y @stratabook/sdk markets --json", "npx -y @stratabook/sdk quote --market SOL/USDC --side sell --amount-atoms 10000000 --json", "npx -y @stratabook/sdk swap-quote --input-asset-id INPUT_ASSET_ID --output-asset-id OUTPUT_ASSET_ID --amount-atoms 10000000 --json", "npx -y @stratabook/sdk order-slo --market-id MARKET_ID --owner-wallet OWNER_PUBLIC_KEY --json"];
20
22
  };
21
23
  readonly workflow: readonly [{
22
24
  readonly id: "discover_capabilities";
23
25
  readonly instruction: "Read the live capability catalog before every objective. Never infer permission from documentation, package support, or an earlier session.";
24
26
  }, {
25
27
  readonly id: "establish_mode";
26
- 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.";
28
+ readonly instruction: "Read the compact action graph and the complete platform graph, then identify which operation and workflow nodes are live. The external agent owner configures its permissions and signer authority; static documentation never enables a Strata operation.";
27
29
  }, {
28
30
  readonly id: "understand_objective";
29
- readonly instruction: "Resolve the user's market, side, amount, and tolerance. Ask before proceeding when any economically meaningful input is ambiguous.";
31
+ readonly instruction: "Resolve the user's market or input/output assets, side when applicable, amount, and tolerance. Ask before proceeding when any economically meaningful input is ambiguous.";
30
32
  }, {
31
33
  readonly id: "discover_market";
32
- readonly instruction: "List markets, select one marked ready, and use its discovered base and quote decimals. Do not guess market identifiers or token decimals.";
34
+ readonly instruction: "List catalog assets and markets, select currently available product identities, and use discovered decimals. Do not guess identifiers or token decimals.";
33
35
  }, {
34
36
  readonly id: "read_market_data";
35
37
  readonly instruction: "When books.read is live, use the opaque market ID to read the Strata book, status, fees, and recent trades. Subscribe to the market stream for changes and recover from any sequence gap with a fresh snapshot.";
36
38
  }, {
37
39
  readonly id: "read_account";
38
- readonly instruction: "When account.read is live, use the owner-configured signer to authorize the exact wallet, market, request time, and fill limit. Read or stream only the sanitized orders and fills returned by the official SDK, and recover stream gaps from a fresh signed snapshot.";
40
+ readonly instruction: "Read the whole account with one public call by wallet address (portfolio.read / strata_portfolio / `account.read(wallet)`): balances, positions, open orders, and recent fills across every live market — no signature, no session key, no market selection. Per-market signed account reads and streams (account.read / account.stream) exist only for owners who want a signed, per-market view; never make them a prerequisite for trading.";
41
+ }, {
42
+ readonly id: "read_portfolio";
43
+ readonly instruction: "Before sizing any action, read the account once (portfolio.read): exact per-asset total, available, and locked atoms, per-market positions, open orders, recent fills, and USD totals with the observed slot. Treat null USD totals as an incomplete valuation, never as zero; markets listed in unavailable_market_ids did not report orders and fills for that snapshot; use the typed stored-history operation for past equity.";
44
+ }, {
45
+ readonly id: "read_vault";
46
+ readonly instruction: "Before session-owned execution, read the official Vault status for the owner and external session key. Continue only when the product is active, the session is active, and market_execution_ready is true; treat opaque asset limits and withdrawal access as authoritative.";
47
+ }, {
48
+ readonly id: "protect_vault";
49
+ readonly instruction: "When an owner requests a Vault pause or resume and vault.pause is live, prepare the exact transaction with the official SDK, verify that the wallet and requested state are unchanged, then have the owner-configured signer sign and broadcast it externally. Preparation alone does not change state.";
50
+ }, {
51
+ readonly id: "onboard_vault";
52
+ readonly instruction: "Onboarding is one owner signature, once: register the external session key with vault.setup (only the wallet and the session key are required; one session then trades every market) or simply name the session key on the first vault.deposit, which registers it in the same transaction. Policy fields — expiry, cadence, tolerance, per-asset limits — are optional. Verify every echoed field and the prepared transaction before external owner signing and broadcast; retain the session key only in the owner's signer.";
53
+ }, {
54
+ readonly id: "fund_vault";
55
+ readonly instruction: "When vault.deposit is live, select an asset from the discovered market and use an exact positive atomic amount. Verify the echoed owner, market, asset, and amount plus the prepared transaction before external owner signing and broadcast.";
56
+ }, {
57
+ readonly id: "withdraw_vault";
58
+ readonly instruction: "When vault.withdraw is live, choose an exact market asset, destination-owner wallet, and positive atomic amount. Verify every echoed binding and the prepared transaction before external owner signing and broadcast; the on-chain withdrawal policy remains authoritative.";
59
+ }, {
60
+ readonly id: "revoke_vault_session";
61
+ readonly instruction: "When an owner requests session revocation and vault.delegate.manage is live, bind the exact owner wallet and external session public key. Verify both identities and the destructive revoke action before external owner signing and broadcast; preparation alone does not revoke access.";
62
+ }, {
63
+ readonly id: "control_vault_withdrawals";
64
+ readonly instruction: "When vault.policy.manage is live, use blocked mode with no allowed wallets to freeze withdrawals or restricted mode with one to eight exact destination-owner wallets. Verify the echoed mode and complete wallet list before external owner signing and broadcast.";
65
+ }, {
66
+ readonly id: "reconcile_maker_status";
67
+ readonly instruction: "When mm.status.read is live, read the maker's products by wallet address (public, no signature) before and after any maker action: resting firm orders, the intent budget, live signed quotes, each Strand and Current with its remaining exposure and expiry, oracle health, and armed dead-man guards. Reconcile against what the agent believes it posted; treat missing, expired, or disabled products as not quoting.";
68
+ }, {
69
+ readonly id: "stream_maker_fills";
70
+ readonly instruction: "When mm.fills.stream is live, keep one maker stream open per market through the official SDK by wallet address (public, no signature): start from the maker snapshot, apply only contiguous maker_fill and maker_status events, and recover any gap or reconnect from a fresh snapshot. Reconcile every fill and exposure change against the maker's own state before quoting further.";
71
+ }, {
72
+ readonly id: "inspect_maker_reputation";
73
+ readonly instruction: "When mm.reputation.read is live, read the maker's record by wallet address (public, no signature). Use the tier, reliability counters, tier-progress gates, signed-quote eligibility, and minimum cadence before choosing the maker transport; do not infer hidden counterparties or execution paths.";
39
74
  }, {
40
75
  readonly id: "preserve_atoms";
41
76
  readonly instruction: "Represent token amounts as unsigned base-10 atomic strings. Never pass settlement amounts through floating-point arithmetic.";
77
+ }, {
78
+ readonly id: "authorize_community_actions";
79
+ readonly instruction: "For referral link or claim actions, generate the exact official SDK authorization payload, have the affected owner wallet sign it externally, and submit only the detached signature with the same referral code or payout wallet binding.";
42
80
  }, {
43
81
  readonly id: "request_quote";
44
- readonly instruction: "Request a fresh Sonar quote with an explicit side, exact input atoms, and execution tolerance supplied by the external agent.";
82
+ readonly instruction: "Request a fresh Sonar quote using either a selected market and explicit side or selected input/output asset IDs, plus exact input atoms and the execution tolerance supplied by the external agent.";
45
83
  }, {
46
84
  readonly id: "validate_quote";
47
- readonly instruction: "Verify the quote binds to the selected market, side, and input. Check labelled fees, minimum output, price impact, server time, and expiry.";
85
+ readonly instruction: "Verify the quote binds to the selected market and side or the selected input/output assets, plus the exact input and tolerance. Check labelled fees, minimum output, price impact, server time, and expiry.";
48
86
  }, {
49
87
  readonly id: "report_result";
50
88
  readonly instruction: "Report consumed input, expected output, minimum output, fees by asset side, price impact, and remaining validity.";
51
89
  }, {
52
90
  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 or exact opaque order set, then submit the externally signed transaction with idempotency. Resting-order control supports place, cancel, bounded cancel-all, atomic replace, and atomic heterogeneous batches of up to six operations. Every incoming resting order selects an explicit self-trade prevention policy; no policy permits a self-fill.";
91
+ readonly instruction: "When prepare and submit are exposed, keep signing external to Strata and use one signature per action: send the operation itself to prepare (orders, TWAP, quote-bound execution), verify the returned transaction, sign only that transaction with the session key, then submit with idempotency. The SDK's built-in verifier decodes the transaction and requires it to be exactly the requested operation for that market with the session co-signing only delegated instructions and never paying; a stricter owner verifier may replace it. The two-step challenge path (authorization bytes signed first) remains available. Resting-order control supports place, cancel, bounded cancel-all, atomic replace, and atomic heterogeneous batches of up to six operations. Every incoming resting order selects an explicit self-trade prevention policy; no policy permits a self-fill.";
54
92
  }, {
55
93
  readonly id: "stream_order_commands";
56
94
  readonly instruction: "When orders.prepare and orders.submit advertise websocket transport, use the official SDK persistent order-command connection. Sign its owner/session/market challenge externally, require contiguous sequences and correlated request IDs, treat the submit result as RPC broadcast only, and consume the pushed terminal status without blocking the placement hot path.";
@@ -60,12 +98,18 @@ export declare const STRATA_AGENT_HARNESS: {
60
98
  }, {
61
99
  readonly id: "certify_order_command_slo";
62
100
  readonly instruction: "Use the official non-trading order-command certification harness before release and on the production schedule. Retain its machine-readable connection count, load, latency percentiles, sequence/error rate, thresholds, and pass/fail result; package support alone is not a latency claim.";
101
+ }, {
102
+ readonly id: "stream_execution_state";
103
+ readonly instruction: "When execution.stream is live, watch every execution handle you prepared through the official SDK's sequenced execution stream instead of polling status: start from its snapshot, apply only contiguous execution_update, execution_expired, and execution_unknown events, recover any gap from a fresh snapshot, and treat an expired or unknown handle as not executed unless a confirmed receipt says otherwise.";
104
+ }, {
105
+ readonly id: "stream_twap_progress";
106
+ readonly instruction: "When algos.twap.stream is live, keep the official SDK's TWAP stream open for the owner wallet across the markets with active schedules: start from the snapshot, apply only contiguous twap_update events, and recover any gap from a fresh snapshot. Report executed size, achieved value, fees, and the terminal receipt from the streamed rows rather than polling.";
63
107
  }, {
64
108
  readonly id: "monitor_outcome";
65
109
  readonly instruction: "After an authorized submission, report the RPC-broadcast receipt and then the durable terminal status or explicit failure. If the request times out or either process restarts, recover it with the same control ID and idempotency key. Never claim chain completion from preparation, signing, or the immediate broadcast receipt.";
66
110
  }];
67
111
  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."];
68
- 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.", "Never select a self-trade policy implicitly, suppress an order-command sequence gap, or disarm a dead-man ticket merely because the client is shutting down.", "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."];
112
+ 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 the tolerance, refresh changed economics, substitute a market, or retry a non-retryable failure.", "Never select a self-trade policy implicitly, suppress an order-command sequence gap, or disarm a dead-man ticket merely because the client is shutting down.", "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."];
69
113
  };
70
114
  export declare const STRATA_AGENT_HARNESS_URI = "strata://agent-harness/v1";
71
115
  export declare const STRATA_ACTION_GRAPH: {
@@ -507,4 +551,4 @@ export declare const STRATA_ACTION_GRAPH: {
507
551
  }];
508
552
  };
509
553
  export declare const STRATA_ACTION_GRAPH_URI = "strata://action-graph/v1";
510
- 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. When websocket order transport is live, prefer the official SDK persistent command stream, choose explicit self-trade prevention, keep its durable dead-man guard armed for resting exposure, and distinguish immediate RPC broadcast from pushed terminal chain status. If submission is ambiguous, recover durable status with the same control ID and idempotency key. Order control supports place, cancel, bounded cancel-all, atomic replace, and atomic heterogeneous batches of up to six operations. Stop on ambiguity, sequence gaps, unavailable capabilities, paused markets, unsupported contracts, inconsistent bindings, expiry, or missing signer authority.";
554
+ export declare const STRATA_AGENT_HARNESS_INSTRUCTIONS = "Strata Agent Harness 1.0. Start every objective with strata_capabilities, then strata_action_graph, then strata_platform_graph, then strata_status, then strata_markets. Read strata://agent-harness/v1, strata://action-graph/v1, and strata://platform-graph/v2. 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 a market and side or catalog input/output asset IDs, plus exact input atoms and tolerance, before strata_quote or strata_swap_quote. When portfolio.read is live, read the owner's live Vault portfolio before sizing any action and treat null USD totals as an incomplete valuation, never as zero. When mm.status.read is live, reconcile the owner's own maker products, exposure, and dead-man guards through the authorized status read before and after every maker action, and when mm.fills.stream is live keep the official SDK's authenticated maker stream open to apply contiguous maker fills and exposure changes. When algos.twap.stream is live, follow TWAP progress through the official SDK's sequenced TWAP stream instead of polling, and when execution.stream is live watch prepared execution handles through the sequenced execution stream. Before selecting a maker transport, read the externally authorized owner-scoped maker reputation record and follow its signed-quote eligibility, cadence, and tier-progress fields. 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. When websocket order transport is live, prefer the official SDK persistent command stream, choose explicit self-trade prevention, keep its durable dead-man guard armed for resting exposure, and distinguish immediate RPC broadcast from pushed terminal chain status. If submission is ambiguous, recover durable status with the same control ID and idempotency key. Order control supports place, cancel, bounded cancel-all, atomic replace, and atomic heterogeneous batches of up to six operations. Stop on ambiguity, sequence gaps, unavailable capabilities, paused markets, unsupported contracts, inconsistent bindings, expiry, or missing signer authority.";