Skip to main content
Glama
d3v1an
by d3v1an

ssh_exec_interactive

Execute interactive commands on remote SSH servers with automated prompt responses for sudo passwords and confirmations, featuring safety confirmations for destructive operations.

Instructions

Ejecuta un comando interactivo en el servidor remoto con PTY. Permite responder automáticamente a prompts (ej: sudo password, confirmaciones yes/no). Si el comando es destructivo requiere confirm: true

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
commandYesComando a ejecutar en el servidor remoto
responsesNoLista de respuestas automáticas a prompts. Cada entrada tiene un regex que detecta el prompt y la respuesta a enviar
timeoutNoTimeout global en milisegundos (default: 30000)
confirmNoConfirmar ejecución de comandos peligrosos. Requerido cuando el comando es detectado como destructivo

Implementation Reference

  • The `handleExecInteractive` method implements the logic for executing interactive commands over SSH using a PTY, handling automatic responses to prompts and timeouts.
    private async handleExecInteractive(args: any): Promise<CallToolResult> {
      this.requireConnection();
      const command = args.command as string;
      const responses = (args.responses || []) as PromptResponse[];
      const timeout = (args.timeout as number) || SSHMCPServer.EXEC_TIMEOUT;
      const confirm = args.confirm as boolean | undefined;
    
      const check = isDangerousCommand(command);
      if (check.dangerous && !confirm) {
        return {
          content: [
            {
              type: "text",
              text: [
                `ADVERTENCIA: Comando potencialmente destructivo detectado.`,
                `Comando: ${command}`,
                `Razón: ${check.reason}`,
                ``,
                `Para ejecutar este comando, reenvía con confirm: true.`,
              ].join("\n"),
            },
          ],
        };
      }
    
      // Compilar regex de prompts
      const compiledResponses = responses.map((r) => ({
        regex: new RegExp(r.prompt),
        answer: r.answer,
        sensitive: r.sensitive || false,
      }));
    
      const auditResponses = responses
        .map((r) => (r.sensitive ? `${r.prompt}:[REDACTED]` : `${r.prompt}:${r.answer}`))
        .join(", ");
    
      return new Promise<CallToolResult>((resolve, reject) => {
        this.sshClient!.exec(command, { pty: true }, (err, stream) => {
          if (err) {
            this.audit("ssh_exec_interactive", `${command} responses=[${auditResponses}]`, "error");
            reject(new Error(`Error ejecutando comando interactivo: ${err.message}`));
            return;
          }
    
          let output = "";
          let settled = false;
          let settleTimer: ReturnType<typeof setTimeout> | null = null;
          let globalTimer: ReturnType<typeof setTimeout> | null = null;
    
          const cleanup = () => {
            if (settleTimer) clearTimeout(settleTimer);
            if (globalTimer) clearTimeout(globalTimer);
          };
    
          const finish = () => {
            if (settled) return;
            settled = true;
            cleanup();
            this.audit("ssh_exec_interactive", `${command} responses=[${auditResponses}]`, "ok");
            const cleanOutput = stripAnsi(output) || "(sin salida)";
            this.recordOperation("ssh_exec_interactive", { command, responses: responses.length }, cleanOutput, false);
            resolve({
              content: [{ type: "text", text: cleanOutput }],
            });
          };
    
          const resetSettle = () => {
            if (settleTimer) clearTimeout(settleTimer);
            settleTimer = setTimeout(finish, SSHMCPServer.SETTLE_TIMEOUT);
          };
    
          globalTimer = setTimeout(() => {
            if (!settled) {
              settled = true;
              if (settleTimer) clearTimeout(settleTimer);
              stream.destroy();
              this.audit("ssh_exec_interactive", `${command} (timeout)`, "ok");
              resolve({
                content: [
                  {
                    type: "text",
                    text: stripAnsi(output) + "\n[timeout: comando excedió el tiempo límite]",
                  },
                ],
              });
            }
          }, timeout);
    
          stream.on("data", (data: Buffer) => {
            const chunk = data.toString();
            output += chunk;
  • Definition of the `ssh_exec_interactive` tool, including its name, description, and input schema.
    {
      name: "ssh_exec_interactive",
      description:
        "Ejecuta un comando interactivo en el servidor remoto con PTY. Permite responder automáticamente a prompts (ej: sudo password, confirmaciones yes/no). Si el comando es destructivo requiere confirm: true",
      inputSchema: {
        type: "object",
        properties: {
          command: {
            type: "string",
            description: "Comando a ejecutar en el servidor remoto",
          },
          responses: {
            type: "array",
            description:
              "Lista de respuestas automáticas a prompts. Cada entrada tiene un regex que detecta el prompt y la respuesta a enviar",
            items: {
              type: "object",
              properties: {
                prompt: {
                  type: "string",
                  description: "Regex para detectar el prompt (ej: '[Pp]assword[:\\s]')",
                },
  • src/index.ts:77-78 (registration)
    Registration of the `ssh_exec_interactive` tool in the main request handler switch block.
    case "ssh_exec_interactive":
      return await this.handleExecInteractive(args);

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/d3v1an/ssh-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server