@stratabook/mcp 0.2.0 → 0.2.2

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.
@@ -188,7 +188,7 @@ export declare const STRATA_ACTION_GRAPH: {
188
188
  }, {
189
189
  readonly id: "read_market_status";
190
190
  readonly kind: "read";
191
- readonly summary: "Read tick size, minimum order size, and current market status.";
191
+ readonly summary: "Read tick size, the smallest valid base-atom size, and current market status.";
192
192
  readonly required_capabilities: readonly ["books.read"];
193
193
  readonly available: true;
194
194
  readonly operation: {
@@ -325,7 +325,7 @@ export const STRATA_ACTION_GRAPH = {
325
325
  {
326
326
  "id": "read_market_status",
327
327
  "kind": "read",
328
- "summary": "Read tick size, minimum order size, and current market status.",
328
+ "summary": "Read tick size, the smallest valid base-atom size, and current market status.",
329
329
  "required_capabilities": [
330
330
  "books.read"
331
331
  ],
@@ -1443,6 +1443,185 @@ export async function createStrataMcpServer(options = {}) {
1443
1443
  const response = await platformClient.orders.status(marketId, { orderControlId, idempotencyKey });
1444
1444
  return toolResult(response, `Order control ${response.order_control_id} is ${response.status}.`);
1445
1445
  }));
1446
+ const makerStrandPrepare = server.registerTool("strata_market_making_strand_prepare", {
1447
+ title: "Prepare Strata Strand control",
1448
+ 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.",
1449
+ inputSchema: {
1450
+ marketId: z.string().regex(/^market_[0-9a-f]{32}$/),
1451
+ action: z.enum(["upsert", "recenter", "set_enabled", "cancel"]),
1452
+ makerWallet: z.string().regex(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/),
1453
+ enabled: z.boolean().optional(),
1454
+ asyncOnly: z.boolean().optional(),
1455
+ syncSpreadTicks: z.number().int().min(0).max(65_535).optional(),
1456
+ midPriceAtoms: z.string().regex(/^[1-9][0-9]*$/).max(20).optional(),
1457
+ maxExposureBaseAtoms: z.string().regex(/^[1-9][0-9]*$/).max(20).optional(),
1458
+ bidOffsetsTicks: z.array(z.number().int().min(0).max(65_535)).length(16).optional(),
1459
+ askOffsetsTicks: z.array(z.number().int().min(0).max(65_535)).length(16).optional(),
1460
+ bidSizesBaseAtoms: z.array(z.string().regex(/^(?:0|[1-9][0-9]*)$/).max(20)).length(16).optional(),
1461
+ askSizesBaseAtoms: z.array(z.string().regex(/^(?:0|[1-9][0-9]*)$/).max(20)).length(16).optional(),
1462
+ newMidPriceAtoms: z.string().regex(/^[1-9][0-9]*$/).max(20).optional(),
1463
+ validUntilSlot: z.string().regex(/^(?:0|[1-9][0-9]*)$/).max(20).optional(),
1464
+ },
1465
+ annotations: {
1466
+ readOnlyHint: false,
1467
+ destructiveHint: true,
1468
+ idempotentHint: false,
1469
+ openWorldHint: true,
1470
+ },
1471
+ }, async (args) => guardedTool(client, "mm.strand.manage", async () => {
1472
+ let request;
1473
+ if (args.action === "upsert") {
1474
+ if (args.enabled === undefined || args.asyncOnly === undefined
1475
+ || args.syncSpreadTicks === undefined || args.midPriceAtoms === undefined
1476
+ || args.maxExposureBaseAtoms === undefined || args.bidOffsetsTicks === undefined
1477
+ || args.askOffsetsTicks === undefined || args.bidSizesBaseAtoms === undefined
1478
+ || args.askSizesBaseAtoms === undefined || args.validUntilSlot === undefined) {
1479
+ return toolError("invalid_request", "Strand upsert requires every level, exposure, midpoint, spread, flag, and expiry field.", false);
1480
+ }
1481
+ request = {
1482
+ action: "upsert",
1483
+ makerWallet: args.makerWallet,
1484
+ enabled: args.enabled,
1485
+ asyncOnly: args.asyncOnly,
1486
+ syncSpreadTicks: args.syncSpreadTicks,
1487
+ midPriceAtoms: args.midPriceAtoms,
1488
+ maxExposureBaseAtoms: args.maxExposureBaseAtoms,
1489
+ bidOffsetsTicks: args.bidOffsetsTicks,
1490
+ askOffsetsTicks: args.askOffsetsTicks,
1491
+ bidSizesBaseAtoms: args.bidSizesBaseAtoms,
1492
+ askSizesBaseAtoms: args.askSizesBaseAtoms,
1493
+ validUntilSlot: args.validUntilSlot,
1494
+ };
1495
+ }
1496
+ else if (args.action === "recenter") {
1497
+ if (args.newMidPriceAtoms === undefined || args.validUntilSlot === undefined) {
1498
+ return toolError("invalid_request", "Strand recenter requires newMidPriceAtoms and validUntilSlot.", false);
1499
+ }
1500
+ request = {
1501
+ action: "recenter",
1502
+ makerWallet: args.makerWallet,
1503
+ newMidPriceAtoms: args.newMidPriceAtoms,
1504
+ validUntilSlot: args.validUntilSlot,
1505
+ };
1506
+ }
1507
+ else if (args.action === "set_enabled") {
1508
+ if (args.enabled === undefined) {
1509
+ return toolError("invalid_request", "Strand set_enabled requires enabled.", false);
1510
+ }
1511
+ request = { action: "set_enabled", makerWallet: args.makerWallet, enabled: args.enabled };
1512
+ }
1513
+ else {
1514
+ request = { action: "cancel", makerWallet: args.makerWallet };
1515
+ }
1516
+ const response = await platformClient.marketMaking.strand.prepare(args.marketId, request);
1517
+ return toolResult(response, `Prepared ${response.action} control ${response.maker_control_id}; verify and sign only this transaction with ${response.maker_wallet} before ${response.expires_at_ms}.`);
1518
+ }));
1519
+ const makerStrandSubmit = server.registerTool("strata_market_making_strand_submit", {
1520
+ title: "Submit Strata Strand control",
1521
+ description: "Submit the exact externally maker-signed Strand transaction with a stable retry key.",
1522
+ inputSchema: {
1523
+ marketId: z.string().regex(/^market_[0-9a-f]{32}$/),
1524
+ makerControlId: z.string().regex(/^mc_[0-9a-f]{32}$/),
1525
+ signedTransactionBase64: z.string().min(4).max(4_096).regex(/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/),
1526
+ idempotencyKey: z.string().min(1).max(64).regex(/^[A-Za-z0-9._-]+$/),
1527
+ },
1528
+ annotations: {
1529
+ readOnlyHint: false,
1530
+ destructiveHint: true,
1531
+ idempotentHint: true,
1532
+ openWorldHint: true,
1533
+ },
1534
+ }, async ({ marketId, makerControlId, signedTransactionBase64, idempotencyKey }) => guardedTool(client, "mm.strand.manage", async () => {
1535
+ const response = await platformClient.marketMaking.strand.submit(marketId, {
1536
+ makerControlId,
1537
+ signedTransactionBase64,
1538
+ idempotencyKey,
1539
+ });
1540
+ return toolResult(response, `Submitted ${response.action} as ${response.signature}.`);
1541
+ }));
1542
+ const makerCurrentPrepare = server.registerTool("strata_market_making_current_prepare", {
1543
+ title: "Prepare Strata Current control",
1544
+ description: "Build one exact unsigned maker-owned Current transaction. Upsert fails closed until the market has a verified on-chain reference; cancel does not need that reference.",
1545
+ inputSchema: {
1546
+ marketId: z.string().regex(/^market_[0-9a-f]{32}$/),
1547
+ action: z.enum(["upsert", "cancel"]),
1548
+ makerWallet: z.string().regex(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/),
1549
+ enabled: z.boolean().optional(),
1550
+ asyncOnly: z.boolean().optional(),
1551
+ halfSpreadBps: z.number().int().min(1).max(65_535).optional(),
1552
+ bandStepBps: z.number().int().min(0).max(65_535).optional(),
1553
+ maxConfidenceBps: z.number().int().min(1).max(100).optional(),
1554
+ maxOracleDeviationBps: z.number().int().min(1).max(500).optional(),
1555
+ maxOracleAgeSeconds: z.number().int().min(0).max(4_294_967_295).optional(),
1556
+ syncSpreadBps: z.number().int().min(0).max(65_535).optional(),
1557
+ maxExposureBaseAtoms: z.string().regex(/^[1-9][0-9]*$/).max(20).optional(),
1558
+ bidDepthBaseAtoms: z.array(z.string().regex(/^(?:0|[1-9][0-9]*)$/).max(20)).length(8).optional(),
1559
+ askDepthBaseAtoms: z.array(z.string().regex(/^(?:0|[1-9][0-9]*)$/).max(20)).length(8).optional(),
1560
+ validUntilSlot: z.string().regex(/^(?:0|[1-9][0-9]*)$/).max(20).optional(),
1561
+ },
1562
+ annotations: {
1563
+ readOnlyHint: false,
1564
+ destructiveHint: true,
1565
+ idempotentHint: false,
1566
+ openWorldHint: true,
1567
+ },
1568
+ }, async (args) => guardedTool(client, "mm.current.manage", async () => {
1569
+ let request;
1570
+ if (args.action === "cancel") {
1571
+ request = { action: "cancel", makerWallet: args.makerWallet };
1572
+ }
1573
+ else {
1574
+ if (args.enabled === undefined || args.asyncOnly === undefined
1575
+ || args.halfSpreadBps === undefined || args.bandStepBps === undefined
1576
+ || args.maxConfidenceBps === undefined || args.maxOracleDeviationBps === undefined
1577
+ || args.maxOracleAgeSeconds === undefined || args.syncSpreadBps === undefined
1578
+ || args.maxExposureBaseAtoms === undefined || args.bidDepthBaseAtoms === undefined
1579
+ || args.askDepthBaseAtoms === undefined || args.validUntilSlot === undefined) {
1580
+ return toolError("invalid_request", "Current upsert requires every depth, exposure, spread, oracle-bound, flag, and expiry field.", false);
1581
+ }
1582
+ request = {
1583
+ action: "upsert",
1584
+ makerWallet: args.makerWallet,
1585
+ enabled: args.enabled,
1586
+ asyncOnly: args.asyncOnly,
1587
+ halfSpreadBps: args.halfSpreadBps,
1588
+ bandStepBps: args.bandStepBps,
1589
+ maxConfidenceBps: args.maxConfidenceBps,
1590
+ maxOracleDeviationBps: args.maxOracleDeviationBps,
1591
+ maxOracleAgeSeconds: args.maxOracleAgeSeconds,
1592
+ syncSpreadBps: args.syncSpreadBps,
1593
+ maxExposureBaseAtoms: args.maxExposureBaseAtoms,
1594
+ bidDepthBaseAtoms: args.bidDepthBaseAtoms,
1595
+ askDepthBaseAtoms: args.askDepthBaseAtoms,
1596
+ validUntilSlot: args.validUntilSlot,
1597
+ };
1598
+ }
1599
+ const response = await platformClient.marketMaking.current.prepare(args.marketId, request);
1600
+ return toolResult(response, `Prepared ${response.action} control ${response.maker_control_id}; verify and sign only this transaction with ${response.maker_wallet} before ${response.expires_at_ms}.`);
1601
+ }));
1602
+ const makerCurrentSubmit = server.registerTool("strata_market_making_current_submit", {
1603
+ title: "Submit Strata Current control",
1604
+ description: "Submit the exact externally maker-signed Current transaction with a stable retry key.",
1605
+ inputSchema: {
1606
+ marketId: z.string().regex(/^market_[0-9a-f]{32}$/),
1607
+ makerControlId: z.string().regex(/^mc_[0-9a-f]{32}$/),
1608
+ signedTransactionBase64: z.string().min(4).max(4_096).regex(/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/),
1609
+ idempotencyKey: z.string().min(1).max(64).regex(/^[A-Za-z0-9._-]+$/),
1610
+ },
1611
+ annotations: {
1612
+ readOnlyHint: false,
1613
+ destructiveHint: true,
1614
+ idempotentHint: true,
1615
+ openWorldHint: true,
1616
+ },
1617
+ }, async ({ marketId, makerControlId, signedTransactionBase64, idempotencyKey }) => guardedTool(client, "mm.current.manage", async () => {
1618
+ const response = await platformClient.marketMaking.current.submit(marketId, {
1619
+ makerControlId,
1620
+ signedTransactionBase64,
1621
+ idempotencyKey,
1622
+ });
1623
+ return toolResult(response, `Submitted ${response.action} as ${response.signature}.`);
1624
+ }));
1446
1625
  registerAutonomyTools(server, client, platformClient, options.sessionAutonomy, () => typeof Date !== "undefined" ? Date.now() : 0);
1447
1626
  const handles = {
1448
1627
  markets,
@@ -1455,6 +1634,10 @@ export async function createStrataMcpServer(options = {}) {
1455
1634
  orderPrepare,
1456
1635
  orderSubmit,
1457
1636
  orderStatus,
1637
+ makerStrandPrepare,
1638
+ makerStrandSubmit,
1639
+ makerCurrentPrepare,
1640
+ makerCurrentSubmit,
1458
1641
  };
1459
1642
  applyCapabilityCatalog(handles, initialCatalog);
1460
1643
  let closed = false;
@@ -1737,6 +1920,12 @@ function applyCapabilityCatalog(handles, catalog) {
1737
1920
  setToolEnabled(handles.orderPrepare, capabilityAvailable(catalog, "orders.prepare"));
1738
1921
  setToolEnabled(handles.orderSubmit, capabilityAvailable(catalog, "orders.submit"));
1739
1922
  setToolEnabled(handles.orderStatus, capabilityAvailable(catalog, "orders.submit"));
1923
+ const strandEnabled = capabilityAvailable(catalog, "mm.strand.manage");
1924
+ setToolEnabled(handles.makerStrandPrepare, strandEnabled);
1925
+ setToolEnabled(handles.makerStrandSubmit, strandEnabled);
1926
+ const currentEnabled = capabilityAvailable(catalog, "mm.current.manage");
1927
+ setToolEnabled(handles.makerCurrentPrepare, currentEnabled);
1928
+ setToolEnabled(handles.makerCurrentSubmit, currentEnabled);
1740
1929
  }
1741
1930
  function setToolEnabled(tool, enabled) {
1742
1931
  if (enabled)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stratabook/mcp",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
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.0",
47
+ "@stratabook/sdk": "0.2.2",
48
48
  "zod": "^3.25.76"
49
49
  },
50
50
  "devDependencies": {