Skip to main content
Glama
HasanJahidul

Terminal History MCP

failed_commands

Retrieve recent shell commands that failed with a non-zero exit code to debug errors. Filter by time and limit results.

Instructions

Recent commands with non-zero exit code. Useful for debugging recent shell errors.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
since_ts_msNo
limitNo

Implementation Reference

  • The `failedCommands` function is the handler/executor that queries the database for commands with non-zero exit codes, filtered by an optional timestamp and limited in count.
    export function failedCommands(db: Database.Database, sinceTs: number | null, limit = 20): SearchRow[] {
      const stmt = db.prepare(`
        SELECT id, cmd, ts, shell, cwd, exit_code, duration_ms FROM commands
        WHERE exit_code IS NOT NULL AND exit_code != 0
          AND (? IS NULL OR ts >= ?)
        ORDER BY ts DESC LIMIT ?
      `);
      return stmt.all(sinceTs, sinceTs, limit) as SearchRow[];
    }
  • The input schema definition for the 'failed_commands' tool, declaring `since_ts_ms` (number|null) and `limit` (number, default 20) parameters.
    {
      name: "failed_commands",
      description: "Recent commands with non-zero exit code. Useful for debugging recent shell errors.",
      inputSchema: {
        type: "object",
        properties: {
          since_ts_ms: { type: ["number", "null"] },
          limit: { type: "number", default: 20 },
        },
      },
    },
  • src/index.ts:95-133 (registration)
    The tool name 'failed_commands' is registered in the CallToolRequestSchema handler at lines 114-119, where it parses Zod-validated args and calls the failedCommands function from search.ts.
    server.setRequestHandler(CallToolRequestSchema, async (req) => {
      const name = req.params.name;
      const args = (req.params.arguments ?? {}) as any;
    
      try {
        if (name === "reindex") {
          const entries = loadHistoryFiles();
          const r = indexEntries(db, entries);
          const ext = ingestExtendedLog(db);
          return { content: [{ type: "text", text: `parsed=${entries.length} inserted=${r.inserted} skipped=${r.skipped} ext_applied=${ext.applied} ext_inserted=${ext.inserted}` }] };
        }
        if (name === "search_history") {
          const { query, limit } = z.object({ query: z.string(), limit: z.number().optional() }).parse(args);
          return { content: [{ type: "text", text: fmt(searchHistory(db, query, limit ?? 20)) }] };
        }
        if (name === "recent_in_dir") {
          const { cwd, limit } = z.object({ cwd: z.string(), limit: z.number().optional() }).parse(args);
          return { content: [{ type: "text", text: fmt(recentInDir(db, cwd, limit ?? 20)) }] };
        }
        if (name === "failed_commands") {
          const { since_ts_ms, limit } = z.object({
            since_ts_ms: z.number().nullable().optional(),
            limit: z.number().optional(),
          }).parse(args);
          return { content: [{ type: "text", text: fmt(failedCommands(db, since_ts_ms ?? null, limit ?? 20)) }] };
        }
        if (name === "command_chains") {
          const { query, window_ms, limit } = z.object({
            query: z.string(), window_ms: z.number().optional(), limit: z.number().optional(),
          }).parse(args);
          const chains = commandChains(db, query, window_ms ?? 300000, limit ?? 5);
          const text = chains.map((c, i) => `--- chain ${i + 1} ---\n${fmt(c)}`).join("\n\n");
          return { content: [{ type: "text", text: text || "(no chains)" }] };
        }
        return { content: [{ type: "text", text: `unknown tool: ${name}` }], isError: true };
      } catch (e: any) {
        return { content: [{ type: "text", text: `error: ${e?.message ?? String(e)}` }], isError: true };
      }
    });
  • src/index.ts:37-91 (registration)
    The tool 'failed_commands' is also registered in the TOOLS array (lines 67-77) which is served via ListToolsRequestSchema, making it discoverable by clients.
    const TOOLS = [
      {
        name: "reindex",
        description: "Re-parse ~/.zsh_history and ~/.bash_history into the local index. Run after new shell activity.",
        inputSchema: { type: "object", properties: {}, additionalProperties: false },
      },
      {
        name: "search_history",
        description: "Full-text search across indexed shell history. Returns matching commands with timestamp/cwd/exit code.",
        inputSchema: {
          type: "object",
          properties: {
            query: { type: "string", description: "Keywords to search. Supports prefix match." },
            limit: { type: "number", default: 20 },
          },
          required: ["query"],
        },
      },
      {
        name: "recent_in_dir",
        description: "List recent commands run in a specific working directory (requires cwd capture, may be empty for legacy entries).",
        inputSchema: {
          type: "object",
          properties: {
            cwd: { type: "string" },
            limit: { type: "number", default: 20 },
          },
          required: ["cwd"],
        },
      },
      {
        name: "failed_commands",
        description: "Recent commands with non-zero exit code. Useful for debugging recent shell errors.",
        inputSchema: {
          type: "object",
          properties: {
            since_ts_ms: { type: ["number", "null"] },
            limit: { type: "number", default: 20 },
          },
        },
      },
      {
        name: "command_chains",
        description: "For each match of query, return commands run within ±5 min — reveals multi-step sequences (cd → build → deploy).",
        inputSchema: {
          type: "object",
          properties: {
            query: { type: "string" },
            window_ms: { type: "number", default: 300000 },
            limit: { type: "number", default: 5 },
          },
          required: ["query"],
        },
      },
    ];
  • The `fmt` helper function formats SearchRow results into human-readable text, used by the handler to display failed commands output.
    function fmt(rows: SearchRow[]): string {
      if (!rows.length) return "(no results)";
      return rows.map((r) => {
        const when = r.ts ? new Date(r.ts).toISOString() : "?";
        const exit = r.exit_code == null ? "" : ` exit=${r.exit_code}`;
        const cwd = r.cwd ? ` cwd=${r.cwd}` : "";
        return `[${r.shell} ${when}${exit}${cwd}] ${r.cmd}`;
      }).join("\n");
    }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are present, so the description must convey behavioral traits. It indicates the tool retrieves recent failed commands but does not disclose whether it is read-only, potential side effects, authentication needs, or output format. The description is insufficient for an agent to infer safety or limits.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description consists of two short sentences that immediately convey the core purpose and a key use case. It is well front-loaded and avoids unnecessary words, though it could be slightly more detailed without losing conciseness.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no output schema and simple parameters, the description provides minimal context. It fails to explain return values, ordering, pagination (beyond limit default), or how parameters interact. The tool's purpose is clear, but operational details are lacking.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema property descriptions are absent (0% coverage), and the tool description does not explain the parameters 'since_ts_ms' or 'limit'. While the schema provides types and defaults, agents must infer meaning from parameter names, which may be ambiguous.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it lists recent commands with non-zero exit code, which precisely defines the tool's function. However, it does not explicitly differentiate from sibling tools like command_chains or recent_in_dir, though the mention of 'non-zero exit code' provides implicit distinction.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The phrase 'Useful for debugging recent shell errors' suggests a usage scenario but lacks explicit guidance on when to use this tool versus siblings. No information on prerequisites or when not to use is provided.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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/HasanJahidul/terminal-history-mcp'

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