kill-switch-mcp 1.1.8 → 1.1.10

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 +236 -26
  2. package/package.json +1 -1
package/dist/server.js CHANGED
@@ -7,7 +7,9 @@ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
7
7
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
8
8
  import {
9
9
  CallToolRequestSchema,
10
- ListToolsRequestSchema
10
+ ListToolsRequestSchema,
11
+ ListResourcesRequestSchema,
12
+ ReadResourceRequestSchema
11
13
  } from "@modelcontextprotocol/sdk/types.js";
12
14
  import { existsSync as existsSync3 } from "fs";
13
15
  import { readFile as readFile2 } from "fs/promises";
@@ -4109,19 +4111,16 @@ execute it by sending code to the game via execute_code.
4109
4111
  - bot.attackNpc("name" or /pattern/i) — attack an NPC
4110
4112
  - bot.walkTo(x, z) — pathfind and walk (complex, uses server pathfinding)
4111
4113
 
4112
- ### sdk methods (low-level, instant):
4113
- - sdk.sendWalk(x, z) click a tile to walk there (fast, no pathfinding)
4114
- - sdk.getState() full game state object
4114
+ ### sdk methods (low-level):
4115
+ State (sync): sdk.getState(), sdk.getInventory(), sdk.getEquipment(), sdk.getNearbyPlayers(), sdk.getGroundItems()
4116
+ Search (sync): sdk.findInventoryItem(/pat/i), sdk.findGroundItem(/pat/i), sdk.findNearbyPlayer(/pat/i)
4117
+ Commands (async): sdk.sendWalk(x, z), sdk.sendPickup(x, z, itemId), sdk.sendInteractLoc(x, z, locId, option)
4118
+ Timing (async): await sdk.waitForTicks(n) — each tick ~0.6s
4119
+
4120
+ Key state paths:
4115
4121
  - sdk.getState().player.worldX / .worldZ — your position
4116
- - sdk.getState().player.hp — your current HP
4117
- - sdk.getState().player.maxHp your max HP
4118
- - sdk.getInventory() — array of inventory items (each has .name)
4119
- - sdk.getEquipment() — array of equipment items
4120
- - sdk.findInventoryItem(/pattern/i) — find item in inventory
4121
- - sdk.findGroundItem(/pattern/i) — find item on ground (returns { name, x, z, distance } — NOT .worldX!)
4122
- - sdk.getGroundItems() — all nearby ground items (each has .name, .x, .z, .distance, .id, .count)
4123
- - sdk.getNearbyPlayers() — nearby players (each has .name, .combatLevel, .distance, .x, .z)
4124
- - sdk.waitForTicks(n) — wait n game ticks (~0.6s each)
4122
+ - sdk.getState().player.hp / .maxHp — your hitpoints
4123
+ - Ground items use .x / .z (NOT .worldX)
4125
4124
 
4126
4125
  ### actions (pre-built strategies, await each one):
4127
4126
  Actions are loaded from your bot's actions/ directory at login. Default actions:
@@ -4131,8 +4130,11 @@ Actions are loaded from your bot's actions/ directory at login. Default actions:
4131
4130
 
4132
4131
  ### IMPORTANT NOTES:
4133
4132
  - Blocking UI is auto-dismissed before every execute_code call — you do NOT need to call bot.dismissBlockingUI()
4133
+ - bot methods THROW on failure — use try/catch if you want to handle errors gracefully
4134
4134
  - bot.walkTo() uses server pathfinding (can be slow). For quick movement, use sdk.sendWalk(x, z) + sdk.waitForTicks(5)
4135
- - State uses .player (NOT .localPlayer): sdk.getState().player.worldX (NOT state.localPlayer.x)
4135
+ - State path: sdk.getState().player.worldX / .worldZ / .hp / .maxHp (NOT .localPlayer, NOT .hitpoints)
4136
+ - Ground items use .x / .z (NOT .worldX / .worldZ): sdk.getGroundItems()[0].x
4137
+ - Players use .x / .z for nearby players, .worldX / .worldZ for your own player
4136
4138
  - Keep execute_code calls to 15-30 seconds, then check state and adapt
4137
4139
 
4138
4140
  ## Key Tips
@@ -4140,7 +4142,201 @@ Actions are loaded from your bot's actions/ directory at login. Default actions:
4140
4142
  - Grab a weapon first, then food, then armor
4141
4143
  - Risk vs reward: center has the best loot but everyone converges there
