Skip to content

Duplicate Code: MCP script handler execution envelope #29496

@github-actions

Description

@github-actions

Summary

Semantic duplicate-code analysis found a repeated MCP script execution pattern across the language-specific handler modules. The Go, Python, JavaScript, and Shell handlers each own similar process execution, stdout/stderr debug logging, timeout/maxBuffer setup, result formatting, and MCP content response construction.

This is significant because the common execution envelope is duplicated across multiple runtime handlers, so fixes to timeout behavior, stdout parsing, error shape, or MCP response formatting can drift between languages.

Duplication Details

Pattern: Language-specific MCP handler execution wrapper

  • Severity: Medium
  • Occurrences: 4 handler modules, with the strongest exact duplication across 3 modules and partial duplication in the shell handler
  • Locations:
    • actions/setup/js/mcp_handler_go.cjs (lines 25-96)
    • actions/setup/js/mcp_handler_python.cjs (lines 25-96)
    • actions/setup/js/mcp_handler_javascript.cjs (lines 25-108)
    • actions/setup/js/mcp_handler_shell.cjs (lines 28-153)
Representative duplicated block
const child = execFile(
  command,
  args,
  {
    env: process.env,
    cwd: process.env.GITHUB_WORKSPACE || process.cwd(),
    timeout: timeoutSeconds * 1000,
    maxBuffer: 10 * 1024 * 1024,
  },
  (error, stdout, stderr) => {
    if (stdout) {
      server.debug(`  [${toolName}] stdout: ${stdout.substring(0, 500)}${stdout.length > 500 ? "..." : ""}`);
    }
    if (stderr) {
      server.debug(`  [${toolName}] stderr: ${stderr.substring(0, 500)}${stderr.length > 500 ? "..." : ""}`);
    }

    if (error) {
      server.debugError(`  [${toolName}] script error: `, error);
      reject(error);
      return;
    }

    let result;
    try {
      if (stdout && stdout.trim()) {
        result = JSON.parse(stdout.trim());
      } else {
        result = { stdout: stdout || "", stderr: stderr || "" };
      }
    } catch (parseError) {
      server.debug(`  [${toolName}] Output is not JSON, returning as text`);
      result = { stdout: stdout || "", stderr: stderr || "" };
    }

    resolve({
      content: [
        {
          type: "text",
          text: JSON.stringify(result),
        },
      ],
    });
  }
);

Impact Analysis

  • Maintainability: Shared behavior like cwd selection, timeout handling, maxBuffer size, debug truncation, stdout JSON parsing, and MCP response formatting must be changed in multiple files.
  • Bug Risk: Error handling has already diverged: JavaScript and Shell build enhanced errors with stdout/stderr, while Go and Python reject the raw error. Future fixes could land in one handler and miss the others.
  • Code Bloat: Roughly 50+ lines of process execution and response formatting are repeated across the handler set.

Refactoring Recommendations

  1. Extract a shared process execution helper

    • Suggested location: actions/setup/js/mcp_handler_process.cjs
    • Centralize execFile, cwd, timeout, maxBuffer, stdout/stderr debug logging, stdout JSON parsing, and MCP content wrapping.
    • Let each language handler pass { command, args, env, inputJson, languageLabel, errorFormatter, resultMapper } or a similarly small options object.
  2. Normalize error enrichment policy

    • Decide whether all handlers should include stdout/stderr in rejected errors.
    • Apply that behavior through the shared helper so Go/Python/JavaScript/Shell stay consistent.
  3. Preserve shell-specific output handling as an extension point

    • Keep shell's GITHUB_OUTPUT parsing in the shell handler or expose a mapResult(stdout, stderr) hook from the shared helper.

Implementation Checklist

  • Add shared handler execution helper
  • Refactor Go/Python/JavaScript handlers to use it
  • Refactor Shell handler to reuse the common execution envelope while preserving output-file parsing
  • Update existing handler tests for shared behavior and language-specific behavior
  • Run make fmt-cjs and the relevant .cjs tests

Analysis Metadata

  • Analyzed Files: 1,025 eligible .go/.cjs source files from commit 0b1b18db13b2dbab8197431937d7a98ae9c2893a
  • Detection Method: Serena symbol overview/find-symbol plus normalized duplicate-window scan
  • Analysis Date: 2026-05-01

Warning

Firewall blocked 4 domains

The following domains were blocked by the firewall during workflow execution:

  • ab.chatgpt.com
  • api.github.com
  • chatgpt.com
  • github.com

💡 Tip: api.github.com is blocked because GitHub API access uses the built-in GitHub tools by default. Instead of adding api.github.com to network.allowed, use tools.github.mode: gh-proxy for direct pre-authenticated GitHub CLI access without requiring network access to api.github.com:

tools:
  github:
    mode: gh-proxy

See GitHub Tools for more information on gh-proxy mode.

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "ab.chatgpt.com"
    - "api.github.com"
    - "chatgpt.com"
    - "github.com"

See Network Configuration for more information.

Generated by Duplicate Code Detector ·

Metadata

Metadata

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions