UNPKG

mcp-c64

Version:

An MCP server for developing BASIC and Assembly Language programs for the Commodore 64

123 lines (122 loc) 6.27 kB
import dotenv from "dotenv"; dotenv.config({ path: `.env`, quiet: true }); import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { zodToJsonSchema } from "zod-to-json-schema"; import { VERSION } from "./common/version.js"; import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js"; import { AssembleProgramSchema, assembleProgram } from "./operations/assembler.js"; import { TokenizeProgramSchema, tokenizeProgram } from "./operations/tokenizer.js"; import { runProgram, RunProgramSchema } from "./operations/emulator.js"; export const createServer = () => { // Instantiate the MCP server const server = new Server({ name: "mcp-c64", version: VERSION, }, { capabilities: { tools: {}, }, }); // Register MCP request handlers server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: "assemble_program", description: `Assemble an assembly language program.\n\tOnly the .asm source filename is required in file parameter, output .prg and .map files will be generated.\n\tAny additional args such as -a, -cbm-prg, etc. should be supplied in an array in the args parameter.`, inputSchema: zodToJsonSchema(AssembleProgramSchema), }, { name: "tokenize_program", description: `Tokenize a BASIC program.\n\tOnly the .bas source filename is required in file parameter, output .prg file will be generated.\n\tAny additional args such as -w2, etc. should be supplied in an array in the args parameter.`, inputSchema: zodToJsonSchema(TokenizeProgramSchema), }, { name: "run_program", description: `Run an assembled or tokenized program.\n\tThe .prg filename is required in file parameter, and the program's path is required in path parameter.\n\tAny additional args such as -console, etc. should be supplied in an array in the args parameter.`, inputSchema: zodToJsonSchema(RunProgramSchema), } ], }; }); server.setRequestHandler(CallToolRequestSchema, async (request) => { try { switch (request.params.name) { case "assemble_program": { // Process the parameters const params = AssembleProgramSchema.parse(request.params.arguments); const command = process.env.ASSEMBLER; const path = params.path ?? process.env.ASM_PATH ?? process.cwd(); const args = params.args ?? ["-a", "--cbm-prg"]; if (!command) { throw new Error("Assembler command is not defined. Provide it as ASSEMBLER in the environment."); } if (!path) { throw new Error("Assembly source path is not defined. Provide it in the call or set ASM_PATH in the environment."); } const operationParams = { path, "filename": params.filename, "args": args, }; const result = await assembleProgram(operationParams); return { structuredContent: result, content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } case "tokenize_program": { // Process the parameters const params = TokenizeProgramSchema.parse(request.params.arguments); const command = process.env.TOKENIZER; const path = params.path ?? process.env.BASIC_PATH ?? process.cwd(); const args = params.args ?? ["-w2"]; if (!command) { throw new Error("Tokenizer command is not defined. Provide it as TOKENIZER in the environment."); } if (!path) { throw new Error("BASIC source path is not defined. Provide it in the call or set BASIC_PATH in the environment."); } const operationParams = { path, "filename": params.filename, "args": args, }; const result = await tokenizeProgram(operationParams); return { structuredContent: result, content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } case "run_program": { // Process the parameters const params = RunProgramSchema.parse(request.params.arguments); const command = process.env.EMULATOR; const path = params.path; if (!command) { throw new Error("Emulator command is not defined. Provide it as EMULATOR in the environment."); } if (!path) { throw new Error("Executable program path is not defined."); } const operationParams = { path, "filename": params.filename, "args": params.args, }; const result = await runProgram(operationParams); return { structuredContent: result, content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } default: throw new Error(`Unknown tool: ${request.params.name}`); } } catch (error) { throw new Error(`Error processing request: ${error instanceof Error ? error.message : "unknown error"}`); } }); return { server }; };