Skip to content

[duplicate-code] Duplicate Code Pattern: HTTP Backend Check Repeated in GetOrLaunch and GetOrLaunchForSession #7254

@github-actions

Description

@github-actions

🔍 Duplicate Code Pattern: HTTP Backend Check Repeated in GetOrLaunch and GetOrLaunchForSession

Part of duplicate code analysis: #aw_abc123def456

Summary

In internal/launcher/launcher.go, both GetOrLaunch (line 121) and GetOrLaunchForSession (line 186) call l.getServerConfig(serverID) and then check if serverCfg.Type == "http". GetOrLaunchForSession performs this check only to immediately delegate back to GetOrLaunch for HTTP servers, duplicating the config lookup and type check logic without adding value.

Duplication Details

Pattern: Repeated HTTP type check before delegation

  • Severity: Low
  • Occurrences: 2 (both functions in launcher/launcher.go)
  • Locations:
    • internal/launcher/launcher.go lines 121–184 — GetOrLaunch
    • internal/launcher/launcher.go lines 186–237 — GetOrLaunchForSession

Code Sample — Duplicated block in GetOrLaunchForSession:

func GetOrLaunchForSession(l *Launcher, serverID, sessionID string) (*mcp.Connection, error) {
    // ...
    serverCfg, err := l.getServerConfig(serverID)  // ← duplicates GetOrLaunch
    if err != nil {
        return nil, err
    }

    // For HTTP backends, use the regular GetOrLaunch (stateless)
    if serverCfg.Type == "http" {                   // ← duplicates GetOrLaunch logic
        logLauncher.Printf("HTTP backend detected...")
        return GetOrLaunch(l, serverID)              // ← GetOrLaunch will fetch config again
    }
    // ... session pool logic for stdio backends
}

In GetOrLaunch — the same check also appears:

func GetOrLaunch(l *Launcher, serverID string) (*mcp.Connection, error) {
    serverCfg, err := l.getServerConfig(serverID)  // ← same config lookup
    // ...
    return syncutil.GetOrCreate(&l.mu, l.connections, serverID, func() (*mcp.Connection, error) {
        if serverCfg.Type == "http" {               // ← same type check
            // handle HTTP...
        }
        // handle stdio...
    })
}

When GetOrLaunchForSession calls GetOrLaunch for HTTP backends, the config is fetched twice (once in GetOrLaunchForSession, then again inside GetOrLaunch).

Impact Analysis

  • Maintainability: Adding a new backend type (e.g., grpc) requires updating the type check in both functions
  • Bug Risk: Low — functionally correct, but the double config lookup is wasteful
  • Performance: getServerConfig acquires a read lock on each call; for HTTP backends this lock is acquired twice per request to GetOrLaunchForSession

Refactoring Recommendations

  1. Pass config to the session function (preferred)

    • Refactor GetOrLaunchForSession to only handle stdio backends (remove the HTTP check)
    • At the call site in server/tool_registry.go, dispatch to GetOrLaunch vs GetOrLaunchForSession based on server type
    • Estimated effort: 1 hour
  2. Unified dispatch function (alternative)

    // GetOrLaunchAny selects the appropriate launch strategy based on backend type
    func GetOrLaunchAny(l *Launcher, serverID, sessionID string) (*mcp.Connection, error) {
        serverCfg, err := l.getServerConfig(serverID)
        if err != nil { return nil, err }
        if serverCfg.Type == "http" {
            return GetOrLaunch(l, serverID)
        }
        return getOrLaunchForSessionStdio(l, serverID, sessionID, serverCfg)
    }
    • This makes the dispatch logic explicit and avoids the double config lookup
    • Estimated effort: 1–2 hours

Implementation Checklist

  • Review duplication findings
  • Identify all callers of GetOrLaunchForSession (check server/tool_registry.go)
  • Refactor to eliminate double config lookup
  • Verify HTTP backends still route correctly
  • Run make agent-finished to verify

Parent Issue

See parent analysis report: #aw_abc123def456

Generated by Duplicate Code Detector · sonnet46 12.3M ·

  • expires on Jun 16, 2026, 3:49 AM UTC

Metadata

Metadata

Assignees

No one assigned

    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