kill-switch-mcp 1.2.1 → 1.2.3

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.
Files changed (2) hide show
  1. package/dist/server.js +88 -126
  2. package/package.json +1 -1
package/dist/server.js CHANGED
@@ -3834,10 +3834,6 @@ var SERVER_URL = (() => {
3834
3834
  return process.argv[idx + 1];
3835
3835
  return process.env.KILL_SWITCH_SERVER || "localhost";
3836
3836
  })();
3837
- function getWebBase() {
3838
- const isLocal = SERVER_URL === "localhost" || SERVER_URL === "127.0.0.1";
3839
- return isLocal ? "http://localhost:8888" : `https://${SERVER_URL}`;
3840
- }
3841
3837
  var ERC20_ABI = [
3842
3838
  {
3843
3839
  name: "approve",
@@ -4000,14 +3996,6 @@ function saveAccessKey(privateKey, accountAddress) {
4000
3996
  createdAt: new Date().toISOString()
4001
3997
  });
4002
3998
  }
4003
- async function getTournamentSchedule() {
4004
- const res = await fetch(`${getWebBase()}/api/paid-schedule`);
4005
- const data = await res.json();
4006
- if (data.error) {
4007
- throw new Error(data.error);
4008
- }
4009
- return data.slots || [];
4010
- }
4011
3999
  async function joinTournament(tournamentAddress, username) {
4012
4000
  const wallet = loadWallet();
4013
4001
  if (!wallet) {
@@ -4084,7 +4072,7 @@ YOU are the brain of your bot. Your human talks strategy, you execute it in the
4084
4072
  ## Quick Start
4085
4073
 
4086
4074
  1. \`login\` — connects to the game (creates account if needed)
4087
- 2. \`join_game\` with mode \`"shorty"\` queues you up
4075
+ 2. \`join_game\` shows available games and buy-in tiers, or joins an existing queued game
4088
4076
  3. \`wait_for_game_start\` — blocks until teleported to the arena
4089
4077
  4. \`execute_code\` — fight! Use \`bot\`, \`sdk\`, and \`actions\` globals.
4090
4078
 
@@ -4092,18 +4080,25 @@ Before writing any execute_code, read \`killswitch://sdk-reference\` for the com
4092
4080
 
4093
4081
  ---
4094
4082
 
4095
- ## Game Modes
4083
+ ## Joining a Game
4084
+
4085
+ Call \`join_game\` with no arguments to see what's available:
4086
+ - **If a game is queued**: You'll see the current game's buy-in and player count. You can only join that game.
4087
+ - **If no game is queued**: You'll see all available buy-in tiers (Free, $5, $15, $50, $100, $1000). Call \`join_game\` with a \`tier_id\` to start a new game.
4088
+ - **If a game is active**: You must wait for it to finish.
4089
+
4090
+ **Paid games** require a Tempo wallet (\`setup_game_wallet\`). Your buy-in is deposited on-chain when you join. No refunds once deposited — the only refund path is if the game is cancelled (not enough players).
4096
4091
 
4097
- ### Shorty (Quick Battle Royale)
4098
- - **Arena**: Draynor Manor fenced grounds
4092
+ **Game start triggers:**
4093
+ - 12 players join starts immediately
4094
+ - 2+ players joined and 5-minute countdown expires → starts with whoever joined
4095
+ - Only 1 player after 30 minutes → game cancelled (refunded if paid)
4096
+
4097
+ ### The Arena
4099
4098
  - **Stats**: 50 Attack, 50 Strength, 50 Defence, 99 Hitpoints
4100
4099
  - **Start**: Empty inventory — everything comes from ground loot
4101
4100
  - **Win condition**: Last agent alive
4102
4101
 
4103
- ### Longy (Coming Soon)
4104
- - Large map: Falador to Port Sarim
4105
- - Level 1 everything — skill up, craft gear, fish food, outlast everyone
4106
-
4107
4102
  ---
4108
4103
 
4109
4104
  ## The Arena (Shorty)
@@ -4482,17 +4477,15 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
4482
4477
  },
4483
4478
  {
4484
4479
  name: "join_game",
4485
- description: "Join a game mode queue. Call after login. After joining, call wait_for_game_start.",
4480
+ description: "Join an available game. Call with no arguments to see what's available, or provide tier_id to join a specific buy-in tier. For paid games, handles deposit automatically. After joining, call wait_for_game_start.",
4486
4481
  inputSchema: {
4487
4482
  type: "object",
4488
4483
  properties: {
4489
- mode: {
4490
- type: "string",
4491
- enum: ["shorty", "longy"],
4492
- description: 'Game mode: "shorty" (quick battle royale) or "longy" (coming soon)'
4484
+ tier_id: {
4485
+ type: "number",
4486
+ description: "Tier ID to join (from available tiers list). Only needed when starting a new game — omit to join an existing queued game."
4493
4487
  }
4494
- },
4495
- required: ["mode"]
4488
+ }
4496
4489
  }
4497
4490
  },
4498
4491
  {
@@ -4524,28 +4517,6 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
4524
4517
  type: "object",
4525
4518
  properties: {}
4526
4519
  }
4527
- },
4528
- {
4529
- name: "tournament_schedule",
4530
- description: "View upcoming paid tournaments — start times, buy-ins, player counts. Read-only.",
4531
- inputSchema: {
4532
- type: "object",
4533
- properties: {}
4534
- }
4535
- },
4536
- {
4537
- name: "join_tournament",
4538
- description: "Join a paid tournament by depositing buy-in from game wallet. SPENDS REAL MONEY. Confirm with user before calling. Must be logged in.",
4539
- inputSchema: {
4540
- type: "object",
4541
- properties: {
4542
- tournament_address: {
4543
- type: "string",
4544
- description: "Tournament contract address (from tournament_schedule)"
4545
- }
4546
- },
4547
- required: ["tournament_address"]
4548
- }
4549
4520
  }
4550
4521
  ]
4551
4522
  };
@@ -4981,29 +4952,84 @@ server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
4981
4952
  if (!connection) {
4982
4953
  return errorResponse("Not connected. Call login first.");
4983
4954
  }
4984
- const mode = args?.mode;
4985
- if (!mode || !["shorty", "longy"].includes(mode)) {
4986
- return errorResponse('mode must be "shorty" or "longy"');
4987
- }
4988
4955
  const isLocal = SERVER_URL2 === "localhost" || SERVER_URL2 === "127.0.0.1";
4989
4956
  const webBase = isLocal ? `http://localhost:8888` : `https://${SERVER_URL2}`;
4990
- const apiUrl = `${webBase}/api/join-game?username=${encodeURIComponent(activeBotName)}&mode=${encodeURIComponent(mode)}`;
4957
+ const availRes = await fetch(`${webBase}/api/game/available`);
4958
+ const available = await availRes.json();
4959
+ if (available.status === "active") {
4960
+ return errorResponse(`A game is currently in progress with ${available.player_count} player(s) remaining. Try again when it finishes.`);
4961
+ }
4962
+ const tierId = args?.tier_id;
4963
+ if (available.status === "open" && !tierId) {
4964
+ const tiers = available.tiers;
4965
+ const lines = [
4966
+ "No game currently queued. Available buy-in tiers:",
4967
+ "",
4968
+ ...tiers.map((t) => ` [${t.tier_id}] ${t.label} — $${(t.buy_in / 100).toFixed(2)} buy-in (max ${t.max_players} players)`),
4969
+ "",
4970
+ "Call join_game again with tier_id to start a game."
4971
+ ];
4972
+ return { content: [{ type: "text", text: lines.join(`
4973
+ `) }] };
4974
+ }
4991
4975
  try {
4992
- const res = await fetch(apiUrl, { method: "POST" });
4993
- const data = await res.json();
4994
- if (data.error) {
4995
- return errorResponse(data.error);
4976
+ const joinUrl = `${webBase}/api/game/join?username=${encodeURIComponent(activeBotName)}&tier_id=${tierId ?? ""}`;
4977
+ const joinRes = await fetch(joinUrl, { method: "POST" });
4978
+ const joinData = await joinRes.json();
4979
+ if (joinData.error) {
4980
+ return errorResponse(joinData.error);
4981
+ }
4982
+ if (joinData.contract_address && joinData.player_count === 0) {
4983
+ if (!hasGameWallet()) {
4984
+ return errorResponse("This is a paid game but no game wallet found. Run setup_game_wallet first.");
4985
+ }
4986
+ try {
4987
+ const result = await joinTournament(joinData.contract_address, activeBotName);
4988
+ const parts2 = [
4989
+ `Joined game ${joinData.game_id} (paid).`,
4990
+ `Buy-in deposited: $${result.amount} USDC`,
4991
+ `Transaction: ${result.txHash}`,
4992
+ `Players: waiting for more...`,
4993
+ "",
4994
+ "Once deposited, you cannot leave or get a refund (unless the game is cancelled).",
4995
+ "Next: call wait_for_game_start to wait for the match."
4996
+ ];
4997
+ return { content: [{ type: "text", text: parts2.join(`
4998
+ `) }] };
4999
+ } catch (e) {
5000
+ return errorResponse(`Failed to deposit: ${e.message}`);
5001
+ }
5002
+ }
5003
+ if (joinData.contract_address && joinData.player_count > 0) {
5004
+ if (!hasGameWallet()) {
5005
+ return errorResponse("This is a paid game but no game wallet found. Run setup_game_wallet first.");
5006
+ }
5007
+ try {
5008
+ const result = await joinTournament(joinData.contract_address, activeBotName);
5009
+ const parts2 = [
5010
+ `Joined game ${joinData.game_id} (paid).`,
5011
+ `Buy-in deposited: $${result.amount} USDC`,
5012
+ `Players: ${joinData.player_count}/${joinData.max_players}`,
5013
+ "",
5014
+ "Once deposited, you cannot leave or get a refund (unless the game is cancelled).",
5015
+ "Next: call wait_for_game_start to wait for the match."
5016
+ ];
5017
+ return { content: [{ type: "text", text: parts2.join(`
5018
+ `) }] };
5019
+ } catch (e) {
5020
+ return errorResponse(`Failed to deposit: ${e.message}`);
5021
+ }
4996
5022
  }
4997
5023
  const parts = [
4998
- `Joined ${mode.toUpperCase()} queue.`,
4999
- `Players in queue: ${data.queuePlayers?.join(", ") || "just you"}`,
5024
+ `Joined game ${joinData.game_id} (free).`,
5025
+ `Players: ${joinData.player_count}/${joinData.max_players}`,
5000
5026
  "",
5001
5027
  "Next: call wait_for_game_start to wait for the match."
5002
5028
  ];
5003
5029
  return { content: [{ type: "text", text: parts.join(`
5004
5030
  `) }] };
5005
5031
  } catch (e) {
5006
- return errorResponse(`Failed to join game: ${e.message}. Is the game server running?`);
5032
+ return errorResponse(`Failed to join game: ${e.message}`);
5007
5033
  }
5008
5034
  }
5009
5035
  case "disconnect_bot": {
@@ -5087,7 +5113,7 @@ Prerequisites:
5087
5113
  `Account: ${info.address}`,
5088
5114
  `USDC Balance: $${info.balance}`,
5089
5115
  "",
5090
- info.balanceRaw === 0n ? "Your wallet is empty. Fund it by sending USDC to your account address on the Tempo network." : "Your wallet is funded and ready for paid tournaments. Use tournament_schedule to see upcoming games."
5116
+ info.balanceRaw === 0n ? "Your wallet is empty. Fund it by sending USDC to your account address on the Tempo network." : "Your wallet is funded and ready for paid games. Use join_game to see available tiers."
5091
5117
  ].join(`
5092
5118
  `)
5093
5119
  }]
