literateMCP
by YUZongmin
- src
#!/usr/bin/env node
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
import { spawn, ChildProcess } from 'child_process';
import { z } from "zod";
import { zodToJsonSchema } from "zod-to-json-schema";
import { platform } from 'os';
import { Client, ClientChannel } from 'ssh2';
// Schema definitions
const ExecuteCommandArgsSchema = z.object({
command: z.string(),
newSession: z.boolean().optional(),
});
const SSHConnectionArgsSchema = z.object({
host: z.string(),
port: z.number().default(22),
username: z.string(),
password: z.string().optional(),
privateKey: z.string().optional(),
command: z.string(),
newSession: z.boolean().optional(),
});
// Server setup
const server = new Server({
name: "cmd-server",
version: "0.1.0",
}, {
capabilities: {
tools: {},
},
});
let persistentCmd: ChildProcess | null = null;
let persistentSSH: {client: Client, ready: boolean} | null = null;
let persistentSSHConfig: {
host: string,
port: number,
username: string,
password?: string,
privateKey?: string
} | null = null;
function initializePersistentCmd() {
const isWindows = platform() === 'win32';
if (persistentCmd) return;
persistentCmd = spawn(isWindows ? 'cmd' : '/bin/sh', [], {
windowsHide: true,
});
persistentCmd.on('error', (error) => {
console.error('Error in persistent CMD:', error);
persistentCmd = null;
});
persistentCmd.on('exit', () => {
persistentCmd = null;
});
}
async function executeSSHCommand(config: z.infer<typeof SSHConnectionArgsSchema>): Promise<{ output: string, code: number }> {
return new Promise((resolve) => {
const useNewSession = config.newSession || false;
// Check if we need a new session or if connection details changed
if (!useNewSession && persistentSSH?.ready && persistentSSHConfig &&
persistentSSHConfig.host === config.host &&
persistentSSHConfig.port === config.port &&
persistentSSHConfig.username === config.username &&
persistentSSHConfig.password === config.password &&
persistentSSHConfig.privateKey === config.privateKey) {
// Use existing connection
persistentSSH.client.exec(config.command, (err: Error | undefined, stream: ClientChannel) => {
if (err) {
resolve({ output: `SSH exec error: ${err.message}`, code: 1 });
return;
}
let output = '';
let errorOutput = '';
stream.on('close', (code: number) => {
resolve({
output: output + (errorOutput ? `\nErrors:\n${errorOutput}` : ''),
code: code || 0
});
}).on('data', (data: Buffer) => {
output += data.toString('utf8');
}).stderr.on('data', (data: Buffer) => {
errorOutput += data.toString('utf8');
});
});
return;
}
// Need to create new connection
const client = new Client();
const sshConfig = {
host: config.host,
port: config.port,
username: config.username,
...(config.password ? { password: config.password } : {}),
...(config.privateKey ? { privateKey: config.privateKey } : {}),
};
let output = '';
let errorOutput = '';
client.on('ready', () => {
// If this is a persistent session, save the connection
if (!useNewSession) {
if (persistentSSH?.client) {
persistentSSH.client.end();
}
persistentSSH = { client, ready: true };
persistentSSHConfig = sshConfig;
}
client.exec(config.command, (err: Error | undefined, stream: ClientChannel) => {
if (err) {
resolve({ output: `SSH exec error: ${err.message}`, code: 1 });
if (useNewSession) client.end();
return;
}
stream.on('close', (code: number) => {
resolve({
output: output + (errorOutput ? `\nErrors:\n${errorOutput}` : ''),
code: code || 0
});
if (useNewSession) client.end();
}).on('data', (data: Buffer) => {
output += data.toString('utf8');
}).stderr.on('data', (data: Buffer) => {
errorOutput += data.toString('utf8');
});
});
})
.on('error', (err: Error) => {
resolve({ output: `SSH connection error: ${err.message}`, code: 1 });
if (useNewSession) client.end();
})
.connect(sshConfig);
});
}
// Tool handlers
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "execute_command",
description: "Execute a command and return its output. " +
"Commands run in a persistent shell session by default. " +
"Use newSession: true to run in a new shell instance.",
inputSchema: zodToJsonSchema(ExecuteCommandArgsSchema),
},
{
name: "execute_ssh_command",
description: "Execute a command on a remote server via SSH. " +
"Commands run in a persistent SSH session by default. " +
"Use newSession: true to run in a new session.",
inputSchema: zodToJsonSchema(SSHConnectionArgsSchema),
},
],
};
});
server.setRequestHandler(CallToolRequestSchema, async (request) => {
try {
const { name, arguments: args } = request.params;
if (name === "execute_command") {
const parsed = ExecuteCommandArgsSchema.safeParse(args);
if (!parsed.success) {
throw new Error(`Invalid arguments for execute_command: ${parsed.error}`);
}
return new Promise((resolve) => {
const useNewSession = parsed.data.newSession || false;
const isWindows = platform() === 'win32';
if (useNewSession) {
const cmdProcess = spawn(isWindows ? 'cmd' : '/bin/sh', [], {
windowsHide: true,
});
let output = '';
let errorOutput = '';
cmdProcess.stdout.on('data', (data) => {
output += data.toString();
});
cmdProcess.stderr.on('data', (data) => {
errorOutput += data.toString();
});
cmdProcess.on('error', (error) => {
resolve({
content: [{
type: "text",
text: `Failed to execute command: ${error.message}`
}],
isError: true,
});
});
cmdProcess.stdin.write(parsed.data.command + '\n');
cmdProcess.stdin.end();
cmdProcess.on('close', (code) => {
const finalOutput = output + (errorOutput ? `\nErrors:\n${errorOutput}` : '');
resolve({
content: [{
type: "text",
text: finalOutput || `Command completed with code ${code}`
}],
isError: code !== 0,
});
});
} else {
if (!persistentCmd) {
initializePersistentCmd();
}
if (!persistentCmd) {
throw new Error("Failed to initialize persistent CMD session");
}
let output = '';
let errorOutput = '';
let commandComplete = false;
const outputMarker = `__CMD_OUTPUT_${Date.now()}__`;
const markerCommand = isWindows ? `echo ${outputMarker}` : `echo "${outputMarker}"`;
const dataHandler = (data: Buffer) => {
const str = data.toString();
if (str.includes(outputMarker)) {
commandComplete = true;
return;
}
if (!commandComplete) {
output += str;
}
};
const errorHandler = (data: Buffer) => {
errorOutput += data.toString();
};
persistentCmd.stdout?.on('data', dataHandler);
persistentCmd.stderr?.on('data', errorHandler);
persistentCmd.stdin?.write(parsed.data.command + '\n' + markerCommand + '\n');
const checkInterval = setInterval(() => {
if (commandComplete) {
clearInterval(checkInterval);
persistentCmd?.stdout?.removeListener('data', dataHandler);
persistentCmd?.stderr?.removeListener('data', errorHandler);
const finalOutput = output + (errorOutput ? `\nErrors:\n${errorOutput}` : '');
resolve({
content: [{
type: "text",
text: finalOutput || "Command completed"
}],
isError: false,
});
}
}, 50);
setTimeout(() => {
if (!commandComplete) {
clearInterval(checkInterval);
persistentCmd?.stdout?.removeListener('data', dataHandler);
persistentCmd?.stderr?.removeListener('data', errorHandler);
resolve({
content: [{
type: "text",
text: "Command timed out"
}],
isError: true,
});
}
}, 5000);
}
});
} else if (name === "execute_ssh_command") {
const parsed = SSHConnectionArgsSchema.safeParse(args);
if (!parsed.success) {
throw new Error(`Invalid arguments for execute_ssh_command: ${parsed.error}`);
}
const { output, code } = await executeSSHCommand(parsed.data);
return {
content: [{
type: "text",
text: output || `Command completed with code ${code}`
}],
isError: code !== 0,
};
}
throw new Error(`Unknown tool: ${name}`);
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
return {
content: [{ type: "text", text: `Error: ${errorMessage}` }],
isError: true,
};
}
});
// Start server
async function runServer() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Command execution server running on stdio");
initializePersistentCmd();
}
// Cleanup on exit
process.on('exit', () => {
if (persistentCmd) {
persistentCmd.kill();
}
if (persistentSSH?.client) {
persistentSSH.client.end();
}
});
runServer().catch((error) => {
console.error("Fatal error running server:", error);
process.exit(1);
});