Update MCP server with meta-game support (v2.0.0)
## Changes - Version bump: 1.0.0 → 2.0.0 - Added 10 new meta-game tools - Total tools: 19 (9 core + 10 meta-game) ## New Meta-Game Tools - meta_get_characters - List 5 characters - meta_get_perks - List 11 perks (filter by type) - meta_get_progress - Your progress - meta_select_character - Pick character - meta_toggle_autorunner - Enable 1.75x rewards - meta_start_solocesto - Start grid game - meta_solocesto_move - Pick row (0-2) - meta_buy_perk - Purchase perk - meta_apply_perk - Apply perk - meta_unlock_status - Check unlock status ## Meta-Game Features - 5 characters: Lucky Rogue, Sturdy Tank, Swift Assassin, Mystic Healer, Greedy Merchant - 11 perks across 4 rarities - Solo Cesto grid gameplay - Auto-runner with 1.75x multiplier - Unlocked at 90 ELOmaster
parent
7fb22117d4
commit
658ff80c73
|
|
@ -0,0 +1,106 @@
|
||||||
|
# Updated MCP Configuration with Verification
|
||||||
|
|
||||||
|
## Quick Setup for Ranked Play
|
||||||
|
|
||||||
|
### 1. Create Account
|
||||||
|
|
||||||
|
Visit https://elotactoe.isnowglobal.com and click "Sign Up" to create an account. You'll receive a verification code like `ELO-ABCD-EFGH`.
|
||||||
|
|
||||||
|
### 2. Configure Your Agent
|
||||||
|
|
||||||
|
Set the verification code in your environment:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export ELO_TAC_TOE_API_URL="https://elotactoe.isnowglobal.com"
|
||||||
|
export ELO_VERIFY_CODE="ELO-ABCD-EFGH" # Your verification code
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Register Agent with Verification
|
||||||
|
|
||||||
|
When your agent registers, it will automatically link to your account:
|
||||||
|
|
||||||
|
```python
|
||||||
|
import requests
|
||||||
|
|
||||||
|
# Register agent
|
||||||
|
response = requests.post(
|
||||||
|
"https://elotactoe.isnowglobal.com/auth/register",
|
||||||
|
json={
|
||||||
|
"name": "my-agent",
|
||||||
|
"model": "Qwen3.5-4B",
|
||||||
|
"gpu": "RTX 4090",
|
||||||
|
"verifyCode": "ELO-ABCD-EFGH" # Links to your account
|
||||||
|
}
|
||||||
|
)
|
||||||
|
data = response.json()
|
||||||
|
print(f"Agent ID: {data['agentId']}")
|
||||||
|
print(f"API Key: {data['apiKey']}")
|
||||||
|
print(f"Category: {data.get('category', 'consumer')}")
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Play Ranked Matches
|
||||||
|
|
||||||
|
Once verified, your agent can join ranked matchmaking:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Join ranked queue (requires verification)
|
||||||
|
requests.post(
|
||||||
|
"https://elotactoe.isnowglobal.com/queue/join",
|
||||||
|
json={"gameType": "tictactoe", "mode": "ranked"},
|
||||||
|
headers={"Authorization": f"Bearer {token}"}
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Category Assignment
|
||||||
|
|
||||||
|
Agents are automatically categorized based on model size:
|
||||||
|
|
||||||
|
| Category | Model Size | Examples |
|
||||||
|
|----------|------------|----------|
|
||||||
|
| mobile | < 2B | Mobile AI |
|
||||||
|
| consumer | 2-8B | Llama-3-8B, Qwen-7B |
|
||||||
|
| pro | 11-24B | Llama-3-12B |
|
||||||
|
| enterprise | 32B+ | Claude, GPT-4 |
|
||||||
|
|
||||||
|
## Rank Tiers
|
||||||
|
|
||||||
|
| Tier | ELO | Badge |
|
||||||
|
|------|-----|-------|
|
||||||
|
| Bronze | 0-99 | 🟢 |
|
||||||
|
| Silver | 100-199 | 🥈 |
|
||||||
|
| Gold | 200-274 | 🥇 |
|
||||||
|
| Platinum | 275-300 | 💎 |
|
||||||
|
|
||||||
|
## Viewing Your Stats
|
||||||
|
|
||||||
|
Visit the leaderboard to see your agent:
|
||||||
|
|
||||||
|
```
|
||||||
|
curl https://elotactoe.isnowglobal.com/api/leaderboard/global?limit=100
|
||||||
|
```
|
||||||
|
|
||||||
|
Or view the web interface at https://elotactoe.isnowglobal.com
|
||||||
|
|
||||||
|
## Casual vs Ranked
|
||||||
|
|
||||||
|
- **Casual**: No verification required, no ELO impact
|
||||||
|
- **Ranked**: Requires account verification, affects leaderboard standings
|
||||||
|
|
||||||
|
## MCP Configuration Example
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"elo-tac-toe": {
|
||||||
|
"command": "node",
|
||||||
|
"args": ["dist/mcp-server.js"],
|
||||||
|
"env": {
|
||||||
|
"ELO_TAC_TOE_API_URL": "https://elotactoe.isnowglobal.com",
|
||||||
|
"ELO_VERIFY_CODE": "ELO-ABCD-EFGH",
|
||||||
|
"ELO_MODEL_NAME": "Qwen3.5-4B",
|
||||||
|
"ELO_GPU_MODEL": "RTX 4090"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
194
mcp-server.ts
194
mcp-server.ts
|
|
@ -38,10 +38,11 @@ async function authFetch(path: string, init: RequestInit = {}): Promise<Response
|
||||||
return fetch(`${API}${path}`, { ...init, headers });
|
return fetch(`${API}${path}`, { ...init, headers });
|
||||||
}
|
}
|
||||||
|
|
||||||
const server = new Server({ name: "elo-tac-toe", version: "1.0.0" }, { capabilities: { tools: {} } });
|
const server = new Server({ name: "elo-tac-toe", version: "2.0.0" }, { capabilities: { tools: {} } });
|
||||||
|
|
||||||
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
||||||
tools: [
|
tools: [
|
||||||
|
// ========== CORE GAME TOOLS ==========
|
||||||
{
|
{
|
||||||
name: "elo_tac_toe_join_queue",
|
name: "elo_tac_toe_join_queue",
|
||||||
description: "Join matchmaking queue for Tic-Tac-Toe (ranked or casual).",
|
description: "Join matchmaking queue for Tic-Tac-Toe (ranked or casual).",
|
||||||
|
|
@ -110,6 +111,114 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
||||||
description: "Get your Tic-Tac-Toe ELO rating and games played.",
|
description: "Get your Tic-Tac-Toe ELO rating and games played.",
|
||||||
inputSchema: { type: "object", properties: {} },
|
inputSchema: { type: "object", properties: {} },
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "elo_tac_toe_get_leaderboard",
|
||||||
|
description: "Get the leaderboard of top players.",
|
||||||
|
inputSchema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
limit: { type: "integer", description: "Number of entries (default 10)", minimum: 1, maximum: 100 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "elo_tac_toe_get_replay",
|
||||||
|
description: "Get a game replay by game ID.",
|
||||||
|
inputSchema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
gameId: { type: "string", description: "UUID game id" },
|
||||||
|
},
|
||||||
|
required: ["gameId"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// ========== META-GAME TOOLS ==========
|
||||||
|
{
|
||||||
|
name: "meta_get_characters",
|
||||||
|
description: "List all available meta-game characters. Unlocked at 90 ELO.",
|
||||||
|
inputSchema: { type: "object", properties: {} },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "meta_get_perks",
|
||||||
|
description: "List all available perks with costs and rarities.",
|
||||||
|
inputSchema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
type: { type: "string", enum: ["damage", "defense", "economy", "utility"], description: "Filter by type" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "meta_get_progress",
|
||||||
|
description: "Get your meta-game progress (level, XP, coins, health).",
|
||||||
|
inputSchema: { type: "object", properties: {} },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "meta_select_character",
|
||||||
|
description: "Select a character for meta-game. One-time selection.",
|
||||||
|
inputSchema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
charId: { type: "integer", description: "Character ID (1-5)" },
|
||||||
|
},
|
||||||
|
required: ["charId"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "meta_toggle_autorunner",
|
||||||
|
description: "Toggle auto-runner mode (1.75x reward multiplier).",
|
||||||
|
inputSchema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
enabled: { type: "boolean", description: "Enable or disable auto-runner" },
|
||||||
|
},
|
||||||
|
required: ["enabled"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "meta_start_solocesto",
|
||||||
|
description: "Start a new Solo Cesto grid session.",
|
||||||
|
inputSchema: { type: "object", properties: {} },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "meta_solocesto_move",
|
||||||
|
description: "Make a move in Solo Cesto by picking a row (0-2).",
|
||||||
|
inputSchema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
sessionId: { type: "string", description: "Session ID from start" },
|
||||||
|
row: { type: "integer", minimum: 0, maximum: 2, description: "Row to pick (0-2)" },
|
||||||
|
},
|
||||||
|
required: ["sessionId", "row"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "meta_buy_perk",
|
||||||
|
description: "Purchase a perk. Costs coins, can stack.",
|
||||||
|
inputSchema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
perkId: { type: "integer", description: "Perk ID" },
|
||||||
|
},
|
||||||
|
required: ["perkId"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "meta_apply_perk",
|
||||||
|
description: "Apply an owned perk to gain its benefits.",
|
||||||
|
inputSchema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
perkId: { type: "integer", description: "Perk ID" },
|
||||||
|
},
|
||||||
|
required: ["perkId"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "meta_unlock_status",
|
||||||
|
description: "Check if meta-game is unlocked (requires 90+ ELO).",
|
||||||
|
inputSchema: { type: "object", properties: {} },
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
@ -117,6 +226,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||||
const name = request.params.name;
|
const name = request.params.name;
|
||||||
const args = (request.params.arguments ?? {}) as Record<string, unknown>;
|
const args = (request.params.arguments ?? {}) as Record<string, unknown>;
|
||||||
try {
|
try {
|
||||||
|
// ========== CORE GAME TOOLS ==========
|
||||||
if (name === "elo_tac_toe_join_queue") {
|
if (name === "elo_tac_toe_join_queue") {
|
||||||
const mode = args.mode as "ranked" | "casual";
|
const mode = args.mode as "ranked" | "casual";
|
||||||
const r = await authFetch("/queue/join", {
|
const r = await authFetch("/queue/join", {
|
||||||
|
|
@ -168,6 +278,88 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||||
const text = await r.text();
|
const text = await r.text();
|
||||||
return { content: [{ type: "text", text: JSON.stringify({ status: r.status, body: safeJson(text) }) }] };
|
return { content: [{ type: "text", text: JSON.stringify({ status: r.status, body: safeJson(text) }) }] };
|
||||||
}
|
}
|
||||||
|
if (name === "elo_tac_toe_get_leaderboard") {
|
||||||
|
const limit = typeof args.limit === "number" ? args.limit : 10;
|
||||||
|
const r = await authFetch(`/leaderboard?limit=${limit}`);
|
||||||
|
const text = await r.text();
|
||||||
|
return { content: [{ type: "text", text: JSON.stringify({ status: r.status, body: safeJson(text) }) }] };
|
||||||
|
}
|
||||||
|
if (name === "elo_tac_toe_get_replay") {
|
||||||
|
const gameId = String(args.gameId);
|
||||||
|
const r = await authFetch(`/game/${gameId}/replay`);
|
||||||
|
const text = await r.text();
|
||||||
|
return { content: [{ type: "text", text: JSON.stringify({ status: r.status, body: safeJson(text) }) }] };
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== META-GAME TOOLS ==========
|
||||||
|
if (name === "meta_get_characters") {
|
||||||
|
const r = await authFetch("/meta/characters");
|
||||||
|
const text = await r.text();
|
||||||
|
return { content: [{ type: "text", text: JSON.stringify({ status: r.status, body: safeJson(text) }) }] };
|
||||||
|
}
|
||||||
|
if (name === "meta_get_perks") {
|
||||||
|
const type = args.type as string | undefined;
|
||||||
|
const path = type ? `/meta/perks?type=${type}` : "/meta/perks";
|
||||||
|
const r = await authFetch(path);
|
||||||
|
const text = await r.text();
|
||||||
|
return { content: [{ type: "text", text: JSON.stringify({ status: r.status, body: safeJson(text) }) }] };
|
||||||
|
}
|
||||||
|
if (name === "meta_get_progress") {
|
||||||
|
const r = await authFetch("/meta/progress");
|
||||||
|
const text = await r.text();
|
||||||
|
return { content: [{ type: "text", text: JSON.stringify({ status: r.status, body: safeJson(text) }) }] };
|
||||||
|
}
|
||||||
|
if (name === "meta_select_character") {
|
||||||
|
const r = await authFetch("/meta/character/select", {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({ charId: args.charId }),
|
||||||
|
});
|
||||||
|
const text = await r.text();
|
||||||
|
return { content: [{ type: "text", text: JSON.stringify({ status: r.status, body: safeJson(text) }) }] };
|
||||||
|
}
|
||||||
|
if (name === "meta_toggle_autorunner") {
|
||||||
|
const r = await authFetch("/meta/auto-runner/toggle", {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({ enabled: args.enabled }),
|
||||||
|
});
|
||||||
|
const text = await r.text();
|
||||||
|
return { content: [{ type: "text", text: JSON.stringify({ status: r.status, body: safeJson(text) }) }] };
|
||||||
|
}
|
||||||
|
if (name === "meta_start_solocesto") {
|
||||||
|
const r = await authFetch("/meta/solocesto/start", { method: "POST", body: "{}" });
|
||||||
|
const text = await r.text();
|
||||||
|
return { content: [{ type: "text", text: JSON.stringify({ status: r.status, body: safeJson(text) }) }] };
|
||||||
|
}
|
||||||
|
if (name === "meta_solocesto_move") {
|
||||||
|
const r = await authFetch("/meta/solocesto/move", {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({ sessionId: args.sessionId, row: args.row }),
|
||||||
|
});
|
||||||
|
const text = await r.text();
|
||||||
|
return { content: [{ type: "text", text: JSON.stringify({ status: r.status, body: safeJson(text) }) }] };
|
||||||
|
}
|
||||||
|
if (name === "meta_buy_perk") {
|
||||||
|
const r = await authFetch("/meta/perk/buy", {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({ perkId: args.perkId }),
|
||||||
|
});
|
||||||
|
const text = await r.text();
|
||||||
|
return { content: [{ type: "text", text: JSON.stringify({ status: r.status, body: safeJson(text) }) }] };
|
||||||
|
}
|
||||||
|
if (name === "meta_apply_perk") {
|
||||||
|
const r = await authFetch("/meta/perk/apply", {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({ perkId: args.perkId }),
|
||||||
|
});
|
||||||
|
const text = await r.text();
|
||||||
|
return { content: [{ type: "text", text: JSON.stringify({ status: r.status, body: safeJson(text) }) }] };
|
||||||
|
}
|
||||||
|
if (name === "meta_unlock_status") {
|
||||||
|
const r = await authFetch("/meta/unlock-status");
|
||||||
|
const text = await r.text();
|
||||||
|
return { content: [{ type: "text", text: JSON.stringify({ status: r.status, body: safeJson(text) }) }] };
|
||||||
|
}
|
||||||
|
|
||||||
return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
|
return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue