@mixrpay/agent-sdk 0.3.2 → 0.3.4

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/dist/index.js CHANGED
@@ -1433,6 +1433,540 @@ var AgentWallet = class {
1433
1433
  createdAt: new Date(data.createdAt || data.created_at)
1434
1434
  };
1435
1435
  }
1436
+ // ===========================================================================
1437
+ // MCP (Model Context Protocol) Methods
1438
+ // ===========================================================================
1439
+ /**
1440
+ * Get authentication headers for MCP wallet-based authentication.
1441
+ *
1442
+ * These headers prove wallet ownership without transmitting the private key.
1443
+ * Use for direct pay-per-call mode (no session needed).
1444
+ *
1445
+ * @returns Headers object with X-Mixr-Wallet, X-Mixr-Signature, X-Mixr-Timestamp
1446
+ *
1447
+ * @example
1448
+ * ```typescript
1449
+ * const headers = await wallet.getMCPAuthHeaders();
1450
+ * const response = await fetch('https://mixrpay.com/api/mcp', {
1451
+ * method: 'POST',
1452
+ * headers: {
1453
+ * 'Content-Type': 'application/json',
1454
+ * ...headers,
1455
+ * },
1456
+ * body: JSON.stringify({
1457
+ * jsonrpc: '2.0',
1458
+ * method: 'tools/list',
1459
+ * id: 1,
1460
+ * }),
1461
+ * });
1462
+ * ```
1463
+ */
1464
+ async getMCPAuthHeaders() {
1465
+ const timestamp = Date.now().toString();
1466
+ const message = `MixrPay MCP Auth
1467
+ Wallet: ${this.walletAddress}
1468
+ Timestamp: ${timestamp}`;
1469
+ const signature = await this.sessionKey.signMessage(message);
1470
+ return {
1471
+ "X-Mixr-Wallet": this.walletAddress,
1472
+ "X-Mixr-Signature": signature,
1473
+ "X-Mixr-Timestamp": timestamp
1474
+ };
1475
+ }
1476
+ /**
1477
+ * List available MCP tools from the MixrPay gateway.
1478
+ *
1479
+ * Returns all tools exposed by MCP providers on the MixrPay marketplace.
1480
+ * Each tool includes pricing information.
1481
+ *
1482
+ * @returns Array of MCP tools with pricing and metadata
1483
+ *
1484
+ * @example
1485
+ * ```typescript
1486
+ * const tools = await wallet.listMCPTools();
1487
+ * for (const tool of tools) {
1488
+ * console.log(`${tool.name}: $${tool.priceUsd} - ${tool.description}`);
1489
+ * }
1490
+ * ```
1491
+ */
1492
+ async listMCPTools() {
1493
+ this.logger.debug("listMCPTools");
1494
+ const response = await fetch(`${this.baseUrl}/api/mcp`, {
1495
+ method: "POST",
1496
+ headers: { "Content-Type": "application/json" },
1497
+ body: JSON.stringify({
1498
+ jsonrpc: "2.0",
1499
+ method: "tools/list",
1500
+ id: Date.now()
1501
+ })
1502
+ });
1503
+ if (!response.ok) {
1504
+ throw new MixrPayError(`Failed to list MCP tools: ${response.status}`);
1505
+ }
1506
+ const result = await response.json();
1507
+ if (result.error) {
1508
+ throw new MixrPayError(result.error.message || "Failed to list MCP tools");
1509
+ }
1510
+ return (result.result?.tools || []).map((tool) => ({
1511
+ name: tool.name,
1512
+ description: tool.description,
1513
+ inputSchema: tool.inputSchema,
1514
+ priceUsd: tool["x-mixrpay"]?.priceUsd || 0,
1515
+ merchantName: tool["x-mixrpay"]?.merchantName,
1516
+ merchantSlug: tool["x-mixrpay"]?.merchantSlug,
1517
+ verified: tool["x-mixrpay"]?.verified || false
1518
+ }));
1519
+ }
1520
+ /**
1521
+ * Call an MCP tool with wallet authentication (direct pay per call).
1522
+ *
1523
+ * This method signs a fresh auth message for each call, charging
1524
+ * directly from your wallet balance without needing a session.
1525
+ *
1526
+ * @param toolName - The tool name in format "merchant/tool"
1527
+ * @param args - Arguments to pass to the tool
1528
+ * @returns Tool execution result
1529
+ *
1530
+ * @example
1531
+ * ```typescript
1532
+ * const result = await wallet.callMCPTool('firecrawl/scrape', {
1533
+ * url: 'https://example.com',
1534
+ * });
1535
+ * console.log(result.data);
1536
+ * console.log(`Charged: $${result.chargedUsd}`);
1537
+ * ```
1538
+ */
1539
+ async callMCPTool(toolName, args = {}) {
1540
+ this.logger.debug("callMCPTool", { toolName, args });
1541
+ const authHeaders = await this.getMCPAuthHeaders();
1542
+ const response = await fetch(`${this.baseUrl}/api/mcp`, {
1543
+ method: "POST",
1544
+ headers: {
1545
+ "Content-Type": "application/json",
1546
+ ...authHeaders
1547
+ },
1548
+ body: JSON.stringify({
1549
+ jsonrpc: "2.0",
1550
+ method: "tools/call",
1551
+ params: { name: toolName, arguments: args },
1552
+ id: Date.now()
1553
+ })
1554
+ });
1555
+ const result = await response.json();
1556
+ if (result.error) {
1557
+ throw new MixrPayError(result.error.message || "MCP tool call failed");
1558
+ }
1559
+ const content = result.result?.content?.[0];
1560
+ const data = content?.text ? JSON.parse(content.text) : null;
1561
+ const mixrpay = result.result?._mixrpay || {};
1562
+ if (mixrpay.chargedUsd) {
1563
+ const payment = {
1564
+ amountUsd: mixrpay.chargedUsd,
1565
+ recipient: toolName.split("/")[0] || toolName,
1566
+ txHash: mixrpay.txHash,
1567
+ timestamp: /* @__PURE__ */ new Date(),
1568
+ description: `MCP: ${toolName}`,
1569
+ url: `${this.baseUrl}/api/mcp`
1570
+ };
1571
+ this.payments.push(payment);
1572
+ this.totalSpentUsd += mixrpay.chargedUsd;
1573
+ this.logger.payment(mixrpay.chargedUsd, toolName, "MCP call");
1574
+ if (this.onPayment) {
1575
+ this.onPayment(payment);
1576
+ }
1577
+ }
1578
+ return {
1579
+ data,
1580
+ chargedUsd: mixrpay.chargedUsd || 0,
1581
+ txHash: mixrpay.txHash,
1582
+ latencyMs: mixrpay.latencyMs
1583
+ };
1584
+ }
1585
+ // ===========================================================================
1586
+ // Agent Runtime API
1587
+ // ===========================================================================
1588
+ /**
1589
+ * Run an AI agent with LLM and tool execution.
1590
+ *
1591
+ * This method orchestrates a full agentic loop:
1592
+ * - Multi-turn reasoning with LLM
1593
+ * - Automatic tool execution
1594
+ * - Bundled billing (single charge at end)
1595
+ * - Optional streaming via SSE
1596
+ *
1597
+ * @param options - Agent run options
1598
+ * @returns Agent run result with response and cost breakdown
1599
+ *
1600
+ * @example Basic usage
1601
+ * ```typescript
1602
+ * const result = await wallet.runAgent({
1603
+ * sessionId: 'sess_abc123',
1604
+ * messages: [{ role: 'user', content: 'Find AI startups in SF' }],
1605
+ * });
1606
+ *
1607
+ * console.log(result.response);
1608
+ * console.log(`Cost: $${result.cost.totalUsd.toFixed(4)}`);
1609
+ * ```
1610
+ *
1611
+ * @example With custom config
1612
+ * ```typescript
1613
+ * const result = await wallet.runAgent({
1614
+ * sessionId: 'sess_abc123',
1615
+ * messages: [{ role: 'user', content: 'Research quantum computing' }],
1616
+ * config: {
1617
+ * model: 'gpt-4o',
1618
+ * maxIterations: 15,
1619
+ * tools: ['platform/exa-search', 'platform/firecrawl-scrape'],
1620
+ * systemPrompt: 'You are a research assistant.',
1621
+ * },
1622
+ * });
1623
+ * ```
1624
+ *
1625
+ * @example With streaming
1626
+ * ```typescript
1627
+ * await wallet.runAgent({
1628
+ * sessionId: 'sess_abc123',
1629
+ * messages: [{ role: 'user', content: 'Analyze this company' }],
1630
+ * stream: true,
1631
+ * onEvent: (event) => {
1632
+ * if (event.type === 'llm_chunk') {
1633
+ * process.stdout.write(event.delta);
1634
+ * } else if (event.type === 'tool_call') {
1635
+ * console.log(`Calling tool: ${event.tool}`);
1636
+ * }
1637
+ * },
1638
+ * });
1639
+ * ```
1640
+ */
1641
+ async runAgent(options) {
1642
+ const {
1643
+ sessionId,
1644
+ messages,
1645
+ config = {},
1646
+ stream = false,
1647
+ idempotencyKey,
1648
+ onEvent
1649
+ } = options;
1650
+ this.logger.debug("runAgent", { sessionId, messageCount: messages.length, config, stream });
1651
+ const body = {
1652
+ session_id: sessionId,
1653
+ messages: messages.map((m) => ({ role: m.role, content: m.content })),
1654
+ config: {
1655
+ model: config.model,
1656
+ max_iterations: config.maxIterations,
1657
+ tools: config.tools,
1658
+ system_prompt: config.systemPrompt
1659
+ },
1660
+ stream,
1661
+ idempotency_key: idempotencyKey
1662
+ };
1663
+ const AGENT_RUN_TIMEOUT = 18e4;
1664
+ if (!stream) {
1665
+ const response = await fetch(`${this.baseUrl}/api/v2/agent/run`, {
1666
+ method: "POST",
1667
+ headers: {
1668
+ "Content-Type": "application/json",
1669
+ "X-Mixr-Session": sessionId
1670
+ },
1671
+ body: JSON.stringify(body),
1672
+ signal: AbortSignal.timeout(AGENT_RUN_TIMEOUT)
1673
+ });
1674
+ if (!response.ok) {
1675
+ const error = await response.json().catch(() => ({}));
1676
+ throw new MixrPayError(error.error || `Agent run failed: ${response.status}`);
1677
+ }
1678
+ const data = await response.json();
1679
+ if (data.cost?.total_usd > 0) {
1680
+ const payment = {
1681
+ amountUsd: data.cost.total_usd,
1682
+ recipient: "mixrpay-agent-run",
1683
+ txHash: data.tx_hash,
1684
+ timestamp: /* @__PURE__ */ new Date(),
1685
+ description: `Agent run: ${data.run_id}`,
1686
+ url: `${this.baseUrl}/api/v2/agent/run`
1687
+ };
1688
+ this.payments.push(payment);
1689
+ this.totalSpentUsd += data.cost.total_usd;
1690
+ this.logger.payment(data.cost.total_usd, "agent-run", data.run_id);
1691
+ if (this.onPayment) {
1692
+ this.onPayment(payment);
1693
+ }
1694
+ }
1695
+ return {
1696
+ runId: data.run_id,
1697
+ status: data.status,
1698
+ response: data.response,
1699
+ iterations: data.iterations,
1700
+ toolsUsed: data.tools_used,
1701
+ cost: {
1702
+ llmUsd: data.cost.llm_usd,
1703
+ toolsUsd: data.cost.tools_usd,
1704
+ totalUsd: data.cost.total_usd
1705
+ },
1706
+ tokens: data.tokens,
1707
+ sessionRemainingUsd: data.session_remaining_usd,
1708
+ txHash: data.tx_hash
1709
+ };
1710
+ }
1711
+ return this.runAgentStreaming(sessionId, body, onEvent);
1712
+ }
1713
+ /**
1714
+ * Internal: Handle streaming agent run via SSE
1715
+ */
1716
+ async runAgentStreaming(sessionId, body, onEvent) {
1717
+ const STREAMING_TIMEOUT = 3e5;
1718
+ const response = await fetch(`${this.baseUrl}/api/v2/agent/run`, {
1719
+ method: "POST",
1720
+ headers: {
1721
+ "Content-Type": "application/json",
1722
+ "X-Mixr-Session": sessionId
1723
+ },
1724
+ body: JSON.stringify(body),
1725
+ signal: AbortSignal.timeout(STREAMING_TIMEOUT)
1726
+ });
1727
+ if (!response.ok) {
1728
+ const error = await response.json().catch(() => ({}));
1729
+ throw new MixrPayError(error.error || `Agent run failed: ${response.status}`);
1730
+ }
1731
+ const reader = response.body?.getReader();
1732
+ if (!reader) {
1733
+ throw new MixrPayError("No response body for streaming");
1734
+ }
1735
+ const decoder = new TextDecoder();
1736
+ let buffer = "";
1737
+ let result = null;
1738
+ while (true) {
1739
+ const { done, value } = await reader.read();
1740
+ if (done) break;
1741
+ buffer += decoder.decode(value, { stream: true });
1742
+ const lines = buffer.split("\n");
1743
+ buffer = lines.pop() || "";
1744
+ let currentEvent = "";
1745
+ for (const line of lines) {
1746
+ if (line.startsWith("event: ")) {
1747
+ currentEvent = line.slice(7).trim();
1748
+ } else if (line.startsWith("data: ") && currentEvent) {
1749
+ try {
1750
+ const data = JSON.parse(line.slice(6));
1751
+ const event = this.parseSSEEvent(currentEvent, data);
1752
+ if (event) {
1753
+ onEvent?.(event);
1754
+ if (currentEvent === "complete") {
1755
+ result = {
1756
+ runId: data.run_id,
1757
+ status: "completed",
1758
+ response: data.response,
1759
+ iterations: data.iterations,
1760
+ toolsUsed: data.tools_used,
1761
+ cost: {
1762
+ llmUsd: 0,
1763
+ // Not provided in streaming complete
1764
+ toolsUsd: 0,
1765
+ totalUsd: data.total_cost_usd
1766
+ },
1767
+ tokens: { prompt: 0, completion: 0 },
1768
+ sessionRemainingUsd: 0,
1769
+ txHash: data.tx_hash
1770
+ };
1771
+ if (data.total_cost_usd > 0) {
1772
+ const payment = {
1773
+ amountUsd: data.total_cost_usd,
1774
+ recipient: "mixrpay-agent-run",
1775
+ txHash: data.tx_hash,
1776
+ timestamp: /* @__PURE__ */ new Date(),
1777
+ description: `Agent run: ${data.run_id}`,
1778
+ url: `${this.baseUrl}/api/v2/agent/run`
1779
+ };
1780
+ this.payments.push(payment);
1781
+ this.totalSpentUsd += data.total_cost_usd;
1782
+ if (this.onPayment) {
1783
+ this.onPayment(payment);
1784
+ }
1785
+ }
1786
+ }
1787
+ if (currentEvent === "error") {
1788
+ throw new MixrPayError(data.error || "Agent run failed");
1789
+ }
1790
+ }
1791
+ } catch (e) {
1792
+ if (e instanceof MixrPayError) throw e;
1793
+ this.logger.warn("Failed to parse SSE event:", e);
1794
+ }
1795
+ currentEvent = "";
1796
+ }
1797
+ }
1798
+ }
1799
+ if (!result) {
1800
+ throw new MixrPayError("Agent run completed without final result");
1801
+ }
1802
+ return result;
1803
+ }
1804
+ /**
1805
+ * Internal: Parse SSE event into typed event object
1806
+ */
1807
+ parseSSEEvent(eventType, data) {
1808
+ switch (eventType) {
1809
+ case "run_start":
1810
+ return { type: "run_start", runId: data.run_id };
1811
+ case "iteration_start":
1812
+ return { type: "iteration_start", iteration: data.iteration };
1813
+ case "llm_chunk":
1814
+ return { type: "llm_chunk", delta: data.delta };
1815
+ case "tool_call":
1816
+ return { type: "tool_call", tool: data.tool, arguments: data.arguments };
1817
+ case "tool_result":
1818
+ return {
1819
+ type: "tool_result",
1820
+ tool: data.tool,
1821
+ success: data.success,
1822
+ costUsd: data.cost_usd,
1823
+ error: data.error
1824
+ };
1825
+ case "iteration_complete":
1826
+ return {
1827
+ type: "iteration_complete",
1828
+ iteration: data.iteration,
1829
+ tokens: data.tokens,
1830
+ costUsd: data.cost_usd
1831
+ };
1832
+ case "complete":
1833
+ return {
1834
+ type: "complete",
1835
+ runId: data.run_id,
1836
+ response: data.response,
1837
+ totalCostUsd: data.total_cost_usd,
1838
+ txHash: data.tx_hash,
1839
+ iterations: data.iterations,
1840
+ toolsUsed: data.tools_used
1841
+ };
1842
+ case "error":
1843
+ return {
1844
+ type: "error",
1845
+ error: data.error,
1846
+ partialCostUsd: data.partial_cost_usd
1847
+ };
1848
+ default:
1849
+ return null;
1850
+ }
1851
+ }
1852
+ /**
1853
+ * Get the status of an agent run by ID.
1854
+ *
1855
+ * @param runId - The agent run ID
1856
+ * @param sessionId - The session ID (for authentication)
1857
+ * @returns Agent run status and results
1858
+ *
1859
+ * @example
1860
+ * ```typescript
1861
+ * const status = await wallet.getAgentRunStatus('run_abc123', 'sess_xyz789');
1862
+ * console.log(`Status: ${status.status}`);
1863
+ * if (status.status === 'completed') {
1864
+ * console.log(status.response);
1865
+ * }
1866
+ * ```
1867
+ */
1868
+ async getAgentRunStatus(runId, sessionId) {
1869
+ this.logger.debug("getAgentRunStatus", { runId, sessionId });
1870
+ const response = await fetch(`${this.baseUrl}/api/v2/agent/run/${runId}`, {
1871
+ headers: {
1872
+ "X-Mixr-Session": sessionId
1873
+ }
1874
+ });
1875
+ if (!response.ok) {
1876
+ const error = await response.json().catch(() => ({}));
1877
+ throw new MixrPayError(error.error || `Failed to get run status: ${response.status}`);
1878
+ }
1879
+ const data = await response.json();
1880
+ return {
1881
+ runId: data.run_id,
1882
+ status: data.status,
1883
+ response: data.response,
1884
+ iterations: data.iterations,
1885
+ toolsUsed: data.tools_used,
1886
+ cost: {
1887
+ llmUsd: data.cost.llm_usd,
1888
+ toolsUsd: data.cost.tools_usd,
1889
+ totalUsd: data.cost.total_usd
1890
+ },
1891
+ tokens: data.tokens,
1892
+ txHash: data.tx_hash,
1893
+ error: data.error,
1894
+ startedAt: new Date(data.started_at),
1895
+ completedAt: data.completed_at ? new Date(data.completed_at) : void 0
1896
+ };
1897
+ }
1898
+ /**
1899
+ * Call an MCP tool using session authorization (pre-authorized spending limit).
1900
+ *
1901
+ * Use this when you've already created a session with the tool provider
1902
+ * and want to use that spending limit instead of direct wallet charges.
1903
+ *
1904
+ * @param sessionId - The session ID for the tool provider
1905
+ * @param toolName - The tool name in format "merchant/tool"
1906
+ * @param args - Arguments to pass to the tool
1907
+ * @returns Tool execution result
1908
+ *
1909
+ * @example
1910
+ * ```typescript
1911
+ * // Create session with provider first
1912
+ * const session = await wallet.getOrCreateSession({
1913
+ * merchantPublicKey: 'pk_live_firecrawl_...',
1914
+ * spendingLimitUsd: 50,
1915
+ * });
1916
+ *
1917
+ * // Use session for multiple calls
1918
+ * const result = await wallet.callMCPToolWithSession(
1919
+ * session.id,
1920
+ * 'firecrawl/scrape',
1921
+ * { url: 'https://example.com' }
1922
+ * );
1923
+ * ```
1924
+ */
1925
+ async callMCPToolWithSession(sessionId, toolName, args = {}) {
1926
+ this.logger.debug("callMCPToolWithSession", { sessionId, toolName, args });
1927
+ const response = await fetch(`${this.baseUrl}/api/mcp`, {
1928
+ method: "POST",
1929
+ headers: {
1930
+ "Content-Type": "application/json",
1931
+ "X-Mixr-Session": sessionId
1932
+ },
1933
+ body: JSON.stringify({
1934
+ jsonrpc: "2.0",
1935
+ method: "tools/call",
1936
+ params: { name: toolName, arguments: args },
1937
+ id: Date.now()
1938
+ })
1939
+ });
1940
+ const result = await response.json();
1941
+ if (result.error) {
1942
+ throw new MixrPayError(result.error.message || "MCP tool call failed");
1943
+ }
1944
+ const content = result.result?.content?.[0];
1945
+ const data = content?.text ? JSON.parse(content.text) : null;
1946
+ const mixrpay = result.result?._mixrpay || {};
1947
+ if (mixrpay.chargedUsd) {
1948
+ const payment = {
1949
+ amountUsd: mixrpay.chargedUsd,
1950
+ recipient: toolName.split("/")[0] || toolName,
1951
+ txHash: mixrpay.txHash,
1952
+ timestamp: /* @__PURE__ */ new Date(),
1953
+ description: `MCP: ${toolName}`,
1954
+ url: `${this.baseUrl}/api/mcp`
1955
+ };
1956
+ this.payments.push(payment);
1957
+ this.totalSpentUsd += mixrpay.chargedUsd;
1958
+ this.logger.payment(mixrpay.chargedUsd, toolName, "MCP call (session)");
1959
+ if (this.onPayment) {
1960
+ this.onPayment(payment);
1961
+ }
1962
+ }
1963
+ return {
1964
+ data,
1965
+ chargedUsd: mixrpay.chargedUsd || 0,
1966
+ txHash: mixrpay.txHash,
1967
+ latencyMs: mixrpay.latencyMs
1968
+ };
1969
+ }
1436
1970
  };
1437
1971
  export {
1438
1972
  AgentWallet,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mixrpay/agent-sdk",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "description": "MixrPay Agent SDK - Enable AI agents to make x402 payments with session keys",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -29,19 +29,7 @@
29
29
  "typecheck": "tsc --noEmit",
30
30
  "prepublishOnly": "npm run build"
31
31
  },
32
- "keywords": [
33
- "payments",
34
- "ai-agents",
35
- "x402",
36
- "cryptocurrency",
37
- "usdc",
38
- "blockchain",
39
- "web3",
40
- "vercel-ai-sdk",
41
- "langchain",
42
- "ai",
43
- "agent"
44
- ],
32
+ "keywords": [],
45
33
  "author": "MixrPay <support@mixrpay.com>",
46
34
  "license": "MIT",
47
35
  "repository": {