@alpha-arcade/mcp 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alpha Arcade
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,124 @@
1
+ # @alpha-arcade/mcp
2
+
3
+ MCP (Model Context Protocol) server for [Alpha Arcade](https://alphaarcade.com) prediction markets on Algorand.
4
+
5
+ Lets AI agents (Claude, Cursor, Copilot, etc.) browse markets, place orders, manage positions, and trade on-chain prediction markets.
6
+
7
+ ## Tools
8
+
9
+ | Tool | Description | Requires Wallet |
10
+ |------|-------------|:---:|
11
+ | `get_markets` | Fetch all live tradeable markets | No |
12
+ | `get_market` | Fetch a single market by ID | No |
13
+ | `get_orderbook` | Get the full on-chain orderbook for a market | No |
14
+ | `get_open_orders` | Get open orders for a wallet on a market | No |
15
+ | `get_positions` | Get YES/NO token positions for a wallet | No |
16
+ | `create_limit_order` | Place a limit order on a market | Yes |
17
+ | `create_market_order` | Place a market order with auto-matching | Yes |
18
+ | `cancel_order` | Cancel an open order | Yes |
19
+ | `propose_match` | Match two existing orders | Yes |
20
+ | `split_shares` | Split USDC into YES + NO tokens | Yes |
21
+ | `merge_shares` | Merge YES + NO tokens back into USDC | Yes |
22
+ | `claim` | Redeem outcome tokens from a resolved market | Yes |
23
+
24
+ ## Setup
25
+
26
+ ### Environment Variables
27
+
28
+ | Variable | Required | Description |
29
+ |----------|:--------:|-------------|
30
+ | `ALPHA_MNEMONIC` | For trading | 25-word Algorand mnemonic |
31
+ | `ALPHA_API_KEY` | No | Alpha partners API key. If set, markets are fetched via API (richer data). If omitted, markets are discovered on-chain. |
32
+ | `ALPHA_ALGOD_SERVER` | No | Algod URL (default: mainnet Algonode) |
33
+ | `ALPHA_INDEXER_SERVER` | No | Indexer URL (default: mainnet Algonode) |
34
+ | `ALPHA_MATCHER_APP_ID` | No | Matcher app ID (default: 3078581851) |
35
+ | `ALPHA_USDC_ASSET_ID` | No | USDC ASA ID (default: 31566704) |
36
+
37
+ ### Cursor (read-only, zero config)
38
+
39
+ Add to your `.cursor/mcp.json` (project-level) or `~/.cursor/mcp.json` (global):
40
+
41
+ ```json
42
+ {
43
+ "mcpServers": {
44
+ "alpha-arcade": {
45
+ "command": "npx",
46
+ "args": ["-y", "@alpha-arcade/mcp"]
47
+ }
48
+ }
49
+ }
50
+ ```
51
+
52
+ That's it -- no API key needed. Your AI can browse markets, view orderbooks, and check positions.
53
+
54
+ ### Cursor (with trading)
55
+
56
+ To enable trading, add your mnemonic:
57
+
58
+ ```json
59
+ {
60
+ "mcpServers": {
61
+ "alpha-arcade": {
62
+ "command": "npx",
63
+ "args": ["-y", "@alpha-arcade/mcp"],
64
+ "env": {
65
+ "ALPHA_MNEMONIC": "your twenty five word mnemonic here"
66
+ }
67
+ }
68
+ }
69
+ }
70
+ ```
71
+
72
+ ### Claude Desktop
73
+
74
+ Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
75
+
76
+ ```json
77
+ {
78
+ "mcpServers": {
79
+ "alpha-arcade": {
80
+ "command": "npx",
81
+ "args": ["-y", "@alpha-arcade/mcp"],
82
+ "env": {
83
+ "ALPHA_MNEMONIC": "your twenty five word mnemonic here"
84
+ }
85
+ }
86
+ }
87
+ }
88
+ ```
89
+
90
+ ### VS Code / Copilot
91
+
92
+ Add to `.vscode/mcp.json`:
93
+
94
+ ```json
95
+ {
96
+ "servers": {
97
+ "alpha-arcade": {
98
+ "command": "npx",
99
+ "args": ["-y", "@alpha-arcade/mcp"],
100
+ "env": {
101
+ "ALPHA_MNEMONIC": "your twenty five word mnemonic here"
102
+ }
103
+ }
104
+ }
105
+ }
106
+ ```
107
+
108
+ ## Zero Config Mode
109
+
110
+ With no environment variables at all, the server works in **read-only mode**. Markets are discovered directly from the Algorand blockchain -- no API key needed. You can browse markets, view orderbooks, and check positions. Trading tools will return an error explaining that a mnemonic is required.
111
+
112
+ ## Price and Quantity Units
113
+
114
+ All prices and quantities use **microunits** (1,000,000 = $1.00 or 1 share):
115
+
116
+ - Price `500000` = $0.50
117
+ - Quantity `1000000` = 1 share
118
+ - Slippage `50000` = $0.05
119
+
120
+ ## Links
121
+
122
+ - SDK: [npmjs.com/package/@alpha-arcade/sdk](https://www.npmjs.com/package/@alpha-arcade/sdk)
123
+ - GitHub: [github.com/phara23/alpha-mcp](https://github.com/phara23/alpha-mcp)
124
+ - Alpha Arcade: [alphaarcade.com](https://alphaarcade.com)
package/dist/index.js ADDED
@@ -0,0 +1,336 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
6
+ import { AlphaClient } from "@alpha-arcade/sdk";
7
+ import algosdk from "algosdk";
8
+ import { z } from "zod";
9
+ var MNEMONIC = process.env.ALPHA_MNEMONIC;
10
+ var API_KEY = process.env.ALPHA_API_KEY;
11
+ var ALGOD_SERVER = process.env.ALPHA_ALGOD_SERVER || "https://mainnet-api.algonode.cloud";
12
+ var ALGOD_TOKEN = process.env.ALPHA_ALGOD_TOKEN || "";
13
+ var ALGOD_PORT = process.env.ALPHA_ALGOD_PORT || "443";
14
+ var INDEXER_SERVER = process.env.ALPHA_INDEXER_SERVER || "https://mainnet-idx.algonode.cloud";
15
+ var INDEXER_TOKEN = process.env.ALPHA_INDEXER_TOKEN || "";
16
+ var INDEXER_PORT = process.env.ALPHA_INDEXER_PORT || "443";
17
+ var MATCHER_APP_ID = Number(process.env.ALPHA_MATCHER_APP_ID || "3078581851");
18
+ var USDC_ASSET_ID = Number(process.env.ALPHA_USDC_ASSET_ID || "31566704");
19
+ var API_BASE_URL = process.env.ALPHA_API_BASE_URL || "https://partners.alphaarcade.com/api";
20
+ var createTradingClient = () => {
21
+ if (!MNEMONIC) return null;
22
+ const algodClient = new algosdk.Algodv2(ALGOD_TOKEN, ALGOD_SERVER, ALGOD_PORT);
23
+ const indexerClient = new algosdk.Indexer(INDEXER_TOKEN, INDEXER_SERVER, INDEXER_PORT);
24
+ const account = algosdk.mnemonicToSecretKey(MNEMONIC);
25
+ const signer = algosdk.makeBasicAccountTransactionSigner(account);
26
+ return new AlphaClient({
27
+ algodClient,
28
+ indexerClient,
29
+ signer,
30
+ activeAddress: account.addr,
31
+ matcherAppId: MATCHER_APP_ID,
32
+ usdcAssetId: USDC_ASSET_ID,
33
+ apiBaseUrl: API_BASE_URL,
34
+ apiKey: API_KEY || void 0
35
+ });
36
+ };
37
+ var createReadOnlyClient = () => {
38
+ const algodClient = new algosdk.Algodv2(ALGOD_TOKEN, ALGOD_SERVER, ALGOD_PORT);
39
+ const indexerClient = new algosdk.Indexer(INDEXER_TOKEN, INDEXER_SERVER, INDEXER_PORT);
40
+ const dummySigner = async () => [];
41
+ return new AlphaClient({
42
+ algodClient,
43
+ indexerClient,
44
+ signer: dummySigner,
45
+ activeAddress: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ",
46
+ matcherAppId: MATCHER_APP_ID,
47
+ usdcAssetId: USDC_ASSET_ID,
48
+ apiBaseUrl: API_BASE_URL,
49
+ apiKey: API_KEY || void 0
50
+ });
51
+ };
52
+ var requireTradingClient = () => {
53
+ const client = createTradingClient();
54
+ if (!client) {
55
+ throw new Error(
56
+ "ALPHA_MNEMONIC environment variable is required for trading operations. Set it in your MCP server configuration."
57
+ );
58
+ }
59
+ return client;
60
+ };
61
+ var getReadOnlyClient = () => {
62
+ return createTradingClient() ?? createReadOnlyClient();
63
+ };
64
+ var formatPrice = (microunits) => `$${(microunits / 1e6).toFixed(2)}`;
65
+ var formatQty = (microunits) => `${(microunits / 1e6).toFixed(2)} shares`;
66
+ var textResult = (text) => ({
67
+ content: [{ type: "text", text }]
68
+ });
69
+ var server = new McpServer({
70
+ name: "alpha-arcade",
71
+ version: "0.1.0"
72
+ });
73
+ server.tool(
74
+ "get_markets",
75
+ {
76
+ description: "Fetch all live, tradeable prediction markets from Alpha Arcade. Returns market titles, prices, volume, and app IDs."
77
+ },
78
+ async () => {
79
+ const client = getReadOnlyClient();
80
+ const markets = await client.getMarkets();
81
+ const summary = markets.map((m) => ({
82
+ id: m.id,
83
+ title: m.title,
84
+ marketAppId: m.marketAppId,
85
+ yesPrice: formatPrice(m.yesProb),
86
+ noPrice: formatPrice(m.noProb),
87
+ volume: formatPrice(m.volume),
88
+ endsAt: new Date(m.endTs * 1e3).toISOString(),
89
+ isResolved: m.isResolved ?? false,
90
+ categories: m.categories ?? []
91
+ }));
92
+ return textResult(JSON.stringify(summary, null, 2));
93
+ }
94
+ );
95
+ server.tool(
96
+ "get_market",
97
+ {
98
+ description: "Fetch a single market by its ID. Returns full market details including options for multi-choice markets.",
99
+ marketId: z.string().describe("The market ID")
100
+ },
101
+ async ({ marketId }) => {
102
+ const client = getReadOnlyClient();
103
+ const market = await client.getMarket(marketId);
104
+ if (!market) return textResult(`Market "${marketId}" not found.`);
105
+ return textResult(JSON.stringify(market, null, 2));
106
+ }
107
+ );
108
+ server.tool(
109
+ "get_orderbook",
110
+ {
111
+ description: "Fetch the full on-chain orderbook for a market. Shows all YES and NO bids and asks with prices, quantities, and escrow app IDs.",
112
+ marketAppId: z.number().describe("The market app ID (number)")
113
+ },
114
+ async ({ marketAppId }) => {
115
+ const client = getReadOnlyClient();
116
+ const book = await client.getOrderbook(marketAppId);
117
+ const formatSide = (entries) => entries.map((e) => ({
118
+ price: formatPrice(e.price),
119
+ quantity: formatQty(e.quantity),
120
+ escrowAppId: e.escrowAppId,
121
+ owner: e.owner
122
+ }));
123
+ const result = {
124
+ yes: { bids: formatSide(book.yes.bids), asks: formatSide(book.yes.asks) },
125
+ no: { bids: formatSide(book.no.bids), asks: formatSide(book.no.asks) },
126
+ totalOrders: book.yes.bids.length + book.yes.asks.length + book.no.bids.length + book.no.asks.length
127
+ };
128
+ return textResult(JSON.stringify(result, null, 2));
129
+ }
130
+ );
131
+ server.tool(
132
+ "get_open_orders",
133
+ {
134
+ description: "Fetch all open orders for a wallet on a specific market. Defaults to the configured wallet if no address is provided.",
135
+ marketAppId: z.number().describe("The market app ID"),
136
+ walletAddress: z.string().optional().describe("Algorand wallet address (defaults to configured wallet)")
137
+ },
138
+ async ({ marketAppId, walletAddress }) => {
139
+ const client = getReadOnlyClient();
140
+ const orders = await client.getOpenOrders(marketAppId, walletAddress);
141
+ const formatted = orders.map((o) => ({
142
+ escrowAppId: o.escrowAppId,
143
+ position: o.position === 1 ? "YES" : "NO",
144
+ side: o.side === 1 ? "BUY" : "SELL",
145
+ price: formatPrice(o.price),
146
+ quantity: formatQty(o.quantity),
147
+ filled: formatQty(o.quantityFilled),
148
+ remaining: formatQty(o.quantity - o.quantityFilled)
149
+ }));
150
+ return textResult(
151
+ formatted.length > 0 ? JSON.stringify(formatted, null, 2) : "No open orders found for this wallet on this market."
152
+ );
153
+ }
154
+ );
155
+ server.tool(
156
+ "get_positions",
157
+ {
158
+ description: "Fetch all YES/NO token positions for a wallet across all markets. Defaults to the configured wallet.",
159
+ walletAddress: z.string().optional().describe("Algorand wallet address (defaults to configured wallet)")
160
+ },
161
+ async ({ walletAddress }) => {
162
+ const client = getReadOnlyClient();
163
+ const positions = await client.getPositions(walletAddress);
164
+ const formatted = positions.map((p) => ({
165
+ marketAppId: p.marketAppId,
166
+ yesBalance: formatQty(p.yesBalance),
167
+ noBalance: formatQty(p.noBalance)
168
+ }));
169
+ return textResult(
170
+ formatted.length > 0 ? JSON.stringify(formatted, null, 2) : "No positions found for this wallet."
171
+ );
172
+ }
173
+ );
174
+ server.tool(
175
+ "create_limit_order",
176
+ {
177
+ description: "Place a limit order on a prediction market. The order sits on the orderbook at your exact price until matched or cancelled. Price is in microunits (500000 = $0.50). Quantity is in microunits (1000000 = 1 share).",
178
+ marketAppId: z.number().describe("The market app ID"),
179
+ position: z.union([z.literal(0), z.literal(1)]).describe("1 = Yes, 0 = No"),
180
+ price: z.number().describe("Price in microunits (e.g. 500000 = $0.50)"),
181
+ quantity: z.number().describe("Quantity in microunits (e.g. 1000000 = 1 share)"),
182
+ isBuying: z.boolean().describe("true = buy order, false = sell order")
183
+ },
184
+ async ({ marketAppId, position, price, quantity, isBuying }) => {
185
+ const client = requireTradingClient();
186
+ const result = await client.createLimitOrder({
187
+ marketAppId,
188
+ position,
189
+ price,
190
+ quantity,
191
+ isBuying
192
+ });
193
+ return textResult(
194
+ `Limit order created.
195
+ Escrow App ID: ${result.escrowAppId}
196
+ Position: ${position === 1 ? "YES" : "NO"}
197
+ Side: ${isBuying ? "BUY" : "SELL"}
198
+ Price: ${formatPrice(price)}
199
+ Quantity: ${formatQty(quantity)}
200
+ Tx IDs: ${result.txIds.join(", ")}
201
+ Confirmed round: ${result.confirmedRound}`
202
+ );
203
+ }
204
+ );
205
+ server.tool(
206
+ "create_market_order",
207
+ {
208
+ description: "Place a market order that automatically matches against existing orders on the orderbook. Fetches the best counterparty orders within your slippage tolerance and matches atomically. Price is in microunits (500000 = $0.50). Slippage is in microunits (50000 = $0.05).",
209
+ marketAppId: z.number().describe("The market app ID"),
210
+ position: z.union([z.literal(0), z.literal(1)]).describe("1 = Yes, 0 = No"),
211
+ price: z.number().describe("Price in microunits (e.g. 500000 = $0.50)"),
212
+ quantity: z.number().describe("Quantity in microunits (e.g. 1000000 = 1 share)"),
213
+ isBuying: z.boolean().describe("true = buy order, false = sell order"),
214
+ slippage: z.number().describe("Slippage tolerance in microunits (e.g. 50000 = $0.05)")
215
+ },
216
+ async ({ marketAppId, position, price, quantity, isBuying, slippage }) => {
217
+ const client = requireTradingClient();
218
+ const result = await client.createMarketOrder({
219
+ marketAppId,
220
+ position,
221
+ price,
222
+ quantity,
223
+ isBuying,
224
+ slippage
225
+ });
226
+ return textResult(
227
+ `Market order created and matched.
228
+ Escrow App ID: ${result.escrowAppId}
229
+ Position: ${position === 1 ? "YES" : "NO"}
230
+ Side: ${isBuying ? "BUY" : "SELL"}
231
+ Price: ${formatPrice(price)}
232
+ Quantity: ${formatQty(quantity)}
233
+ Matched: ${formatQty(result.matchedQuantity)}
234
+ Tx IDs: ${result.txIds.join(", ")}
235
+ Confirmed round: ${result.confirmedRound}`
236
+ );
237
+ }
238
+ );
239
+ server.tool(
240
+ "cancel_order",
241
+ {
242
+ description: "Cancel an open order by its escrow app ID. Returns escrowed funds to the order owner and reclaims ALGO minimum balance.",
243
+ marketAppId: z.number().describe("The market app ID"),
244
+ escrowAppId: z.number().describe("The escrow app ID of the order to cancel"),
245
+ orderOwner: z.string().describe("The Algorand address that owns the order")
246
+ },
247
+ async ({ marketAppId, escrowAppId, orderOwner }) => {
248
+ const client = requireTradingClient();
249
+ const result = await client.cancelOrder({ marketAppId, escrowAppId, orderOwner });
250
+ return textResult(
251
+ result.success ? `Order cancelled successfully.
252
+ Escrow App ID: ${escrowAppId}
253
+ Tx IDs: ${result.txIds.join(", ")}` : `Failed to cancel order ${escrowAppId}.`
254
+ );
255
+ }
256
+ );
257
+ server.tool(
258
+ "propose_match",
259
+ {
260
+ description: "Propose a match between an existing maker order and the configured wallet as taker. Use this for advanced matching when you want to explicitly specify which order to match against.",
261
+ marketAppId: z.number().describe("The market app ID"),
262
+ makerEscrowAppId: z.number().describe("The escrow app ID of the maker order"),
263
+ makerAddress: z.string().describe("The Algorand address of the maker"),
264
+ quantityMatched: z.number().describe("Quantity to match in microunits")
265
+ },
266
+ async ({ marketAppId, makerEscrowAppId, makerAddress, quantityMatched }) => {
267
+ const client = requireTradingClient();
268
+ const result = await client.proposeMatch({
269
+ marketAppId,
270
+ makerEscrowAppId,
271
+ makerAddress,
272
+ quantityMatched
273
+ });
274
+ return textResult(
275
+ result.success ? `Match proposed successfully.
276
+ Maker escrow: ${makerEscrowAppId}
277
+ Quantity: ${formatQty(quantityMatched)}
278
+ Tx IDs: ${result.txIds.join(", ")}` : `Failed to propose match with escrow ${makerEscrowAppId}.`
279
+ );
280
+ }
281
+ );
282
+ server.tool(
283
+ "split_shares",
284
+ {
285
+ description: "Split USDC into equal amounts of YES and NO outcome tokens for a market. For example, splitting 1 USDC (1000000 microunits) gives you 1 YES + 1 NO token. Together they are always worth $1.00.",
286
+ marketAppId: z.number().describe("The market app ID"),
287
+ amount: z.number().describe("Amount to split in microunits (e.g. 1000000 = $1.00 USDC)")
288
+ },
289
+ async ({ marketAppId, amount }) => {
290
+ const client = requireTradingClient();
291
+ const result = await client.splitShares({ marketAppId, amount });
292
+ return textResult(
293
+ `Split ${formatPrice(amount)} USDC into YES + NO tokens.
294
+ Tx IDs: ${result.txIds.join(", ")}
295
+ Confirmed round: ${result.confirmedRound}`
296
+ );
297
+ }
298
+ );
299
+ server.tool(
300
+ "merge_shares",
301
+ {
302
+ description: "Merge equal amounts of YES and NO outcome tokens back into USDC. The inverse of split: 1 YES + 1 NO = 1 USDC, always.",
303
+ marketAppId: z.number().describe("The market app ID"),
304
+ amount: z.number().describe("Amount to merge in microunits")
305
+ },
306
+ async ({ marketAppId, amount }) => {
307
+ const client = requireTradingClient();
308
+ const result = await client.mergeShares({ marketAppId, amount });
309
+ return textResult(
310
+ `Merged YES + NO tokens back into ${formatPrice(amount)} USDC.
311
+ Tx IDs: ${result.txIds.join(", ")}
312
+ Confirmed round: ${result.confirmedRound}`
313
+ );
314
+ }
315
+ );
316
+ server.tool(
317
+ "claim",
318
+ {
319
+ description: "Claim USDC from a resolved market by redeeming outcome tokens. Winning tokens are redeemed 1:1 for USDC. Losing tokens are burned.",
320
+ marketAppId: z.number().describe("The market app ID"),
321
+ assetId: z.number().describe("The outcome token ASA ID to redeem"),
322
+ amount: z.number().optional().describe("Amount to claim in microunits (omit to claim entire balance)")
323
+ },
324
+ async ({ marketAppId, assetId, amount }) => {
325
+ const client = requireTradingClient();
326
+ const result = await client.claim({ marketAppId, assetId, amount });
327
+ return textResult(
328
+ `Claim successful.
329
+ Tx IDs: ${result.txIds.join(", ")}
330
+ Confirmed round: ${result.confirmedRound}`
331
+ );
332
+ }
333
+ );
334
+ var transport = new StdioServerTransport();
335
+ await server.connect(transport);
336
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { AlphaClient } from '@alpha-arcade/sdk';\nimport algosdk from 'algosdk';\nimport { z } from 'zod';\n\n// ============================================\n// Configuration from environment variables\n// ============================================\n\nconst MNEMONIC = process.env.ALPHA_MNEMONIC;\nconst API_KEY = process.env.ALPHA_API_KEY;\nconst ALGOD_SERVER = process.env.ALPHA_ALGOD_SERVER || 'https://mainnet-api.algonode.cloud';\nconst ALGOD_TOKEN = process.env.ALPHA_ALGOD_TOKEN || '';\nconst ALGOD_PORT = process.env.ALPHA_ALGOD_PORT || '443';\nconst INDEXER_SERVER = process.env.ALPHA_INDEXER_SERVER || 'https://mainnet-idx.algonode.cloud';\nconst INDEXER_TOKEN = process.env.ALPHA_INDEXER_TOKEN || '';\nconst INDEXER_PORT = process.env.ALPHA_INDEXER_PORT || '443';\nconst MATCHER_APP_ID = Number(process.env.ALPHA_MATCHER_APP_ID || '3078581851');\nconst USDC_ASSET_ID = Number(process.env.ALPHA_USDC_ASSET_ID || '31566704');\nconst API_BASE_URL = process.env.ALPHA_API_BASE_URL || 'https://partners.alphaarcade.com/api';\n\n// ============================================\n// Build the Alpha client\n// ============================================\n\n/** Creates a full trading client (requires mnemonic) */\nconst createTradingClient = (): AlphaClient | null => {\n if (!MNEMONIC) return null;\n\n const algodClient = new algosdk.Algodv2(ALGOD_TOKEN, ALGOD_SERVER, ALGOD_PORT);\n const indexerClient = new algosdk.Indexer(INDEXER_TOKEN, INDEXER_SERVER, INDEXER_PORT);\n const account = algosdk.mnemonicToSecretKey(MNEMONIC);\n const signer = algosdk.makeBasicAccountTransactionSigner(account);\n\n return new AlphaClient({\n algodClient,\n indexerClient,\n signer,\n activeAddress: account.addr,\n matcherAppId: MATCHER_APP_ID,\n usdcAssetId: USDC_ASSET_ID,\n apiBaseUrl: API_BASE_URL,\n apiKey: API_KEY || undefined,\n });\n};\n\n/** Creates a read-only client (no mnemonic needed, works with zero config) */\nconst createReadOnlyClient = (): AlphaClient => {\n const algodClient = new algosdk.Algodv2(ALGOD_TOKEN, ALGOD_SERVER, ALGOD_PORT);\n const indexerClient = new algosdk.Indexer(INDEXER_TOKEN, INDEXER_SERVER, INDEXER_PORT);\n const dummySigner: algosdk.TransactionSigner = async () => [];\n\n return new AlphaClient({\n algodClient,\n indexerClient,\n signer: dummySigner,\n activeAddress: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ',\n matcherAppId: MATCHER_APP_ID,\n usdcAssetId: USDC_ASSET_ID,\n apiBaseUrl: API_BASE_URL,\n apiKey: API_KEY || undefined,\n });\n};\n\nconst requireTradingClient = (): AlphaClient => {\n const client = createTradingClient();\n if (!client) {\n throw new Error(\n 'ALPHA_MNEMONIC environment variable is required for trading operations. ' +\n 'Set it in your MCP server configuration.'\n );\n }\n return client;\n};\n\nconst getReadOnlyClient = (): AlphaClient => {\n return createTradingClient() ?? createReadOnlyClient();\n};\n\n// ============================================\n// Helpers\n// ============================================\n\nconst formatPrice = (microunits: number): string => `$${(microunits / 1_000_000).toFixed(2)}`;\nconst formatQty = (microunits: number): string => `${(microunits / 1_000_000).toFixed(2)} shares`;\n\nconst textResult = (text: string) => ({\n content: [{ type: 'text' as const, text }],\n});\n\n// ============================================\n// MCP Server\n// ============================================\n\nconst server = new McpServer({\n name: 'alpha-arcade',\n version: '0.1.0',\n});\n\n// ------------------------------------------\n// Read-only tools (only need API key)\n// ------------------------------------------\n\nserver.tool(\n 'get_markets',\n {\n description: 'Fetch all live, tradeable prediction markets from Alpha Arcade. Returns market titles, prices, volume, and app IDs.',\n },\n async () => {\n const client = getReadOnlyClient();\n const markets = await client.getMarkets();\n const summary = markets.map((m) => ({\n id: m.id,\n title: m.title,\n marketAppId: m.marketAppId,\n yesPrice: formatPrice(m.yesProb),\n noPrice: formatPrice(m.noProb),\n volume: formatPrice(m.volume),\n endsAt: new Date(m.endTs * 1000).toISOString(),\n isResolved: m.isResolved ?? false,\n categories: m.categories ?? [],\n }));\n return textResult(JSON.stringify(summary, null, 2));\n },\n);\n\nserver.tool(\n 'get_market',\n {\n description: 'Fetch a single market by its ID. Returns full market details including options for multi-choice markets.',\n marketId: z.string().describe('The market ID'),\n },\n async ({ marketId }) => {\n const client = getReadOnlyClient();\n const market = await client.getMarket(marketId);\n if (!market) return textResult(`Market \"${marketId}\" not found.`);\n return textResult(JSON.stringify(market, null, 2));\n },\n);\n\nserver.tool(\n 'get_orderbook',\n {\n description: 'Fetch the full on-chain orderbook for a market. Shows all YES and NO bids and asks with prices, quantities, and escrow app IDs.',\n marketAppId: z.number().describe('The market app ID (number)'),\n },\n async ({ marketAppId }) => {\n const client = getReadOnlyClient();\n const book = await client.getOrderbook(marketAppId);\n\n const formatSide = (entries: Array<{ price: number; quantity: number; escrowAppId: number; owner: string }>) =>\n entries.map((e) => ({\n price: formatPrice(e.price),\n quantity: formatQty(e.quantity),\n escrowAppId: e.escrowAppId,\n owner: e.owner,\n }));\n\n const result = {\n yes: { bids: formatSide(book.yes.bids), asks: formatSide(book.yes.asks) },\n no: { bids: formatSide(book.no.bids), asks: formatSide(book.no.asks) },\n totalOrders:\n book.yes.bids.length + book.yes.asks.length + book.no.bids.length + book.no.asks.length,\n };\n return textResult(JSON.stringify(result, null, 2));\n },\n);\n\nserver.tool(\n 'get_open_orders',\n {\n description: 'Fetch all open orders for a wallet on a specific market. Defaults to the configured wallet if no address is provided.',\n marketAppId: z.number().describe('The market app ID'),\n walletAddress: z.string().optional().describe('Algorand wallet address (defaults to configured wallet)'),\n },\n async ({ marketAppId, walletAddress }) => {\n const client = getReadOnlyClient();\n const orders = await client.getOpenOrders(marketAppId, walletAddress);\n const formatted = orders.map((o) => ({\n escrowAppId: o.escrowAppId,\n position: o.position === 1 ? 'YES' : 'NO',\n side: o.side === 1 ? 'BUY' : 'SELL',\n price: formatPrice(o.price),\n quantity: formatQty(o.quantity),\n filled: formatQty(o.quantityFilled),\n remaining: formatQty(o.quantity - o.quantityFilled),\n }));\n return textResult(\n formatted.length > 0\n ? JSON.stringify(formatted, null, 2)\n : 'No open orders found for this wallet on this market.',\n );\n },\n);\n\nserver.tool(\n 'get_positions',\n {\n description: 'Fetch all YES/NO token positions for a wallet across all markets. Defaults to the configured wallet.',\n walletAddress: z.string().optional().describe('Algorand wallet address (defaults to configured wallet)'),\n },\n async ({ walletAddress }) => {\n const client = getReadOnlyClient();\n const positions = await client.getPositions(walletAddress);\n const formatted = positions.map((p) => ({\n marketAppId: p.marketAppId,\n yesBalance: formatQty(p.yesBalance),\n noBalance: formatQty(p.noBalance),\n }));\n return textResult(\n formatted.length > 0\n ? JSON.stringify(formatted, null, 2)\n : 'No positions found for this wallet.',\n );\n },\n);\n\n// ------------------------------------------\n// Write tools (require mnemonic + API key)\n// ------------------------------------------\n\nserver.tool(\n 'create_limit_order',\n {\n description:\n 'Place a limit order on a prediction market. The order sits on the orderbook at your exact price until matched or cancelled. ' +\n 'Price is in microunits (500000 = $0.50). Quantity is in microunits (1000000 = 1 share).',\n marketAppId: z.number().describe('The market app ID'),\n position: z.union([z.literal(0), z.literal(1)]).describe('1 = Yes, 0 = No'),\n price: z.number().describe('Price in microunits (e.g. 500000 = $0.50)'),\n quantity: z.number().describe('Quantity in microunits (e.g. 1000000 = 1 share)'),\n isBuying: z.boolean().describe('true = buy order, false = sell order'),\n },\n async ({ marketAppId, position, price, quantity, isBuying }) => {\n const client = requireTradingClient();\n const result = await client.createLimitOrder({\n marketAppId,\n position: position as 0 | 1,\n price,\n quantity,\n isBuying,\n });\n return textResult(\n `Limit order created.\\n` +\n ` Escrow App ID: ${result.escrowAppId}\\n` +\n ` Position: ${position === 1 ? 'YES' : 'NO'}\\n` +\n ` Side: ${isBuying ? 'BUY' : 'SELL'}\\n` +\n ` Price: ${formatPrice(price)}\\n` +\n ` Quantity: ${formatQty(quantity)}\\n` +\n ` Tx IDs: ${result.txIds.join(', ')}\\n` +\n ` Confirmed round: ${result.confirmedRound}`,\n );\n },\n);\n\nserver.tool(\n 'create_market_order',\n {\n description:\n 'Place a market order that automatically matches against existing orders on the orderbook. ' +\n 'Fetches the best counterparty orders within your slippage tolerance and matches atomically. ' +\n 'Price is in microunits (500000 = $0.50). Slippage is in microunits (50000 = $0.05).',\n marketAppId: z.number().describe('The market app ID'),\n position: z.union([z.literal(0), z.literal(1)]).describe('1 = Yes, 0 = No'),\n price: z.number().describe('Price in microunits (e.g. 500000 = $0.50)'),\n quantity: z.number().describe('Quantity in microunits (e.g. 1000000 = 1 share)'),\n isBuying: z.boolean().describe('true = buy order, false = sell order'),\n slippage: z.number().describe('Slippage tolerance in microunits (e.g. 50000 = $0.05)'),\n },\n async ({ marketAppId, position, price, quantity, isBuying, slippage }) => {\n const client = requireTradingClient();\n const result = await client.createMarketOrder({\n marketAppId,\n position: position as 0 | 1,\n price,\n quantity,\n isBuying,\n slippage,\n });\n return textResult(\n `Market order created and matched.\\n` +\n ` Escrow App ID: ${result.escrowAppId}\\n` +\n ` Position: ${position === 1 ? 'YES' : 'NO'}\\n` +\n ` Side: ${isBuying ? 'BUY' : 'SELL'}\\n` +\n ` Price: ${formatPrice(price)}\\n` +\n ` Quantity: ${formatQty(quantity)}\\n` +\n ` Matched: ${formatQty(result.matchedQuantity)}\\n` +\n ` Tx IDs: ${result.txIds.join(', ')}\\n` +\n ` Confirmed round: ${result.confirmedRound}`,\n );\n },\n);\n\nserver.tool(\n 'cancel_order',\n {\n description:\n 'Cancel an open order by its escrow app ID. Returns escrowed funds to the order owner and reclaims ALGO minimum balance.',\n marketAppId: z.number().describe('The market app ID'),\n escrowAppId: z.number().describe('The escrow app ID of the order to cancel'),\n orderOwner: z.string().describe('The Algorand address that owns the order'),\n },\n async ({ marketAppId, escrowAppId, orderOwner }) => {\n const client = requireTradingClient();\n const result = await client.cancelOrder({ marketAppId, escrowAppId, orderOwner });\n return textResult(\n result.success\n ? `Order cancelled successfully.\\n Escrow App ID: ${escrowAppId}\\n Tx IDs: ${result.txIds.join(', ')}`\n : `Failed to cancel order ${escrowAppId}.`,\n );\n },\n);\n\nserver.tool(\n 'propose_match',\n {\n description:\n 'Propose a match between an existing maker order and the configured wallet as taker. ' +\n 'Use this for advanced matching when you want to explicitly specify which order to match against.',\n marketAppId: z.number().describe('The market app ID'),\n makerEscrowAppId: z.number().describe('The escrow app ID of the maker order'),\n makerAddress: z.string().describe('The Algorand address of the maker'),\n quantityMatched: z.number().describe('Quantity to match in microunits'),\n },\n async ({ marketAppId, makerEscrowAppId, makerAddress, quantityMatched }) => {\n const client = requireTradingClient();\n const result = await client.proposeMatch({\n marketAppId,\n makerEscrowAppId,\n makerAddress,\n quantityMatched,\n });\n return textResult(\n result.success\n ? `Match proposed successfully.\\n Maker escrow: ${makerEscrowAppId}\\n Quantity: ${formatQty(quantityMatched)}\\n Tx IDs: ${result.txIds.join(', ')}`\n : `Failed to propose match with escrow ${makerEscrowAppId}.`,\n );\n },\n);\n\nserver.tool(\n 'split_shares',\n {\n description:\n 'Split USDC into equal amounts of YES and NO outcome tokens for a market. ' +\n 'For example, splitting 1 USDC (1000000 microunits) gives you 1 YES + 1 NO token. ' +\n 'Together they are always worth $1.00.',\n marketAppId: z.number().describe('The market app ID'),\n amount: z.number().describe('Amount to split in microunits (e.g. 1000000 = $1.00 USDC)'),\n },\n async ({ marketAppId, amount }) => {\n const client = requireTradingClient();\n const result = await client.splitShares({ marketAppId, amount });\n return textResult(\n `Split ${formatPrice(amount)} USDC into YES + NO tokens.\\n` +\n ` Tx IDs: ${result.txIds.join(', ')}\\n` +\n ` Confirmed round: ${result.confirmedRound}`,\n );\n },\n);\n\nserver.tool(\n 'merge_shares',\n {\n description:\n 'Merge equal amounts of YES and NO outcome tokens back into USDC. ' +\n 'The inverse of split: 1 YES + 1 NO = 1 USDC, always.',\n marketAppId: z.number().describe('The market app ID'),\n amount: z.number().describe('Amount to merge in microunits'),\n },\n async ({ marketAppId, amount }) => {\n const client = requireTradingClient();\n const result = await client.mergeShares({ marketAppId, amount });\n return textResult(\n `Merged YES + NO tokens back into ${formatPrice(amount)} USDC.\\n` +\n ` Tx IDs: ${result.txIds.join(', ')}\\n` +\n ` Confirmed round: ${result.confirmedRound}`,\n );\n },\n);\n\nserver.tool(\n 'claim',\n {\n description:\n 'Claim USDC from a resolved market by redeeming outcome tokens. ' +\n 'Winning tokens are redeemed 1:1 for USDC. Losing tokens are burned.',\n marketAppId: z.number().describe('The market app ID'),\n assetId: z.number().describe('The outcome token ASA ID to redeem'),\n amount: z.number().optional().describe('Amount to claim in microunits (omit to claim entire balance)'),\n },\n async ({ marketAppId, assetId, amount }) => {\n const client = requireTradingClient();\n const result = await client.claim({ marketAppId, assetId, amount });\n return textResult(\n `Claim successful.\\n` +\n ` Tx IDs: ${result.txIds.join(', ')}\\n` +\n ` Confirmed round: ${result.confirmedRound}`,\n );\n },\n);\n\n// ============================================\n// Start the server\n// ============================================\n\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@alpha-arcade/mcp",
3
+ "version": "0.1.0",
4
+ "description": "MCP server for Alpha Arcade prediction markets on Algorand",
5
+ "type": "module",
6
+ "bin": {
7
+ "alpha-mcp": "./dist/index.js"
8
+ },
9
+ "main": "./dist/index.js",
10
+ "scripts": {
11
+ "build": "tsup",
12
+ "prepublishOnly": "npm run build"
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "README.md",
17
+ "LICENSE"
18
+ ],
19
+ "keywords": [
20
+ "mcp",
21
+ "model-context-protocol",
22
+ "algorand",
23
+ "prediction-markets",
24
+ "alpha-arcade",
25
+ "trading",
26
+ "ai"
27
+ ],
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "https://github.com/phara23/alpha-mcp.git"
31
+ },
32
+ "license": "MIT",
33
+ "dependencies": {
34
+ "@algorandfoundation/algokit-utils": "^6.0.2",
35
+ "@alpha-arcade/sdk": "^0.2.0",
36
+ "@modelcontextprotocol/sdk": "^1.26.0",
37
+ "algosdk": "^2.7.0",
38
+ "zod": "^3.25.0"
39
+ },
40
+ "devDependencies": {
41
+ "@types/node": "^22.0.0",
42
+ "tsup": "^8.5.0",
43
+ "typescript": "^5.7.0"
44
+ }
45
+ }