Skip to main content
Glama

openai_review

Analyze code changes for quality and issues using OpenAI's Codex. Review uncommitted modifications or compare against specific branches to identify potential improvements.

Instructions

Code review via Codex review (non-interactive). Reviews uncommitted changes or changes against a base branch.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
instructionsNoCustom review instructions (e.g., 'Focus on error handling and race conditions')
uncommittedNoReview uncommitted changes (default true)
baseNoReview against this base branch
commitNoReview a specific commit SHA
timeoutNoTimeout in seconds (default 120)
cwdNoWorking directory (git repo root)

Implementation Reference

  • Tool registration and handler for 'openai_review' - defines the code review tool that uses Codex CLI to review git changes. Includes input schema (instructions, uncommitted, base, commit, timeout, cwd) and the async handler function that executes 'codex review --ephemeral' with the provided parameters.
    mcpServer.registerTool(
      "openai_review",
      {
        description:
          "Code review via Codex review (non-interactive). Reviews uncommitted changes or changes against a base branch.",
        inputSchema: {
          instructions: z
            .string()
            .optional()
            .describe("Custom review instructions (e.g., 'Focus on error handling and race conditions')"),
          uncommitted: z
            .boolean()
            .default(true)
            .describe("Review uncommitted changes (default true)"),
          base: z
            .string()
            .optional()
            .describe("Review against this base branch"),
          commit: z
            .string()
            .optional()
            .describe("Review a specific commit SHA"),
          timeout: z
            .number()
            .default(120)
            .describe("Timeout in seconds (default 120)"),
          cwd: z
            .string()
            .optional()
            .describe("Working directory (git repo root)"),
        },
      },
      async ({ instructions, uncommitted = true, base, commit, timeout = 120, cwd }) => {
        const timeoutMs = timeout * 1000;
    
        try {
          log(`Review: uncommitted=${uncommitted}, base=${base || "none"}, timeout=${timeout}s`);
          const startTime = Date.now();
    
          const args = ["review", "--ephemeral"];
    
          if (uncommitted) {
            args.push("--uncommitted");
          }
          if (base) {
            args.push("--base", base);
          }
          if (commit) {
            args.push("--commit", commit);
          }
    
          if (instructions) {
            args.push("-");
          }
    
          const { stdout, stderr, exitCode } = await runCodex(args, {
            timeoutMs,
            stdin: instructions || undefined,
            cwd,
          });
    
          const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
          const combined = stdout + stderr;
    
          const error = detectError(combined);
          if (error) {
            log(`${error.errorType}: ${error.message}`);
            return {
              content: [{ type: "text", text: error.message }],
              isError: true,
            };
          }
    
          const response = combined.trim() || "No review output";
          log(`Review OK in ${elapsed}s (${response.length} chars)`);
    
          return {
            content: [{ type: "text", text: response }],
          };
        } catch (error) {
          const knownError = detectError(error.message);
          if (knownError) {
            log(`${knownError.errorType}: ${knownError.message}`);
            return {
              content: [{ type: "text", text: knownError.message }],
              isError: true,
            };
          }
    
          log(`Error: ${error.message}`);
          return {
            content: [{ type: "text", text: `Codex review error: ${error.message}` }],
            isError: true,
          };
        }
      }
    );
  • Main handler function for openai_review tool. Constructs codex CLI arguments, handles optional parameters (instructions, uncommitted, base, commit), calls runCodex, detects errors, and returns the review output as text content.
    async ({ instructions, uncommitted = true, base, commit, timeout = 120, cwd }) => {
      const timeoutMs = timeout * 1000;
    
      try {
        log(`Review: uncommitted=${uncommitted}, base=${base || "none"}, timeout=${timeout}s`);
        const startTime = Date.now();
    
        const args = ["review", "--ephemeral"];
    
        if (uncommitted) {
          args.push("--uncommitted");
        }
        if (base) {
          args.push("--base", base);
        }
        if (commit) {
          args.push("--commit", commit);
        }
    
        if (instructions) {
          args.push("-");
        }
    
        const { stdout, stderr, exitCode } = await runCodex(args, {
          timeoutMs,
          stdin: instructions || undefined,
          cwd,
        });
    
        const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
        const combined = stdout + stderr;
    
        const error = detectError(combined);
        if (error) {
          log(`${error.errorType}: ${error.message}`);
          return {
            content: [{ type: "text", text: error.message }],
            isError: true,
          };
        }
    
        const response = combined.trim() || "No review output";
        log(`Review OK in ${elapsed}s (${response.length} chars)`);
    
        return {
          content: [{ type: "text", text: response }],
        };
      } catch (error) {
        const knownError = detectError(error.message);
        if (knownError) {
          log(`${knownError.errorType}: ${knownError.message}`);
          return {
            content: [{ type: "text", text: knownError.message }],
            isError: true,
          };
        }
    
        log(`Error: ${error.message}`);
        return {
          content: [{ type: "text", text: `Codex review error: ${error.message}` }],
          isError: true,
        };
      }
    }
  • Input schema definition for openai_review tool using Zod. Defines parameters: instructions (optional string), uncommitted (boolean, default true), base (optional string), commit (optional string), timeout (number, default 120), and cwd (optional string).
    {
      description:
        "Code review via Codex review (non-interactive). Reviews uncommitted changes or changes against a base branch.",
      inputSchema: {
        instructions: z
          .string()
          .optional()
          .describe("Custom review instructions (e.g., 'Focus on error handling and race conditions')"),
        uncommitted: z
          .boolean()
          .default(true)
          .describe("Review uncommitted changes (default true)"),
        base: z
          .string()
          .optional()
          .describe("Review against this base branch"),
        commit: z
          .string()
          .optional()
          .describe("Review a specific commit SHA"),
        timeout: z
          .number()
          .default(120)
          .describe("Timeout in seconds (default 120)"),
        cwd: z
          .string()
          .optional()
          .describe("Working directory (git repo root)"),
      },
  • runCodex helper function - spawns the codex CLI process with timeout, handles stdout/stderr buffering, process cleanup, and returns a promise with {stdout, stderr, exitCode}. Used by both openai_chat and openai_review tools.
    function runCodex(args, options = {}) {
      const { timeoutMs = 90000, stdin: stdinData, cwd } = options;
    
      return new Promise((resolve, reject) => {
        const proc = spawn("codex", args, {
          cwd: cwd || process.cwd(),
          stdio: ["pipe", "pipe", "pipe"],
          env: {
            ...process.env,
            CODEX_HOME,
          },
        });
    
        let stdout = "";
        let stderr = "";
        let killed = false;
        let killTimer;
    
        const timer = setTimeout(() => {
          killed = true;
          proc.kill("SIGTERM");
          killTimer = setTimeout(() => {
            try { if (!proc.killed) proc.kill("SIGKILL"); } catch {}
          }, 5000);
        }, timeoutMs);
    
        proc.stdout.on("data", (data) => {
          stdout += data.toString();
          if (stdout.length > MAX_BUFFER) {
            killed = true;
            proc.kill("SIGTERM");
          }
        });
    
        proc.stderr.on("data", (data) => {
          stderr += data.toString();
          if (stderr.length > MAX_BUFFER) {
            killed = true;
            proc.kill("SIGTERM");
          }
        });
    
        if (stdinData) {
          proc.stdin.write(stdinData);
          proc.stdin.end();
        } else {
          proc.stdin.end();
        }
    
        proc.on("close", (exitCode) => {
          clearTimeout(timer);
          clearTimeout(killTimer);
          if (killed) {
            reject(new Error(`Process killed after ${timeoutMs / 1000}s timeout. Partial output: ${(stdout + stderr).slice(-200)}`));
          } else {
            resolve({ stdout, stderr, exitCode });
          }
        });
    
        proc.on("error", (err) => {
          clearTimeout(timer);
          clearTimeout(killTimer);
          reject(err);
        });
      });
    }
  • detectError helper function - analyzes output for known error patterns (QUOTA_EXCEEDED, MODEL_NOT_SUPPORTED, AUTH_EXPIRED) and returns structured error information. Used by tool handlers to provide clear error messages to users.
    function detectError(output) {
      const combined = output.toLowerCase();
    
      if (combined.includes("usage limit") || combined.includes("hit your usage limit")) {
        const match = output.match(/try again at (.+?)[\.\n]/);
        const resetDate = match ? match[1] : "unknown";
        return {
          isError: true,
          errorType: "QUOTA_EXCEEDED",
          message: `Codex usage limit reached. Credits reset at: ${resetDate}. Use a fallback provider.`,
        };
      }
    
      if (combined.includes("not supported when using codex with a chatgpt account")) {
        return {
          isError: true,
          errorType: "MODEL_NOT_SUPPORTED",
          message: "This model is not available with ChatGPT Plus. Use the default model.",
        };
      }
    
      if (combined.includes("auth") && (combined.includes("expired") || combined.includes("login"))) {
        return {
          isError: true,
          errorType: "AUTH_EXPIRED",
          message: "Codex auth token expired. Run 'codex login' to re-authenticate.",
        };
      }
    
      return null;
    }
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/spyrae/claude-concilium'

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