@scoutagent/mcp-server 1.0.8 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,211 @@
1
+ # @scoutagent/mcp-server
2
+
3
+ [![npm](https://img.shields.io/npm/v/@scoutagent/mcp-server)](https://www.npmjs.com/package/@scoutagent/mcp-server)
4
+
5
+ MCP (Model Context Protocol) Server for **ScoutAgent** -- the AI Scout prediction market on X Layer. This server lets any MCP-compatible client (Claude Desktop, Cursor, Windsurf, etc.) interact with ScoutAgent: browse markets, mint Agent NFTs, place bets, view leaderboards, and more.
6
+
7
+ ## Quick Start
8
+
9
+ ```bash
10
+ npx @scoutagent/mcp-server
11
+ ```
12
+
13
+ Or install globally:
14
+
15
+ ```bash
16
+ npm install -g @scoutagent/mcp-server
17
+ scoutagent-mcp
18
+ ```
19
+
20
+ ## Configuration
21
+
22
+ ### Environment Variables
23
+
24
+ | Variable | Default | Description |
25
+ |---|---|---|
26
+ | `SCOUT_AGENT_API` | `http://localhost:3001` | Base URL of the ScoutAgent Runtime API |
27
+
28
+ ### Claude Desktop
29
+
30
+ Add to your `claude_desktop_config.json`:
31
+
32
+ ```json
33
+ {
34
+ "mcpServers": {
35
+ "scoutagent-xlayer": {
36
+ "command": "npx",
37
+ "args": ["-y", "@scoutagent/mcp-server"],
38
+ "env": {
39
+ "SCOUT_AGENT_API": "http://localhost:3001"
40
+ }
41
+ }
42
+ }
43
+ }
44
+ ```
45
+
46
+ ### Cursor
47
+
48
+ Add to your `.cursor/mcp.json`:
49
+
50
+ ```json
51
+ {
52
+ "mcpServers": {
53
+ "scoutagent-xlayer": {
54
+ "command": "npx",
55
+ "args": ["-y", "@scoutagent/mcp-server"],
56
+ "env": {
57
+ "SCOUT_AGENT_API": "http://localhost:3001"
58
+ }
59
+ }
60
+ }
61
+ }
62
+ ```
63
+
64
+ ## Available Tools
65
+
66
+ ### `xlayer_list_markets`
67
+
68
+ List all ScoutAgent prediction markets on X Layer.
69
+
70
+ | Parameter | Type | Required | Description |
71
+ |---|---|---|---|
72
+ | `status` | `OPEN \| LOCKED \| RESOLVED` | No | Filter by market status |
73
+ | `matchDateFrom` | `string` (ISO 8601) | No | Filter matches from this date |
74
+ | `matchDateTo` | `string` (ISO 8601) | No | Filter matches up to this date |
75
+
76
+ ### `xlayer_get_market`
77
+
78
+ Get detailed information about a single prediction market.
79
+
80
+ | Parameter | Type | Required | Description |
81
+ |---|---|---|---|
82
+ | `marketId` | `string` | Yes | The market ID to look up |
83
+
84
+ ### `xlayer_mint_agent`
85
+
86
+ Mint a new AI Scout Agent NFT on X Layer.
87
+
88
+ | Parameter | Type | Required | Description |
89
+ |---|---|---|---|
90
+ | `riskLevel` | `number` (1-5) | Yes | Risk appetite from 1 (conservative) to 5 (degen) |
91
+ | `style` | `ATTACKING \| DEFENSIVE \| DATA_DRIVEN \| CONTRARIAN \| MOMENTUM` | Yes | Betting strategy style |
92
+ | `bankrollPct` | `number` (1-100) | Yes | Percentage of bankroll to use per bet |
93
+ | `favoriteTeams` | `string[]` | No | Favorite team names for bias weighting |
94
+
95
+ ### `xlayer_place_bet`
96
+
97
+ Place a bet on a prediction market using an AI Scout Agent.
98
+
99
+ | Parameter | Type | Required | Description |
100
+ |---|---|---|---|
101
+ | `agentId` | `string` | Yes | The agent ID placing the bet |
102
+ | `marketId` | `string` | Yes | The market ID to bet on |
103
+ | `outcome` | `HOME \| DRAW \| AWAY` | Yes | Predicted outcome |
104
+ | `amount` | `string` | Yes | Bet amount in OKB (e.g. `"0.5"`) |
105
+
106
+ ### `xlayer_get_agent_stats`
107
+
108
+ Get performance statistics for an AI Scout Agent.
109
+
110
+ | Parameter | Type | Required | Description |
111
+ |---|---|---|---|
112
+ | `agentId` | `string` | Yes | The agent ID |
113
+
114
+ ### `xlayer_leaderboard`
115
+
116
+ Get the ScoutAgent leaderboard ranked by PnL.
117
+
118
+ | Parameter | Type | Required | Description |
119
+ |---|---|---|---|
120
+ | `top` | `number` (1-100) | No | Number of agents to return (default 10) |
121
+ | `period` | `24h \| 7d \| all` | No | Leaderboard time period |
122
+
123
+ ### `xlayer_natural_intent`
124
+
125
+ Parse natural language into a ScoutAgent action intent.
126
+
127
+ | Parameter | Type | Required | Description |
128
+ |---|---|---|---|
129
+ | `text` | `string` | Yes | Natural language input |
130
+ | `agentId` | `string` | No | Agent ID for context-aware parsing |
131
+
132
+ ## Available Resources
133
+
134
+ ### `xlayer://match/{matchId}`
135
+
136
+ Returns detailed match data as JSON, including team names, date, venue, and statistics.
137
+
138
+ ### `xlayer://agent/{agentId}/strategy`
139
+
140
+ Returns the strategy gene configuration for an AI Scout Agent as JSON, including style, risk level, and weighting parameters.
141
+
142
+ ## Usage Examples
143
+
144
+ **In Claude Desktop or Cursor chat:**
145
+
146
+ > "Show me all open prediction markets"
147
+
148
+ > "Mint me an aggressive agent with risk level 4, ATTACKING style, and 20% bankroll"
149
+
150
+ > "Place a 0.5 OKB bet on Brazil to win using agent abc123"
151
+
152
+ > "How is my agent xyz789 performing?"
153
+
154
+ > "Show me the top 5 agents this week"
155
+
156
+ > "I want to bet on the underdog in the next match" (uses natural intent parsing)
157
+
158
+ ## Development
159
+
160
+ ```bash
161
+ # Install dependencies
162
+ pnpm install
163
+
164
+ # Run in development mode
165
+ pnpm dev
166
+
167
+ # Build for production
168
+ pnpm build
169
+
170
+ # Type-check
171
+ pnpm lint
172
+ ```
173
+
174
+ ## Architecture
175
+
176
+ ```
177
+ src/
178
+ index.ts MCP server entry point (stdio transport)
179
+ types.ts Shared TypeScript types
180
+ clients.ts HTTP client for ScoutAgent Runtime API
181
+ tools/
182
+ list_markets.ts xlayer_list_markets tool
183
+ get_market.ts xlayer_get_market tool
184
+ mint_agent.ts xlayer_mint_agent tool
185
+ place_bet.ts xlayer_place_bet tool
186
+ get_agent_stats.ts xlayer_get_agent_stats tool
187
+ leaderboard.ts xlayer_leaderboard tool
188
+ natural_intent.ts xlayer_natural_intent tool
189
+ resources/
190
+ match_data.ts xlayer://match/{matchId} resource
191
+ agent_strategies.ts xlayer://agent/{agentId}/strategy resource
192
+ ```
193
+
194
+ ## Publishing
195
+
196
+ To publish the package to npm:
197
+
198
+ ```bash
199
+ npm login
200
+ cd apps/mcp-server
201
+ npm publish --access public
202
+ ```
203
+
204
+ > **Fallback package name:** If the scoped name `@scoutagent/mcp-server` is
205
+ > unavailable or causes issues with npm (e.g., scope not claimed), change the
206
+ > `name` field in `package.json` to `scoutagent-mcp` and publish again. The CLI
207
+ > binary name (`scoutagent-mcp`) stays the same either way.
208
+
209
+ ## License
210
+
211
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,538 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ var import_server = require("@modelcontextprotocol/sdk/server/index.js");
5
+ var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
6
+ var import_types = require("@modelcontextprotocol/sdk/types.js");
7
+
8
+ // src/tools/list_markets.ts
9
+ var import_zod = require("zod");
10
+
11
+ // src/clients.ts
12
+ var BASE_URL = process.env.SCOUT_AGENT_API?.replace(/\/+$/, "") ?? "http://localhost:3001";
13
+ async function apiGet(path, query) {
14
+ const url = new URL(path, BASE_URL);
15
+ if (query) {
16
+ for (const [k, v] of Object.entries(query)) {
17
+ if (v !== void 0 && v !== "") url.searchParams.set(k, v);
18
+ }
19
+ }
20
+ const res = await fetch(url.toString(), {
21
+ method: "GET",
22
+ headers: { Accept: "application/json" }
23
+ });
24
+ const data = await res.json();
25
+ return { ok: res.ok, status: res.status, data };
26
+ }
27
+ async function apiPost(path, body) {
28
+ const res = await fetch(new URL(path, BASE_URL).toString(), {
29
+ method: "POST",
30
+ headers: {
31
+ "Content-Type": "application/json",
32
+ Accept: "application/json"
33
+ },
34
+ body: JSON.stringify(body)
35
+ });
36
+ const data = await res.json();
37
+ return { ok: res.ok, status: res.status, data };
38
+ }
39
+
40
+ // src/tools/list_markets.ts
41
+ var listMarketsSchema = import_zod.z.object({
42
+ status: import_zod.z.enum(["OPEN", "LOCKED", "RESOLVED"]).optional().describe("Filter by market status"),
43
+ matchDateFrom: import_zod.z.string().optional().describe("Filter matches from this date (ISO 8601)"),
44
+ matchDateTo: import_zod.z.string().optional().describe("Filter matches up to this date (ISO 8601)")
45
+ });
46
+ var listMarketsDef = {
47
+ name: "xlayer_list_markets",
48
+ description: "List all ScoutAgent prediction markets on X Layer. Optionally filter by status or match date range.",
49
+ inputSchema: {
50
+ type: "object",
51
+ properties: {
52
+ status: {
53
+ type: "string",
54
+ enum: ["OPEN", "LOCKED", "RESOLVED"],
55
+ description: "Filter by market status"
56
+ },
57
+ matchDateFrom: {
58
+ type: "string",
59
+ description: "Filter matches from this date (ISO 8601)"
60
+ },
61
+ matchDateTo: {
62
+ type: "string",
63
+ description: "Filter matches up to this date (ISO 8601)"
64
+ }
65
+ }
66
+ }
67
+ };
68
+ async function handleListMarkets(params) {
69
+ const parsed = listMarketsSchema.parse(params);
70
+ const res = await apiGet("/api/markets", {
71
+ status: parsed.status,
72
+ matchDateFrom: parsed.matchDateFrom,
73
+ matchDateTo: parsed.matchDateTo
74
+ });
75
+ if (!res.ok) {
76
+ return {
77
+ content: [{ type: "text", text: `API error ${res.status}: ${JSON.stringify(res.data)}` }],
78
+ isError: true
79
+ };
80
+ }
81
+ const markets = res.data;
82
+ const summary = markets.map(
83
+ (m) => `[${m.id}] ${m.homeTeam} vs ${m.awayTeam} | ${m.matchDate} | ${m.status} | Pool: ${m.totalPool}`
84
+ );
85
+ return {
86
+ content: [
87
+ {
88
+ type: "text",
89
+ text: markets.length === 0 ? "No markets found matching the criteria." : `Found ${markets.length} market(s):
90
+
91
+ ${summary.join("\n")}`
92
+ }
93
+ ]
94
+ };
95
+ }
96
+
97
+ // src/tools/get_market.ts
98
+ var import_zod2 = require("zod");
99
+ var getMarketSchema = import_zod2.z.object({
100
+ marketId: import_zod2.z.string().describe("The market ID to look up")
101
+ });
102
+ var getMarketDef = {
103
+ name: "xlayer_get_market",
104
+ description: "Get detailed information about a single ScoutAgent prediction market on X Layer, including odds and pool size.",
105
+ inputSchema: {
106
+ type: "object",
107
+ properties: {
108
+ marketId: {
109
+ type: "string",
110
+ description: "The market ID to look up"
111
+ }
112
+ },
113
+ required: ["marketId"]
114
+ }
115
+ };
116
+ async function handleGetMarket(params) {
117
+ const { marketId } = getMarketSchema.parse(params);
118
+ const res = await apiGet(`/api/markets/${marketId}`);
119
+ if (!res.ok) {
120
+ return {
121
+ content: [{ type: "text", text: `API error ${res.status}: ${JSON.stringify(res.data)}` }],
122
+ isError: true
123
+ };
124
+ }
125
+ const m = res.data;
126
+ const text = [
127
+ `Market: ${m.id}`,
128
+ `Match: ${m.homeTeam} vs ${m.awayTeam}`,
129
+ `Date: ${m.matchDate}`,
130
+ `Status: ${m.status}`,
131
+ `Odds: Home ${m.odds.home} | Draw ${m.odds.draw} | Away ${m.odds.away}`,
132
+ `Total Pool: ${m.totalPool}`,
133
+ m.resolvedOutcome ? `Resolved Outcome: ${m.resolvedOutcome}` : null
134
+ ].filter(Boolean).join("\n");
135
+ return { content: [{ type: "text", text }] };
136
+ }
137
+
138
+ // src/tools/mint_agent.ts
139
+ var import_zod3 = require("zod");
140
+ var mintAgentSchema = import_zod3.z.object({
141
+ riskLevel: import_zod3.z.number().int().min(1).max(5).describe("Risk appetite from 1 (conservative) to 5 (degen)"),
142
+ style: import_zod3.z.enum(["ATTACKING", "DEFENSIVE", "DATA_DRIVEN", "CONTRARIAN", "MOMENTUM"]).describe("Betting strategy style"),
143
+ bankrollPct: import_zod3.z.number().min(1).max(100).describe("Percentage of bankroll to use per bet (1-100)"),
144
+ favoriteTeams: import_zod3.z.array(import_zod3.z.string()).optional().default([]).describe("Optional list of favorite team names for bias weighting")
145
+ });
146
+ var mintAgentDef = {
147
+ name: "xlayer_mint_agent",
148
+ description: "Mint a new AI Scout Agent NFT on X Layer. The agent will autonomously bet on World Cup prediction markets based on its strategy gene.",
149
+ inputSchema: {
150
+ type: "object",
151
+ properties: {
152
+ riskLevel: {
153
+ type: "number",
154
+ minimum: 1,
155
+ maximum: 5,
156
+ description: "Risk appetite from 1 (conservative) to 5 (degen)"
157
+ },
158
+ style: {
159
+ type: "string",
160
+ enum: ["ATTACKING", "DEFENSIVE", "DATA_DRIVEN", "CONTRARIAN", "MOMENTUM"],
161
+ description: "Betting strategy style"
162
+ },
163
+ bankrollPct: {
164
+ type: "number",
165
+ minimum: 1,
166
+ maximum: 100,
167
+ description: "Percentage of bankroll to use per bet (1-100)"
168
+ },
169
+ favoriteTeams: {
170
+ type: "array",
171
+ items: { type: "string" },
172
+ description: "Optional list of favorite team names for bias weighting"
173
+ }
174
+ },
175
+ required: ["riskLevel", "style", "bankrollPct"]
176
+ }
177
+ };
178
+ async function handleMintAgent(params) {
179
+ const parsed = mintAgentSchema.parse(params);
180
+ const res = await apiPost("/api/agents/mint", parsed);
181
+ if (!res.ok) {
182
+ return {
183
+ content: [{ type: "text", text: `API error ${res.status}: ${JSON.stringify(res.data)}` }],
184
+ isError: true
185
+ };
186
+ }
187
+ const a = res.data;
188
+ const text = [
189
+ `Agent minted successfully!`,
190
+ `Agent ID: ${a.agentId}`,
191
+ `Token ID: ${a.tokenId}`,
192
+ `Wallet: ${a.walletAddress}`,
193
+ `Style: ${a.style} | Risk: ${a.riskLevel} | Bankroll%: ${a.bankrollPct}`,
194
+ a.favoriteTeams.length > 0 ? `Favorite Teams: ${a.favoriteTeams.join(", ")}` : null
195
+ ].filter(Boolean).join("\n");
196
+ return { content: [{ type: "text", text }] };
197
+ }
198
+
199
+ // src/tools/place_bet.ts
200
+ var import_zod4 = require("zod");
201
+ var placeBetSchema = import_zod4.z.object({
202
+ agentId: import_zod4.z.string().describe("The agent ID placing the bet"),
203
+ marketId: import_zod4.z.string().describe("The market ID to bet on"),
204
+ outcome: import_zod4.z.enum(["HOME", "DRAW", "AWAY"]).describe("Predicted outcome: HOME, DRAW, or AWAY"),
205
+ amount: import_zod4.z.string().describe("Bet amount in OKB (as a decimal string, e.g. '0.5')")
206
+ });
207
+ var placeBetDef = {
208
+ name: "xlayer_place_bet",
209
+ description: "Place a bet on a ScoutAgent prediction market on X Layer using an AI Scout Agent. Returns the transaction hash and explorer URL.",
210
+ inputSchema: {
211
+ type: "object",
212
+ properties: {
213
+ agentId: {
214
+ type: "string",
215
+ description: "The agent ID placing the bet"
216
+ },
217
+ marketId: {
218
+ type: "string",
219
+ description: "The market ID to bet on"
220
+ },
221
+ outcome: {
222
+ type: "string",
223
+ enum: ["HOME", "DRAW", "AWAY"],
224
+ description: "Predicted outcome: HOME, DRAW, or AWAY"
225
+ },
226
+ amount: {
227
+ type: "string",
228
+ description: "Bet amount in OKB (as a decimal string, e.g. '0.5')"
229
+ }
230
+ },
231
+ required: ["agentId", "marketId", "outcome", "amount"]
232
+ }
233
+ };
234
+ async function handlePlaceBet(params) {
235
+ const parsed = placeBetSchema.parse(params);
236
+ const res = await apiPost("/api/bets", parsed);
237
+ if (!res.ok) {
238
+ return {
239
+ content: [{ type: "text", text: `API error ${res.status}: ${JSON.stringify(res.data)}` }],
240
+ isError: true
241
+ };
242
+ }
243
+ const b = res.data;
244
+ const text = [
245
+ `Bet placed successfully!`,
246
+ `Tx Hash: ${b.txHash}`,
247
+ `Explorer: ${b.explorerUrl}`,
248
+ `Market: ${b.marketId} | Outcome: ${b.outcome} | Amount: ${b.amount}`,
249
+ `Estimated Payout: ${b.estimatedPayout}`
250
+ ].join("\n");
251
+ return { content: [{ type: "text", text }] };
252
+ }
253
+
254
+ // src/tools/get_agent_stats.ts
255
+ var import_zod5 = require("zod");
256
+ var getAgentStatsSchema = import_zod5.z.object({
257
+ agentId: import_zod5.z.string().describe("The agent ID to get statistics for")
258
+ });
259
+ var getAgentStatsDef = {
260
+ name: "xlayer_get_agent_stats",
261
+ description: "Get performance statistics for an AI Scout Agent on X Layer, including win rate, PnL, ROI, and streak.",
262
+ inputSchema: {
263
+ type: "object",
264
+ properties: {
265
+ agentId: {
266
+ type: "string",
267
+ description: "The agent ID to get statistics for"
268
+ }
269
+ },
270
+ required: ["agentId"]
271
+ }
272
+ };
273
+ async function handleGetAgentStats(params) {
274
+ const { agentId } = getAgentStatsSchema.parse(params);
275
+ const res = await apiGet(`/api/agents/${agentId}/stats`);
276
+ if (!res.ok) {
277
+ return {
278
+ content: [{ type: "text", text: `API error ${res.status}: ${JSON.stringify(res.data)}` }],
279
+ isError: true
280
+ };
281
+ }
282
+ const s = res.data;
283
+ const text = [
284
+ `Agent ${s.agentId} Stats`,
285
+ `\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`,
286
+ `Record: ${s.wins}W / ${s.losses}L / ${s.draws}D (${s.totalBets} total bets)`,
287
+ `Win Rate: ${(s.winRate * 100).toFixed(1)}%`,
288
+ `Total PnL: ${s.totalPnl} OKB`,
289
+ `ROI: ${(s.roi * 100).toFixed(1)}%`,
290
+ `Current Streak: ${s.streak > 0 ? `${s.streak}W` : s.streak < 0 ? `${Math.abs(s.streak)}L` : "0"}`
291
+ ].join("\n");
292
+ return { content: [{ type: "text", text }] };
293
+ }
294
+
295
+ // src/tools/leaderboard.ts
296
+ var import_zod6 = require("zod");
297
+ var leaderboardSchema = import_zod6.z.object({
298
+ top: import_zod6.z.number().int().min(1).max(100).optional().default(10).describe("Number of top agents to return (default 10)"),
299
+ period: import_zod6.z.enum(["24h", "7d", "all"]).optional().describe("Leaderboard time period: 24h, 7d, or all")
300
+ });
301
+ var leaderboardDef = {
302
+ name: "xlayer_leaderboard",
303
+ description: "Get the ScoutAgent leaderboard on X Layer, ranked by PnL. Filter by time period.",
304
+ inputSchema: {
305
+ type: "object",
306
+ properties: {
307
+ top: {
308
+ type: "number",
309
+ minimum: 1,
310
+ maximum: 100,
311
+ description: "Number of top agents to return (default 10)"
312
+ },
313
+ period: {
314
+ type: "string",
315
+ enum: ["24h", "7d", "all"],
316
+ description: "Leaderboard time period: 24h, 7d, or all"
317
+ }
318
+ }
319
+ }
320
+ };
321
+ async function handleLeaderboard(params) {
322
+ const parsed = leaderboardSchema.parse(params);
323
+ const res = await apiGet("/api/leaderboard", {
324
+ top: String(parsed.top),
325
+ period: parsed.period
326
+ });
327
+ if (!res.ok) {
328
+ return {
329
+ content: [{ type: "text", text: `API error ${res.status}: ${JSON.stringify(res.data)}` }],
330
+ isError: true
331
+ };
332
+ }
333
+ const entries = res.data;
334
+ if (entries.length === 0) {
335
+ return { content: [{ type: "text", text: "Leaderboard is empty." }] };
336
+ }
337
+ const header = `ScoutAgent Leaderboard${parsed.period ? ` (${parsed.period})` : ""}
338
+ ${"\u2550".repeat(50)}`;
339
+ const rows = entries.map(
340
+ (e) => `#${e.rank} | Agent ${e.agentId} | PnL: ${e.pnl} OKB | WR: ${(e.winRate * 100).toFixed(1)}% | ${e.totalBets} bets | ${e.style}`
341
+ );
342
+ return { content: [{ type: "text", text: `${header}
343
+ ${rows.join("\n")}` }] };
344
+ }
345
+
346
+ // src/tools/natural_intent.ts
347
+ var import_zod7 = require("zod");
348
+ var naturalIntentSchema = import_zod7.z.object({
349
+ text: import_zod7.z.string().describe("Natural language text describing what the user wants to do"),
350
+ agentId: import_zod7.z.string().optional().describe("Optional agent ID for context-aware intent parsing")
351
+ });
352
+ var naturalIntentDef = {
353
+ name: "xlayer_natural_intent",
354
+ description: 'Parse natural language into a ScoutAgent action intent. For example: "bet 0.5 OKB on Brazil to win" becomes a structured place_bet intent.',
355
+ inputSchema: {
356
+ type: "object",
357
+ properties: {
358
+ text: {
359
+ type: "string",
360
+ description: "Natural language text describing what the user wants to do"
361
+ },
362
+ agentId: {
363
+ type: "string",
364
+ description: "Optional agent ID for context-aware intent parsing"
365
+ }
366
+ },
367
+ required: ["text"]
368
+ }
369
+ };
370
+ async function handleNaturalIntent(params) {
371
+ const parsed = naturalIntentSchema.parse(params);
372
+ const res = await apiPost("/api/intent", parsed);
373
+ if (!res.ok) {
374
+ return {
375
+ content: [{ type: "text", text: `API error ${res.status}: ${JSON.stringify(res.data)}` }],
376
+ isError: true
377
+ };
378
+ }
379
+ const r = res.data;
380
+ const text = [
381
+ `Intent: ${r.intent}`,
382
+ `Confidence: ${(r.confidence * 100).toFixed(0)}%`,
383
+ `Parameters: ${JSON.stringify(r.params, null, 2)}`,
384
+ r.suggestedAction ? `
385
+ Suggested action: ${r.suggestedAction}` : null
386
+ ].filter(Boolean).join("\n");
387
+ return { content: [{ type: "text", text }] };
388
+ }
389
+
390
+ // src/resources/match_data.ts
391
+ async function handleMatchData(matchId) {
392
+ const res = await apiGet(`/api/matches/${matchId}`);
393
+ if (!res.ok) {
394
+ return {
395
+ contents: [
396
+ {
397
+ uri: `xlayer://match/${matchId}`,
398
+ mimeType: "application/json",
399
+ text: JSON.stringify({ error: `API error ${res.status}`, details: res.data })
400
+ }
401
+ ]
402
+ };
403
+ }
404
+ return {
405
+ contents: [
406
+ {
407
+ uri: `xlayer://match/${matchId}`,
408
+ mimeType: "application/json",
409
+ text: JSON.stringify(res.data, null, 2)
410
+ }
411
+ ]
412
+ };
413
+ }
414
+
415
+ // src/resources/agent_strategies.ts
416
+ async function handleAgentStrategy(agentId) {
417
+ const res = await apiGet(`/api/agents/${agentId}/strategy`);
418
+ if (!res.ok) {
419
+ return {
420
+ contents: [
421
+ {
422
+ uri: `xlayer://agent/${agentId}/strategy`,
423
+ mimeType: "application/json",
424
+ text: JSON.stringify({ error: `API error ${res.status}`, details: res.data })
425
+ }
426
+ ]
427
+ };
428
+ }
429
+ return {
430
+ contents: [
431
+ {
432
+ uri: `xlayer://agent/${agentId}/strategy`,
433
+ mimeType: "application/json",
434
+ text: JSON.stringify(res.data, null, 2)
435
+ }
436
+ ]
437
+ };
438
+ }
439
+
440
+ // src/index.ts
441
+ var server = new import_server.Server(
442
+ { name: "scoutagent-xlayer", version: "0.1.0" },
443
+ {
444
+ capabilities: {
445
+ tools: {},
446
+ resources: {}
447
+ }
448
+ }
449
+ );
450
+ var TOOLS = [
451
+ listMarketsDef,
452
+ getMarketDef,
453
+ mintAgentDef,
454
+ placeBetDef,
455
+ getAgentStatsDef,
456
+ leaderboardDef,
457
+ naturalIntentDef
458
+ ];
459
+ var TOOL_HANDLERS = {
460
+ [listMarketsDef.name]: handleListMarkets,
461
+ [getMarketDef.name]: handleGetMarket,
462
+ [mintAgentDef.name]: handleMintAgent,
463
+ [placeBetDef.name]: handlePlaceBet,
464
+ [getAgentStatsDef.name]: handleGetAgentStats,
465
+ [leaderboardDef.name]: handleLeaderboard,
466
+ [naturalIntentDef.name]: handleNaturalIntent
467
+ };
468
+ var RESOURCE_TEMPLATES = [
469
+ {
470
+ uriTemplate: "xlayer://match/{matchId}",
471
+ name: "Match Data",
472
+ description: "Detailed match data including teams, date, venue, and statistics.",
473
+ mimeType: "application/json"
474
+ },
475
+ {
476
+ uriTemplate: "xlayer://agent/{agentId}/strategy",
477
+ name: "Agent Strategy Gene",
478
+ description: "Strategy gene configuration for an AI Scout Agent.",
479
+ mimeType: "application/json"
480
+ }
481
+ ];
482
+ server.setRequestHandler(import_types.ListToolsRequestSchema, async () => {
483
+ return { tools: TOOLS };
484
+ });
485
+ server.setRequestHandler(import_types.CallToolRequestSchema, async (request) => {
486
+ const { name, arguments: args } = request.params;
487
+ const handler = TOOL_HANDLERS[name];
488
+ if (!handler) {
489
+ return {
490
+ content: [{ type: "text", text: `Unknown tool: ${name}` }],
491
+ isError: true
492
+ };
493
+ }
494
+ try {
495
+ return await handler(args ?? {});
496
+ } catch (err) {
497
+ const message = err instanceof Error ? err.message : String(err);
498
+ return {
499
+ content: [{ type: "text", text: `Error executing ${name}: ${message}` }],
500
+ isError: true
501
+ };
502
+ }
503
+ });
504
+ server.setRequestHandler(import_types.ListResourcesRequestSchema, async () => {
505
+ return { resources: [] };
506
+ });
507
+ server.setRequestHandler(import_types.ListResourceTemplatesRequestSchema, async () => {
508
+ return { resourceTemplates: RESOURCE_TEMPLATES };
509
+ });
510
+ server.setRequestHandler(import_types.ReadResourceRequestSchema, async (request) => {
511
+ const { uri } = request.params;
512
+ const matchMatch = uri.match(/^xlayer:\/\/match\/(.+)$/);
513
+ if (matchMatch) {
514
+ return await handleMatchData(matchMatch[1]);
515
+ }
516
+ const strategyMatch = uri.match(/^xlayer:\/\/agent\/(.+)\/strategy$/);
517
+ if (strategyMatch) {
518
+ return await handleAgentStrategy(strategyMatch[1]);
519
+ }
520
+ return {
521
+ contents: [
522
+ {
523
+ uri,
524
+ mimeType: "text/plain",
525
+ text: `Unknown resource URI: ${uri}`
526
+ }
527
+ ]
528
+ };
529
+ });
530
+ async function main() {
531
+ const transport = new import_stdio.StdioServerTransport();
532
+ await server.connect(transport);
533
+ console.error("ScoutAgent MCP Server running on stdio");
534
+ }
535
+ main().catch((err) => {
536
+ console.error("Fatal error starting ScoutAgent MCP Server:", err);
537
+ process.exit(1);
538
+ });
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/index.js ADDED
@@ -0,0 +1,544 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
5
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
6
+ import {
7
+ CallToolRequestSchema,
8
+ ListToolsRequestSchema,
9
+ ListResourcesRequestSchema,
10
+ ListResourceTemplatesRequestSchema,
11
+ ReadResourceRequestSchema
12
+ } from "@modelcontextprotocol/sdk/types.js";
13
+
14
+ // src/tools/list_markets.ts
15
+ import { z } from "zod";
16
+
17
+ // src/clients.ts
18
+ var BASE_URL = process.env.SCOUT_AGENT_API?.replace(/\/+$/, "") ?? "http://localhost:3001";
19
+ async function apiGet(path, query) {
20
+ const url = new URL(path, BASE_URL);
21
+ if (query) {
22
+ for (const [k, v] of Object.entries(query)) {
23
+ if (v !== void 0 && v !== "") url.searchParams.set(k, v);
24
+ }
25
+ }
26
+ const res = await fetch(url.toString(), {
27
+ method: "GET",
28
+ headers: { Accept: "application/json" }
29
+ });
30
+ const data = await res.json();
31
+ return { ok: res.ok, status: res.status, data };
32
+ }
33
+ async function apiPost(path, body) {
34
+ const res = await fetch(new URL(path, BASE_URL).toString(), {
35
+ method: "POST",
36
+ headers: {
37
+ "Content-Type": "application/json",
38
+ Accept: "application/json"
39
+ },
40
+ body: JSON.stringify(body)
41
+ });
42
+ const data = await res.json();
43
+ return { ok: res.ok, status: res.status, data };
44
+ }
45
+
46
+ // src/tools/list_markets.ts
47
+ var listMarketsSchema = z.object({
48
+ status: z.enum(["OPEN", "LOCKED", "RESOLVED"]).optional().describe("Filter by market status"),
49
+ matchDateFrom: z.string().optional().describe("Filter matches from this date (ISO 8601)"),
50
+ matchDateTo: z.string().optional().describe("Filter matches up to this date (ISO 8601)")
51
+ });
52
+ var listMarketsDef = {
53
+ name: "xlayer_list_markets",
54
+ description: "List all ScoutAgent prediction markets on X Layer. Optionally filter by status or match date range.",
55
+ inputSchema: {
56
+ type: "object",
57
+ properties: {
58
+ status: {
59
+ type: "string",
60
+ enum: ["OPEN", "LOCKED", "RESOLVED"],
61
+ description: "Filter by market status"
62
+ },
63
+ matchDateFrom: {
64
+ type: "string",
65
+ description: "Filter matches from this date (ISO 8601)"
66
+ },
67
+ matchDateTo: {
68
+ type: "string",
69
+ description: "Filter matches up to this date (ISO 8601)"
70
+ }
71
+ }
72
+ }
73
+ };
74
+ async function handleListMarkets(params) {
75
+ const parsed = listMarketsSchema.parse(params);
76
+ const res = await apiGet("/api/markets", {
77
+ status: parsed.status,
78
+ matchDateFrom: parsed.matchDateFrom,
79
+ matchDateTo: parsed.matchDateTo
80
+ });
81
+ if (!res.ok) {
82
+ return {
83
+ content: [{ type: "text", text: `API error ${res.status}: ${JSON.stringify(res.data)}` }],
84
+ isError: true
85
+ };
86
+ }
87
+ const markets = res.data;
88
+ const summary = markets.map(
89
+ (m) => `[${m.id}] ${m.homeTeam} vs ${m.awayTeam} | ${m.matchDate} | ${m.status} | Pool: ${m.totalPool}`
90
+ );
91
+ return {
92
+ content: [
93
+ {
94
+ type: "text",
95
+ text: markets.length === 0 ? "No markets found matching the criteria." : `Found ${markets.length} market(s):
96
+
97
+ ${summary.join("\n")}`
98
+ }
99
+ ]
100
+ };
101
+ }
102
+
103
+ // src/tools/get_market.ts
104
+ import { z as z2 } from "zod";
105
+ var getMarketSchema = z2.object({
106
+ marketId: z2.string().describe("The market ID to look up")
107
+ });
108
+ var getMarketDef = {
109
+ name: "xlayer_get_market",
110
+ description: "Get detailed information about a single ScoutAgent prediction market on X Layer, including odds and pool size.",
111
+ inputSchema: {
112
+ type: "object",
113
+ properties: {
114
+ marketId: {
115
+ type: "string",
116
+ description: "The market ID to look up"
117
+ }
118
+ },
119
+ required: ["marketId"]
120
+ }
121
+ };
122
+ async function handleGetMarket(params) {
123
+ const { marketId } = getMarketSchema.parse(params);
124
+ const res = await apiGet(`/api/markets/${marketId}`);
125
+ if (!res.ok) {
126
+ return {
127
+ content: [{ type: "text", text: `API error ${res.status}: ${JSON.stringify(res.data)}` }],
128
+ isError: true
129
+ };
130
+ }
131
+ const m = res.data;
132
+ const text = [
133
+ `Market: ${m.id}`,
134
+ `Match: ${m.homeTeam} vs ${m.awayTeam}`,
135
+ `Date: ${m.matchDate}`,
136
+ `Status: ${m.status}`,
137
+ `Odds: Home ${m.odds.home} | Draw ${m.odds.draw} | Away ${m.odds.away}`,
138
+ `Total Pool: ${m.totalPool}`,
139
+ m.resolvedOutcome ? `Resolved Outcome: ${m.resolvedOutcome}` : null
140
+ ].filter(Boolean).join("\n");
141
+ return { content: [{ type: "text", text }] };
142
+ }
143
+
144
+ // src/tools/mint_agent.ts
145
+ import { z as z3 } from "zod";
146
+ var mintAgentSchema = z3.object({
147
+ riskLevel: z3.number().int().min(1).max(5).describe("Risk appetite from 1 (conservative) to 5 (degen)"),
148
+ style: z3.enum(["ATTACKING", "DEFENSIVE", "DATA_DRIVEN", "CONTRARIAN", "MOMENTUM"]).describe("Betting strategy style"),
149
+ bankrollPct: z3.number().min(1).max(100).describe("Percentage of bankroll to use per bet (1-100)"),
150
+ favoriteTeams: z3.array(z3.string()).optional().default([]).describe("Optional list of favorite team names for bias weighting")
151
+ });
152
+ var mintAgentDef = {
153
+ name: "xlayer_mint_agent",
154
+ description: "Mint a new AI Scout Agent NFT on X Layer. The agent will autonomously bet on World Cup prediction markets based on its strategy gene.",
155
+ inputSchema: {
156
+ type: "object",
157
+ properties: {
158
+ riskLevel: {
159
+ type: "number",
160
+ minimum: 1,
161
+ maximum: 5,
162
+ description: "Risk appetite from 1 (conservative) to 5 (degen)"
163
+ },
164
+ style: {
165
+ type: "string",
166
+ enum: ["ATTACKING", "DEFENSIVE", "DATA_DRIVEN", "CONTRARIAN", "MOMENTUM"],
167
+ description: "Betting strategy style"
168
+ },
169
+ bankrollPct: {
170
+ type: "number",
171
+ minimum: 1,
172
+ maximum: 100,
173
+ description: "Percentage of bankroll to use per bet (1-100)"
174
+ },
175
+ favoriteTeams: {
176
+ type: "array",
177
+ items: { type: "string" },
178
+ description: "Optional list of favorite team names for bias weighting"
179
+ }
180
+ },
181
+ required: ["riskLevel", "style", "bankrollPct"]
182
+ }
183
+ };
184
+ async function handleMintAgent(params) {
185
+ const parsed = mintAgentSchema.parse(params);
186
+ const res = await apiPost("/api/agents/mint", parsed);
187
+ if (!res.ok) {
188
+ return {
189
+ content: [{ type: "text", text: `API error ${res.status}: ${JSON.stringify(res.data)}` }],
190
+ isError: true
191
+ };
192
+ }
193
+ const a = res.data;
194
+ const text = [
195
+ `Agent minted successfully!`,
196
+ `Agent ID: ${a.agentId}`,
197
+ `Token ID: ${a.tokenId}`,
198
+ `Wallet: ${a.walletAddress}`,
199
+ `Style: ${a.style} | Risk: ${a.riskLevel} | Bankroll%: ${a.bankrollPct}`,
200
+ a.favoriteTeams.length > 0 ? `Favorite Teams: ${a.favoriteTeams.join(", ")}` : null
201
+ ].filter(Boolean).join("\n");
202
+ return { content: [{ type: "text", text }] };
203
+ }
204
+
205
+ // src/tools/place_bet.ts
206
+ import { z as z4 } from "zod";
207
+ var placeBetSchema = z4.object({
208
+ agentId: z4.string().describe("The agent ID placing the bet"),
209
+ marketId: z4.string().describe("The market ID to bet on"),
210
+ outcome: z4.enum(["HOME", "DRAW", "AWAY"]).describe("Predicted outcome: HOME, DRAW, or AWAY"),
211
+ amount: z4.string().describe("Bet amount in OKB (as a decimal string, e.g. '0.5')")
212
+ });
213
+ var placeBetDef = {
214
+ name: "xlayer_place_bet",
215
+ description: "Place a bet on a ScoutAgent prediction market on X Layer using an AI Scout Agent. Returns the transaction hash and explorer URL.",
216
+ inputSchema: {
217
+ type: "object",
218
+ properties: {
219
+ agentId: {
220
+ type: "string",
221
+ description: "The agent ID placing the bet"
222
+ },
223
+ marketId: {
224
+ type: "string",
225
+ description: "The market ID to bet on"
226
+ },
227
+ outcome: {
228
+ type: "string",
229
+ enum: ["HOME", "DRAW", "AWAY"],
230
+ description: "Predicted outcome: HOME, DRAW, or AWAY"
231
+ },
232
+ amount: {
233
+ type: "string",
234
+ description: "Bet amount in OKB (as a decimal string, e.g. '0.5')"
235
+ }
236
+ },
237
+ required: ["agentId", "marketId", "outcome", "amount"]
238
+ }
239
+ };
240
+ async function handlePlaceBet(params) {
241
+ const parsed = placeBetSchema.parse(params);
242
+ const res = await apiPost("/api/bets", parsed);
243
+ if (!res.ok) {
244
+ return {
245
+ content: [{ type: "text", text: `API error ${res.status}: ${JSON.stringify(res.data)}` }],
246
+ isError: true
247
+ };
248
+ }
249
+ const b = res.data;
250
+ const text = [
251
+ `Bet placed successfully!`,
252
+ `Tx Hash: ${b.txHash}`,
253
+ `Explorer: ${b.explorerUrl}`,
254
+ `Market: ${b.marketId} | Outcome: ${b.outcome} | Amount: ${b.amount}`,
255
+ `Estimated Payout: ${b.estimatedPayout}`
256
+ ].join("\n");
257
+ return { content: [{ type: "text", text }] };
258
+ }
259
+
260
+ // src/tools/get_agent_stats.ts
261
+ import { z as z5 } from "zod";
262
+ var getAgentStatsSchema = z5.object({
263
+ agentId: z5.string().describe("The agent ID to get statistics for")
264
+ });
265
+ var getAgentStatsDef = {
266
+ name: "xlayer_get_agent_stats",
267
+ description: "Get performance statistics for an AI Scout Agent on X Layer, including win rate, PnL, ROI, and streak.",
268
+ inputSchema: {
269
+ type: "object",
270
+ properties: {
271
+ agentId: {
272
+ type: "string",
273
+ description: "The agent ID to get statistics for"
274
+ }
275
+ },
276
+ required: ["agentId"]
277
+ }
278
+ };
279
+ async function handleGetAgentStats(params) {
280
+ const { agentId } = getAgentStatsSchema.parse(params);
281
+ const res = await apiGet(`/api/agents/${agentId}/stats`);
282
+ if (!res.ok) {
283
+ return {
284
+ content: [{ type: "text", text: `API error ${res.status}: ${JSON.stringify(res.data)}` }],
285
+ isError: true
286
+ };
287
+ }
288
+ const s = res.data;
289
+ const text = [
290
+ `Agent ${s.agentId} Stats`,
291
+ `\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`,
292
+ `Record: ${s.wins}W / ${s.losses}L / ${s.draws}D (${s.totalBets} total bets)`,
293
+ `Win Rate: ${(s.winRate * 100).toFixed(1)}%`,
294
+ `Total PnL: ${s.totalPnl} OKB`,
295
+ `ROI: ${(s.roi * 100).toFixed(1)}%`,
296
+ `Current Streak: ${s.streak > 0 ? `${s.streak}W` : s.streak < 0 ? `${Math.abs(s.streak)}L` : "0"}`
297
+ ].join("\n");
298
+ return { content: [{ type: "text", text }] };
299
+ }
300
+
301
+ // src/tools/leaderboard.ts
302
+ import { z as z6 } from "zod";
303
+ var leaderboardSchema = z6.object({
304
+ top: z6.number().int().min(1).max(100).optional().default(10).describe("Number of top agents to return (default 10)"),
305
+ period: z6.enum(["24h", "7d", "all"]).optional().describe("Leaderboard time period: 24h, 7d, or all")
306
+ });
307
+ var leaderboardDef = {
308
+ name: "xlayer_leaderboard",
309
+ description: "Get the ScoutAgent leaderboard on X Layer, ranked by PnL. Filter by time period.",
310
+ inputSchema: {
311
+ type: "object",
312
+ properties: {
313
+ top: {
314
+ type: "number",
315
+ minimum: 1,
316
+ maximum: 100,
317
+ description: "Number of top agents to return (default 10)"
318
+ },
319
+ period: {
320
+ type: "string",
321
+ enum: ["24h", "7d", "all"],
322
+ description: "Leaderboard time period: 24h, 7d, or all"
323
+ }
324
+ }
325
+ }
326
+ };
327
+ async function handleLeaderboard(params) {
328
+ const parsed = leaderboardSchema.parse(params);
329
+ const res = await apiGet("/api/leaderboard", {
330
+ top: String(parsed.top),
331
+ period: parsed.period
332
+ });
333
+ if (!res.ok) {
334
+ return {
335
+ content: [{ type: "text", text: `API error ${res.status}: ${JSON.stringify(res.data)}` }],
336
+ isError: true
337
+ };
338
+ }
339
+ const entries = res.data;
340
+ if (entries.length === 0) {
341
+ return { content: [{ type: "text", text: "Leaderboard is empty." }] };
342
+ }
343
+ const header = `ScoutAgent Leaderboard${parsed.period ? ` (${parsed.period})` : ""}
344
+ ${"\u2550".repeat(50)}`;
345
+ const rows = entries.map(
346
+ (e) => `#${e.rank} | Agent ${e.agentId} | PnL: ${e.pnl} OKB | WR: ${(e.winRate * 100).toFixed(1)}% | ${e.totalBets} bets | ${e.style}`
347
+ );
348
+ return { content: [{ type: "text", text: `${header}
349
+ ${rows.join("\n")}` }] };
350
+ }
351
+
352
+ // src/tools/natural_intent.ts
353
+ import { z as z7 } from "zod";
354
+ var naturalIntentSchema = z7.object({
355
+ text: z7.string().describe("Natural language text describing what the user wants to do"),
356
+ agentId: z7.string().optional().describe("Optional agent ID for context-aware intent parsing")
357
+ });
358
+ var naturalIntentDef = {
359
+ name: "xlayer_natural_intent",
360
+ description: 'Parse natural language into a ScoutAgent action intent. For example: "bet 0.5 OKB on Brazil to win" becomes a structured place_bet intent.',
361
+ inputSchema: {
362
+ type: "object",
363
+ properties: {
364
+ text: {
365
+ type: "string",
366
+ description: "Natural language text describing what the user wants to do"
367
+ },
368
+ agentId: {
369
+ type: "string",
370
+ description: "Optional agent ID for context-aware intent parsing"
371
+ }
372
+ },
373
+ required: ["text"]
374
+ }
375
+ };
376
+ async function handleNaturalIntent(params) {
377
+ const parsed = naturalIntentSchema.parse(params);
378
+ const res = await apiPost("/api/intent", parsed);
379
+ if (!res.ok) {
380
+ return {
381
+ content: [{ type: "text", text: `API error ${res.status}: ${JSON.stringify(res.data)}` }],
382
+ isError: true
383
+ };
384
+ }
385
+ const r = res.data;
386
+ const text = [
387
+ `Intent: ${r.intent}`,
388
+ `Confidence: ${(r.confidence * 100).toFixed(0)}%`,
389
+ `Parameters: ${JSON.stringify(r.params, null, 2)}`,
390
+ r.suggestedAction ? `
391
+ Suggested action: ${r.suggestedAction}` : null
392
+ ].filter(Boolean).join("\n");
393
+ return { content: [{ type: "text", text }] };
394
+ }
395
+
396
+ // src/resources/match_data.ts
397
+ async function handleMatchData(matchId) {
398
+ const res = await apiGet(`/api/matches/${matchId}`);
399
+ if (!res.ok) {
400
+ return {
401
+ contents: [
402
+ {
403
+ uri: `xlayer://match/${matchId}`,
404
+ mimeType: "application/json",
405
+ text: JSON.stringify({ error: `API error ${res.status}`, details: res.data })
406
+ }
407
+ ]
408
+ };
409
+ }
410
+ return {
411
+ contents: [
412
+ {
413
+ uri: `xlayer://match/${matchId}`,
414
+ mimeType: "application/json",
415
+ text: JSON.stringify(res.data, null, 2)
416
+ }
417
+ ]
418
+ };
419
+ }
420
+
421
+ // src/resources/agent_strategies.ts
422
+ async function handleAgentStrategy(agentId) {
423
+ const res = await apiGet(`/api/agents/${agentId}/strategy`);
424
+ if (!res.ok) {
425
+ return {
426
+ contents: [
427
+ {
428
+ uri: `xlayer://agent/${agentId}/strategy`,
429
+ mimeType: "application/json",
430
+ text: JSON.stringify({ error: `API error ${res.status}`, details: res.data })
431
+ }
432
+ ]
433
+ };
434
+ }
435
+ return {
436
+ contents: [
437
+ {
438
+ uri: `xlayer://agent/${agentId}/strategy`,
439
+ mimeType: "application/json",
440
+ text: JSON.stringify(res.data, null, 2)
441
+ }
442
+ ]
443
+ };
444
+ }
445
+
446
+ // src/index.ts
447
+ var server = new Server(
448
+ { name: "scoutagent-xlayer", version: "0.1.0" },
449
+ {
450
+ capabilities: {
451
+ tools: {},
452
+ resources: {}
453
+ }
454
+ }
455
+ );
456
+ var TOOLS = [
457
+ listMarketsDef,
458
+ getMarketDef,
459
+ mintAgentDef,
460
+ placeBetDef,
461
+ getAgentStatsDef,
462
+ leaderboardDef,
463
+ naturalIntentDef
464
+ ];
465
+ var TOOL_HANDLERS = {
466
+ [listMarketsDef.name]: handleListMarkets,
467
+ [getMarketDef.name]: handleGetMarket,
468
+ [mintAgentDef.name]: handleMintAgent,
469
+ [placeBetDef.name]: handlePlaceBet,
470
+ [getAgentStatsDef.name]: handleGetAgentStats,
471
+ [leaderboardDef.name]: handleLeaderboard,
472
+ [naturalIntentDef.name]: handleNaturalIntent
473
+ };
474
+ var RESOURCE_TEMPLATES = [
475
+ {
476
+ uriTemplate: "xlayer://match/{matchId}",
477
+ name: "Match Data",
478
+ description: "Detailed match data including teams, date, venue, and statistics.",
479
+ mimeType: "application/json"
480
+ },
481
+ {
482
+ uriTemplate: "xlayer://agent/{agentId}/strategy",
483
+ name: "Agent Strategy Gene",
484
+ description: "Strategy gene configuration for an AI Scout Agent.",
485
+ mimeType: "application/json"
486
+ }
487
+ ];
488
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
489
+ return { tools: TOOLS };
490
+ });
491
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
492
+ const { name, arguments: args } = request.params;
493
+ const handler = TOOL_HANDLERS[name];
494
+ if (!handler) {
495
+ return {
496
+ content: [{ type: "text", text: `Unknown tool: ${name}` }],
497
+ isError: true
498
+ };
499
+ }
500
+ try {
501
+ return await handler(args ?? {});
502
+ } catch (err) {
503
+ const message = err instanceof Error ? err.message : String(err);
504
+ return {
505
+ content: [{ type: "text", text: `Error executing ${name}: ${message}` }],
506
+ isError: true
507
+ };
508
+ }
509
+ });
510
+ server.setRequestHandler(ListResourcesRequestSchema, async () => {
511
+ return { resources: [] };
512
+ });
513
+ server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => {
514
+ return { resourceTemplates: RESOURCE_TEMPLATES };
515
+ });
516
+ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
517
+ const { uri } = request.params;
518
+ const matchMatch = uri.match(/^xlayer:\/\/match\/(.+)$/);
519
+ if (matchMatch) {
520
+ return await handleMatchData(matchMatch[1]);
521
+ }
522
+ const strategyMatch = uri.match(/^xlayer:\/\/agent\/(.+)\/strategy$/);
523
+ if (strategyMatch) {
524
+ return await handleAgentStrategy(strategyMatch[1]);
525
+ }
526
+ return {
527
+ contents: [
528
+ {
529
+ uri,
530
+ mimeType: "text/plain",
531
+ text: `Unknown resource URI: ${uri}`
532
+ }
533
+ ]
534
+ };
535
+ });
536
+ async function main() {
537
+ const transport = new StdioServerTransport();
538
+ await server.connect(transport);
539
+ console.error("ScoutAgent MCP Server running on stdio");
540
+ }
541
+ main().catch((err) => {
542
+ console.error("Fatal error starting ScoutAgent MCP Server:", err);
543
+ process.exit(1);
544
+ });
package/package.json CHANGED
@@ -1,20 +1,70 @@
1
1
  {
2
2
  "name": "@scoutagent/mcp-server",
3
- "version": "1.0.8",
4
- "description": "MCP Server for ScoutAgent",
3
+ "version": "1.2.0",
4
+ "description": "MCP Server for ScoutAgent - AI Scout prediction market on X Layer",
5
+ "type": "module",
6
+ "main": "dist/index.cjs",
7
+ "module": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.js",
12
+ "require": "./dist/index.cjs",
13
+ "types": "./dist/index.d.ts"
14
+ }
15
+ },
5
16
  "bin": {
6
- "mcp-server": "./index.js"
17
+ "scoutagentmcp": "./dist/index.cjs"
7
18
  },
