@scoutagent/mcp-server 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/README.md +211 -0
- package/dist/index.cjs +539 -0
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +544 -0
- package/package.json +70 -0
package/README.md
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# @scoutagent/mcp-server
|
|
2
|
+
|
|
3
|
+
[](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,539 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
// src/index.ts
|
|
5
|
+
var import_server = require("@modelcontextprotocol/sdk/server/index.js");
|
|
6
|
+
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
7
|
+
var import_types = require("@modelcontextprotocol/sdk/types.js");
|
|
8
|
+
|
|
9
|
+
// src/tools/list_markets.ts
|
|
10
|
+
var import_zod = require("zod");
|
|
11
|
+
|
|
12
|
+
// src/clients.ts
|
|
13
|
+
var BASE_URL = process.env.SCOUT_AGENT_API?.replace(/\/+$/, "") ?? "http://localhost:3001";
|
|
14
|
+
async function apiGet(path, query) {
|
|
15
|
+
const url = new URL(path, BASE_URL);
|
|
16
|
+
if (query) {
|
|
17
|
+
for (const [k, v] of Object.entries(query)) {
|
|
18
|
+
if (v !== void 0 && v !== "") url.searchParams.set(k, v);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
const res = await fetch(url.toString(), {
|
|
22
|
+
method: "GET",
|
|
23
|
+
headers: { Accept: "application/json" }
|
|
24
|
+
});
|
|
25
|
+
const data = await res.json();
|
|
26
|
+
return { ok: res.ok, status: res.status, data };
|
|
27
|
+
}
|
|
28
|
+
async function apiPost(path, body) {
|
|
29
|
+
const res = await fetch(new URL(path, BASE_URL).toString(), {
|
|
30
|
+
method: "POST",
|
|
31
|
+
headers: {
|
|
32
|
+
"Content-Type": "application/json",
|
|
33
|
+
Accept: "application/json"
|
|
34
|
+
},
|
|
35
|
+
body: JSON.stringify(body)
|
|
36
|
+
});
|
|
37
|
+
const data = await res.json();
|
|
38
|
+
return { ok: res.ok, status: res.status, data };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// src/tools/list_markets.ts
|
|
42
|
+
var listMarketsSchema = import_zod.z.object({
|
|
43
|
+
status: import_zod.z.enum(["OPEN", "LOCKED", "RESOLVED"]).optional().describe("Filter by market status"),
|
|
44
|
+
matchDateFrom: import_zod.z.string().optional().describe("Filter matches from this date (ISO 8601)"),
|
|
45
|
+
matchDateTo: import_zod.z.string().optional().describe("Filter matches up to this date (ISO 8601)")
|
|
46
|
+
});
|
|
47
|
+
var listMarketsDef = {
|
|
48
|
+
name: "xlayer_list_markets",
|
|
49
|
+
description: "List all ScoutAgent prediction markets on X Layer. Optionally filter by status or match date range.",
|
|
50
|
+
inputSchema: {
|
|
51
|
+
type: "object",
|
|
52
|
+
properties: {
|
|
53
|
+
status: {
|
|
54
|
+
type: "string",
|
|
55
|
+
enum: ["OPEN", "LOCKED", "RESOLVED"],
|
|
56
|
+
description: "Filter by market status"
|
|
57
|
+
},
|
|
58
|
+
matchDateFrom: {
|
|
59
|
+
type: "string",
|
|
60
|
+
description: "Filter matches from this date (ISO 8601)"
|
|
61
|
+
},
|
|
62
|
+
matchDateTo: {
|
|
63
|
+
type: "string",
|
|
64
|
+
description: "Filter matches up to this date (ISO 8601)"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
async function handleListMarkets(params) {
|
|
70
|
+
const parsed = listMarketsSchema.parse(params);
|
|
71
|
+
const res = await apiGet("/api/markets", {
|
|
72
|
+
status: parsed.status,
|
|
73
|
+
matchDateFrom: parsed.matchDateFrom,
|
|
74
|
+
matchDateTo: parsed.matchDateTo
|
|
75
|
+
});
|
|
76
|
+
if (!res.ok) {
|
|
77
|
+
return {
|
|
78
|
+
content: [{ type: "text", text: `API error ${res.status}: ${JSON.stringify(res.data)}` }],
|
|
79
|
+
isError: true
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const markets = res.data;
|
|
83
|
+
const summary = markets.map(
|
|
84
|
+
(m) => `[${m.id}] ${m.homeTeam} vs ${m.awayTeam} | ${m.matchDate} | ${m.status} | Pool: ${m.totalPool}`
|
|
85
|
+
);
|
|
86
|
+
return {
|
|
87
|
+
content: [
|
|
88
|
+
{
|
|
89
|
+
type: "text",
|
|
90
|
+
text: markets.length === 0 ? "No markets found matching the criteria." : `Found ${markets.length} market(s):
|
|
91
|
+
|
|
92
|
+
${summary.join("\n")}`
|
|
93
|
+
}
|
|
94
|
+
]
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// src/tools/get_market.ts
|
|
99
|
+
var import_zod2 = require("zod");
|
|
100
|
+
var getMarketSchema = import_zod2.z.object({
|
|
101
|
+
marketId: import_zod2.z.string().describe("The market ID to look up")
|
|
102
|
+
});
|
|
103
|
+
var getMarketDef = {
|
|
104
|
+
name: "xlayer_get_market",
|
|
105
|
+
description: "Get detailed information about a single ScoutAgent prediction market on X Layer, including odds and pool size.",
|
|
106
|
+
inputSchema: {
|
|
107
|
+
type: "object",
|
|
108
|
+
properties: {
|
|
109
|
+
marketId: {
|
|
110
|
+
type: "string",
|
|
111
|
+
description: "The market ID to look up"
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
required: ["marketId"]
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
async function handleGetMarket(params) {
|
|
118
|
+
const { marketId } = getMarketSchema.parse(params);
|
|
119
|
+
const res = await apiGet(`/api/markets/${marketId}`);
|
|
120
|
+
if (!res.ok) {
|
|
121
|
+
return {
|
|
122
|
+
content: [{ type: "text", text: `API error ${res.status}: ${JSON.stringify(res.data)}` }],
|
|
123
|
+
isError: true
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
const m = res.data;
|
|
127
|
+
const text = [
|
|
128
|
+
`Market: ${m.id}`,
|
|
129
|
+
`Match: ${m.homeTeam} vs ${m.awayTeam}`,
|
|
130
|
+
`Date: ${m.matchDate}`,
|
|
131
|
+
`Status: ${m.status}`,
|
|
132
|
+
`Odds: Home ${m.odds.home} | Draw ${m.odds.draw} | Away ${m.odds.away}`,
|
|
133
|
+
`Total Pool: ${m.totalPool}`,
|
|
134
|
+
m.resolvedOutcome ? `Resolved Outcome: ${m.resolvedOutcome}` : null
|
|
135
|
+
].filter(Boolean).join("\n");
|
|
136
|
+
return { content: [{ type: "text", text }] };
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// src/tools/mint_agent.ts
|
|
140
|
+
var import_zod3 = require("zod");
|
|
141
|
+
var mintAgentSchema = import_zod3.z.object({
|
|
142
|
+
riskLevel: import_zod3.z.number().int().min(1).max(5).describe("Risk appetite from 1 (conservative) to 5 (degen)"),
|
|
143
|
+
style: import_zod3.z.enum(["ATTACKING", "DEFENSIVE", "DATA_DRIVEN", "CONTRARIAN", "MOMENTUM"]).describe("Betting strategy style"),
|
|
144
|
+
bankrollPct: import_zod3.z.number().min(1).max(100).describe("Percentage of bankroll to use per bet (1-100)"),
|
|
145
|
+
favoriteTeams: import_zod3.z.array(import_zod3.z.string()).optional().default([]).describe("Optional list of favorite team names for bias weighting")
|
|
146
|
+
});
|
|
147
|
+
var mintAgentDef = {
|
|
148
|
+
name: "xlayer_mint_agent",
|
|
149
|
+
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.",
|
|
150
|
+
inputSchema: {
|
|
151
|
+
type: "object",
|
|
152
|
+
properties: {
|
|
153
|
+
riskLevel: {
|
|
154
|
+
type: "number",
|
|
155
|
+
minimum: 1,
|
|
156
|
+
maximum: 5,
|
|
157
|
+
description: "Risk appetite from 1 (conservative) to 5 (degen)"
|
|
158
|
+
},
|
|
159
|
+
style: {
|
|
160
|
+
type: "string",
|
|
161
|
+
enum: ["ATTACKING", "DEFENSIVE", "DATA_DRIVEN", "CONTRARIAN", "MOMENTUM"],
|
|
162
|
+
description: "Betting strategy style"
|
|
163
|
+
},
|
|
164
|
+
bankrollPct: {
|
|
165
|
+
type: "number",
|
|
166
|
+
minimum: 1,
|
|
167
|
+
maximum: 100,
|
|
168
|
+
description: "Percentage of bankroll to use per bet (1-100)"
|
|
169
|
+
},
|
|
170
|
+
favoriteTeams: {
|
|
171
|
+
type: "array",
|
|
172
|
+
items: { type: "string" },
|
|
173
|
+
description: "Optional list of favorite team names for bias weighting"
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
required: ["riskLevel", "style", "bankrollPct"]
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
async function handleMintAgent(params) {
|
|
180
|
+
const parsed = mintAgentSchema.parse(params);
|
|
181
|
+
const res = await apiPost("/api/agents/mint", parsed);
|
|
182
|
+
if (!res.ok) {
|
|
183
|
+
return {
|
|
184
|
+
content: [{ type: "text", text: `API error ${res.status}: ${JSON.stringify(res.data)}` }],
|
|
185
|
+
isError: true
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
const a = res.data;
|
|
189
|
+
const text = [
|
|
190
|
+
`Agent minted successfully!`,
|
|
191
|
+
`Agent ID: ${a.agentId}`,
|
|
192
|
+
`Token ID: ${a.tokenId}`,
|
|
193
|
+
`Wallet: ${a.walletAddress}`,
|
|
194
|
+
`Style: ${a.style} | Risk: ${a.riskLevel} | Bankroll%: ${a.bankrollPct}`,
|
|
195
|
+
a.favoriteTeams.length > 0 ? `Favorite Teams: ${a.favoriteTeams.join(", ")}` : null
|
|
196
|
+
].filter(Boolean).join("\n");
|
|
197
|
+
return { content: [{ type: "text", text }] };
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// src/tools/place_bet.ts
|
|
201
|
+
var import_zod4 = require("zod");
|
|
202
|
+
var placeBetSchema = import_zod4.z.object({
|
|
203
|
+
agentId: import_zod4.z.string().describe("The agent ID placing the bet"),
|
|
204
|
+
marketId: import_zod4.z.string().describe("The market ID to bet on"),
|
|
205
|
+
outcome: import_zod4.z.enum(["HOME", "DRAW", "AWAY"]).describe("Predicted outcome: HOME, DRAW, or AWAY"),
|
|
206
|
+
amount: import_zod4.z.string().describe("Bet amount in OKB (as a decimal string, e.g. '0.5')")
|
|
207
|
+
});
|
|
208
|
+
var placeBetDef = {
|
|
209
|
+
name: "xlayer_place_bet",
|
|
210
|
+
description: "Place a bet on a ScoutAgent prediction market on X Layer using an AI Scout Agent. Returns the transaction hash and explorer URL.",
|
|
211
|
+
inputSchema: {
|
|
212
|
+
type: "object",
|
|
213
|
+
properties: {
|
|
214
|
+
agentId: {
|
|
215
|
+
type: "string",
|
|
216
|
+
description: "The agent ID placing the bet"
|
|
217
|
+
},
|
|
218
|
+
marketId: {
|
|
219
|
+
type: "string",
|
|
220
|
+
description: "The market ID to bet on"
|
|
221
|
+
},
|
|
222
|
+
outcome: {
|
|
223
|
+
type: "string",
|
|
224
|
+
enum: ["HOME", "DRAW", "AWAY"],
|
|
225
|
+
description: "Predicted outcome: HOME, DRAW, or AWAY"
|
|
226
|
+
},
|
|
227
|
+
amount: {
|
|
228
|
+
type: "string",
|
|
229
|
+
description: "Bet amount in OKB (as a decimal string, e.g. '0.5')"
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
required: ["agentId", "marketId", "outcome", "amount"]
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
async function handlePlaceBet(params) {
|
|
236
|
+
const parsed = placeBetSchema.parse(params);
|
|
237
|
+
const res = await apiPost("/api/bets", parsed);
|
|
238
|
+
if (!res.ok) {
|
|
239
|
+
return {
|
|
240
|
+
content: [{ type: "text", text: `API error ${res.status}: ${JSON.stringify(res.data)}` }],
|
|
241
|
+
isError: true
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
const b = res.data;
|
|
245
|
+
const text = [
|
|
246
|
+
`Bet placed successfully!`,
|
|
247
|
+
`Tx Hash: ${b.txHash}`,
|
|
248
|
+
`Explorer: ${b.explorerUrl}`,
|
|
249
|
+
`Market: ${b.marketId} | Outcome: ${b.outcome} | Amount: ${b.amount}`,
|
|
250
|
+
`Estimated Payout: ${b.estimatedPayout}`
|
|
251
|
+
].join("\n");
|
|
252
|
+
return { content: [{ type: "text", text }] };
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// src/tools/get_agent_stats.ts
|
|
256
|
+
var import_zod5 = require("zod");
|
|
257
|
+
var getAgentStatsSchema = import_zod5.z.object({
|
|
258
|
+
agentId: import_zod5.z.string().describe("The agent ID to get statistics for")
|
|
259
|
+
});
|
|
260
|
+
var getAgentStatsDef = {
|
|
261
|
+
name: "xlayer_get_agent_stats",
|
|
262
|
+
description: "Get performance statistics for an AI Scout Agent on X Layer, including win rate, PnL, ROI, and streak.",
|
|
263
|
+
inputSchema: {
|
|
264
|
+
type: "object",
|
|
265
|
+
properties: {
|
|
266
|
+
agentId: {
|
|
267
|
+
type: "string",
|
|
268
|
+
description: "The agent ID to get statistics for"
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
required: ["agentId"]
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
async function handleGetAgentStats(params) {
|
|
275
|
+
const { agentId } = getAgentStatsSchema.parse(params);
|
|
276
|
+
const res = await apiGet(`/api/agents/${agentId}/stats`);
|
|
277
|
+
if (!res.ok) {
|
|
278
|
+
return {
|
|
279
|
+
content: [{ type: "text", text: `API error ${res.status}: ${JSON.stringify(res.data)}` }],
|
|
280
|
+
isError: true
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
const s = res.data;
|
|
284
|
+
const text = [
|
|
285
|
+
`Agent ${s.agentId} Stats`,
|
|
286
|
+
`\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`,
|
|
287
|
+
`Record: ${s.wins}W / ${s.losses}L / ${s.draws}D (${s.totalBets} total bets)`,
|
|
288
|
+
`Win Rate: ${(s.winRate * 100).toFixed(1)}%`,
|
|
289
|
+
`Total PnL: ${s.totalPnl} OKB`,
|
|
290
|
+
`ROI: ${(s.roi * 100).toFixed(1)}%`,
|
|
291
|
+
`Current Streak: ${s.streak > 0 ? `${s.streak}W` : s.streak < 0 ? `${Math.abs(s.streak)}L` : "0"}`
|
|
292
|
+
].join("\n");
|
|
293
|
+
return { content: [{ type: "text", text }] };
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// src/tools/leaderboard.ts
|
|
297
|
+
var import_zod6 = require("zod");
|
|
298
|
+
var leaderboardSchema = import_zod6.z.object({
|
|
299
|
+
top: import_zod6.z.number().int().min(1).max(100).optional().default(10).describe("Number of top agents to return (default 10)"),
|
|
300
|
+
period: import_zod6.z.enum(["24h", "7d", "all"]).optional().describe("Leaderboard time period: 24h, 7d, or all")
|
|
301
|
+
});
|
|
302
|
+
var leaderboardDef = {
|
|
303
|
+
name: "xlayer_leaderboard",
|
|
304
|
+
description: "Get the ScoutAgent leaderboard on X Layer, ranked by PnL. Filter by time period.",
|
|
305
|
+
inputSchema: {
|
|
306
|
+
type: "object",
|
|
307
|
+
properties: {
|
|
308
|
+
top: {
|
|
309
|
+
type: "number",
|
|
310
|
+
minimum: 1,
|
|
311
|
+
maximum: 100,
|
|
312
|
+
description: "Number of top agents to return (default 10)"
|
|
313
|
+
},
|
|
314
|
+
period: {
|
|
315
|
+
type: "string",
|
|
316
|
+
enum: ["24h", "7d", "all"],
|
|
317
|
+
description: "Leaderboard time period: 24h, 7d, or all"
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
async function handleLeaderboard(params) {
|
|
323
|
+
const parsed = leaderboardSchema.parse(params);
|
|
324
|
+
const res = await apiGet("/api/leaderboard", {
|
|
325
|
+
top: String(parsed.top),
|
|
326
|
+
period: parsed.period
|
|
327
|
+
});
|
|
328
|
+
if (!res.ok) {
|
|
329
|
+
return {
|
|
330
|
+
content: [{ type: "text", text: `API error ${res.status}: ${JSON.stringify(res.data)}` }],
|
|
331
|
+
isError: true
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
const entries = res.data;
|
|
335
|
+
if (entries.length === 0) {
|
|
336
|
+
return { content: [{ type: "text", text: "Leaderboard is empty." }] };
|
|
337
|
+
}
|
|
338
|
+
const header = `ScoutAgent Leaderboard${parsed.period ? ` (${parsed.period})` : ""}
|
|
339
|
+
${"\u2550".repeat(50)}`;
|
|
340
|
+
const rows = entries.map(
|
|
341
|
+
(e) => `#${e.rank} | Agent ${e.agentId} | PnL: ${e.pnl} OKB | WR: ${(e.winRate * 100).toFixed(1)}% | ${e.totalBets} bets | ${e.style}`
|
|
342
|
+
);
|
|
343
|
+
return { content: [{ type: "text", text: `${header}
|
|
344
|
+
${rows.join("\n")}` }] };
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// src/tools/natural_intent.ts
|
|
348
|
+
var import_zod7 = require("zod");
|
|
349
|
+
var naturalIntentSchema = import_zod7.z.object({
|
|
350
|
+
text: import_zod7.z.string().describe("Natural language text describing what the user wants to do"),
|
|
351
|
+
agentId: import_zod7.z.string().optional().describe("Optional agent ID for context-aware intent parsing")
|
|
352
|
+
});
|
|
353
|
+
var naturalIntentDef = {
|
|
354
|
+
name: "xlayer_natural_intent",
|
|
355
|
+
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.',
|
|
356
|
+
inputSchema: {
|
|
357
|
+
type: "object",
|
|
358
|
+
properties: {
|
|
359
|
+
text: {
|
|
360
|
+
type: "string",
|
|
361
|
+
description: "Natural language text describing what the user wants to do"
|
|
362
|
+
},
|
|
363
|
+
agentId: {
|
|
364
|
+
type: "string",
|
|
365
|
+
description: "Optional agent ID for context-aware intent parsing"
|
|
366
|
+
}
|
|
367
|
+
},
|
|
368
|
+
required: ["text"]
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
async function handleNaturalIntent(params) {
|
|
372
|
+
const parsed = naturalIntentSchema.parse(params);
|
|
373
|
+
const res = await apiPost("/api/intent", parsed);
|
|
374
|
+
if (!res.ok) {
|
|
375
|
+
return {
|
|
376
|
+
content: [{ type: "text", text: `API error ${res.status}: ${JSON.stringify(res.data)}` }],
|
|
377
|
+
isError: true
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
const r = res.data;
|
|
381
|
+
const text = [
|
|
382
|
+
`Intent: ${r.intent}`,
|
|
383
|
+
`Confidence: ${(r.confidence * 100).toFixed(0)}%`,
|
|
384
|
+
`Parameters: ${JSON.stringify(r.params, null, 2)}`,
|
|
385
|
+
r.suggestedAction ? `
|
|
386
|
+
Suggested action: ${r.suggestedAction}` : null
|
|
387
|
+
].filter(Boolean).join("\n");
|
|
388
|
+
return { content: [{ type: "text", text }] };
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// src/resources/match_data.ts
|
|
392
|
+
async function handleMatchData(matchId) {
|
|
393
|
+
const res = await apiGet(`/api/matches/${matchId}`);
|
|
394
|
+
if (!res.ok) {
|
|
395
|
+
return {
|
|
396
|
+
contents: [
|
|
397
|
+
{
|
|
398
|
+
uri: `xlayer://match/${matchId}`,
|
|
399
|
+
mimeType: "application/json",
|
|
400
|
+
text: JSON.stringify({ error: `API error ${res.status}`, details: res.data })
|
|
401
|
+
}
|
|
402
|
+
]
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
return {
|
|
406
|
+
contents: [
|
|
407
|
+
{
|
|
408
|
+
uri: `xlayer://match/${matchId}`,
|
|
409
|
+
mimeType: "application/json",
|
|
410
|
+
text: JSON.stringify(res.data, null, 2)
|
|
411
|
+
}
|
|
412
|
+
]
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// src/resources/agent_strategies.ts
|
|
417
|
+
async function handleAgentStrategy(agentId) {
|
|
418
|
+
const res = await apiGet(`/api/agents/${agentId}/strategy`);
|
|
419
|
+
if (!res.ok) {
|
|
420
|
+
return {
|
|
421
|
+
contents: [
|
|
422
|
+
{
|
|
423
|
+
uri: `xlayer://agent/${agentId}/strategy`,
|
|
424
|
+
mimeType: "application/json",
|
|
425
|
+
text: JSON.stringify({ error: `API error ${res.status}`, details: res.data })
|
|
426
|
+
}
|
|
427
|
+
]
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
return {
|
|
431
|
+
contents: [
|
|
432
|
+
{
|
|
433
|
+
uri: `xlayer://agent/${agentId}/strategy`,
|
|
434
|
+
mimeType: "application/json",
|
|
435
|
+
text: JSON.stringify(res.data, null, 2)
|
|
436
|
+
}
|
|
437
|
+
]
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// src/index.ts
|
|
442
|
+
var server = new import_server.Server(
|
|
443
|
+
{ name: "scoutagent-xlayer", version: "0.1.0" },
|
|
444
|
+
{
|
|
445
|
+
capabilities: {
|
|
446
|
+
tools: {},
|
|
447
|
+
resources: {}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
);
|
|
451
|
+
var TOOLS = [
|
|
452
|
+
listMarketsDef,
|
|
453
|
+
getMarketDef,
|
|
454
|
+
mintAgentDef,
|
|
455
|
+
placeBetDef,
|
|
456
|
+
getAgentStatsDef,
|
|
457
|
+
leaderboardDef,
|
|
458
|
+
naturalIntentDef
|
|
459
|
+
];
|
|
460
|
+
var TOOL_HANDLERS = {
|
|
461
|
+
[listMarketsDef.name]: handleListMarkets,
|
|
462
|
+
[getMarketDef.name]: handleGetMarket,
|
|
463
|
+
[mintAgentDef.name]: handleMintAgent,
|
|
464
|
+
[placeBetDef.name]: handlePlaceBet,
|
|
465
|
+
[getAgentStatsDef.name]: handleGetAgentStats,
|
|
466
|
+
[leaderboardDef.name]: handleLeaderboard,
|
|
467
|
+
[naturalIntentDef.name]: handleNaturalIntent
|
|
468
|
+
};
|
|
469
|
+
var RESOURCE_TEMPLATES = [
|
|
470
|
+
{
|
|
471
|
+
uriTemplate: "xlayer://match/{matchId}",
|
|
472
|
+
name: "Match Data",
|
|
473
|
+
description: "Detailed match data including teams, date, venue, and statistics.",
|
|
474
|
+
mimeType: "application/json"
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
uriTemplate: "xlayer://agent/{agentId}/strategy",
|
|
478
|
+
name: "Agent Strategy Gene",
|
|
479
|
+
description: "Strategy gene configuration for an AI Scout Agent.",
|
|
480
|
+
mimeType: "application/json"
|
|
481
|
+
}
|
|
482
|
+
];
|
|
483
|
+
server.setRequestHandler(import_types.ListToolsRequestSchema, async () => {
|
|
484
|
+
return { tools: TOOLS };
|
|
485
|
+
});
|
|
486
|
+
server.setRequestHandler(import_types.CallToolRequestSchema, async (request) => {
|
|
487
|
+
const { name, arguments: args } = request.params;
|
|
488
|
+
const handler = TOOL_HANDLERS[name];
|
|
489
|
+
if (!handler) {
|
|
490
|
+
return {
|
|
491
|
+
content: [{ type: "text", text: `Unknown tool: ${name}` }],
|
|
492
|
+
isError: true
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
try {
|
|
496
|
+
return await handler(args ?? {});
|
|
497
|
+
} catch (err) {
|
|
498
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
499
|
+
return {
|
|
500
|
+
content: [{ type: "text", text: `Error executing ${name}: ${message}` }],
|
|
501
|
+
isError: true
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
});
|
|
505
|
+
server.setRequestHandler(import_types.ListResourcesRequestSchema, async () => {
|
|
506
|
+
return { resources: [] };
|
|
507
|
+
});
|
|
508
|
+
server.setRequestHandler(import_types.ListResourceTemplatesRequestSchema, async () => {
|
|
509
|
+
return { resourceTemplates: RESOURCE_TEMPLATES };
|
|
510
|
+
});
|
|
511
|
+
server.setRequestHandler(import_types.ReadResourceRequestSchema, async (request) => {
|
|
512
|
+
const { uri } = request.params;
|
|
513
|
+
const matchMatch = uri.match(/^xlayer:\/\/match\/(.+)$/);
|
|
514
|
+
if (matchMatch) {
|
|
515
|
+
return await handleMatchData(matchMatch[1]);
|
|
516
|
+
}
|
|
517
|
+
const strategyMatch = uri.match(/^xlayer:\/\/agent\/(.+)\/strategy$/);
|
|
518
|
+
if (strategyMatch) {
|
|
519
|
+
return await handleAgentStrategy(strategyMatch[1]);
|
|
520
|
+
}
|
|
521
|
+
return {
|
|
522
|
+
contents: [
|
|
523
|
+
{
|
|
524
|
+
uri,
|
|
525
|
+
mimeType: "text/plain",
|
|
526
|
+
text: `Unknown resource URI: ${uri}`
|
|
527
|
+
}
|
|
528
|
+
]
|
|
529
|
+
};
|
|
530
|
+
});
|
|
531
|
+
async function main() {
|
|
532
|
+
const transport = new import_stdio.StdioServerTransport();
|
|
533
|
+
await server.connect(transport);
|
|
534
|
+
console.error("ScoutAgent MCP Server running on stdio");
|
|
535
|
+
}
|
|
536
|
+
main().catch((err) => {
|
|
537
|
+
console.error("Fatal error starting ScoutAgent MCP Server:", err);
|
|
538
|
+
process.exit(1);
|
|
539
|
+
});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/index.d.ts
ADDED
|
@@ -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
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@scoutagent/mcp-server",
|
|
3
|
+
"version": "0.1.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
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"bin": {
|
|
17
|
+
"scoutagent-mcp": "./dist/index.js"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist/",
|
|
21
|
+
"README.md"
|
|
22
|
+
],
|
|
23
|
+
"scripts": {
|
|
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"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"mcp",
|
|
32
|
+
"model-context-protocol",
|
|
33
|
+
"scoutagent",
|
|
34
|
+
"prediction-market",
|
|
35
|
+
"xlayer",
|
|
36
|
+
"ai-agent",
|
|
37
|
+
"nft",
|
|
38
|
+
"okb",
|
|
39
|
+
"claude-desktop",
|
|
40
|
+
"cursor"
|
|
41
|
+
],
|
|
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
|
+
},
|
|
56
|
+
"publishConfig": {
|
|
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"
|
|
69
|
+
}
|
|
70
|
+
}
|