breakpoint-mcp 1.0.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.
@@ -0,0 +1,125 @@
1
+ import { z } from "zod";
2
+ import { gate } from "../confirm.js";
3
+ import { ok } from "./lsp-common.js";
4
+ const confirmField = {
5
+ confirm: z.boolean().optional().describe("Auto-approve this destructive action (skip the confirmation prompt)"),
6
+ };
7
+ /**
8
+ * Runtime-bridge tools (Plane C). Each forwards to the in-game autoload
9
+ * (BreakpointRuntimeBridge) over TCP. These only work while the project is running.
10
+ */
11
+ function fail(err) {
12
+ const be = err;
13
+ return {
14
+ isError: true,
15
+ content: [{ type: "text", text: `Runtime error [${be?.code ?? "error"}]: ${be?.message ?? String(err)}` }],
16
+ };
17
+ }
18
+ export function registerRuntimeTools(server, runtime) {
19
+ const call = async (method, params = {}) => {
20
+ try {
21
+ return ok(await runtime.request(method, params));
22
+ }
23
+ catch (err) {
24
+ return fail(err);
25
+ }
26
+ };
27
+ server.registerTool("runtime_get_tree", {
28
+ title: "Runtime scene tree",
29
+ description: "Traverse the LIVE SceneTree of the running game (name, type, path, visibility, children).",
30
+ inputSchema: { max_depth: z.number().int().positive().optional().describe("Max recursion depth (default 64)") },
31
+ }, async ({ max_depth }) => call("runtime.get_tree", max_depth ? { max_depth } : {}));
32
+ server.registerTool("runtime_get_property", {
33
+ title: "Runtime get property",
34
+ description: "Read a property from a live node (path relative to the current scene; '/root/...' absolute allowed).",
35
+ inputSchema: { path: z.string(), property: z.string() },
36
+ }, async ({ path, property }) => call("runtime.get_property", { path, property }));
37
+ server.registerTool("runtime_set_property", {
38
+ title: "Runtime set property",
39
+ description: "Set a property on a live node. DESTRUCTIVE (mutates running game state) — gated by confirmation. Rich types use the {\"__type__\":...} convention.",
40
+ inputSchema: { path: z.string(), property: z.string(), value: z.any(), ...confirmField },
41
+ }, async ({ path, property, value, confirm }) => {
42
+ const blocked = await gate(server, confirm, `Set live property ${path}.${property}`);
43
+ if (blocked)
44
+ return blocked;
45
+ return call("runtime.set_property", { path, property, value });
46
+ });
47
+ server.registerTool("runtime_call_method", {
48
+ title: "Runtime call method",
49
+ description: "Invoke a method on a live node. DESTRUCTIVE (arbitrary invocation) — gated by confirmation. Args use the tagged-Variant convention.",
50
+ inputSchema: { path: z.string(), method: z.string(), args: z.array(z.any()).optional(), ...confirmField },
51
+ }, async ({ path, method, args, confirm }) => {
52
+ const blocked = await gate(server, confirm, `Call ${path}.${method}() on the running game`);
53
+ if (blocked)
54
+ return blocked;
55
+ return call("runtime.call_method", { path, method, args: args ?? [] });
56
+ });
57
+ server.registerTool("runtime_emit_signal", {
58
+ title: "Runtime emit signal",
59
+ description: "Emit a signal from a live node. DESTRUCTIVE — gated by confirmation.",
60
+ inputSchema: { path: z.string(), signal: z.string(), args: z.array(z.any()).optional(), ...confirmField },
61
+ }, async ({ path, signal, args, confirm }) => {
62
+ const blocked = await gate(server, confirm, `Emit signal "${signal}" from ${path}`);
63
+ if (blocked)
64
+ return blocked;
65
+ return call("runtime.emit_signal", { path, signal, args: args ?? [] });
66
+ });
67
+ server.registerTool("runtime_inject_input", {
68
+ title: "Runtime inject input",
69
+ description: "Inject a synthetic input event for automated play-testing. DESTRUCTIVE. " +
70
+ "event.kind is 'action' | 'key' | 'mouse_button' | 'mouse_motion'. " +
71
+ "Example: {\"kind\":\"action\",\"action\":\"jump\",\"pressed\":true}.",
72
+ inputSchema: {
73
+ event: z.object({
74
+ kind: z.enum(["action", "key", "mouse_button", "mouse_motion"]),
75
+ action: z.string().optional(),
76
+ strength: z.number().optional(),
77
+ keycode: z.number().int().optional(),
78
+ button: z.number().int().optional(),
79
+ pressed: z.boolean().optional(),
80
+ position: z.any().optional(),
81
+ relative: z.any().optional(),
82
+ }),
83
+ ...confirmField,
84
+ },
85
+ }, async ({ event, confirm }) => {
86
+ const blocked = await gate(server, confirm, `Inject ${event.kind} input event into the running game`);
87
+ if (blocked)
88
+ return blocked;
89
+ return call("runtime.inject_input", { event });
90
+ });
91
+ server.registerTool("runtime_get_monitors", {
92
+ title: "Runtime performance monitors",
93
+ description: "Read live Performance monitors (FPS, draw calls, node count, physics, audio output latency, ...). " +
94
+ "Pass specific keys or omit for all. Keys include time/fps, render/total_draw_calls, audio/output_latency.",
95
+ inputSchema: { keys: z.array(z.string()).optional() },
96
+ }, async ({ keys }) => call("runtime.get_monitors", keys ? { keys } : {}));
97
+ server.registerTool("runtime_screenshot", {
98
+ title: "Runtime screenshot",
99
+ description: "Capture the current game frame as a PNG and return it as image content so the assistant can see the running game.",
100
+ inputSchema: {},
101
+ }, async () => {
102
+ try {
103
+ const r = (await runtime.request("runtime.screenshot", {}));
104
+ return {
105
+ content: [
106
+ { type: "image", data: r.base64, mimeType: r.mime },
107
+ { type: "text", text: `Captured game frame (${r.width}x${r.height}).` },
108
+ ],
109
+ };
110
+ }
111
+ catch (err) {
112
+ return fail(err);
113
+ }
114
+ });
115
+ server.registerTool("runtime_get_log", {
116
+ title: "Runtime log",
117
+ description: "Read the runtime log ring buffer (entries game code pushed via BreakpointRuntimeBridge.push_log). " +
118
+ "Use since_seq for incremental reads.",
119
+ inputSchema: {
120
+ since_seq: z.number().int().optional().describe("Return only entries with seq greater than this (default 0)"),
121
+ levels: z.array(z.string()).optional().describe("Filter to these levels, e.g. [\"error\",\"warning\"]"),
122
+ },
123
+ }, async ({ since_seq, levels }) => call("runtime.get_log", { since_seq: since_seq ?? 0, levels: levels ?? [] }));
124
+ }
125
+ //# sourceMappingURL=runtime.js.map
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "breakpoint-mcp",
3
+ "version": "1.0.0",
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
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": {
8
+ "name": "James Livingston",
9
+ "url": "https://github.com/jlivingston-Cipher"
10
+ },
11
+ "homepage": "https://github.com/jlivingston-Cipher/godot-breakpoint-mcp#readme",
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/jlivingston-Cipher/godot-breakpoint-mcp.git",
15
+ "directory": "host"
16
+ },
17
+ "bugs": {
18
+ "url": "https://github.com/jlivingston-Cipher/godot-breakpoint-mcp/issues"
19
+ },
20
+ "keywords": [
21
+ "godot",
22
+ "mcp",
23
+ "model-context-protocol",
24
+ "claude",
25
+ "gdscript",
26
+ "game-development",
27
+ "lsp",
28
+ "dap"
29
+ ],
30
+ "bin": {
31
+ "breakpoint-mcp": "dist/index.js"
32
+ },
33
+ "files": [
34
+ "dist/**/*.js",
35
+ "README.md",
36
+ "LICENSE"
37
+ ],
38
+ "scripts": {
39
+ "build": "tsc",
40
+ "typecheck": "tsc --noEmit",
41
+ "test": "tsc -p tsconfig.test.json && node --test dist-test/test/*.test.js",
42
+ "start": "node dist/index.js",
43
+ "dev": "tsc && node dist/index.js",
44
+ "prepublishOnly": "npm run build"
45
+ },
46
+ "engines": {
47
+ "node": ">=18"
48
+ },
49
+ "dependencies": {
50
+ "@modelcontextprotocol/sdk": "^1.17.0",
51
+ "zod": "^3.23.8"
52
+ },
53
+ "devDependencies": {
54
+ "@types/node": "^20.14.0",
55
+ "typescript": "^5.5.0"
56
+ }
57
+ }