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 ELO
master
isnowglobal git 2026-04-13 11:24:03 -04:00
parent 7fb22117d4
commit 658ff80c73
2 changed files with 299 additions and 1 deletions

106
README-UPDATED.md Normal file
View File

@ -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"
}
}
}
}
```

View File

@ -38,10 +38,11 @@ async function authFetch(path: string, init: RequestInit = {}): Promise<Response
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 () => ({
tools: [
// ========== CORE GAME TOOLS ==========
{
name: "elo_tac_toe_join_queue",
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.",
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 args = (request.params.arguments ?? {}) as Record<string, unknown>;
try {
// ========== CORE GAME TOOLS ==========
if (name === "elo_tac_toe_join_queue") {
const mode = args.mode as "ranked" | "casual";
const r = await authFetch("/queue/join", {
@ -168,6 +278,88 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
const text = await r.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 };
} catch (e) {
return {