@stratabook/mcp 0.2.3 → 0.2.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 +25 -0
- package/dist/src/generated-harness.d.ts +2 -2
- package/dist/src/generated-harness.js +3 -1
- package/dist/src/server.js +258 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -45,6 +45,8 @@ The tools currently available are:
|
|
|
45
45
|
- `strata_portfolio_history`
|
|
46
46
|
- `strata_market_making_status`
|
|
47
47
|
- `strata_market_making_reputation`
|
|
48
|
+
- `strata_market_making_prepare` — start or stop a Strand/Current from a market label, decimal base size, spread, and duration; no arrays or atom conversion
|
|
49
|
+
- `strata_market_making_submit_and_wait` — submit the externally signed preparation idempotently and wait for matching chain-derived state
|
|
48
50
|
- `strata_market_making_strand_prepare`, `strata_market_making_strand_submit`
|
|
49
51
|
- `strata_market_making_current_prepare`, `strata_market_making_current_submit`
|
|
50
52
|
- `strata_vault_status`
|
|
@@ -82,6 +84,29 @@ so a disabled capability stops immediately even if a client cached an older
|
|
|
82
84
|
tool list. Tool discovery from the connected server remains authoritative for
|
|
83
85
|
self-hosted deployments or any future policy change.
|
|
84
86
|
|
|
87
|
+
For normal maker operation, use two calls:
|
|
88
|
+
|
|
89
|
+
1. Call `strata_market_making_prepare` with `action: "start"`, a label such as
|
|
90
|
+
`SOL/USDC`, `product: "current"` or `"strand"`, `spreadBps`, a decimal size
|
|
91
|
+
such as `0.01 SOL`, and the maker wallet. Duration defaults to ten minutes
|
|
92
|
+
and levels default to three.
|
|
93
|
+
2. Verify and sign only `prepared.transaction_base64` in the external wallet,
|
|
94
|
+
then pass it, `prepared.maker_control_id`, and the unchanged
|
|
95
|
+
`preparationToken` to `strata_market_making_submit_and_wait`.
|
|
96
|
+
|
|
97
|
+
The second call returns only after Strata's chain-derived maker status matches
|
|
98
|
+
the exact product settings. The token contains no signing authority and keeps
|
|
99
|
+
the two-call flow working across stateless HTTP requests or an MCP process
|
|
100
|
+
restart. Use `action: "stop"` through the same pair. The older product-specific
|
|
101
|
+
tools remain available for strategies that deliberately manage every low-level
|
|
102
|
+
array and safety field.
|
|
103
|
+
|
|
104
|
+
For maker funding, initialize the market Vault if needed, activate the Strand
|
|
105
|
+
or Current, then deposit with `strata_vault_deposit`. The market keeps that
|
|
106
|
+
available collateral while a control is live and returns it after the final
|
|
107
|
+
control is disabled, exhausted, expired, or cancelled. Current follows Strata's
|
|
108
|
+
live mark and needs no separate publisher transaction.
|
|
109
|
+
|
|
85
110
|
## Hosted Streamable HTTP
|
|
86
111
|
|
|
87
112
|
The managed public endpoint is:
|
|
@@ -17,7 +17,7 @@ export declare const STRATA_AGENT_HARNESS: {
|
|
|
17
17
|
readonly manifest: "https://api.stratabook.app/.well-known/strata-agent.json";
|
|
18
18
|
};
|
|
19
19
|
readonly interfaces: {
|
|
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"];
|
|
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_market_making_prepare", "strata_market_making_submit_and_wait", "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
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"];
|
|
22
22
|
};
|
|
23
23
|
readonly workflow: readonly [{
|
|
@@ -551,4 +551,4 @@ export declare const STRATA_ACTION_GRAPH: {
|
|
|
551
551
|
}];
|
|
552
552
|
};
|
|
553
553
|
export declare const STRATA_ACTION_GRAPH_URI = "strata://action-graph/v1";
|
|
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.";
|
|
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. For normal Strand or Current operation, prefer strata_market_making_prepare, sign only its prepared transaction externally, then pass its unchanged preparationToken with the signed transaction to strata_market_making_submit_and_wait; the token carries no signing authority and survives stateless HTTP requests. 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.";
|
|
@@ -35,6 +35,8 @@ export const STRATA_AGENT_HARNESS = {
|
|
|
35
35
|
"strata_portfolio_history",
|
|
36
36
|
"strata_market_making_status",
|
|
37
37
|
"strata_market_making_reputation",
|
|
38
|
+
"strata_market_making_prepare",
|
|
39
|
+
"strata_market_making_submit_and_wait",
|
|
38
40
|
"strata_vault_status",
|
|
39
41
|
"strata_vault_setup",
|
|
40
42
|
"strata_vault_deposit",
|
|
@@ -786,4 +788,4 @@ export const STRATA_ACTION_GRAPH = {
|
|
|
786
788
|
]
|
|
787
789
|
};
|
|
788
790
|
export const STRATA_ACTION_GRAPH_URI = "strata://action-graph/v1";
|
|
789
|
-
export 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.";
|
|
791
|
+
export 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. For normal Strand or Current operation, prefer strata_market_making_prepare, sign only its prepared transaction externally, then pass its unchanged preparationToken with the signed transaction to strata_market_making_submit_and_wait; the token carries no signing authority and survives stateless HTTP requests. 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.";
|
package/dist/src/server.js
CHANGED
|
@@ -6,6 +6,155 @@ import { STRATA_AGENT_HARNESS, STRATA_AGENT_HARNESS_INSTRUCTIONS, STRATA_AGENT_H
|
|
|
6
6
|
import { SERVER_VERSION } from "./version.js";
|
|
7
7
|
const REFRESH_INTERVAL_MS = 5_000;
|
|
8
8
|
export const STRATA_PLATFORM_GRAPH_URI = "strata://platform-graph/v2";
|
|
9
|
+
const makerPublicKeySchema = z.string().regex(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/);
|
|
10
|
+
const makerMarketIdSchema = z.string().regex(/^market_[0-9a-f]{32}$/);
|
|
11
|
+
const makerAssetIdSchema = z.string().regex(/^asset_[0-9a-f]{32}$/);
|
|
12
|
+
const makerControlIdSchema = z.string().regex(/^mc_[0-9a-f]{32}$/);
|
|
13
|
+
const makerAtomicSchema = z.string().regex(/^(?:0|[1-9][0-9]*)$/).max(20);
|
|
14
|
+
const makerPositiveAtomicSchema = z.string().regex(/^[1-9][0-9]*$/).max(20);
|
|
15
|
+
const makerBase64Schema = z.string().min(4).max(4_096)
|
|
16
|
+
.regex(/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/);
|
|
17
|
+
const makerMarketSchema = z.object({
|
|
18
|
+
market_id: makerMarketIdSchema,
|
|
19
|
+
label: z.string().min(1).max(128),
|
|
20
|
+
base_asset_id: makerAssetIdSchema,
|
|
21
|
+
quote_asset_id: makerAssetIdSchema,
|
|
22
|
+
status: z.enum([
|
|
23
|
+
"active",
|
|
24
|
+
"read_only",
|
|
25
|
+
"quote_only",
|
|
26
|
+
"cancel_only",
|
|
27
|
+
"paused",
|
|
28
|
+
"warming",
|
|
29
|
+
"degraded",
|
|
30
|
+
"unavailable",
|
|
31
|
+
]),
|
|
32
|
+
available_actions: z.array(z.enum([
|
|
33
|
+
"quote",
|
|
34
|
+
"execute_immediate",
|
|
35
|
+
"place_order",
|
|
36
|
+
"schedule_twap",
|
|
37
|
+
])).max(4),
|
|
38
|
+
}).strict();
|
|
39
|
+
const makerAssetSchema = z.object({
|
|
40
|
+
asset_id: makerAssetIdSchema,
|
|
41
|
+
symbol: z.string().min(1).max(32),
|
|
42
|
+
name: z.string().min(1).max(128),
|
|
43
|
+
decimals: z.number().int().min(0).max(18),
|
|
44
|
+
logo_url: z.string().url().optional(),
|
|
45
|
+
network: z.literal("solana"),
|
|
46
|
+
}).strict();
|
|
47
|
+
const makerStrandOperationSchema = z.discriminatedUnion("action", [
|
|
48
|
+
z.object({
|
|
49
|
+
action: z.literal("upsert"),
|
|
50
|
+
makerWallet: makerPublicKeySchema,
|
|
51
|
+
enabled: z.boolean(),
|
|
52
|
+
asyncOnly: z.boolean(),
|
|
53
|
+
syncSpreadTicks: z.number().int().min(0).max(65_535),
|
|
54
|
+
midPriceAtoms: makerPositiveAtomicSchema,
|
|
55
|
+
maxExposureBaseAtoms: makerPositiveAtomicSchema,
|
|
56
|
+
bidOffsetsTicks: z.array(z.number().int().min(0).max(65_535)).length(16),
|
|
57
|
+
askOffsetsTicks: z.array(z.number().int().min(0).max(65_535)).length(16),
|
|
58
|
+
bidSizesBaseAtoms: z.array(makerAtomicSchema).length(16),
|
|
59
|
+
askSizesBaseAtoms: z.array(makerAtomicSchema).length(16),
|
|
60
|
+
validUntilSlot: makerPositiveAtomicSchema,
|
|
61
|
+
}).strict(),
|
|
62
|
+
z.object({
|
|
63
|
+
action: z.literal("cancel"),
|
|
64
|
+
makerWallet: makerPublicKeySchema,
|
|
65
|
+
}).strict(),
|
|
66
|
+
]);
|
|
67
|
+
const makerCurrentOperationSchema = z.discriminatedUnion("action", [
|
|
68
|
+
z.object({
|
|
69
|
+
action: z.literal("upsert"),
|
|
70
|
+
makerWallet: makerPublicKeySchema,
|
|
71
|
+
enabled: z.boolean(),
|
|
72
|
+
asyncOnly: z.boolean(),
|
|
73
|
+
halfSpreadBps: z.number().int().min(1).max(65_535),
|
|
74
|
+
bandStepBps: z.number().int().min(0).max(65_535),
|
|
75
|
+
maxConfidenceBps: z.number().int().min(1).max(100),
|
|
76
|
+
maxOracleDeviationBps: z.number().int().min(1).max(500),
|
|
77
|
+
maxOracleAgeSeconds: z.number().int().min(0).max(4_294_967_295),
|
|
78
|
+
syncSpreadBps: z.number().int().min(0).max(65_535),
|
|
79
|
+
maxExposureBaseAtoms: makerPositiveAtomicSchema,
|
|
80
|
+
bidDepthBaseAtoms: z.array(makerAtomicSchema).length(8),
|
|
81
|
+
askDepthBaseAtoms: z.array(makerAtomicSchema).length(8),
|
|
82
|
+
validUntilSlot: makerPositiveAtomicSchema,
|
|
83
|
+
}).strict(),
|
|
84
|
+
z.object({
|
|
85
|
+
action: z.literal("cancel"),
|
|
86
|
+
makerWallet: makerPublicKeySchema,
|
|
87
|
+
}).strict(),
|
|
88
|
+
]);
|
|
89
|
+
const makerPreparedResponseSchema = z.object({
|
|
90
|
+
schema_version: z.literal(2),
|
|
91
|
+
contract_version: z.literal("2.0"),
|
|
92
|
+
maker_control_id: makerControlIdSchema,
|
|
93
|
+
market_id: makerMarketIdSchema,
|
|
94
|
+
maker_wallet: makerPublicKeySchema,
|
|
95
|
+
product: z.enum(["strand", "current"]),
|
|
96
|
+
action: z.enum([
|
|
97
|
+
"strand_upsert",
|
|
98
|
+
"strand_recenter",
|
|
99
|
+
"strand_set_enabled",
|
|
100
|
+
"strand_cancel",
|
|
101
|
+
"current_upsert",
|
|
102
|
+
"current_cancel",
|
|
103
|
+
]),
|
|
104
|
+
transaction_base64: makerBase64Schema,
|
|
105
|
+
recent_blockhash: makerPublicKeySchema,
|
|
106
|
+
last_valid_block_height: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
|
|
107
|
+
expires_at_ms: z.number().int().min(1).max(Number.MAX_SAFE_INTEGER),
|
|
108
|
+
}).strict();
|
|
109
|
+
const makerPreparationSchema = z.object({
|
|
110
|
+
market: makerMarketSchema,
|
|
111
|
+
base_asset: makerAssetSchema.optional(),
|
|
112
|
+
product: z.enum(["strand", "current"]),
|
|
113
|
+
operation: z.union([makerStrandOperationSchema, makerCurrentOperationSchema]),
|
|
114
|
+
prepared: makerPreparedResponseSchema,
|
|
115
|
+
}).strict();
|
|
116
|
+
const makerPreparationEnvelopeSchema = z.object({
|
|
117
|
+
version: z.literal(1),
|
|
118
|
+
preparation: makerPreparationSchema,
|
|
119
|
+
}).strict();
|
|
120
|
+
function encodeMakerPreparationToken(preparation) {
|
|
121
|
+
const checked = makerPreparationSchema.parse(preparation);
|
|
122
|
+
return Buffer.from(JSON.stringify({ version: 1, preparation: checked }), "utf8")
|
|
123
|
+
.toString("base64url");
|
|
124
|
+
}
|
|
125
|
+
function decodeMakerPreparationToken(token) {
|
|
126
|
+
let decoded;
|
|
127
|
+
try {
|
|
128
|
+
const bytes = Buffer.from(token, "base64url");
|
|
129
|
+
if (bytes.toString("base64url") !== token) {
|
|
130
|
+
throw new Error("non-canonical base64url");
|
|
131
|
+
}
|
|
132
|
+
decoded = JSON.parse(bytes.toString("utf8"));
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
throw new Error("preparationToken is not valid encoded JSON");
|
|
136
|
+
}
|
|
137
|
+
const { preparation } = makerPreparationEnvelopeSchema.parse(decoded);
|
|
138
|
+
const expectedAction = preparation.product === "strand"
|
|
139
|
+
? preparation.operation.action === "upsert" ? "strand_upsert" : "strand_cancel"
|
|
140
|
+
: preparation.operation.action === "upsert" ? "current_upsert" : "current_cancel";
|
|
141
|
+
if (preparation.prepared.product !== preparation.product
|
|
142
|
+
|| preparation.prepared.action !== expectedAction
|
|
143
|
+
|| preparation.prepared.market_id !== preparation.market.market_id
|
|
144
|
+
|| preparation.prepared.maker_wallet !== preparation.operation.makerWallet
|
|
145
|
+
|| (preparation.product === "strand"
|
|
146
|
+
&& preparation.operation.action === "upsert"
|
|
147
|
+
&& !("midPriceAtoms" in preparation.operation))
|
|
148
|
+
|| (preparation.product === "current"
|
|
149
|
+
&& preparation.operation.action === "upsert"
|
|
150
|
+
&& !("halfSpreadBps" in preparation.operation))
|
|
151
|
+
|| (preparation.operation.action === "upsert" && preparation.base_asset === undefined)
|
|
152
|
+
|| (preparation.base_asset !== undefined
|
|
153
|
+
&& preparation.base_asset.asset_id !== preparation.market.base_asset_id)) {
|
|
154
|
+
throw new Error("preparationToken contains inconsistent maker bindings");
|
|
155
|
+
}
|
|
156
|
+
return preparation;
|
|
157
|
+
}
|
|
9
158
|
const LEGACY_TOOL_CAPABILITIES = {
|
|
10
159
|
strata_markets: { ids: ["markets.read"] },
|
|
11
160
|
strata_quote: { ids: ["quotes.read"] },
|
|
@@ -21,6 +170,8 @@ const LEGACY_TOOL_CAPABILITIES = {
|
|
|
21
170
|
strata_market_making_strand_submit: { ids: ["mm.strand.manage"] },
|
|
22
171
|
strata_market_making_current_prepare: { ids: ["mm.current.manage"] },
|
|
23
172
|
strata_market_making_current_submit: { ids: ["mm.current.manage"] },
|
|
173
|
+
strata_market_making_prepare: { ids: ["mm.strand.manage", "mm.current.manage"], match: "any" },
|
|
174
|
+
strata_market_making_submit_and_wait: { ids: ["mm.strand.manage", "mm.current.manage"], match: "any" },
|
|
24
175
|
strata_execute_quote: { ids: ["trade.submit"] },
|
|
25
176
|
strata_order_execute: { ids: ["orders.prepare", "orders.submit"] },
|
|
26
177
|
};
|
|
@@ -61,6 +212,8 @@ const PLATFORM_TOOL_CAPABILITIES = {
|
|
|
61
212
|
strata_market_making_strand_submit: { ids: ["mm.strand.manage"] },
|
|
62
213
|
strata_market_making_current_prepare: { ids: ["mm.current.manage"] },
|
|
63
214
|
strata_market_making_current_submit: { ids: ["mm.current.manage"] },
|
|
215
|
+
strata_market_making_prepare: { ids: ["mm.strand.manage", "mm.current.manage"], match: "any" },
|
|
216
|
+
strata_market_making_submit_and_wait: { ids: ["mm.strand.manage", "mm.current.manage"], match: "any" },
|
|
64
217
|
strata_rewards: { ids: ["rewards.read"] },
|
|
65
218
|
strata_referrals: { ids: ["referrals.read"] },
|
|
66
219
|
strata_referral_link: { ids: ["referrals.link"] },
|
|
@@ -1509,6 +1662,109 @@ export async function createStrataMcpServer(options = {}) {
|
|
|
1509
1662
|
const response = await platformClient.orders.status(marketId, { orderControlId, idempotencyKey });
|
|
1510
1663
|
return toolResult(response, `Order control ${response.order_control_id} is ${response.status}.`);
|
|
1511
1664
|
}));
|
|
1665
|
+
const makerPrepare = registerTool("strata_market_making_prepare", {
|
|
1666
|
+
title: "Prepare simple Strata market making",
|
|
1667
|
+
description: "Prepare a pro-level Strand or Current from a market label, decimal base size, spread, and duration. Strata resolves IDs, decimals, live mark, tick grid, expiry, safety bounds, and fixed on-chain arrays. Sign only the returned transaction externally, then call submit_and_wait.",
|
|
1668
|
+
inputSchema: {
|
|
1669
|
+
action: z.enum(["start", "stop"]),
|
|
1670
|
+
market: z.string().min(1).max(128),
|
|
1671
|
+
product: z.enum(["strand", "current"]),
|
|
1672
|
+
makerWallet: z.string().regex(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/),
|
|
1673
|
+
spreadBps: z.number().int().min(1).max(5_000).optional(),
|
|
1674
|
+
size: z.string().min(1).max(64).optional(),
|
|
1675
|
+
duration: z.union([
|
|
1676
|
+
z.number().int().min(1).max(604_800),
|
|
1677
|
+
z.string().regex(/^[1-9][0-9]*(?:s|m|h|d)$/i),
|
|
1678
|
+
]).optional(),
|
|
1679
|
+
levels: z.number().int().min(1).max(16).optional(),
|
|
1680
|
+
levelStepBps: z.number().int().min(1).max(5_000).optional(),
|
|
1681
|
+
side: z.enum(["both", "buy", "sell"]).optional(),
|
|
1682
|
+
asyncOnly: z.boolean().optional(),
|
|
1683
|
+
},
|
|
1684
|
+
annotations: {
|
|
1685
|
+
readOnlyHint: false,
|
|
1686
|
+
destructiveHint: true,
|
|
1687
|
+
idempotentHint: false,
|
|
1688
|
+
openWorldHint: true,
|
|
1689
|
+
},
|
|
1690
|
+
}, async (args) => guardedTool(client, `mm.${args.product}.manage`, async () => {
|
|
1691
|
+
const prepared = args.action === "stop"
|
|
1692
|
+
? await platformClient.marketMaking.prepareStop({
|
|
1693
|
+
market: args.market,
|
|
1694
|
+
product: args.product,
|
|
1695
|
+
makerWallet: args.makerWallet,
|
|
1696
|
+
})
|
|
1697
|
+
: (() => {
|
|
1698
|
+
if (args.spreadBps === undefined || args.size === undefined) {
|
|
1699
|
+
return undefined;
|
|
1700
|
+
}
|
|
1701
|
+
return platformClient.marketMaking.prepareStart({
|
|
1702
|
+
market: args.market,
|
|
1703
|
+
product: args.product,
|
|
1704
|
+
makerWallet: args.makerWallet,
|
|
1705
|
+
spreadBps: args.spreadBps,
|
|
1706
|
+
size: args.size,
|
|
1707
|
+
...(args.duration === undefined ? {} : { duration: args.duration }),
|
|
1708
|
+
...(args.levels === undefined ? {} : { levels: args.levels }),
|
|
1709
|
+
...(args.levelStepBps === undefined ? {} : { levelStepBps: args.levelStepBps }),
|
|
1710
|
+
...(args.side === undefined ? {} : { side: args.side }),
|
|
1711
|
+
...(args.asyncOnly === undefined ? {} : { asyncOnly: args.asyncOnly }),
|
|
1712
|
+
});
|
|
1713
|
+
})();
|
|
1714
|
+
if (prepared === undefined) {
|
|
1715
|
+
return toolError("invalid_request", "Starting market making requires spreadBps and size.", false);
|
|
1716
|
+
}
|
|
1717
|
+
const resolved = await prepared;
|
|
1718
|
+
const response = {
|
|
1719
|
+
action: args.action,
|
|
1720
|
+
market: resolved.market,
|
|
1721
|
+
product: resolved.product,
|
|
1722
|
+
...("base_asset" in resolved ? { base_asset: resolved.base_asset } : {}),
|
|
1723
|
+
operation: resolved.operation,
|
|
1724
|
+
prepared: resolved.prepared,
|
|
1725
|
+
preparationToken: encodeMakerPreparationToken(resolved),
|
|
1726
|
+
};
|
|
1727
|
+
return toolResult(response, `Prepared ${args.action} for ${resolved.market.label} as ${resolved.prepared.maker_control_id}. Verify and sign only prepared.transaction_base64, then pass preparationToken unchanged to submit_and_wait within 30 seconds.`);
|
|
1728
|
+
}));
|
|
1729
|
+
const makerSubmitAndWait = registerTool("strata_market_making_submit_and_wait", {
|
|
1730
|
+
title: "Submit and confirm Strata market making",
|
|
1731
|
+
description: "Submit the exact externally signed quickstart transaction with the unchanged preparation token and wait until Strata's chain-derived maker state confirms the product started or stopped. The token survives stateless HTTP requests and server restarts; the control ID is its default idempotency key.",
|
|
1732
|
+
inputSchema: {
|
|
1733
|
+
makerControlId: z.string().regex(/^mc_[0-9a-f]{32}$/),
|
|
1734
|
+
preparationToken: z.string().min(16).max(32_768).regex(/^[A-Za-z0-9_-]+$/),
|
|
1735
|
+
signedTransactionBase64: z.string().min(4).max(4_096).regex(/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/),
|
|
1736
|
+
idempotencyKey: z.string().min(1).max(64).regex(/^[A-Za-z0-9._-]+$/).optional(),
|
|
1737
|
+
confirmationTimeoutMs: z.number().int().min(1_000).max(120_000).optional(),
|
|
1738
|
+
},
|
|
1739
|
+
annotations: {
|
|
1740
|
+
readOnlyHint: false,
|
|
1741
|
+
destructiveHint: true,
|
|
1742
|
+
idempotentHint: true,
|
|
1743
|
+
openWorldHint: true,
|
|
1744
|
+
},
|
|
1745
|
+
}, async (args) => {
|
|
1746
|
+
let prepared;
|
|
1747
|
+
try {
|
|
1748
|
+
prepared = decodeMakerPreparationToken(args.preparationToken);
|
|
1749
|
+
}
|
|
1750
|
+
catch {
|
|
1751
|
+
return toolError("invalid_request", "preparationToken is invalid. Pass the token returned by strata_market_making_prepare unchanged.", false);
|
|
1752
|
+
}
|
|
1753
|
+
if (prepared.prepared.maker_control_id !== args.makerControlId) {
|
|
1754
|
+
return toolError("binding_mismatch", "makerControlId does not match preparationToken.", false);
|
|
1755
|
+
}
|
|
1756
|
+
return guardedTool(client, `mm.${prepared.product}.manage`, async () => {
|
|
1757
|
+
const response = await platformClient.marketMaking.submitPrepared({
|
|
1758
|
+
prepared,
|
|
1759
|
+
signedTransactionBase64: args.signedTransactionBase64,
|
|
1760
|
+
...(args.idempotencyKey === undefined ? {} : { idempotencyKey: args.idempotencyKey }),
|
|
1761
|
+
...(args.confirmationTimeoutMs === undefined
|
|
1762
|
+
? {}
|
|
1763
|
+
: { confirmationTimeoutMs: args.confirmationTimeoutMs }),
|
|
1764
|
+
});
|
|
1765
|
+
return toolResult(response, `${response.product} is confirmed ${response.operation.action === "cancel" ? "stopped" : "live"} on ${response.market.label}.`);
|
|
1766
|
+
});
|
|
1767
|
+
});
|
|
1512
1768
|
const makerStrandPrepare = registerTool("strata_market_making_strand_prepare", {
|
|
1513
1769
|
title: "Prepare Strata Strand control",
|
|
1514
1770
|
description: "Build one exact unsigned maker-owned Strand transaction. Every exposure and level size is expressed in base-asset atoms, never lots or whole tokens. Verify and sign it externally with the maker wallet, then submit it with the Strand submit tool.",
|
|
@@ -1700,6 +1956,8 @@ export async function createStrataMcpServer(options = {}) {
|
|
|
1700
1956
|
orderPrepare,
|
|
1701
1957
|
orderSubmit,
|
|
1702
1958
|
orderStatus,
|
|
1959
|
+
makerPrepare,
|
|
1960
|
+
makerSubmitAndWait,
|
|
1703
1961
|
makerStrandPrepare,
|
|
1704
1962
|
makerStrandSubmit,
|
|
1705
1963
|
makerCurrentPrepare,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stratabook/mcp",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.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.2.
|
|
47
|
+
"@stratabook/sdk": "0.2.6",
|
|
48
48
|
"zod": "^3.25.76"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|