breakpoint-mcp 1.13.0 → 1.14.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/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  The MCP **host** for [Breakpoint MCP](https://github.com/jlivingston-Cipher/godot-breakpoint-mcp) —
4
4
  a [Model Context Protocol](https://modelcontextprotocol.io) server that exposes the
5
5
  Godot game engine to AI coding assistants across four planes: headless CLI, the live
6
- editor, Godot's own LSP + DAP, and a runtime bridge inside the running game. **270 tools
6
+ editor, Godot's own LSP + DAP, and a runtime bridge inside the running game. **271 tools
7
7
  + 5 MCP resources**, built against the stable `@modelcontextprotocol/sdk` 1.x API.
8
8
  Developed and tested with **Claude**; because MCP is an open protocol, other clients can
9
9
  connect too (currently untested — reports welcome).
package/dist/schemas.js CHANGED
@@ -693,6 +693,7 @@ export const outputSchemas = {
693
693
  container_path: z.string(),
694
694
  mode: z.string(),
695
695
  count: z.number(),
696
+ persisted: z.boolean(),
696
697
  instances: z.array(z.object({ index: z.number(), instance_path: z.string() })),
697
698
  },
698
699
  card_deck_from_table: {
@@ -701,6 +702,7 @@ export const outputSchemas = {
701
702
  rows_read: z.number(),
702
703
  rows_skipped: z.number(),
703
704
  unmapped_columns: z.array(z.string()),
705
+ persisted: z.boolean(),
704
706
  instances: z.array(z.object({ row_index: z.number(), instance_path: z.string() })),
705
707
  },
706
708
  card_set_face: {
@@ -771,6 +773,7 @@ export const outputSchemas = {
771
773
  unbound: z.array(z.string()),
772
774
  placed: z.boolean(),
773
775
  cell: z.string().nullable(),
776
+ persisted: z.boolean(),
774
777
  },
775
778
  piece_move: {
776
779
  moved: z.boolean(),
@@ -505,15 +505,20 @@ export async function emitCardHand(emit, args) {
505
505
  const container = args.parent === "" ? "." : args.parent;
506
506
  const base = sceneRootName(args.template_path);
507
507
  const places = computeLayout(args.mode, args.cards.length, args);
508
+ // Finding-A save-persistence (opt-in), threaded per-card through emitOneCard: when
509
+ // set, every card in the hand gets Editable Children so its bound slot data serializes
510
+ // on save instead of reverting on reload. Default off keeps the runtime-bound contract.
511
+ const persisted = args.persist === true;
508
512
  const instances = [];
509
513
  for (let i = 0; i < args.cards.length; i++) {
510
514
  const { instance_path } = await emitOneCard(emit, {
511
515
  template_path: args.template_path, parent: container, data: args.cards[i].data,
512
516
  name: `${base}_${i}`, face_up: args.cards[i].face_up ?? true, placement: places[i],
517
+ persist: args.persist,
513
518
  });
514
519
  instances.push({ index: i, instance_path });
515
520
  }
516
- return { container_path: container, mode: args.mode, count: instances.length, instances };
521
+ return { container_path: container, mode: args.mode, count: instances.length, persisted, instances };
517
522
  }
518
523
  export async function emitDeckFromTable(emit, readFile, args) {
519
524
  const container = args.parent === "" ? "." : args.parent;
@@ -558,13 +563,15 @@ export async function emitDeckFromTable(emit, readFile, args) {
558
563
  const { instance_path } = await emitOneCard(emit, {
559
564
  template_path: args.template_path, parent: container, data, name, face_up,
560
565
  placement: args.layout ? places[i] : undefined,
566
+ persist: args.persist,
561
567
  });
562
568
  instances.push({ row_index: allRows.indexOf(row), instance_path });
563
569
  }
564
570
  const unmapped_columns = [...header].filter((c) => !referenced.has(c)).sort();
565
571
  return {
566
572
  deck_container: container, count: instances.length, rows_read,
567
- rows_skipped: rows_read - instances.length, unmapped_columns, instances,
573
+ rows_skipped: rows_read - instances.length, unmapped_columns,
574
+ persisted: args.persist === true, instances,
568
575
  };
569
576
  }
570
577
  /**
@@ -1023,13 +1030,25 @@ export async function emitPieceInstance(emit, args) {
1023
1030
  const res = await emit("node.call_method", { path: instPath, method: "set_data", args: [args.data] });
1024
1031
  await emit("node.call_method", { path: instPath, method: "set_face", args: [face_up] });
1025
1032
  const { bound, unbound } = splitFromCall(res, args.data);
1033
+ // Finding-A save-persistence (opt-in), mirroring card_instance. set_data mutates the
1034
+ // piece's internal Art/Label nodes, but a sealed sub-scene doesn't serialize those
1035
+ // overrides, so they revert on reload. Enabling "Editable Children" bakes them into the
1036
+ // saved scene. Emitted last, on the piece's final resting path (after any place_on
1037
+ // reparent). Default off preserves the lighter runtime-bound contract.
1038
+ const persisted = args.persist === true;
1026
1039
  if (args.place_on) {
1027
1040
  const placed = await emitBoardPlace(emit, {
1028
1041
  board: args.place_on.board, cell: args.place_on.cell, node: instPath, align: args.place_on.align,
1029
1042
  });
1030
- return { instance_path: placed.node_path, face_up, bound, unbound, placed: true, cell: args.place_on.cell };
1043
+ if (persisted) {
1044
+ await emit("node.set_editable_instance", { path: placed.node_path, editable: true });
1045
+ }
1046
+ return { instance_path: placed.node_path, face_up, bound, unbound, placed: true, cell: args.place_on.cell, persisted };
1047
+ }
1048
+ if (persisted) {
1049
+ await emit("node.set_editable_instance", { path: instPath, editable: true });
1031
1050
  }
1032
- return { instance_path: instPath, face_up, bound, unbound, placed: false, cell: null };
1051
+ return { instance_path: instPath, face_up, bound, unbound, placed: false, cell: null, persisted };
1033
1052
  }
1034
1053
  /**
1035
1054
  * Move a piece onto a destination cell (reusing `board_place` for the reparent +
@@ -1416,6 +1435,7 @@ export function registerTabletopTools(server, bridge, config) {
1416
1435
  })).min(1).describe("One entry per card to instance"),
1417
1436
  mode: z.enum(["row", "fan", "stack", "grid"]).describe("Arrangement mode"),
1418
1437
  ...layoutKnobs,
1438
+ persist: z.boolean().optional().describe("Bake each card's bound slot data into the saved scene by enabling Editable Children on every instanced card (default false = runtime-bound only, reverts on reload)"),
1419
1439
  },
1420
1440
  }, async (raw) => {
1421
1441
  const a = raw;
@@ -1452,6 +1472,7 @@ export function registerTabletopTools(server, bridge, config) {
1452
1472
  align: z.enum(["start", "center", "end"]).optional(),
1453
1473
  origin: z.object({ x: z.number(), y: z.number() }).optional(),
1454
1474
  }).optional().describe("Optional arrangement (same knobs as card_hand_layout); omitted → stacked at origin"),
1475
+ persist: z.boolean().optional().describe("Bake each stamped card's bound slot data into the saved scene by enabling Editable Children on every card (default false = runtime-bound only, reverts on reload)"),
1455
1476
  },
1456
1477
  }, async (raw) => {
1457
1478
  const a = raw;
@@ -1677,6 +1698,7 @@ export function registerTabletopTools(server, bridge, config) {
1677
1698
  cell: z.string().describe("Cell id to place onto (resolves to <board>/cell_<cell>)"),
1678
1699
  align: z.object({ x: z.number(), y: z.number() }).optional().describe("Offset from the cell origin in px (default centred)"),
1679
1700
  }).optional().describe("Optionally place the new piece on a board cell in the same call"),
1701
+ persist: z.boolean().optional().describe("Bake the bound data into the saved scene by enabling Editable Children on the instance (default false = runtime-bound only, reverts on reload)"),
1680
1702
  },
1681
1703
  }, async (raw) => {
1682
1704
  const a = raw;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "breakpoint-mcp",
3
- "version": "1.13.0",
3
+ "version": "1.14.0",
4
4
  "description": "MCP server exposing Godot to AI coding assistants over the Model Context Protocol — developed and tested with Claude — across four planes (CLI, live editor, LSP+DAP, runtime) with elicitation-gated destructive tools, long jobs on the formal MCP task model, captured console output, and MCP resources.",
5
5
  "type": "module",
6
6
  "license": "MIT",