@@ -5096,70 +5122,6 @@ Prerequisites:
5096
5122
  return errorResponse(`Failed to check wallet: ${e.message}`);
5097
5123
  }
5098
5124
  }
5099
- case "tournament_schedule": {
5100
- try {
5101
- const slots = await getTournamentSchedule();
5102
- if (slots.length === 0) {
5103
- return {
5104
- content: [{
5105
- type: "text",
5106
- text: "No upcoming paid tournaments scheduled. Check back later, or paid tournaments may not be enabled on this server."
5107
- }]
5108
- };
5109
- }
5110
- const lines = ["── Upcoming Paid Tournaments ──", ""];
5111
- for (let i = 0;i < slots.length; i++) {
5112
- const s = slots[i];
5113
- const time = new Date(s.startTime).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
5114
- const buyIn = (parseInt(s.buyIn) / 1e6).toFixed(2);
5115
- lines.push(`[${i + 1}] ${time} — $${buyIn} buy-in — ${s.depositorCount}/${s.maxPlayers} players`);
5116
- lines.push(` Contract: ${s.contractAddress}`);
5117
- }
5118
- lines.push("");
5119
- lines.push("To join a tournament, use join_tournament with the contract address.");
5120
- lines.push("Make sure you have enough USDC in your game wallet (check with check_wallet).");
5121
- return { content: [{ type: "text", text: lines.join(`
5122
- `) }] };
5123
- } catch (e) {
5124
- return errorResponse(`Failed to get tournament schedule: ${e.message}`);
5125
- }
5126
- }
5127
- case "join_tournament": {
5128
- const tournamentAddress = args?.tournament_address;
5129
- if (!tournamentAddress || !tournamentAddress.startsWith("0x")) {
5130
- return errorResponse("A valid tournament contract address (0x...) is required. Use tournament_schedule to find one.");
5131
- }
5132
- if (!hasGameWallet()) {
5133
- return errorResponse("No game wallet found. Run setup_game_wallet first.");
5134
- }
5135
- if (!activeBotName) {
5136
- return errorResponse("Not logged in. Call login first so we know your in-game username.");
5137
- }
5138
- try {
5139
- const result = await joinTournament(tournamentAddress, activeBotName);
5140
- return {
5141
- content: [{
5142
- type: "text",
5143
- text: [
5144
- "Tournament joined!",
5145
- "",
5146
- `Buy-in: $${result.amount} USDC`,
5147
- `Transaction: ${result.txHash}`,
5148
- `Username: ${activeBotName}`,
5149
- "",
5150
- "Your deposit is held in the tournament escrow contract.",
5151
- "Be online when the match starts or you'll be eliminated (buy-in stays in the pot).",
5152
- "",
5153
- "If the match is cancelled (< 2 players), you'll get a full refund.",
5154
- "If the server goes down, you can claim a refund after 1 hour."
5155
- ].join(`
5156
- `)
5157
- }]
5158
- };
5159
- } catch (e) {
5160
- return errorResponse(`Failed to join tournament: ${e.message}`);
5161
- }
5162
- }
5163
5125
  default:
5164
5126
  throw new Error(`Unknown tool: ${name}`);
5165
5127
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kill-switch-mcp",
3
- "version": "1.2.1",
3
+ "version": "1.2.3",
4
4
  "description": "Kill Switch MCP Server — AI battle royale powered by Claude Code",
5
5
  "type": "module",
6
6
  "bin": {