cbm-mcp 0.0.0-stage → 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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Manfred Hantschel
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,144 @@
1
- # Temporary Holding Version
1
+ # CBM MCP: VICE Monitor
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ [![Build](https://github.com/thred/cbm-mcp/actions/workflows/build.yml/badge.svg)](https://github.com/thred/cbm-mcp/actions/workflows/build.yml)
4
+ [![License: MIT](https://img.shields.io/github/license/thred/cbm-mcp)](LICENSE)
5
+ [![Node.js](https://img.shields.io/badge/node-%3E%3D24-brightgreen)](package.json)
6
+
7
+ An MCP server that lets AI agents debug Commodore software in a locally running
8
+ [VICE](https://vice-emu.sourceforge.io/) emulator, through VICE's text remote
9
+ monitor.
10
+
11
+ It runs **locally over stdio**, next to VICE. Nothing is hosted, and the
12
+ unauthenticated VICE monitor should never be exposed beyond loopback.
13
+
14
+ ## What You Can Do
15
+
16
+ The server covers the command families of the
17
+ [VICE monitor](https://vice-emu.sourceforge.io/vice_12.html), so an agent can:
18
+
19
+ - **Inspect** CPU registers, memory (as hex, PETSCII or screen codes), the text
20
+ screen, call stacks, memory banks and I/O state.
21
+ - **Disassemble and assemble** code, and annotate it with labels and comments.
22
+ - **Control execution** by stepping, running until a condition, setting
23
+ breakpoints, watchpoints and tracepoints, and resuming or resetting the machine.
24
+ - **Modify state** by writing registers and memory, filling, moving, comparing
25
+ and searching memory, and typing on the emulated keyboard.
26
+ - **Work with media and files** such as disk images, programs, snapshots and
27
+ binary data, as well as VICE settings and resources.
28
+ - **Profile and trace** with CPU history and profiling data, where the VICE
29
+ build supports it.
30
+ - **Export graphics** such as sprites and character sets as images, and capture
31
+ screenshots.
32
+
33
+ The available commands depend on the VICE version, the emulated machine, and
34
+ build options. The server also sends debugging guidance to the agent, covering
35
+ safe inspection, memory banking, side effects and cleanup. A
36
+ [command catalog](docs/commands.md) documents the details.
37
+
38
+ ## Quick Start
39
+
40
+ You need Node.js 24+ and a VICE emulator with its text remote monitor enabled.
41
+
42
+ 1. Start VICE with the text monitor (the executable name depends on your
43
+ installation and machine; do not use the binary monitor):
44
+
45
+ ```sh
46
+ x64sc -remotemonitor -remotemonitoraddress ip4://127.0.0.1:6510
47
+ ```
48
+
49
+ 2. Add the server to your MCP client's configuration:
50
+
51
+ ```json
52
+ {
53
+ "servers": {
54
+ "cbm-mcp": {
55
+ "type": "stdio",
56
+ "command": "npx",
57
+ "args": ["--yes", "cbm-mcp@latest"]
58
+ }
59
+ }
60
+ }
61
+ ```
62
+
63
+ 3. Ask your agent, for example: "Connect to VICE and show the CPU registers."
64
+
65
+ Harnesses differ in where they keep this configuration, and some use
66
+ `mcpServers` instead of `servers`. Pin a version instead of `latest` for
67
+ repeatable setups.
68
+
69
+ ### Configuration
70
+
71
+ Optional environment variables, set in the client's `env` object:
72
+
73
+ | Variable | Default | Meaning |
74
+ | ----------------- | ----------- | ------------------------------------------------- |
75
+ | `VICE_HOST` | `127.0.0.1` | Monitor hostname or IP address, without `ip4://` |
76
+ | `VICE_PORT` | `6510` | Text monitor TCP port |
77
+ | `VICE_TIMEOUT_MS` | `5000` | Timeout per handshake or command, in milliseconds |
78
+
79
+ Invalid settings fail startup with a diagnostic on stderr. Starting the MCP does
80
+ not connect to or pause VICE.
81
+
82
+ ## Agent Skill via APM
83
+
84
+ This repository is also an [APM](https://github.com/microsoft/apm) package. It
85
+ ships the `cbm-mcp` agent skill with C64, VIC-II and 6510 reference material,
86
+ which complements the general guidance the server already provides. Install it
87
+ into a project with:
88
+
89
+ ```sh
90
+ apm install thred/cbm-mcp
91
+ ```
92
+
93
+ APM deploys the skill for your configured agent targets. The MCP server entry in
94
+ [apm.yml](apm.yml) launches a local build (`dist/stdio.js`), so it only works
95
+ inside a source checkout; configure the server for other projects as described
96
+ in Quick Start.
97
+
98
+ ## Safety
99
+
100
+ - Connecting to the monitor **pauses emulation**, and it stays paused until the
101
+ agent resumes it deliberately.
102
+ - Disconnecting never quits VICE. Only one monitor client can be attached at a
103
+ time, so use one controller at a time.
104
+ - Reading I/O can have side effects, which VICE's monitor can be told to
105
+ suppress. Stepping and writes change machine state and are not undone
106
+ automatically. A timeout cannot guarantee that a command did not execute, so
107
+ state-changing operations should not be retried blindly.
108
+ - Some capabilities reset or quit the emulator, write to disks, access host files
109
+ or run monitor scripts. Host paths are interpreted by VICE without a sandbox.
110
+ Use your MCP client's approval controls; tool annotations and confirmation
111
+ fields are not a security boundary, and only trusted clients and files should be
112
+ used.
113
+
114
+ ## Development
115
+
116
+ Install from source and run the checks:
117
+
118
+ ```sh
119
+ npm install
120
+ npm run build
121
+ npm test
122
+ npm run test:typecheck
123
+ ```
124
+
125
+ To use a checkout instead of the npm package, configure the client with
126
+ `"command": "node"` and `"args": ["/absolute/path/to/cbm-mcp/dist/cli.js"]`.
127
+ Launch the executable directly rather than through `npm start`, whose banners
128
+ would corrupt the MCP stream on stdout. `npm run dev` starts the TypeScript
129
+ sources for manual runs. Restart the server in the client after rebuilding.
130
+
131
+ The default tests use an in-process fixture instead of VICE. With VICE's text
132
+ monitor running, `npm run test:live` additionally runs read-only checks against
133
+ the real emulator. **It pauses the emulator and leaves it paused.** The live test
134
+ is skipped by default.
135
+
136
+ If a new connection times out even though the port is listening, disconnect other
137
+ monitor clients. VICE can also retain a stale session while paused: leave the
138
+ monitor or resume once in VICE's UI, then reconnect.
139
+
140
+ The source layout is small: the monitor connection (`src/vice/monitor-client.ts`)
141
+ is independent of MCP, the tools live in `src/vice/monitor-tools.ts`, the server
142
+ factory is in `src/server.ts`, and `src/cli.ts` and `src/stdio.ts` provide the
143
+ stdio executable. Other MCP transports can reuse the server factory; a
144
+ network-facing transport needs proper authentication.
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import "./stdio.js";
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,YAAY,CAAC"}
package/dist/cli.js ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import "./stdio.js";
3
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,YAAY,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { McpUtils, type McpTool, type ToolArguments } from "./mcp-utils.js";
2
+ export { createViceMonitorServer, createViceServer } from "./server.js";
3
+ export { MonitorClient, type MonitorOptions } from "./vice/monitor-client.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC5E,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,EAAE,aAAa,EAAE,KAAK,cAAc,EAAE,MAAM,0BAA0B,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { McpUtils } from "./mcp-utils.js";
2
+ export { createViceMonitorServer, createViceServer } from "./server.js";
3
+ export { MonitorClient } from "./vice/monitor-client.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAoC,MAAM,gBAAgB,CAAC;AAC5E,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,EAAE,aAAa,EAAuB,MAAM,0BAA0B,CAAC"}
@@ -0,0 +1,59 @@
1
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
+ import { type Tool } from "@modelcontextprotocol/sdk/types.js";
3
+ export type ToolArguments = Record<string, unknown>;
4
+ export interface McpTool extends Tool {
5
+ run: (args: ToolArguments) => Promise<string>;
6
+ }
7
+ export type McpToolMetadata = Pick<Tool, "name" | "description" | "inputSchema" | "annotations">;
8
+ export type FormattedArguments = Record<string, string>;
9
+ export interface ToolField {
10
+ schema: Record<string, unknown>;
11
+ optional?: boolean;
12
+ format: (value: unknown) => string;
13
+ }
14
+ /** Shared MCP server and argument helpers for the project's separate servers. */
15
+ export declare class McpUtils {
16
+ /** Mark a behavior method as an MCP tool using explicit runtime metadata. */
17
+ static tool(metadata: McpToolMetadata): MethodDecorator;
18
+ /** Validate an integer argument against an inclusive range. */
19
+ static integer(args: ToolArguments, name: string, min: number, max: number, fallback?: number): number;
20
+ /** Format a number as a VICE-style hexadecimal value. */
21
+ static hex(value: number, width?: number): string;
22
+ /** Validate a string argument against a fixed set of choices. */
23
+ static choice(args: ToolArguments, name: string, values: readonly string[], fallback?: string): string;
24
+ /** Build MCP tool metadata and an input schema from reusable field definitions. */
25
+ static toolMetadata(name: string, description: string, fields: Record<string, ToolField>, annotations?: Tool["annotations"]): McpToolMetadata;
26
+ /** Define an inclusive integer field and format its values for commands. */
27
+ static numberField(min?: number, max?: number, decimal?: boolean): ToolField;
28
+ /** Define a fixed-choice field, optionally formatting numeric choices as hexadecimal. */
29
+ static enumerationField(values: readonly (string | number | boolean)[], hexadecimal?: boolean): ToolField;
30
+ /** Define a bounded string field constrained by a regular expression. */
31
+ static textField(pattern: RegExp, description: string, maxLength?: number): ToolField;
32
+ /** Define a command-safe quoted string field. */
33
+ static quotedField(description: string, allowEmpty?: boolean): ToolField;
34
+ /** Define a string field for literal text that cannot contain control characters or backslashes. */
35
+ static keyboardTextField(description: string, maxLength?: number): ToolField;
36
+ /** Make a field optional and supply its command-token fallback when omitted. */
37
+ static optionalField(field: ToolField, fallback?: string): ToolField;
38
+ /** Define a bounded array field and format its entries as space-separated tokens. */
39
+ static arrayField(field: ToolField, maxItems?: number, unique?: boolean): ToolField;
40
+ /** Validate and format all provided values, rejecting unknown or null fields. */
41
+ static formatArguments(args: ToolArguments, fields: Record<string, ToolField>): FormattedArguments;
42
+ /** Join nonempty formatted arguments into a command token string. */
43
+ static joinArguments(...values: string[]): string;
44
+ private static containsLineBreakOrNull;
45
+ private static containsControlCharacter;
46
+ /** Create a protocol server from either a decorated catalog or an existing tool array. */
47
+ static createToolServer(name: string, catalog: object, options?: {
48
+ version?: string;
49
+ instructions?: string;
50
+ isError?: (text: string) => boolean;
51
+ }): Server;
52
+ static createToolServer(name: string, tools: McpTool[], options?: {
53
+ version?: string;
54
+ instructions?: string;
55
+ isError?: (text: string) => boolean;
56
+ }): Server;
57
+ private static decoratedTools;
58
+ }
59
+ //# sourceMappingURL=mcp-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-utils.d.ts","sourceRoot":"","sources":["../src/mcp-utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,259 @@
1
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
+ import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
3
+ const decoratedMethods = new WeakMap();
4
+ /** Shared MCP server and argument helpers for the project's separate servers. */
5
+ export class McpUtils {
6
+ /** Mark a behavior method as an MCP tool using explicit runtime metadata. */
7
+ static tool(metadata) {
8
+ return (target, propertyKey) => {
9
+ let methods = decoratedMethods.get(target);
10
+ if (!methods) {
11
+ methods = new Map();
12
+ decoratedMethods.set(target, methods);
13
+ }
14
+ methods.set(propertyKey, metadata);
15
+ };
16
+ }
17
+ /** Validate an integer argument against an inclusive range. */
18
+ static integer(args, name, min, max, fallback) {
19
+ const value = args[name] ?? fallback;
20
+ if (typeof value !== "number" || !Number.isInteger(value) || value < min || value > max) {
21
+ throw new Error(`${name} must be an integer from ${min} to ${max}.`);
22
+ }
23
+ return value;
24
+ }
25
+ /** Format a number as a VICE-style hexadecimal value. */
26
+ static hex(value, width = 4) {
27
+ return `$${value.toString(16).padStart(width, "0")}`;
28
+ }
29
+ /** Validate a string argument against a fixed set of choices. */
30
+ static choice(args, name, values, fallback) {
31
+ const value = args[name] ?? fallback;
32
+ if (typeof value !== "string" || !values.includes(value)) {
33
+ throw new Error(`${name} must be one of: ${values.join(", ")}.`);
34
+ }
35
+ return value;
36
+ }
37
+ /** Build MCP tool metadata and an input schema from reusable field definitions. */
38
+ static toolMetadata(name, description, fields, annotations) {
39
+ return {
40
+ name,
41
+ description,
42
+ inputSchema: {
43
+ type: "object",
44
+ properties: Object.fromEntries(Object.entries(fields).map(([key, field]) => [key, field.schema])),
45
+ required: Object.entries(fields)
46
+ .filter(([, field]) => !field.optional)
47
+ .map(([key]) => key),
48
+ additionalProperties: false,
49
+ },
50
+ ...(annotations === undefined ? {} : { annotations }),
51
+ };
52
+ }
53
+ /** Define an inclusive integer field and format its values for commands. */
54
+ static numberField(min = 0, max = 65535, decimal = false) {
55
+ return {
56
+ schema: { type: "integer", minimum: min, maximum: max },
57
+ format: (value) => {
58
+ if (typeof value !== "number" || !Number.isInteger(value) || value < min || value > max) {
59
+ throw new Error(`Expected an integer from ${min} to ${max}.`);
60
+ }
61
+ return decimal ? String(value) : `$${value.toString(16)}`;
62
+ },
63
+ };
64
+ }
65
+ /** Define a fixed-choice field, optionally formatting numeric choices as hexadecimal. */
66
+ static enumerationField(values, hexadecimal = false) {
67
+ return {
68
+ schema: { type: typeof values[0] === "number" ? "integer" : typeof values[0], enum: values },
69
+ format: (value) => {
70
+ if (!values.includes(value)) {
71
+ throw new Error(`Expected one of: ${values.join(", ")}.`);
72
+ }
73
+ return hexadecimal && typeof value === "number" ? `$${value.toString(16)}` : String(value);
74
+ },
75
+ };
76
+ }
77
+ /** Define a bounded string field constrained by a regular expression. */
78
+ static textField(pattern, description, maxLength = 4096) {
79
+ return {
80
+ schema: { type: "string", minLength: 1, maxLength, pattern: pattern.source, description },
81
+ format: (value) => {
82
+ if (typeof value !== "string" ||
83
+ !value.trim() ||
84
+ value.length > maxLength ||
85
+ McpUtils.containsLineBreakOrNull(value) ||
86
+ !pattern.test(value)) {
87
+ throw new Error(`Expected ${description} (maximum ${maxLength} characters).`);
88
+ }
89
+ return value;
90
+ },
91
+ };
92
+ }
93
+ /** Define a command-safe quoted string field. */
94
+ static quotedField(description, allowEmpty = false) {
95
+ return {
96
+ schema: { type: "string", minLength: allowEmpty ? 0 : 1, maxLength: 4096, description },
97
+ format: (value) => {
98
+ if (typeof value !== "string" ||
99
+ (!allowEmpty && !value.trim()) ||
100
+ value.length > 4096 ||
101
+ value.includes('"') ||
102
+ value.includes("\\") ||
103
+ McpUtils.containsControlCharacter(value)) {
104
+ throw new Error(`Expected ${description}, without double quotes, backslashes, or control characters.`);
105
+ }
106
+ return `"${value}"`;
107
+ },
108
+ };
109
+ }
110
+ /** Define a string field for literal text that cannot contain control characters or backslashes. */
111
+ static keyboardTextField(description, maxLength = 4096) {
112
+ return {
113
+ schema: { type: "string", minLength: 1, maxLength, description },
114
+ format: (value) => {
115
+ if (typeof value !== "string" ||
116
+ !value.trim() ||
117
+ value.length > maxLength ||
118
+ value.includes("\\") ||
119
+ McpUtils.containsControlCharacter(value)) {
120
+ throw new Error(`Expected ${description}, without backslashes or control characters.`);
121
+ }
122
+ return value;
123
+ },
124
+ };
125
+ }
126
+ /** Make a field optional and supply its command-token fallback when omitted. */
127
+ static optionalField(field, fallback = "") {
128
+ return { ...field, optional: true, format: (value) => (value === undefined ? fallback : field.format(value)) };
129
+ }
130
+ /** Define a bounded array field and format its entries as space-separated tokens. */
131
+ static arrayField(field, maxItems = 256, unique = false) {
132
+ return {
133
+ schema: { type: "array", items: field.schema, minItems: 1, maxItems, uniqueItems: unique },
134
+ format: (value) => {
135
+ if (!Array.isArray(value) ||
136
+ value.length < 1 ||
137
+ value.length > maxItems ||
138
+ (unique && new Set(value).size !== value.length)) {
139
+ throw new Error(`Expected 1-${maxItems} ${unique ? "unique " : ""}items.`);
140
+ }
141
+ return value.map((entry) => field.format(entry)).join(" ");
142
+ },
143
+ };
144
+ }
145
+ /** Validate and format all provided values, rejecting unknown or null fields. */
146
+ static formatArguments(args, fields) {
147
+ for (const key of Object.keys(args)) {
148
+ if (!Object.hasOwn(fields, key)) {
149
+ throw new Error(`Unknown argument: ${key}`);
150
+ }
151
+ }
152
+ return Object.fromEntries(Object.entries(fields).map(([key, field]) => {
153
+ if (args[key] === null) {
154
+ throw new Error(`${key} must not be null.`);
155
+ }
156
+ try {
157
+ return [key, field.format(args[key])];
158
+ }
159
+ catch (error) {
160
+ throw new Error(`${key}: ${error instanceof Error ? error.message : String(error)}`, {
161
+ cause: error,
162
+ });
163
+ }
164
+ }));
165
+ }
166
+ /** Join nonempty formatted arguments into a command token string. */
167
+ static joinArguments(...values) {
168
+ return values.filter(Boolean).join(" ");
169
+ }
170
+ static containsLineBreakOrNull(value) {
171
+ for (const character of value) {
172
+ const code = character.charCodeAt(0);
173
+ if (code === 0x0a || code === 0x0d || code === 0x00) {
174
+ return true;
175
+ }
176
+ }
177
+ return false;
178
+ }
179
+ static containsControlCharacter(value) {
180
+ for (const character of value) {
181
+ const code = character.charCodeAt(0);
182
+ if (code < 0x20 || code === 0x7f) {
183
+ return true;
184
+ }
185
+ }
186
+ return false;
187
+ }
188
+ static createToolServer(name, catalogOrTools, options = {}) {
189
+ const tools = Array.isArray(catalogOrTools) ? catalogOrTools : this.decoratedTools(catalogOrTools);
190
+ const names = new Set();
191
+ for (const tool of tools) {
192
+ if (names.has(tool.name)) {
193
+ throw new Error(`Duplicate MCP tool name: ${tool.name}`);
194
+ }
195
+ names.add(tool.name);
196
+ }
197
+ const server = new Server({ name, version: options.version ?? "1.0.0" }, { capabilities: { tools: {} }, instructions: options.instructions });
198
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
199
+ tools: tools.map((tool) => {
200
+ const { run: unused, ...toolWithoutRun } = tool;
201
+ void unused;
202
+ return toolWithoutRun;
203
+ }),
204
+ }));
205
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
206
+ try {
207
+ const tool = tools.find((entry) => entry.name === request.params.name);
208
+ if (!tool) {
209
+ throw new Error(`Unknown tool: ${request.params.name}`);
210
+ }
211
+ const args = request.params.arguments ?? {};
212
+ for (const argumentName of Object.keys(args)) {
213
+ if (!Object.hasOwn(tool.inputSchema.properties ?? {}, argumentName)) {
214
+ throw new Error(`Unknown argument: ${argumentName}`);
215
+ }
216
+ if (args[argumentName] === null) {
217
+ throw new Error(`${argumentName} must not be null.`);
218
+ }
219
+ }
220
+ const text = await tool.run(args);
221
+ if (options.isError?.(text)) {
222
+ throw new Error(text);
223
+ }
224
+ return { content: [{ type: "text", text: text || "Command completed." }] };
225
+ }
226
+ catch (error) {
227
+ return {
228
+ isError: true,
229
+ content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }],
230
+ };
231
+ }
232
+ });
233
+ return server;
234
+ }
235
+ static decoratedTools(catalog) {
236
+ const tools = [];
237
+ for (let prototype = Object.getPrototypeOf(catalog); prototype && prototype !== Object.prototype; prototype = Object.getPrototypeOf(prototype)) {
238
+ for (const methodName of Object.getOwnPropertyNames(prototype)) {
239
+ const metadata = decoratedMethods.get(prototype)?.get(methodName);
240
+ const method = Object.getOwnPropertyDescriptor(prototype, methodName)?.value;
241
+ if (!metadata || typeof method !== "function") {
242
+ continue;
243
+ }
244
+ tools.push({
245
+ ...metadata,
246
+ run: async (args) => {
247
+ const result = await Reflect.apply(method, catalog, [args]);
248
+ if (typeof result !== "string") {
249
+ throw new Error(`Tool ${metadata.name} must return text.`);
250
+ }
251
+ return result;
252
+ },
253
+ });
254
+ }
255
+ }
256
+ return tools;
257
+ }
258
+ }
259
+ //# sourceMappingURL=mcp-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-utils.js","sourceRoot":"","sources":["../src/mcp-utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import { MonitorClient } from "./vice/monitor-client.js";
2
+ /** Creates the text-monitor MCP server without choosing a transport. */
3
+ export declare function createViceMonitorServer(monitor?: MonitorClient): import("@modelcontextprotocol/sdk/server").Server<{
4
+ method: string;
5
+ params?: {
6
+ [x: string]: unknown;
7
+ _meta?: {
8
+ [x: string]: unknown;
9
+ progressToken?: string | number | undefined;
10
+ "io.modelcontextprotocol/related-task"?: {
11
+ taskId: string;
12
+ } | undefined;
13
+ } | undefined;
14
+ } | undefined;
15
+ }, {
16
+ method: string;
17
+ params?: {
18
+ [x: string]: unknown;
19
+ _meta?: {
20
+ [x: string]: unknown;
21
+ progressToken?: string | number | undefined;
22
+ "io.modelcontextprotocol/related-task"?: {
23
+ taskId: string;
24
+ } | undefined;
25
+ } | undefined;
26
+ } | undefined;
27
+ }, {
28
+ [x: string]: unknown;
29
+ _meta?: {
30
+ [x: string]: unknown;
31
+ progressToken?: string | number | undefined;
32
+ "io.modelcontextprotocol/related-task"?: {
33
+ taskId: string;
34
+ } | undefined;
35
+ } | undefined;
36
+ }>;
37
+ /** @deprecated Use createViceMonitorServer for the text-monitor MCP. */
38
+ export declare const createViceServer: typeof createViceMonitorServer;
39
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAazD,wEAAwE;AACxE,wBAAgB,uBAAuB,CAAC,OAAO,gBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAKpE;AAED,wEAAwE;AACxE,eAAO,MAAM,gBAAgB,gCAA0B,CAAC"}
package/dist/server.js ADDED
@@ -0,0 +1,22 @@
1
+ import { McpUtils } from "./mcp-utils.js";
2
+ import { MonitorClient } from "./vice/monitor-client.js";
3
+ import { ViceMonitorTools } from "./vice/monitor-tools.js";
4
+ const DEBUGGER_INSTRUCTIONS = `Debug VICE through its text monitor. Start with vice_status (socket state only), vice_registers, and small reads. Use the current PC for disassembly. Inspection pauses emulation; reuse connections. Confirm machine, device/CPU, bank, and video model before hardware assumptions; use vice_help for command details.
5
+
6
+ JSON integers are decimal (53280 = $d020); prefix numbers in expressions. Length counts bytes; range ends are inclusive. vice_memory/disassemble target C:, while registers/stepping use the current device. Distinguish CPU-visible memory, RAM, and video memory; query vice_bank before choosing a view. Query vice_sidefx before I/O reads; preserve and restore its setting.
7
+
8
+ Prefer testable hypotheses, bounded reads/steps, and temporary checkpoints over patches. Stepping changes state; step-over/run-until can stall. No asynchronous breakpoint notifications: inspection itself can stop execution. Remove only your own checkpoints/labels.
9
+
10
+ Establish user intent before mutations, execution control, or file operations; preserve affected state. Never blindly retry a timed-out mutation. Command delivery is not success acknowledgment. An expected read returning only 'Command completed.' has no usable data; try one read-only reconnect, then ask about VICE's UI if unresponsive.
11
+
12
+ vice_resume sends exit and disconnects; another inspection pauses again. Disconnect does not resume or quit. Keep emulation running when no active debugging need requires a pause; resume after inspection unless the user asked to leave it paused. Longer pauses are fine when justified. Report facts versus hypotheses, changes/cleanup, and final execution state.`;
13
+ /** Creates the text-monitor MCP server without choosing a transport. */
14
+ export function createViceMonitorServer(monitor = new MonitorClient()) {
15
+ return McpUtils.createToolServer("cbm-vice-text-monitor", new ViceMonitorTools(monitor), {
16
+ instructions: DEBUGGER_INSTRUCTIONS,
17
+ isError: (text) => /(?:^|\n)\s*(?:ERROR\b|Unknown command\b)/i.test(text),
18
+ });
19
+ }
20
+ /** @deprecated Use createViceMonitorServer for the text-monitor MCP. */
21
+ export const createViceServer = createViceMonitorServer;
22
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3D,MAAM,qBAAqB,GAAG;;;;;;;;yWAQ2U,CAAC;AAE1W,wEAAwE;AACxE,MAAM,UAAU,uBAAuB,CAAC,OAAO,GAAG,IAAI,aAAa,EAAE;IACjE,OAAO,QAAQ,CAAC,gBAAgB,CAAC,uBAAuB,EAAE,IAAI,gBAAgB,CAAC,OAAO,CAAC,EAAE;QACrF,YAAY,EAAE,qBAAqB;QACnC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,2CAA2C,CAAC,IAAI,CAAC,IAAI,CAAC;KAC5E,CAAC,CAAC;AACP,CAAC;AAED,wEAAwE;AACxE,MAAM,CAAC,MAAM,gBAAgB,GAAG,uBAAuB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=stdio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../src/stdio.ts"],"names":[],"mappings":""}