mcp-server-code-runner
by formulahendry
Verified
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import * as fs from "fs";
import * as path from "path";
import * as os from "os";
import { languageIdToExecutorMap, languageIdToFileExtensionMap } from "./constants.js";
import { exec } from "child_process";
export function createServer(): McpServer {
const server = new McpServer({
name: "Code Runner",
version: "0.1.0",
});
server.tool(
"run-code",
"Run code snippet and return the result.",
{
code: z.string().describe("Code Snippet"),
languageId: z.enum(Object.keys(languageIdToExecutorMap) as [keyof typeof languageIdToExecutorMap]).describe("Language ID"),
},
async ({ code, languageId }) => {
if (!code) {
throw new Error("Code is required.");
}
if (!languageId) {
throw new Error("Language ID is required.");
}
const executor = languageIdToExecutorMap[languageId as keyof typeof languageIdToExecutorMap];
if (!executor) {
throw new Error(`Language '${languageId}' is not supported.`);
}
const filePath = await createTmpFile(code, languageId);
const command = `${executor} "${filePath}"`;
const result = await executeCommand(command);
return {
content: [
{
type: "text",
text: result,
},
],
};
},
);
return server;
}
async function createTmpFile(content: string, languageId: string) {
const tmpDir = os.tmpdir();
const fileExtension = getFileExtension(languageId);
const fileName = `tmp.${fileExtension}`;
const filePath = path.join(tmpDir, fileName);
await fs.promises.writeFile(filePath, content);
console.debug(`Temporary file created at: ${filePath}`);
return filePath;
}
function getFileExtension(languageId: string): string {
const fileExtension = languageIdToFileExtensionMap[languageId as keyof typeof languageIdToFileExtensionMap];
return fileExtension ?? languageId;
}
async function executeCommand(command: string): Promise<string> {
return new Promise((resolve, reject) => {
console.debug(`Executing command: ${command}`);
exec(command, (error: any, stdout: string, stderr: string) => {
if (error) {
reject(`Error: ${error.message}`);
}
if (stderr) {
reject(`Stderr: ${stderr}`);
}
resolve(stdout);
});
});
}