19
+ "files": [
20
+ "dist",
21
+ "README.md"
22
+ ],
8
23
  "scripts": {
9
- "test": "echo \"Error: no test specified\" && exit 1"
24
+ "build": "tsup src/index.ts --format esm,cjs --dts",
25
+ "dev": "tsx src/index.ts",
26
+ "lint": "tsc --noEmit",
27
+ "clean": "rm -rf dist",
28
+ "prepublishOnly": "npm run build"
10
29
  },
11
30
  "keywords": [
12
31
  "mcp",
13
- "scoutagent"
32
+ "model-context-protocol",
33
+ "scoutagent",
34
+ "prediction-market",
35
+ "xlayer",
36
+ "ai-agent",
37
+ "nft",
38
+ "okb",
39
+ "claude-desktop",
40
+ "cursor"
14
41
  ],
15
- "author": "",
16
- "license": "ISC",
42
+ "author": "ScoutAgent Team",
43
+ "license": "MIT",
44
+ "repository": {
45
+ "type": "git",
46
+ "url": "https://github.com/0xCaptain888/scout-agent.git",
47
+ "directory": "apps/mcp-server"
48
+ },
49
+ "homepage": "https://github.com/0xCaptain888/scout-agent/tree/main/apps/mcp-server#readme",
50
+ "bugs": {
51
+ "url": "https://github.com/0xCaptain888/scout-agent/issues"
52
+ },
53
+ "engines": {
54
+ "node": ">=20"
55
+ },
17
56
  "publishConfig": {
18
57
  "access": "public"
58
+ },
59
+ "dependencies": {
60
+ "@modelcontextprotocol/sdk": "^1.12.0",
61
+ "zod": "^3.24.0",
62
+ "node-fetch": "^3.3.0"
63
+ },
64
+ "devDependencies": {
65
+ "typescript": "^5.7.0",
66
+ "tsx": "^4.19.0",
67
+ "tsup": "^8.4.0",
68
+ "@types/node": "^22.0.0"
19
69
  }
20
- }
70
+ }
package/index.js DELETED
@@ -1,14 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- console.log("✅ @scoutagent/mcp-server 已启动");
4
- console.log("MCP Server for ScoutAgent");
5
-
6
- // 简单示例:接收命令行参数
7
- const args = process.argv.slice(2);
8
- if (args.length > 0) {
9
- console.log("收到参数:", args);
10
- } else {
11
- console.log("使用方法: npx @scoutagent/mcp-server [参数]");
12
- }
13
-
14
- // 这里以后可以添加真正的 MCP Server 逻辑