glory-mcp 0.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/dist/index.js ADDED
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env node
2
+ import 'dotenv/config';
3
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
4
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
5
+ import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
6
+ import { initChain } from './chain.js';
7
+ import { initEngine } from './engine.js';
8
+ import { registerReadTools } from './tools/read.js';
9
+ import { registerWriteTools } from './tools/write.js';
10
+ import { registerStrategyTools } from './tools/strategy.js';
11
+ // ── Parse CLI args ──
12
+ function parseArgs() {
13
+ const args = process.argv.slice(2);
14
+ let transport = 'stdio';
15
+ let port = 3002;
16
+ for (let i = 0; i < args.length; i++) {
17
+ if (args[i] === '--transport' && args[i + 1]) {
18
+ const val = args[i + 1].toLowerCase();
19
+ if (val === 'sse')
20
+ transport = 'sse';
21
+ i++;
22
+ }
23
+ else if (args[i] === '--port' && args[i + 1]) {
24
+ port = parseInt(args[i + 1], 10);
25
+ i++;
26
+ }
27
+ }
28
+ return { transport, port };
29
+ }
30
+ const { transport: transportType, port } = parseArgs();
31
+ // ── Validate required env vars ──
32
+ const RPC_URL = process.env.RPC_URL ?? process.env.RH_RPC_URL;
33
+ const ENGINE_URL = process.env.ENGINE_URL ?? 'https://gloryarena.io';
34
+ const REGISTRY_ADDRESS = process.env.REGISTRY_ADDRESS ?? '0xF37831bF334819dF82850efc8Bced54cD66735eD';
35
+ const ESCROW_ADDRESS = process.env.ESCROW_ADDRESS ?? '0xDD4bB62191b838540981e7046fB35D4522Ffe1cC';
36
+ const PRIVATE_KEY = process.env.PRIVATE_KEY;
37
+ if (!RPC_URL) {
38
+ console.error('ERROR: RPC_URL (or RH_RPC_URL) env var is required.');
39
+ console.error('Set it to a Robinhood Chain RPC endpoint (e.g. https://rpc.mainnet.chain.robinhood.com)');
40
+ process.exit(1);
41
+ }
42
+ // ── Initialize chain + engine clients ──
43
+ initChain({
44
+ rpcUrl: RPC_URL,
45
+ privateKey: PRIVATE_KEY,
46
+ registryAddress: REGISTRY_ADDRESS,
47
+ escrowAddress: ESCROW_ADDRESS,
48
+ });
49
+ initEngine(ENGINE_URL);
50
+ // ── Create MCP server ──
51
+ const server = new McpServer({
52
+ name: 'glory',
53
+ version: '0.2.0',
54
+ });
55
+ // ── Register all tools ──
56
+ registerReadTools(server);
57
+ if (transportType !== 'sse') {
58
+ registerWriteTools(server);
59
+ }
60
+ registerStrategyTools(server);
61
+ // ── Connect transport ──
62
+ if (transportType === 'sse') {
63
+ const express = (await import('express')).default;
64
+ const app = express();
65
+ // CORS for all origins
66
+ app.use((_req, res, next) => {
67
+ res.setHeader('Access-Control-Allow-Origin', '*');
68
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
69
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
70
+ if (_req.method === 'OPTIONS') {
71
+ res.status(204).end();
72
+ return;
73
+ }
74
+ next();
75
+ });
76
+ // Track active transports by session ID
77
+ const transports = new Map();
78
+ // GET /sse — establish SSE connection
79
+ app.get('/sse', async (req, res) => {
80
+ const transport = new SSEServerTransport('/messages', res);
81
+ transports.set(transport.sessionId, transport);
82
+ // Send keepalive comment every 30s to prevent CloudFront 180s idle timeout
83
+ const keepalive = setInterval(() => {
84
+ try {
85
+ res.write(': keepalive\n\n');
86
+ }
87
+ catch { }
88
+ }, 30_000);
89
+ transport.onclose = () => {
90
+ clearInterval(keepalive);
91
+ transports.delete(transport.sessionId);
92
+ };
93
+ res.on('close', () => {
94
+ clearInterval(keepalive);
95
+ });
96
+ await server.connect(transport);
97
+ });
98
+ // POST /messages — receive client messages
99
+ app.post('/messages', async (req, res) => {
100
+ const sessionId = req.query.sessionId;
101
+ const transport = transports.get(sessionId);
102
+ if (!transport) {
103
+ res.status(400).json({ error: 'Unknown session' });
104
+ return;
105
+ }
106
+ await transport.handlePostMessage(req, res);
107
+ });
108
+ app.listen(port, '0.0.0.0', () => {
109
+ console.log(`Glory MCP server running on http://0.0.0.0:${port}/sse`);
110
+ });
111
+ }
112
+ else {
113
+ const transport = new StdioServerTransport();
114
+ await server.connect(transport);
115
+ }
116
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerReadTools(server: McpServer): void;
3
+ //# sourceMappingURL=read.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../src/tools/read.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAiDzE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,QAsJlD"}
@@ -0,0 +1,163 @@
1
+ import { z } from 'zod';
2
+ import * as engine from '../engine.js';
3
+ import * as chain from '../chain.js';
4
+ // ── Helpers ──
5
+ function formatWei(wei) {
6
+ if (!wei || wei === '0')
7
+ return '0';
8
+ // Convert wei string to ETH with up to 6 decimal places
9
+ const n = BigInt(wei);
10
+ const eth = Number(n) / 1e18;
11
+ if (eth === 0)
12
+ return '0';
13
+ if (eth < 0.000001)
14
+ return '<0.000001';
15
+ return eth.toFixed(6).replace(/\.?0+$/, '');
16
+ }
17
+ // ── Class info (static knowledge) ──
18
+ const CLASS_INFO = {
19
+ WARRIOR: {
20
+ hp: 100, ac: 16, hitDie: 10,
21
+ strengths: 'Highest base damage. Aggressive coaching gives +30% damage multiplier.',
22
+ weaknesses: 'Counter coaching is 20% less effective. No ranged options.',
23
+ coaching_tips: 'Use aggressive keywords: "attack", "rush", "pressure", "go in". Avoid counter strategies.',
24
+ best_matchups: 'Strong vs MAGE (can rush before spells ramp). Weak vs ROGUE (counters aggression).',
25
+ },
26
+ ROGUE: {
27
+ hp: 90, ac: 14, hitDie: 8,
28
+ strengths: 'Counter coaching gives +30% damage. Excels at punishing aggressive opponents.',
29
+ weaknesses: 'Low HP. Aggressive coaching is 20% less effective.',
30
+ coaching_tips: 'Use counter keywords: "counter", "react", "punish", "bait", "adapt". Best vs aggressive classes.',
31
+ best_matchups: 'Strong vs WARRIOR (counters aggression). Weak vs PALADIN (can\'t burst through high HP).',
32
+ },
33
+ MAGE: {
34
+ hp: 80, ac: 12, hitDie: 6,
35
+ strengths: 'Reckless coaching gives +30% damage and triggers ability round 1. Glass cannon.',
36
+ weaknesses: 'Lowest HP and AC. Conservative coaching is 30% less effective.',
37
+ coaching_tips: 'Use reckless keywords: "all in", "yolo", "reckless". Go for fast kills before you die.',
38
+ best_matchups: 'Strong vs PALADIN (can burst before heals matter). Weak vs WARRIOR (gets rushed down).',
39
+ },
40
+ PALADIN: {
41
+ hp: 110, ac: 15, hitDie: 10,
42
+ strengths: 'Highest HP. Conservative coaching gives +30% damage. Heals +5 HP every 5 rounds.',
43
+ weaknesses: 'Reckless coaching is 20% less effective. Slow starter.',
44
+ coaching_tips: 'Use conservative keywords: "careful", "patient", "defensive", "safe". Outlast opponents.',
45
+ best_matchups: 'Strong vs ROGUE (outlasts low HP). Weak vs MAGE (burst damage ignores sustain).',
46
+ },
47
+ };
48
+ export function registerReadTools(server) {
49
+ // ── arena_get_leaderboard ──
50
+ server.tool('arena_get_leaderboard', 'Get all registered agents with their stats, win rates, and ETH winnings. Shows the competitive landscape.', {}, async () => {
51
+ try {
52
+ const data = await engine.getLeaderboard();
53
+ const summary = data.agents
54
+ .sort((a, b) => b.winRate - a.winRate)
55
+ .map((a, i) => {
56
+ const winPct = a.winRate > 1 ? a.winRate : a.winRate * 100; // engine returns 0-100 integer
57
+ const wonEth = formatWei(a.totalWon);
58
+ return `${i + 1}. ${a.name} (${a.agentClass}) — ${a.wins}W/${a.losses}L (${winPct.toFixed(0)}%) ${a.alive ? '✓' : '☠'} | Won: ${wonEth} ETH`;
59
+ })
60
+ .join('\n');
61
+ return {
62
+ content: [{
63
+ type: 'text',
64
+ text: `Glory Leaderboard (${data.totalBattles} total battles)\n${'─'.repeat(50)}\n${summary || 'No agents registered yet.'}\n\nRaw data available: ${data.agents.length} agents`,
65
+ }],
66
+ };
67
+ }
68
+ catch (e) {
69
+ return { content: [{ type: 'text', text: `Error: ${e.message}` }], isError: true };
70
+ }
71
+ });
72
+ // ── arena_get_class_info ──
73
+ server.tool('arena_get_class_info', 'Get detailed stats, strengths, weaknesses, and coaching tips for all 4 character classes. Essential for strategy.', {}, async () => {
74
+ const lines = Object.entries(CLASS_INFO).map(([name, info]) => `## ${name}\nHP: ${info.hp} | AC: ${info.ac} | Hit Die: d${info.hitDie}\nStrengths: ${info.strengths}\nWeaknesses: ${info.weaknesses}\nCoaching: ${info.coaching_tips}\nMatchups: ${info.best_matchups}`);
75
+ return {
76
+ content: [{
77
+ type: 'text',
78
+ text: `# Glory Class Guide\n\n${lines.join('\n\n')}\n\n## Coaching Keyword System\n- "aggressive/attack/rush" → +2 hit, 1.2x damage\n- "counter/react/punish" → bonus vs aggressive opponents\n- "defensive/careful/patient" → +2 AC, 0.85x damage\n- "reckless/all-in/yolo" → 1.6x damage, ability fires round 1`,
79
+ }],
80
+ };
81
+ });
82
+ // ── arena_get_open_challenges ──
83
+ server.tool('arena_get_open_challenges', 'Get open challenges that a specific agent can accept. Returns opponent info and wager amounts.', { agentId: z.string().describe('The bytes32 agent ID to check challenges for') }, async ({ agentId }) => {
84
+ try {
85
+ const data = await engine.getChallenges(agentId);
86
+ if (data.challenges.length === 0) {
87
+ return { content: [{ type: 'text', text: 'No open challenges for this agent.' }] };
88
+ }
89
+ const lines = data.challenges.map(c => `Challenge ${c.challenge_id.slice(0, 10)}...\n From: ${c.agent_a.slice(0, 10)}... | Wager: ${c.wager ?? '0'} ETH | Status: ${c.status}`);
90
+ return { content: [{ type: 'text', text: `Open Challenges:\n${lines.join('\n\n')}` }] };
91
+ }
92
+ catch (e) {
93
+ return { content: [{ type: 'text', text: `Error: ${e.message}` }], isError: true };
94
+ }
95
+ });
96
+ // ── arena_get_battle_result ──
97
+ server.tool('arena_get_battle_result', 'Get the full result of a battle: winner, loser, rounds played, HP remaining, and combat log.', { challengeId: z.string().describe('The challenge ID (bytes32) to look up') }, async ({ challengeId }) => {
98
+ try {
99
+ const data = await engine.getBattle(challengeId);
100
+ if (!data.log) {
101
+ return { content: [{ type: 'text', text: `Battle ${challengeId.slice(0, 10)}... status: ${data.status}. No result yet.` }] };
102
+ }
103
+ const log = data.log;
104
+ const text = [
105
+ `Battle Result: ${log.winnerName} (${log.winnerClass}) defeats ${log.loserName} (${log.loserClass})`,
106
+ `Rounds: ${log.totalRounds} | Winner HP remaining: ${log.winnerHpRemaining}`,
107
+ `Seed: ${log.seed}`,
108
+ '',
109
+ '── Combat Log ──',
110
+ ...log.logLines.slice(-10), // Last 10 lines for brevity
111
+ ].join('\n');
112
+ return { content: [{ type: 'text', text }] };
113
+ }
114
+ catch (e) {
115
+ return { content: [{ type: 'text', text: `Error: ${e.message}` }], isError: true };
116
+ }
117
+ });
118
+ // ── arena_get_agent_stats ──
119
+ server.tool('arena_get_agent_stats', 'Get detailed on-chain stats for a specific agent: class, wins, losses, level, alive status.', { agentId: z.string().describe('The bytes32 agent ID') }, async ({ agentId }) => {
120
+ try {
121
+ const agent = await chain.getAgent(agentId);
122
+ const className = chain.CLASS_NAMES[agent.agentClass] ?? 'UNKNOWN';
123
+ const winRate = agent.wins + agent.losses > 0
124
+ ? ((agent.wins / (agent.wins + agent.losses)) * 100).toFixed(0)
125
+ : '0';
126
+ const text = [
127
+ `Agent: ${agent.name}`,
128
+ `Class: ${className} | Level: ${agent.level}`,
129
+ `Record: ${agent.wins}W / ${agent.losses}L (${winRate}% win rate)`,
130
+ `Status: ${agent.alive ? 'ALIVE' : 'DEAD (permakilled)'}`,
131
+ `Owner: ${agent.owner}`,
132
+ `ID: ${agent.id}`,
133
+ ].join('\n');
134
+ return { content: [{ type: 'text', text }] };
135
+ }
136
+ catch (e) {
137
+ return { content: [{ type: 'text', text: `Error: ${e.message}` }], isError: true };
138
+ }
139
+ });
140
+ // ── arena_get_my_agents ──
141
+ server.tool('arena_get_my_agents', 'Get all agents owned by the configured wallet. Requires PRIVATE_KEY to be set.', {}, async () => {
142
+ try {
143
+ const address = chain.getWalletAddress();
144
+ if (!address) {
145
+ return { content: [{ type: 'text', text: 'No wallet configured. Set PRIVATE_KEY env var.' }], isError: true };
146
+ }
147
+ const ids = await chain.getAgentsByOwner(address);
148
+ if (ids.length === 0) {
149
+ return { content: [{ type: 'text', text: `No agents owned by ${address}. Use arena_register_agent to create one.` }] };
150
+ }
151
+ const agents = await Promise.all(ids.map(id => chain.getAgent(id)));
152
+ const lines = agents.map(a => {
153
+ const cls = chain.CLASS_NAMES[a.agentClass] ?? 'UNKNOWN';
154
+ return `${a.name} (${cls}) — ${a.wins}W/${a.losses}L ${a.alive ? '✓' : '☠'} | ID: ${a.id.slice(0, 14)}...`;
155
+ });
156
+ return { content: [{ type: 'text', text: `Your Agents (${address}):\n${lines.join('\n')}` }] };
157
+ }
158
+ catch (e) {
159
+ return { content: [{ type: 'text', text: `Error: ${e.message}` }], isError: true };
160
+ }
161
+ });
162
+ }
163
+ //# sourceMappingURL=read.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read.js","sourceRoot":"","sources":["../../src/tools/read.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerStrategyTools(server: McpServer): void;
3
+ //# sourceMappingURL=strategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strategy.d.ts","sourceRoot":"","sources":["../../src/tools/strategy.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA0DzE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,QAwEtD"}
@@ -0,0 +1,120 @@
1
+ import { z } from 'zod';
2
+ import * as engine from '../engine.js';
3
+ import * as chain from '../chain.js';
4
+ // ── Class matchup knowledge ──
5
+ const MATCHUP_TABLE = {
6
+ WARRIOR: {
7
+ WARRIOR: { strategy: 'Mirror match — aggression wins. Go harder than they do.', style: 'aggressive', confidence: 'Medium' },
8
+ ROGUE: { strategy: 'Rogue counters aggression. Switch to conservative or reckless to avoid being countered.', style: 'reckless', confidence: 'Medium' },
9
+ MAGE: { strategy: 'Rush the Mage before spells ramp. Low HP + low AC = fast kill.', style: 'aggressive', confidence: 'High' },
10
+ PALADIN: { strategy: 'Paladin outlasts you. Go aggressive early before their healing kicks in.', style: 'aggressive', confidence: 'Medium' },
11
+ },
12
+ ROGUE: {
13
+ WARRIOR: { strategy: 'Warriors go aggressive — perfect for counter. Punish their overextension.', style: 'counter', confidence: 'High' },
14
+ ROGUE: { strategy: 'Mirror match. Counter is neutral here. Consider aggressive for surprise.', style: 'aggressive', confidence: 'Low' },
15
+ MAGE: { strategy: 'Mage goes reckless. Counter is decent, but aggressive rush works too.', style: 'counter', confidence: 'Medium' },
16
+ PALADIN: { strategy: 'Paladin is conservative — counter is weak vs conservative. Go aggressive.', style: 'aggressive', confidence: 'Medium' },
17
+ },
18
+ MAGE: {
19
+ WARRIOR: { strategy: 'Warrior rushes. You need to burst first. Reckless or die.', style: 'reckless', confidence: 'Medium' },
20
+ ROGUE: { strategy: 'Rogue counters. Reckless bypasses counter timing with round-1 ability.', style: 'reckless', confidence: 'Medium' },
21
+ MAGE: { strategy: 'Glass cannon mirror. Whoever hits first wins. Reckless is mandatory.', style: 'reckless', confidence: 'High' },
22
+ PALADIN: { strategy: 'Paladin heals. You must burst before round 5 healing. Go all-in.', style: 'reckless', confidence: 'High' },
23
+ },
24
+ PALADIN: {
25
+ WARRIOR: { strategy: 'Outlast the warrior. Your HP + healing beats their aggression over time.', style: 'conservative', confidence: 'High' },
26
+ ROGUE: { strategy: 'Rogue can\'t burst through 110 HP. Play patient and grind them down.', style: 'conservative', confidence: 'High' },
27
+ MAGE: { strategy: 'Mage bursts hard. Conservative helps survive the initial onslaught.', style: 'conservative', confidence: 'Medium' },
28
+ PALADIN: { strategy: 'Mirror match. Conservative is strong but slow. Consider aggressive for variance.', style: 'conservative', confidence: 'Low' },
29
+ },
30
+ };
31
+ // ── Coaching keyword templates ──
32
+ const COACHING_TEMPLATES = {
33
+ aggressive: [
34
+ 'Go aggressive from round one. Attack hard, push the pace, rush them down before they can react.',
35
+ 'Full pressure. Attack relentlessly, hit hard, go in and never let up.',
36
+ 'Rush attack. Push forward aggressively and overwhelm with pressure.',
37
+ ],
38
+ conservative: [
39
+ 'Play it careful and patient. Wait for openings, stay defensive, keep yourself safe.',
40
+ 'Slow and steady wins. Be patient, stay safe, play defensive and outlast them.',
41
+ 'Careful approach. Wait for mistakes, stay defensive and steady.',
42
+ ],
43
+ counter: [
44
+ 'Read their attacks and counter. React to their aggression, punish every overextension, adapt and bait.',
45
+ 'Counter everything. React to their moves, punish mistakes, bait them into overcommitting.',
46
+ 'Adapt and respond. Counter their rhythm, punish aggression, read their patterns.',
47
+ ],
48
+ reckless: [
49
+ 'All in. Reckless abandon. Sacrifice defense for everything — yolo, go for the kill immediately.',
50
+ 'Reckless all-in. Everything you have, round one. Sacrifice survival for maximum damage.',
51
+ 'Yolo. All in, reckless offense. No defense, just raw damage from the start.',
52
+ ],
53
+ };
54
+ export function registerStrategyTools(server) {
55
+ // ── arena_get_coaching_advice ──
56
+ server.tool('arena_get_coaching_advice', 'Get an optimized coaching prompt for a specific matchup. Analyzes class strengths/weaknesses, opponent history, and coaching keyword system to generate the best possible coaching prompt.', {
57
+ myAgentId: z.string().describe('Your agent\'s bytes32 ID'),
58
+ opponentAgentId: z.string().describe('Opponent agent\'s bytes32 ID'),
59
+ }, async ({ myAgentId, opponentAgentId }) => {
60
+ try {
61
+ // Fetch both agents
62
+ const [myAgent, opponent] = await Promise.all([
63
+ chain.getAgent(myAgentId),
64
+ chain.getAgent(opponentAgentId),
65
+ ]);
66
+ const myClass = chain.CLASS_NAMES[myAgent.agentClass] ?? 'WARRIOR';
67
+ const oppClass = chain.CLASS_NAMES[opponent.agentClass] ?? 'WARRIOR';
68
+ // Get matchup advice
69
+ const matchup = MATCHUP_TABLE[myClass]?.[oppClass] ?? {
70
+ strategy: 'No specific matchup data. Default to class affinity.',
71
+ style: 'aggressive',
72
+ confidence: 'Low',
73
+ };
74
+ // Pick a coaching template
75
+ const templates = COACHING_TEMPLATES[matchup.style] ?? COACHING_TEMPLATES.aggressive;
76
+ const template = templates[Math.floor(Math.random() * templates.length)];
77
+ // Try to get opponent's battle history from leaderboard
78
+ let historyNote = '';
79
+ try {
80
+ const leaderboard = await engine.getLeaderboard();
81
+ const oppEntry = leaderboard.agents.find(a => a.id === opponentAgentId);
82
+ if (oppEntry) {
83
+ historyNote = `\nOpponent record: ${oppEntry.wins}W/${oppEntry.losses}L (${(oppEntry.winRate * 100).toFixed(0)}% win rate)`;
84
+ if (oppEntry.winRate > 0.6)
85
+ historyNote += ' — DANGEROUS opponent.';
86
+ if (oppEntry.winRate < 0.4 && oppEntry.wins + oppEntry.losses > 2)
87
+ historyNote += ' — Weak opponent, high win probability.';
88
+ }
89
+ }
90
+ catch { /* leaderboard unavailable, skip */ }
91
+ return {
92
+ content: [{
93
+ type: 'text',
94
+ text: [
95
+ `# Coaching Advice: ${myAgent.name} (${myClass}) vs ${opponent.name} (${oppClass})`,
96
+ '',
97
+ `## Matchup Analysis`,
98
+ `Strategy: ${matchup.strategy}`,
99
+ `Recommended style: ${matchup.style.toUpperCase()}`,
100
+ `Confidence: ${matchup.confidence}`,
101
+ historyNote,
102
+ '',
103
+ `## Suggested Coaching Prompt`,
104
+ `"${template}"`,
105
+ '',
106
+ `## Why This Works`,
107
+ `${myClass} has ${matchup.style === 'aggressive' ? '+30%' : matchup.style === 'counter' ? '+30%' : matchup.style === 'reckless' ? '+30%' : '+30%'} damage bonus with ${matchup.style} coaching.`,
108
+ `The keywords in the prompt trigger the ${matchup.style} combat modifier in the engine's coaching parser.`,
109
+ '',
110
+ `Copy the prompt above to arena_submit_coaching, or modify it while keeping the key strategy words.`,
111
+ ].join('\n'),
112
+ }],
113
+ };
114
+ }
115
+ catch (e) {
116
+ return { content: [{ type: 'text', text: `Strategy error: ${e.message}` }], isError: true };
117
+ }
118
+ });
119
+ }
120
+ //# sourceMappingURL=strategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strategy.js","sourceRoot":"","sources":["../../src/tools/strategy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerWriteTools(server: McpServer): void;
3
+ //# sourceMappingURL=write.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../src/tools/write.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIzE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,QAwJnD"}
@@ -0,0 +1,135 @@
1
+ import { z } from 'zod';
2
+ import { ethers } from 'ethers';
3
+ import * as chain from '../chain.js';
4
+ import * as engine from '../engine.js';
5
+ export function registerWriteTools(server) {
6
+ // ── arena_register_agent ──
7
+ server.tool('arena_register_agent', 'Register a new agent on-chain. Requires funded wallet (entry fee in ETH). Agent gets a unique ID and starts at level 1 with 0W/0L. Choose class carefully — it cannot be changed. Permadeath means dead agents are gone forever.', {
8
+ name: z.string().min(1).max(32).describe('Agent name (1-32 chars)'),
9
+ agentClass: z.enum(['WARRIOR', 'ROGUE', 'MAGE', 'PALADIN']).describe('Character class'),
10
+ description: z.string().max(200).optional().describe('Optional agent description'),
11
+ }, async ({ name, agentClass, description }) => {
12
+ try {
13
+ const classNum = chain.classNameToNum(agentClass);
14
+ const fee = await chain.getEntryFee();
15
+ const result = await chain.registerAgent(name, description ?? '', classNum);
16
+ return {
17
+ content: [{
18
+ type: 'text',
19
+ text: [
20
+ `Agent registered successfully!`,
21
+ `Name: ${name} | Class: ${agentClass}`,
22
+ `Agent ID: ${result.agentId}`,
23
+ `Entry fee: ${fee} ETH`,
24
+ `TX: ${result.txHash}`,
25
+ '',
26
+ `Your agent is now alive in the arena. Challenge opponents with arena_create_challenge.`,
27
+ `Remember: death is permanent. Choose your battles wisely.`,
28
+ ].join('\n'),
29
+ }],
30
+ };
31
+ }
32
+ catch (e) {
33
+ return { content: [{ type: 'text', text: `Registration failed: ${e.message}` }], isError: true };
34
+ }
35
+ });
36
+ // ── arena_create_challenge ──
37
+ server.tool('arena_create_challenge', 'Challenge another agent to combat. You choose the opponent and wager amount (min 0.0001 ETH). The wager is locked in escrow. If opponent accepts, battle happens automatically. Winner takes the pot. Loser\'s agent may die permanently.', {
38
+ myAgentId: z.string().describe('Your agent\'s bytes32 ID'),
39
+ opponentAgentId: z.string().describe('Opponent agent\'s bytes32 ID'),
40
+ wagerEth: z.string().describe('Wager amount in ETH (e.g. "0.001")'),
41
+ }, async ({ myAgentId, opponentAgentId, wagerEth }) => {
42
+ try {
43
+ // Validate wager
44
+ const wagerWei = ethers.parseEther(wagerEth);
45
+ const minWager = ethers.parseEther('0.0001');
46
+ if (wagerWei < minWager) {
47
+ return { content: [{ type: 'text', text: `Wager too low. Minimum is 0.0001 ETH.` }], isError: true };
48
+ }
49
+ // Check agent is alive and not locked
50
+ const myAgent = await chain.getAgent(myAgentId);
51
+ if (!myAgent.alive) {
52
+ return { content: [{ type: 'text', text: `Your agent ${myAgent.name} is dead. Dead agents cannot fight.` }], isError: true };
53
+ }
54
+ const locked = await chain.isAgentLocked(myAgentId);
55
+ if (locked) {
56
+ return { content: [{ type: 'text', text: `Your agent is currently locked in another challenge.` }], isError: true };
57
+ }
58
+ const result = await chain.createChallenge(myAgentId, opponentAgentId, wagerEth);
59
+ return {
60
+ content: [{
61
+ type: 'text',
62
+ text: [
63
+ `Challenge created!`,
64
+ `Challenge ID: ${result.challengeId}`,
65
+ `Wager: ${wagerEth} ETH (locked in escrow)`,
66
+ `TX: ${result.txHash}`,
67
+ '',
68
+ `Waiting for opponent to accept. Use arena_submit_coaching to prepare your strategy.`,
69
+ ].join('\n'),
70
+ }],
71
+ };
72
+ }
73
+ catch (e) {
74
+ return { content: [{ type: 'text', text: `Challenge failed: ${e.message}` }], isError: true };
75
+ }
76
+ });
77
+ // ── arena_accept_challenge ──
78
+ server.tool('arena_accept_challenge', 'Accept an incoming challenge. You must match the wager amount exactly (auto-matched from escrow). Battle will begin once both coaching prompts are submitted.', {
79
+ challengeId: z.string().describe('The challenge ID to accept'),
80
+ myAgentId: z.string().describe('Your agent\'s bytes32 ID'),
81
+ }, async ({ challengeId, myAgentId }) => {
82
+ try {
83
+ const myAgent = await chain.getAgent(myAgentId);
84
+ if (!myAgent.alive) {
85
+ return { content: [{ type: 'text', text: `Your agent ${myAgent.name} is dead.` }], isError: true };
86
+ }
87
+ const result = await chain.acceptChallenge(challengeId, myAgentId);
88
+ return {
89
+ content: [{
90
+ type: 'text',
91
+ text: [
92
+ `Challenge accepted!`,
93
+ `TX: ${result.txHash}`,
94
+ '',
95
+ `Submit your coaching prompt with arena_submit_coaching before the battle begins.`,
96
+ `Use arena_get_coaching_advice for strategy suggestions.`,
97
+ ].join('\n'),
98
+ }],
99
+ };
100
+ }
101
+ catch (e) {
102
+ return { content: [{ type: 'text', text: `Accept failed: ${e.message}` }], isError: true };
103
+ }
104
+ });
105
+ // ── arena_submit_coaching ──
106
+ server.tool('arena_submit_coaching', 'Submit a coaching prompt for an upcoming battle. This is your ONE chance to influence the fight. The prompt is parsed for keywords that modify combat: "aggressive/attack" (+hit, +damage), "counter/punish" (bonus vs aggressive), "defensive/patient" (+AC), "reckless/yolo" (huge damage, ability fires immediately). Class affinities matter — check arena_get_class_info.', {
107
+ challengeId: z.string().describe('The challenge ID'),
108
+ prompt: z.string().max(500).describe('Coaching prompt (max 500 chars). Include strategy keywords.'),
109
+ }, async ({ challengeId, prompt }) => {
110
+ try {
111
+ const address = chain.getWalletAddress();
112
+ if (!address) {
113
+ return { content: [{ type: 'text', text: 'No wallet configured. Set PRIVATE_KEY env var.' }], isError: true };
114
+ }
115
+ const result = await engine.submitCoaching(challengeId, address, prompt);
116
+ return {
117
+ content: [{
118
+ type: 'text',
119
+ text: [
120
+ `Coaching submitted!`,
121
+ `Role: Player ${result.role}`,
122
+ `Prompt: "${prompt}"`,
123
+ '',
124
+ `The engine will parse your prompt for strategy keywords.`,
125
+ `Use arena_get_battle_result to check the outcome after the fight.`,
126
+ ].join('\n'),
127
+ }],
128
+ };
129
+ }
130
+ catch (e) {
131
+ return { content: [{ type: 'text', text: `Coaching submission failed: ${e.message}` }], isError: true };
132
+ }
133
+ });
134
+ }
135
+ //# sourceMappingURL=write.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write.js","sourceRoot":"","sources":["../../src/tools/write.ts"],"names":[],"mappings":"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"}