4142
4144
  - The human gives you strategy ("rush center", "play safe", "grab and run") — you turn it into code`;
4143
- var server = new Server({ name: "kill-switch", version: "3.0.0" }, { capabilities: { tools: {} } });
4145
+ var server = new Server({ name: "kill-switch", version: "3.0.0" }, { capabilities: { tools: {}, resources: {} } });
4146
+ var SDK_REFERENCE = `# Kill Switch SDK Reference
4147
+
4148
+ This is the DEFINITIVE API reference. Do NOT guess method names or property paths.
4149
+ If a method or property is not listed here, it does not exist.
4150
+
4151
+ ## Globals available in execute_code
4152
+
4153
+ Three objects are available in every execute_code call:
4154
+ - \`bot\` — High-level game actions (all async, all throw on failure)
4155
+ - \`sdk\` — Low-level state access and direct commands
4156
+ - \`actions\` — Pre-built strategy functions loaded from your bot's actions/ directory
4157
+
4158
+ ---
4159
+
4160
+ ## bot methods
4161
+
4162
+ All bot methods are async. They THROW an error if they fail — you do NOT need to check return values.
4163
+ Wrap in try/catch if you want to handle failures gracefully.
4164
+
4165
+ ### Movement
4166
+ - \`await bot.walkTo(x, z)\` — Pathfind and walk to coordinates. Uses server-side pathfinding. Can be slow and may fail if path is blocked by walls/doors.
4167
+
4168
+ ### Items
4169
+ - \`await bot.pickupItem(pattern)\` — Walk to and pick up a ground item matching the pattern. Example: \`await bot.pickupItem(/rune scimitar/i)\`
4170
+ - \`await bot.equipItem(pattern)\` — Equip an item from inventory. Example: \`await bot.equipItem(/rune scimitar/i)\`
4171
+ - \`await bot.eatFood(pattern)\` — Eat food from inventory. Example: \`await bot.eatFood(/lobster/i)\`
4172
+
4173
+ ### Combat
4174
+ - \`await bot.attackPlayer(nameOrPattern)\` — Attack a player. Example: \`await bot.attackPlayer("Arwen")\` or \`await bot.attackPlayer(/arwen/i)\`
4175
+ - \`await bot.attackNpc(nameOrPattern)\` — Attack an NPC.
4176
+
4177
+ ### NPCs & Objects
4178
+ - \`await bot.talkTo(nameOrPattern)\` — Talk to an NPC.
4179
+ - \`await bot.interactLoc(nameOrPattern, option)\` — Interact with a game object.
4180
+ - \`await bot.interactNpc(nameOrPattern, option)\` — Interact with an NPC.
4181
+ - \`await bot.openDoor(target)\` — Open a door. Pass a NearbyLoc object, string name, or RegExp. With no args, opens nearest door.
4182
+
4183
+ ### Dialog
4184
+ - \`await bot.navigateDialog(choices)\` — Navigate through NPC dialog.
4185
+ - \`await bot.waitForDialogClose()\` — Wait for dialog to close.
4186
+
4187
+ ### Other
4188
+ - \`await bot.dismissBlockingUI()\` — Dismiss modals/dialogs. NOTE: This is called automatically before every execute_code — you do NOT need to call it yourself.
4189
+ - \`await bot.waitForIdle()\` — Wait until the bot is idle (not moving/acting).
4190
+
4191
+ ---
4192
+
4193
+ ## sdk methods
4194
+
4195
+ ### State (instant, not async)
4196
+ - \`sdk.getState()\` — Returns the full game state object. See "State Object Shape" below.
4197
+ - \`sdk.getInventory()\` — Array of inventory items. Each has: \`.name\`, \`.id\`, \`.count\`, \`.slot\`
4198
+ - \`sdk.getEquipment()\` — Array of equipped items. Each has: \`.name\`, \`.id\`, \`.slot\`
4199
+ - \`sdk.getNearbyPlayers()\` — Array of nearby players. Each has: \`.index\`, \`.name\`, \`.combatLevel\`, \`.distance\`, \`.x\`, \`.z\`
4200
+ - \`sdk.getGroundItems()\` — Array of ground items. Each has: \`.name\`, \`.id\`, \`.count\`, \`.x\`, \`.z\`, \`.distance\`
4201
+ - \`sdk.getNearbyLocs()\` — Array of nearby game objects. Each has: \`.id\`, \`.name\`, \`.x\`, \`.z\`, \`.distance\`, \`.options\`
4202
+ - \`sdk.getNearbyNpcs()\` — Array of nearby NPCs. Each has: \`.index\`, \`.name\`, \`.combatLevel\`, \`.x\`, \`.z\`, \`.distance\`, \`.hp\`, \`.maxHp\`, \`.inCombat\`
4203
+
4204
+ ### Search (instant, not async)
4205
+ - \`sdk.findInventoryItem(pattern)\` — Find first matching inventory item. Returns item or null.
4206
+ - \`sdk.findGroundItem(pattern)\` — Find first matching ground item. Returns item or null.
4207
+ - \`sdk.findNearbyPlayer(pattern)\` — Find a nearby player. Returns player or null.
4208
+ - \`sdk.findNearbyNpc(pattern)\` — Find a nearby NPC. Returns NPC or null.
4209
+ - \`sdk.findNearbyLoc(pattern)\` — Find a nearby game object. Returns loc or null.
4210
+
4211
+ ### Direct Commands (async, send action to server)
4212
+ All send* methods are async and return Promise<ActionResult>. Use await or fire-and-forget.
4213
+ - \`sdk.sendWalk(x, z)\` — Click a tile to walk there. Fast, no pathfinding. Use for quick movement.
4214
+ - \`sdk.sendPickup(x, z, itemId)\` — Pick up a ground item. Args are (x, z, itemId) — NOT (itemId, x, z).
4215
+ - \`sdk.sendInteractPlayer(playerIndex, option)\` — Interact with a player. Use player.index from getNearbyPlayers().
4216
+ - \`sdk.sendInteractNpc(npcIndex, option)\` — Interact with an NPC. Use npc.index from getNearbyNpcs(). NOT npcId.
4217
+ - \`sdk.sendInteractLoc(x, z, locId, option)\` — Interact with a game object. Args are (x, z, locId, option) — NOT (locId, x, z).
4218
+ - \`sdk.sendUseItem(slot, option)\` — Use an inventory item. option defaults to 1 (first option, e.g. eat/wear).
4219
+ - \`sdk.sendSetCombatStyle(style)\` — Change combat style (0-3).
4220
+ - \`sdk.sendTogglePrayer(prayer)\` — Toggle a prayer. Accepts prayer name string (e.g. 'protect_from_melee') or prayer ID number.
4221
+
4222
+ ### Timing (async)
4223
+ - \`await sdk.waitForTicks(n)\` — Wait n game ticks. Each tick ≈ 0.6 seconds.
4224
+ - \`await sdk.waitForStateChange(timeoutMs)\` — Wait for any state update.
4225
+ - \`await sdk.waitForCondition(fn, timeoutMs)\` — Wait until fn(state) returns true.
4226
+
4227
+ ---
4228
+
4229
+ ## State Object Shape
4230
+
4231
+ \`\`\`
4232
+ sdk.getState() returns:
4233
+ {
4234
+ tick: number, // Current game tick
4235
+ player: {
4236
+ name: string,
4237
+ worldX: number, // Your X coordinate
4238
+ worldZ: number, // Your Z coordinate
4239
+ level: number, // Floor level (0 = ground)
4240
+ hp: number, // Current hitpoints
4241
+ maxHp: number, // Max hitpoints
4242
+ combatLevel: number,
4243
+ animId: number, // Current animation ID (-1 = idle)
4244
+ combat: { // Combat sub-state
4245
+ inCombat: boolean,
4246
+ targetIndex: number,
4247
+ },
4248
+ },
4249
+ inGame: boolean, // Whether connected to game
4250
+ skills: [...], // Array of skill objects
4251
+ inventory: [...], // Array of inventory slots
4252
+ equipment: [...], // Array of equipment slots
4253
+ groundItems: [...], // Nearby ground items (each has .name, .x, .z, .id, .count, .distance)
4254
+ nearbyPlayers: [...], // Nearby players (each has .index, .name, .x, .z, .distance, .combatLevel)
4255
+ nearbyNpcs: [...], // Nearby NPCs (each has .index, .name, .x, .z, .distance, .hp, .maxHp)
4256
+ nearbyLocs: [...], // Nearby game objects (each has .id, .name, .x, .z, .distance, .options)
4257
+ dialog: { isOpen, ... }, // Dialog state
4258
+ modalOpen: boolean, // Whether a modal is open
4259
+ gameMessages: [...], // Recent game messages
4260
+ }
4261
+ \`\`\`
4262
+
4263
+ IMPORTANT PROPERTY NAMES:
4264
+ - Player position: \`.player.worldX\`, \`.player.worldZ\` (NOT .localPlayer, NOT .x/.z)
4265
+ - Player HP: \`.player.hp\`, \`.player.maxHp\` (NOT .hitpoints, NOT .hitpointsBase)
4266
+ - Ground item position: \`.x\`, \`.z\` (NOT .worldX, NOT .worldZ)
4267
+ - Nearby player position: \`.x\`, \`.z\` (NOT .worldX, NOT .worldZ)
4268
+
4269
+ ---
4270
+
4271
+ ## Common Patterns
4272
+
4273
+ ### Quick loot (walk + pick up):
4274
+ \`\`\`
4275
+ // Option A: Use bot.pickupItem (walks to item automatically, throws on failure)
4276
+ try { await bot.pickupItem(/lobster/i); } catch(e) { console.log("Missed lobster"); }
4277
+
4278
+ // Option B: Manual walk + raw pickup (more control)
4279
+ const item = sdk.findGroundItem(/lobster/i);
4280
+ if (item) {
4281
+ sdk.sendWalk(item.x, item.z); // Walk to item
4282
+ await sdk.waitForTicks(5); // Wait to arrive
4283
+ sdk.sendPickup(item.x, item.z, item.id); // Pick up (args: x, z, itemId)
4284
+ await sdk.waitForTicks(2); // Wait for server
4285
+ }
4286
+
4287
+ // Equip from inventory
4288
+ await bot.equipItem(/scimitar/i);
4289
+ \`\`\`
4290
+
4291
+ ### Combat loop:
4292
+ \`\`\`
4293
+ const endTime = Date.now() + 15000;
4294
+ while (Date.now() < endTime) {
4295
+ const state = sdk.getState();
4296
+ if (state.player.hp < 30) {
4297
+ try { await bot.eatFood(/lobster|swordfish|salmon/i); } catch(e) {}
4298
+ }
4299
+ const players = sdk.getNearbyPlayers();
4300
+ if (players.length > 0) {
4301
+ const target = players.sort((a, b) => a.distance - b.distance)[0];
4302
+ try { await bot.attackPlayer(target.name); } catch(e) {}
4303
+ }
4304
+ await sdk.waitForTicks(2);
4305
+ }
4306
+ \`\`\`
4307
+
4308
+ ### Movement tip:
4309
+ For combat/arena play, use \`sdk.sendWalk(x, z)\` + \`await sdk.waitForTicks(n)\` instead of \`bot.walkTo()\`.
4310
+ \`bot.walkTo()\` uses server pathfinding which can be slow or fail on complex terrain.
4311
+ \`sdk.sendWalk()\` just clicks the tile directly — fast and reliable for short distances.
4312
+ `;
4313
+ server.setRequestHandler(ListResourcesRequestSchema, async () => {
4314
+ return {
4315
+ resources: [
4316
+ {
4317
+ uri: "killswitch://sdk-reference",
4318
+ name: "Kill Switch SDK Reference",
4319
+ description: "Complete API reference for bot, sdk, and actions objects used in execute_code. READ THIS FIRST before writing any game code.",
4320
+ mimeType: "text/markdown"
4321
+ }
4322
+ ]
4323
+ };
4324
+ });
4325
+ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
4326
+ const { uri } = request.params;
4327
+ if (uri === "killswitch://sdk-reference") {
4328
+ return {
4329
+ contents: [
4330
+ {
4331
+ uri: "killswitch://sdk-reference",
4332
+ mimeType: "text/markdown",
4333
+ text: SDK_REFERENCE
4334
+ }
4335
+ ]
4336
+ };
4337
+ }
4338
+ throw new Error(`Unknown resource: ${uri}`);
4339
+ });
4144
4340
  server.setRequestHandler(ListToolsRequestSchema, async () => {
4145
4341
  return {
4146
4342
  tools: [
@@ -4165,16 +4361,17 @@ ${GAME_DESCRIPTION}`,
4165
4361
  },
4166
4362
  {
4167
4363
  name: "execute_code",
4168
- description: `Execute TypeScript code on your connected bot. The code runs in an async context with three globals:
4169
- - bot: High-level actions (await bot.pickupItem(/name/i), bot.equipItem(), bot.eatFood(), bot.attackPlayer(), bot.walkTo())
4170
- - sdk: Low-level state/commands (sdk.getState(), sdk.sendWalk(x,z), sdk.getNearbyPlayers(), sdk.getInventory(), sdk.findGroundItem())
4171
- - actions: Pre-built strategy functions from bot's actions/ directory (listed at login)
4364
+ description: `Execute TypeScript code on your connected bot. Three globals available: bot, sdk, actions.
4172
4365
 
4173
- State object: sdk.getState().player.worldX, .worldZ, .hp, .maxHp
4174
- Movement: sdk.sendWalk(x, z) for quick moves, bot.walkTo(x, z) for pathfinding
4175
- Timing: await sdk.waitForTicks(n) — each tick is ~0.6 seconds
4366
+ IMPORTANT: Read the "Kill Switch SDK Reference" resource (killswitch://sdk-reference) for the complete API.
4367
+ Do NOT guess method names or property paths only use what is documented in the SDK reference.
4176
4368
 
4177
- Blocking UI is auto-dismissed before your code runs — do NOT call bot.dismissBlockingUI().
4369
+ Quick reminders:
4370
+ - bot methods are async and THROW on failure
4371
+ - sdk.getState().player.worldX / .worldZ / .hp / .maxHp
4372
+ - Ground items use .x / .z (NOT .worldX)
4373
+ - sdk.sendWalk(x, z) for fast movement, bot.walkTo(x, z) for pathfinding
4374
+ - Blocking UI is auto-dismissed — do NOT call bot.dismissBlockingUI()
4178
4375
 
4179
4376
  You MUST call login before using this tool.`,
4180
4377
  inputSchema: {
@@ -4572,6 +4769,10 @@ server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
4572
4769
  "",
4573
4770
  "After joining a game, call wait_for_game_start to wait for the game to begin."
4574
4771
  ];
4772
+ parts.push("");
4773
+ parts.push("── IMPORTANT: Read the SDK Reference ──");
4774
+ parts.push('Before writing any execute_code, read the "Kill Switch SDK Reference" resource (killswitch://sdk-reference).');
4775
+ parts.push("It contains the complete API for bot, sdk, and actions. Do NOT guess method names — use only what is documented.");
4575
4776
  if (activeActionDescriptions.length > 0) {
4576
4777
  parts.push("");
4577
4778
  parts.push("── Loaded Actions ──");
@@ -4654,14 +4855,23 @@ server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
4654
4855
  reject(new Error(typeof signal.reason === "string" ? signal.reason : "Code execution cancelled"));
4655
4856
  }, { once: true });
4656
4857
  });
4657
- const cancellable = (target) => new Proxy(target, {
4858
+ const cancellable = (target, throwOnFailure = false) => new Proxy(target, {
4658
4859
  get(obj, prop, receiver) {
4659
4860
  const value = Reflect.get(obj, prop, receiver);
4660
4861
  if (typeof value === "function") {
4661
4862
  return (...args2) => {
4662
4863
  if (signal.aborted)
4663
4864
  throw new Error("Execution cancelled");
4664
- return value.apply(obj, args2);
4865
+ const ret = value.apply(obj, args2);
4866
+ if (throwOnFailure && ret && typeof ret.then === "function") {
4867
+ return ret.then((result2) => {
4868
+ if (result2 && typeof result2 === "object" && result2.success === false) {
4869
+ throw new Error(result2.message || `${String(prop)} failed`);
4870
+ }
4871
+ return result2;
4872
+ });
4873
+ }
4874
+ return ret;
4665
4875
  };
4666
4876
  }
4667
4877
  return value;
@@ -4670,7 +4880,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
4670
4880
  await connection.bot.dismissBlockingUI();
4671
4881
  let result;
4672
4882
  try {
4673
- result = await Promise.race([fn(cancellable(connection.bot), cancellable(connection.sdk), activeActions), timeoutPromise, cancelPromise]);
4883
+ result = await Promise.race([fn(cancellable(connection.bot, true), cancellable(connection.sdk), activeActions), timeoutPromise, cancelPromise]);
4674
4884
  } finally {
4675
4885
  clearTimeout(timeoutId);
4676
4886
  if (!signal.aborted)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kill-switch-mcp",
3
- "version": "1.1.8",
3
+ "version": "1.1.10",
4
4
  "description": "Kill Switch MCP Server — AI battle royale powered by Claude Code",
5
5
  "type": "module",
6
6
  "bin": {