diff --git a/.github/workflows/test-claude-add-issue-comment.lock.yml b/.github/workflows/test-claude-add-issue-comment.lock.yml
index dd848e6b608..5ccd79f90c0 100644
--- a/.github/workflows/test-claude-add-issue-comment.lock.yml
+++ b/.github/workflows/test-claude-add-issue-comment.lock.yml
@@ -491,17 +491,11 @@ jobs:
           {
             "mcpServers": {
               "github": {
-                "command": "docker",
-                "args": [
-                  "run",
-                  "-i",
-                  "--rm",
-                  "-e",
-                  "GITHUB_PERSONAL_ACCESS_TOKEN",
-                  "ghcr.io/github/github-mcp-server:sha-09deac4"
-                ],
-                "env": {
-                  "GITHUB_PERSONAL_ACCESS_TOKEN": "${{ secrets.GITHUB_TOKEN }}"
+                "type": "http",
+                "url": "https://api.github.com/mcp",
+                "headers": {
+                  "Authorization": "Bearer ${{ secrets.GITHUB_TOKEN }}",
+                  "Content-Type": "application/json"
                 }
               }
             }
diff --git a/.github/workflows/test-claude-add-issue-labels.lock.yml b/.github/workflows/test-claude-add-issue-labels.lock.yml
index f7b41d1f612..47e05c35cf8 100644
--- a/.github/workflows/test-claude-add-issue-labels.lock.yml
+++ b/.github/workflows/test-claude-add-issue-labels.lock.yml
@@ -491,17 +491,11 @@ jobs:
           {
             "mcpServers": {
               "github": {
-                "command": "docker",
-                "args": [
-                  "run",
-                  "-i",
-                  "--rm",
-                  "-e",
-                  "GITHUB_PERSONAL_ACCESS_TOKEN",
-                  "ghcr.io/github/github-mcp-server:sha-09deac4"
-                ],
-                "env": {
-                  "GITHUB_PERSONAL_ACCESS_TOKEN": "${{ secrets.GITHUB_TOKEN }}"
+                "type": "http",
+                "url": "https://api.github.com/mcp",
+                "headers": {
+                  "Authorization": "Bearer ${{ secrets.GITHUB_TOKEN }}",
+                  "Content-Type": "application/json"
                 }
               }
             }
diff --git a/.github/workflows/test-claude-command.lock.yml b/.github/workflows/test-claude-command.lock.yml
index 724f7d22fb3..12c413bf282 100644
--- a/.github/workflows/test-claude-command.lock.yml
+++ b/.github/workflows/test-claude-command.lock.yml
@@ -651,17 +651,11 @@ jobs:
           {
             "mcpServers": {
               "github": {
-                "command": "docker",
-                "args": [
-                  "run",
-                  "-i",
-                  "--rm",
-                  "-e",
-                  "GITHUB_PERSONAL_ACCESS_TOKEN",
-                  "ghcr.io/github/github-mcp-server:sha-09deac4"
-                ],
-                "env": {
-                  "GITHUB_PERSONAL_ACCESS_TOKEN": "${{ secrets.GITHUB_TOKEN }}"
+                "type": "http",
+                "url": "https://api.github.com/mcp",
+                "headers": {
+                  "Authorization": "Bearer ${{ secrets.GITHUB_TOKEN }}",
+                  "Content-Type": "application/json"
                 }
               }
             }
diff --git a/.github/workflows/test-claude-create-issue.lock.yml b/.github/workflows/test-claude-create-issue.lock.yml
index 58d2682339f..adb21762bfb 100644
--- a/.github/workflows/test-claude-create-issue.lock.yml
+++ b/.github/workflows/test-claude-create-issue.lock.yml
@@ -162,17 +162,11 @@ jobs:
           {
             "mcpServers": {
               "github": {
-                "command": "docker",
-                "args": [
-                  "run",
-                  "-i",
-                  "--rm",
-                  "-e",
-                  "GITHUB_PERSONAL_ACCESS_TOKEN",
-                  "ghcr.io/github/github-mcp-server:sha-09deac4"
-                ],
-                "env": {
-                  "GITHUB_PERSONAL_ACCESS_TOKEN": "${{ secrets.GITHUB_TOKEN }}"
+                "type": "http",
+                "url": "https://api.github.com/mcp",
+                "headers": {
+                  "Authorization": "Bearer ${{ secrets.GITHUB_TOKEN }}",
+                  "Content-Type": "application/json"
                 }
               }
             }
diff --git a/.github/workflows/test-claude-create-pull-request-review-comment.lock.yml b/.github/workflows/test-claude-create-pull-request-review-comment.lock.yml
index 312a5c8842f..ff1e8a7e24b 100644
--- a/.github/workflows/test-claude-create-pull-request-review-comment.lock.yml
+++ b/.github/workflows/test-claude-create-pull-request-review-comment.lock.yml
@@ -434,17 +434,11 @@ jobs:
           {
             "mcpServers": {
               "github": {
-                "command": "docker",
-                "args": [
-                  "run",
-                  "-i",
-                  "--rm",
-                  "-e",
-                  "GITHUB_PERSONAL_ACCESS_TOKEN",
-                  "ghcr.io/github/github-mcp-server:sha-09deac4"
-                ],
-                "env": {
-                  "GITHUB_PERSONAL_ACCESS_TOKEN": "${{ secrets.GITHUB_TOKEN }}"
+                "type": "http",
+                "url": "https://api.github.com/mcp",
+                "headers": {
+                  "Authorization": "Bearer ${{ secrets.GITHUB_TOKEN }}",
+                  "Content-Type": "application/json"
                 }
               }
             }
diff --git a/.github/workflows/test-claude-create-pull-request.lock.yml b/.github/workflows/test-claude-create-pull-request.lock.yml
index 2f0c90325a5..4ea8dd08766 100644
--- a/.github/workflows/test-claude-create-pull-request.lock.yml
+++ b/.github/workflows/test-claude-create-pull-request.lock.yml
@@ -167,17 +167,11 @@ jobs:
           {
             "mcpServers": {
               "github": {
-                "command": "docker",
-                "args": [
-                  "run",
-                  "-i",
-                  "--rm",
-                  "-e",
-                  "GITHUB_PERSONAL_ACCESS_TOKEN",
-                  "ghcr.io/github/github-mcp-server:sha-09deac4"
-                ],
-                "env": {
-                  "GITHUB_PERSONAL_ACCESS_TOKEN": "${{ secrets.GITHUB_TOKEN }}"
+                "type": "http",
+                "url": "https://api.github.com/mcp",
+                "headers": {
+                  "Authorization": "Bearer ${{ secrets.GITHUB_TOKEN }}",
+                  "Content-Type": "application/json"
                 }
               }
             }
diff --git a/.github/workflows/test-claude-create-security-report.lock.yml b/.github/workflows/test-claude-create-security-report.lock.yml
index a9d233cabcb..e24b575aa6d 100644
--- a/.github/workflows/test-claude-create-security-report.lock.yml
+++ b/.github/workflows/test-claude-create-security-report.lock.yml
@@ -421,17 +421,11 @@ jobs:
           {
             "mcpServers": {
               "github": {
-                "command": "docker",
-                "args": [
-                  "run",
-                  "-i",
-                  "--rm",
-                  "-e",
-                  "GITHUB_PERSONAL_ACCESS_TOKEN",
-                  "ghcr.io/github/github-mcp-server:sha-09deac4"
-                ],
-                "env": {
-                  "GITHUB_PERSONAL_ACCESS_TOKEN": "${{ secrets.GITHUB_TOKEN }}"
+                "type": "http",
+                "url": "https://api.github.com/mcp",
+                "headers": {
+                  "Authorization": "Bearer ${{ secrets.GITHUB_TOKEN }}",
+                  "Content-Type": "application/json"
                 }
               }
             }
diff --git a/.github/workflows/test-claude-mcp.lock.yml b/.github/workflows/test-claude-mcp.lock.yml
index f4cd90b6f53..21d4dd3ec6d 100644
--- a/.github/workflows/test-claude-mcp.lock.yml
+++ b/.github/workflows/test-claude-mcp.lock.yml
@@ -421,17 +421,11 @@ jobs:
           {
             "mcpServers": {
               "github": {
-                "command": "docker",
-                "args": [
-                  "run",
-                  "-i",
-                  "--rm",
-                  "-e",
-                  "GITHUB_PERSONAL_ACCESS_TOKEN",
-                  "ghcr.io/github/github-mcp-server:sha-09deac4"
-                ],
-                "env": {
-                  "GITHUB_PERSONAL_ACCESS_TOKEN": "${{ secrets.GITHUB_TOKEN }}"
+                "type": "http",
+                "url": "https://api.github.com/mcp",
+                "headers": {
+                  "Authorization": "Bearer ${{ secrets.GITHUB_TOKEN }}",
+                  "Content-Type": "application/json"
                 }
               },
               "time": {
diff --git a/.github/workflows/test-claude-push-to-branch.lock.yml b/.github/workflows/test-claude-push-to-branch.lock.yml
index 837ffdbf278..78e4dc43f31 100644
--- a/.github/workflows/test-claude-push-to-branch.lock.yml
+++ b/.github/workflows/test-claude-push-to-branch.lock.yml
@@ -252,17 +252,11 @@ jobs:
           {
             "mcpServers": {
               "github": {
-                "command": "docker",
-                "args": [
-                  "run",
-                  "-i",
-                  "--rm",
-                  "-e",
-                  "GITHUB_PERSONAL_ACCESS_TOKEN",
-                  "ghcr.io/github/github-mcp-server:sha-09deac4"
-                ],
-                "env": {
-                  "GITHUB_PERSONAL_ACCESS_TOKEN": "${{ secrets.GITHUB_TOKEN }}"
+                "type": "http",
+                "url": "https://api.github.com/mcp",
+                "headers": {
+                  "Authorization": "Bearer ${{ secrets.GITHUB_TOKEN }}",
+                  "Content-Type": "application/json"
                 }
               }
             }
diff --git a/.github/workflows/test-claude-update-issue.lock.yml b/.github/workflows/test-claude-update-issue.lock.yml
index 136662338af..7179877f5c9 100644
--- a/.github/workflows/test-claude-update-issue.lock.yml
+++ b/.github/workflows/test-claude-update-issue.lock.yml
@@ -491,17 +491,11 @@ jobs:
           {
             "mcpServers": {
               "github": {
-                "command": "docker",
-                "args": [
-                  "run",
-                  "-i",
-                  "--rm",
-                  "-e",
-                  "GITHUB_PERSONAL_ACCESS_TOKEN",
-                  "ghcr.io/github/github-mcp-server:sha-09deac4"
-                ],
-                "env": {
-                  "GITHUB_PERSONAL_ACCESS_TOKEN": "${{ secrets.GITHUB_TOKEN }}"
+                "type": "http",
+                "url": "https://api.github.com/mcp",
+                "headers": {
+                  "Authorization": "Bearer ${{ secrets.GITHUB_TOKEN }}",
+                  "Content-Type": "application/json"
                 }
               }
             }
diff --git a/.github/workflows/test-codex-command.lock.yml b/.github/workflows/test-codex-command.lock.yml
index f98efef5b79..de788de8a04 100644
--- a/.github/workflows/test-codex-command.lock.yml
+++ b/.github/workflows/test-codex-command.lock.yml
@@ -651,17 +651,11 @@ jobs:
           {
             "mcpServers": {
               "github": {
-                "command": "docker",
-                "args": [
-                  "run",
-                  "-i",
-                  "--rm",
-                  "-e",
-                  "GITHUB_PERSONAL_ACCESS_TOKEN",
-                  "ghcr.io/github/github-mcp-server:sha-09deac4"
-                ],
-                "env": {
-                  "GITHUB_PERSONAL_ACCESS_TOKEN": "${{ secrets.GITHUB_TOKEN }}"
+                "type": "http",
+                "url": "https://api.github.com/mcp",
+                "headers": {
+                  "Authorization": "Bearer ${{ secrets.GITHUB_TOKEN }}",
+                  "Content-Type": "application/json"
                 }
               }
             }
diff --git a/.github/workflows/test-codex-github-mcp.lock.yml b/.github/workflows/test-codex-github-mcp.lock.yml
new file mode 100644
index 00000000000..52858e979e4
--- /dev/null
+++ b/.github/workflows/test-codex-github-mcp.lock.yml
@@ -0,0 +1,469 @@
+# This file was automatically generated by gh-aw. DO NOT EDIT.
+# To update this file, edit the corresponding .md file and run:
+#   gh aw compile
+
+name: "Test GitHub MCP Docker Transport with Codex"
+on:
+  # Start either every 10 minutes, or when some kind of human event occurs.
+  # Because of the implicit "concurrency" section, only one instance of this
+  # workflow will run at a time.
+  schedule:
+    - cron: "0/10 * * * *"
+  issues:
+    types: [opened, edited, closed]
+  issue_comment:
+    types: [created, edited]
+  pull_request:
+    types: [opened, edited, closed]
+  push:
+    branches:
+      - main
+  workflow_dispatch:
+
+permissions: {}
+
+concurrency:
+  group: "gh-aw-${{ github.workflow }}-${{ github.event.issue.number || github.event.pull_request.number }}"
+  cancel-in-progress: true
+
+run-name: "Test GitHub MCP Docker Transport with Codex"
+
+jobs:
+  test-github-mcp-docker-transport-with-codex:
+    runs-on: ubuntu-latest
+    permissions: read-all
+    steps:
+      - name: Check team membership for workflow
+        id: check-team-member
+        uses: actions/github-script@v7
+        env:
+          GITHUB_AW_REQUIRED_ROLES: admin,maintainer
+        with:
+          script: |
+            async function main() {
+              const { eventName } = context;
+              // skip check for safe events
+              const safeEvents = ["workflow_dispatch", "workflow_run", "schedule"];
+              if (safeEvents.includes(eventName)) {
+                console.log(`✅ Event ${eventName} does not require validation`);
+                return;
+              }
+              const actor = context.actor;
+              const { owner, repo } = context.repo;
+              const requiredPermissionsEnv = process.env.GITHUB_AW_REQUIRED_ROLES;
+              const requiredPermissions = requiredPermissionsEnv
+                ? requiredPermissionsEnv.split(",").filter(p => p.trim() !== "")
+                : [];
+              if (!requiredPermissions || requiredPermissions.length === 0) {
+                core.error(
+                  "❌ Configuration error: Required permissions not specified. Contact repository administrator."
+                );
+                process.exit(1);
+              }
+              // Check if the actor has the required repository permissions
+              try {
+                console.log(
+                  `Checking if user '${actor}' has required permissions for ${owner}/${repo}`
+                );
+                console.log(`Required permissions: ${requiredPermissions.join(", ")}`);
+                const repoPermission =
+                  await github.rest.repos.getCollaboratorPermissionLevel({
+                    owner: owner,
+                    repo: repo,
+                    username: actor,
+                  });
+                const permission = repoPermission.data.permission;
+                console.log(`Repository permission level: ${permission}`);
+                // Check if user has one of the required permission levels
+                for (const requiredPerm of requiredPermissions) {
+                  if (
+                    permission === requiredPerm ||
+                    (requiredPerm === "maintainer" && permission === "maintain")
+                  ) {
+                    console.log(`✅ User has ${permission} access to repository`);
+                    return;
+                  }
+                }
+                console.log(
+                  `User permission '${permission}' does not meet requirements: ${requiredPermissions.join(", ")}`
+                );
+              } catch (repoError) {
+                const errorMessage =
+                  repoError instanceof Error ? repoError.message : String(repoError);
+                core.error(`Repository permission check failed: ${errorMessage}`);
+                process.exit(1);
+              }
+              // Fail the job when permission check fails
+              core.warning(
+                `❌ Access denied: Only authorized users can trigger this workflow. User '${actor}' is not authorized. Required permissions: ${requiredPermissions.join(", ")}`
+              );
+              process.exit(78);
+            }
+            await main();
+      - name: Checkout repository
+        uses: actions/checkout@v5
+      - name: Setup Node.js
+        uses: actions/setup-node@v4
+        with:
+          node-version: '24'
+      - name: Install Codex
+        run: npm install -g @openai/codex
+      - name: Setup MCPs
+        run: |
+          mkdir -p /tmp/mcp-config
+          cat > /tmp/mcp-config/config.toml << EOF
+          [history]
+          persistence = "none"
+          
+          [mcp_servers.github]
+          command = "docker"
+          args = [
+            "run",
+            "-i",
+            "--rm",
+            "-e",
+            "GITHUB_PERSONAL_ACCESS_TOKEN",
+            "ghcr.io/github/github-mcp-server:sha-09deac4"
+          ]
+          env = { "GITHUB_PERSONAL_ACCESS_TOKEN" = "${{ secrets.GITHUB_TOKEN }}" }
+          EOF
+      - name: Create prompt
+        env:
+          GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt
+        run: |
+          mkdir -p /tmp/aw-prompts
+          cat > $GITHUB_AW_PROMPT << 'EOF'
+          # Test GitHub MCP Docker Transport with Codex
+          
+          This is a test workflow that uses Codex engine, which should still use Docker transport.
+          
+          EOF
+      - name: Print prompt to step summary
+        run: |
+          echo "## Generated Prompt" >> $GITHUB_STEP_SUMMARY
+          echo "" >> $GITHUB_STEP_SUMMARY
+          echo '``````markdown' >> $GITHUB_STEP_SUMMARY
+          cat $GITHUB_AW_PROMPT >> $GITHUB_STEP_SUMMARY
+          echo '``````' >> $GITHUB_STEP_SUMMARY
+        env:
+          GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt
+      - name: Generate agentic run info
+        uses: actions/github-script@v7
+        with:
+          script: |
+            const fs = require('fs');
+            
+            const awInfo = {
+              engine_id: "codex",
+              engine_name: "Codex",
+              model: "",
+              version: "",
+              workflow_name: "Test GitHub MCP Docker Transport with Codex",
+              experimental: true,
+              supports_tools_whitelist: true,
+              supports_http_transport: false,
+              run_id: context.runId,
+              run_number: context.runNumber,
+              run_attempt: process.env.GITHUB_RUN_ATTEMPT,
+              repository: context.repo.owner + '/' + context.repo.repo,
+              ref: context.ref,
+              sha: context.sha,
+              actor: context.actor,
+              event_name: context.eventName,
+              created_at: new Date().toISOString()
+            };
+            
+            // Write to /tmp directory to avoid inclusion in PR
+            const tmpPath = '/tmp/aw_info.json';
+            fs.writeFileSync(tmpPath, JSON.stringify(awInfo, null, 2));
+            console.log('Generated aw_info.json at:', tmpPath);
+            console.log(JSON.stringify(awInfo, null, 2));
+      - name: Upload agentic run info
+        if: always()
+        uses: actions/upload-artifact@v4
+        with:
+          name: aw_info.json
+          path: /tmp/aw_info.json
+          if-no-files-found: warn
+      - name: Run Codex
+        run: |
+          set -o pipefail
+          INSTRUCTION=$(cat /tmp/aw-prompts/prompt.txt)
+          export CODEX_HOME=/tmp/mcp-config
+          
+          # Create log directory outside git repo
+          mkdir -p /tmp/aw-logs
+          
+          # Run codex with log capture - pipefail ensures codex exit code is preserved
+          codex exec \
+            -c model=o4-mini \
+            --full-auto "$INSTRUCTION" 2>&1 | tee /tmp/test-github-mcp-docker-transport-with-codex.log
+        env:
+          GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt
+          GITHUB_STEP_SUMMARY: ${{ env.GITHUB_STEP_SUMMARY }}
+          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
+      - name: Parse agent logs for step summary
+        if: always()
+        uses: actions/github-script@v7
+        env:
+          AGENT_LOG_FILE: /tmp/test-github-mcp-docker-transport-with-codex.log
+        with:
+          script: |
+            function main() {
+              const fs = require("fs");
+              try {
+                const logFile = process.env.AGENT_LOG_FILE;
+                if (!logFile) {
+                  console.log("No agent log file specified");
+                  return;
+                }
+                if (!fs.existsSync(logFile)) {
+                  console.log(`Log file not found: ${logFile}`);
+                  return;
+                }
+                const content = fs.readFileSync(logFile, "utf8");
+                const parsedLog = parseCodexLog(content);
+                if (parsedLog) {
+                  core.summary.addRaw(parsedLog).write();
+                  console.log("Codex log parsed successfully");
+                } else {
+                  core.error("Failed to parse Codex log");
+                }
+              } catch (error) {
+                core.setFailed(error.message);
+              }
+            }
+            function parseCodexLog(logContent) {
+              try {
+                const lines = logContent.split("\n");
+                let markdown = "## 🤖 Commands and Tools\n\n";
+                const commandSummary = [];
+                // First pass: collect commands for summary
+                for (let i = 0; i < lines.length; i++) {
+                  const line = lines[i];
+                  // Detect tool usage and exec commands
+                  if (line.includes("] tool ") && line.includes("(")) {
+                    // Extract tool name
+                    const toolMatch = line.match(/\] tool ([^(]+)\(/);
+                    if (toolMatch) {
+                      const toolName = toolMatch[1];
+                      // Look ahead to find the result status
+                      let statusIcon = "❓"; // Unknown by default
+                      for (let j = i + 1; j < Math.min(i + 5, lines.length); j++) {
+                        const nextLine = lines[j];
+                        if (nextLine.includes("success in")) {
+                          statusIcon = "✅";
+                          break;
+                        } else if (
+                          nextLine.includes("failure in") ||
+                          nextLine.includes("error in") ||
+                          nextLine.includes("failed in")
+                        ) {
+                          statusIcon = "❌";
+                          break;
+                        }
+                      }
+                      if (toolName.includes(".")) {
+                        // Format as provider::method
+                        const parts = toolName.split(".");
+                        const provider = parts[0];
+                        const method = parts.slice(1).join("_");
+                        commandSummary.push(
+                          `* ${statusIcon} \`${provider}::${method}(...)\``
+                        );
+                      } else {
+                        commandSummary.push(`* ${statusIcon} \`${toolName}(...)\``);
+                      }
+                    }
+                  } else if (line.includes("] exec ")) {
+                    // Extract exec command
+                    const execMatch = line.match(/exec (.+?) in/);
+                    if (execMatch) {
+                      const formattedCommand = formatBashCommand(execMatch[1]);
+                      // Look ahead to find the result status
+                      let statusIcon = "❓"; // Unknown by default
+                      for (let j = i + 1; j < Math.min(i + 5, lines.length); j++) {
+                        const nextLine = lines[j];
+                        if (nextLine.includes("succeeded in")) {
+                          statusIcon = "✅";
+                          break;
+                        } else if (
+                          nextLine.includes("failed in") ||
+                          nextLine.includes("error")
+                        ) {
+                          statusIcon = "❌";
+                          break;
+                        }
+                      }
+                      commandSummary.push(`* ${statusIcon} \`${formattedCommand}\``);
+                    }
+                  }
+                }
+                // Add command summary
+                if (commandSummary.length > 0) {
+                  for (const cmd of commandSummary) {
+                    markdown += `${cmd}\n`;
+                  }
+                } else {
+                  markdown += "No commands or tools used.\n";
+                }
+                // Add Information section
+                markdown += "\n## 📊 Information\n\n";
+                // Extract metadata from Codex logs
+                let totalTokens = 0;
+                const tokenMatches = logContent.match(/tokens used: (\d+)/g);
+                if (tokenMatches) {
+                  for (const match of tokenMatches) {
+                    const tokens = parseInt(match.match(/(\d+)/)[1]);
+                    totalTokens += tokens;
+                  }
+                }
+                if (totalTokens > 0) {
+                  markdown += `**Total Tokens Used:** ${totalTokens.toLocaleString()}\n\n`;
+                }
+                // Count tool calls and exec commands
+                const toolCalls = (logContent.match(/\] tool /g) || []).length;
+                const execCommands = (logContent.match(/\] exec /g) || []).length;
+                if (toolCalls > 0) {
+                  markdown += `**Tool Calls:** ${toolCalls}\n\n`;
+                }
+                if (execCommands > 0) {
+                  markdown += `**Commands Executed:** ${execCommands}\n\n`;
+                }
+                markdown += "\n## 🤖 Reasoning\n\n";
+                // Second pass: process full conversation flow with interleaved reasoning, tools, and commands
+                let inThinkingSection = false;
+                for (let i = 0; i < lines.length; i++) {
+                  const line = lines[i];
+                  // Skip metadata lines
+                  if (
+                    line.includes("OpenAI Codex") ||
+                    line.startsWith("--------") ||
+                    line.includes("workdir:") ||
+                    line.includes("model:") ||
+                    line.includes("provider:") ||
+                    line.includes("approval:") ||
+                    line.includes("sandbox:") ||
+                    line.includes("reasoning effort:") ||
+                    line.includes("reasoning summaries:") ||
+                    line.includes("tokens used:")
+                  ) {
+                    continue;
+                  }
+                  // Process thinking sections
+                  if (line.includes("] thinking")) {
+                    inThinkingSection = true;
+                    continue;
+                  }
+                  // Process tool calls
+                  if (line.includes("] tool ") && line.includes("(")) {
+                    inThinkingSection = false;
+                    const toolMatch = line.match(/\] tool ([^(]+)\(/);
+                    if (toolMatch) {
+                      const toolName = toolMatch[1];
+                      // Look ahead to find the result status
+                      let statusIcon = "❓"; // Unknown by default
+                      for (let j = i + 1; j < Math.min(i + 5, lines.length); j++) {
+                        const nextLine = lines[j];
+                        if (nextLine.includes("success in")) {
+                          statusIcon = "✅";
+                          break;
+                        } else if (
+                          nextLine.includes("failure in") ||
+                          nextLine.includes("error in") ||
+                          nextLine.includes("failed in")
+                        ) {
+                          statusIcon = "❌";
+                          break;
+                        }
+                      }
+                      if (toolName.includes(".")) {
+                        const parts = toolName.split(".");
+                        const provider = parts[0];
+                        const method = parts.slice(1).join("_");
+                        markdown += `${statusIcon} ${provider}::${method}(...)\n\n`;
+                      } else {
+                        markdown += `${statusIcon} ${toolName}(...)\n\n`;
+                      }
+                    }
+                    continue;
+                  }
+                  // Process exec commands
+                  if (line.includes("] exec ")) {
+                    inThinkingSection = false;
+                    const execMatch = line.match(/exec (.+?) in/);
+                    if (execMatch) {
+                      const formattedCommand = formatBashCommand(execMatch[1]);
+                      // Look ahead to find the result status
+                      let statusIcon = "❓"; // Unknown by default
+                      for (let j = i + 1; j < Math.min(i + 5, lines.length); j++) {
+                        const nextLine = lines[j];
+                        if (nextLine.includes("succeeded in")) {
+                          statusIcon = "✅";
+                          break;
+                        } else if (
+                          nextLine.includes("failed in") ||
+                          nextLine.includes("error")
+                        ) {
+                          statusIcon = "❌";
+                          break;
+                        }
+                      }
+                      markdown += `${statusIcon} \`${formattedCommand}\`\n\n`;
+                    }
+                    continue;
+                  }
+                  // Process thinking content
+                  if (
+                    inThinkingSection &&
+                    line.trim().length > 20 &&
+                    !line.startsWith("[2025-")
+                  ) {
+                    const trimmed = line.trim();
+                    // Add thinking content directly
+                    markdown += `${trimmed}\n\n`;
+                  }
+                }
+                return markdown;
+              } catch (error) {
+                core.error(`Error parsing Codex log: ${error}`);
+                return "## 🤖 Commands and Tools\n\nError parsing log content.\n\n## 🤖 Reasoning\n\nUnable to parse reasoning from log.\n\n";
+              }
+            }
+            function formatBashCommand(command) {
+              if (!command) return "";
+              // Convert multi-line commands to single line by replacing newlines with spaces
+              // and collapsing multiple spaces
+              let formatted = command
+                .replace(/\n/g, " ") // Replace newlines with spaces
+                .replace(/\r/g, " ") // Replace carriage returns with spaces
+                .replace(/\t/g, " ") // Replace tabs with spaces
+                .replace(/\s+/g, " ") // Collapse multiple spaces into one
+                .trim(); // Remove leading/trailing whitespace
+              // Escape backticks to prevent markdown issues
+              formatted = formatted.replace(/`/g, "\\`");
+              // Truncate if too long (keep reasonable length for summary)
+              const maxLength = 80;
+              if (formatted.length > maxLength) {
+                formatted = formatted.substring(0, maxLength) + "...";
+              }
+              return formatted;
+            }
+            function truncateString(str, maxLength) {
+              if (!str) return "";
+              if (str.length <= maxLength) return str;
+              return str.substring(0, maxLength) + "...";
+            }
+            // Export for testing
+            if (typeof module !== "undefined" && module.exports) {
+              module.exports = { parseCodexLog, formatBashCommand, truncateString };
+            }
+            main();
+      - name: Upload agent logs
+        if: always()
+        uses: actions/upload-artifact@v4
+        with:
+          name: test-github-mcp-docker-transport-with-codex.log
+          path: /tmp/test-github-mcp-docker-transport-with-codex.log
+          if-no-files-found: warn
+
diff --git a/.github/workflows/test-codex-github-mcp.md b/.github/workflows/test-codex-github-mcp.md
new file mode 100644
index 00000000000..87ef5bcb935
--- /dev/null
+++ b/.github/workflows/test-codex-github-mcp.md
@@ -0,0 +1,10 @@
+---
+engine: codex
+tools:
+  github:
+    allowed: [list_issues, get_issue]
+---
+
+# Test GitHub MCP Docker Transport with Codex
+
+This is a test workflow that uses Codex engine, which should still use Docker transport.
\ No newline at end of file
diff --git a/.github/workflows/test-example-engine-network-permissions.lock.yml b/.github/workflows/test-example-engine-network-permissions.lock.yml
index 12f3196ec8b..d0685bbaacf 100644
--- a/.github/workflows/test-example-engine-network-permissions.lock.yml
+++ b/.github/workflows/test-example-engine-network-permissions.lock.yml
@@ -215,17 +215,11 @@ jobs:
           {
             "mcpServers": {
               "github": {
-                "command": "docker",
-                "args": [
-                  "run",
-                  "-i",
-                  "--rm",
-                  "-e",
-                  "GITHUB_PERSONAL_ACCESS_TOKEN",
-                  "ghcr.io/github/github-mcp-server:sha-09deac4"
-                ],
-                "env": {
-                  "GITHUB_PERSONAL_ACCESS_TOKEN": "${{ secrets.GITHUB_TOKEN }}"
+                "type": "http",
+                "url": "https://api.github.com/mcp",
+                "headers": {
+                  "Authorization": "Bearer ${{ secrets.GITHUB_TOKEN }}",
+                  "Content-Type": "application/json"
                 }
               }
             }
diff --git a/.github/workflows/test-github-mcp.lock.yml b/.github/workflows/test-github-mcp.lock.yml
new file mode 100644
index 00000000000..19e87e92f86
--- /dev/null
+++ b/.github/workflows/test-github-mcp.lock.yml
@@ -0,0 +1,591 @@
+# This file was automatically generated by gh-aw. DO NOT EDIT.
+# To update this file, edit the corresponding .md file and run:
+#   gh aw compile
+
+name: "Test GitHub MCP HTTP Transport"
+on:
+  # Start either every 10 minutes, or when some kind of human event occurs.
+  # Because of the implicit "concurrency" section, only one instance of this
+  # workflow will run at a time.
+  schedule:
+    - cron: "0/10 * * * *"
+  issues:
+    types: [opened, edited, closed]
+  issue_comment:
+    types: [created, edited]
+  pull_request:
+    types: [opened, edited, closed]
+  push:
+    branches:
+      - main
+  workflow_dispatch:
+
+permissions: {}
+
+concurrency:
+  group: "gh-aw-${{ github.workflow }}-${{ github.event.issue.number || github.event.pull_request.number }}"
+  cancel-in-progress: true
+
+run-name: "Test GitHub MCP HTTP Transport"
+
+jobs:
+  test-github-mcp-http-transport:
+    runs-on: ubuntu-latest
+    permissions: read-all
+    steps:
+      - name: Check team membership for workflow
+        id: check-team-member
+        uses: actions/github-script@v7
+        env:
+          GITHUB_AW_REQUIRED_ROLES: admin,maintainer
+        with:
+          script: |
+            async function main() {
+              const { eventName } = context;
+              // skip check for safe events
+              const safeEvents = ["workflow_dispatch", "workflow_run", "schedule"];
+              if (safeEvents.includes(eventName)) {
+                console.log(`✅ Event ${eventName} does not require validation`);
+                return;
+              }
+              const actor = context.actor;
+              const { owner, repo } = context.repo;
+              const requiredPermissionsEnv = process.env.GITHUB_AW_REQUIRED_ROLES;
+              const requiredPermissions = requiredPermissionsEnv
+                ? requiredPermissionsEnv.split(",").filter(p => p.trim() !== "")
+                : [];
+              if (!requiredPermissions || requiredPermissions.length === 0) {
+                core.error(
+                  "❌ Configuration error: Required permissions not specified. Contact repository administrator."
+                );
+                process.exit(1);
+              }
+              // Check if the actor has the required repository permissions
+              try {
+                console.log(
+                  `Checking if user '${actor}' has required permissions for ${owner}/${repo}`
+                );
+                console.log(`Required permissions: ${requiredPermissions.join(", ")}`);
+                const repoPermission =
+                  await github.rest.repos.getCollaboratorPermissionLevel({
+                    owner: owner,
+                    repo: repo,
+                    username: actor,
+                  });
+                const permission = repoPermission.data.permission;
+                console.log(`Repository permission level: ${permission}`);
+                // Check if user has one of the required permission levels
+                for (const requiredPerm of requiredPermissions) {
+                  if (
+                    permission === requiredPerm ||
+                    (requiredPerm === "maintainer" && permission === "maintain")
+                  ) {
+                    console.log(`✅ User has ${permission} access to repository`);
+                    return;
+                  }
+                }
+                console.log(
+                  `User permission '${permission}' does not meet requirements: ${requiredPermissions.join(", ")}`
+                );
+              } catch (repoError) {
+                const errorMessage =
+                  repoError instanceof Error ? repoError.message : String(repoError);
+                core.error(`Repository permission check failed: ${errorMessage}`);
+                process.exit(1);
+              }
+              // Fail the job when permission check fails
+              core.warning(
+                `❌ Access denied: Only authorized users can trigger this workflow. User '${actor}' is not authorized. Required permissions: ${requiredPermissions.join(", ")}`
+              );
+              process.exit(78);
+            }
+            await main();
+      - name: Checkout repository
+        uses: actions/checkout@v5
+      - name: Setup MCPs
+        run: |
+          mkdir -p /tmp/mcp-config
+          cat > /tmp/mcp-config/mcp-servers.json << 'EOF'
+          {
+            "mcpServers": {
+              "github": {
+                "type": "http",
+                "url": "https://api.github.com/mcp",
+                "headers": {
+                  "Authorization": "Bearer ${{ secrets.GITHUB_TOKEN }}",
+                  "Content-Type": "application/json"
+                }
+              }
+            }
+          }
+          EOF
+      - name: Create prompt
+        env:
+          GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt
+        run: |
+          mkdir -p /tmp/aw-prompts
+          cat > $GITHUB_AW_PROMPT << 'EOF'
+          # Test GitHub MCP HTTP Transport
+          
+          This is a test workflow that uses GitHub MCP with HTTP transport.
+          
+          EOF
+      - name: Print prompt to step summary
+        run: |
+          echo "## Generated Prompt" >> $GITHUB_STEP_SUMMARY
+          echo "" >> $GITHUB_STEP_SUMMARY
+          echo '``````markdown' >> $GITHUB_STEP_SUMMARY
+          cat $GITHUB_AW_PROMPT >> $GITHUB_STEP_SUMMARY
+          echo '``````' >> $GITHUB_STEP_SUMMARY
+        env:
+          GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt
+      - name: Generate agentic run info
+        uses: actions/github-script@v7
+        with:
+          script: |
+            const fs = require('fs');
+            
+            const awInfo = {
+              engine_id: "claude",
+              engine_name: "Claude Code",
+              model: "",
+              version: "",
+              workflow_name: "Test GitHub MCP HTTP Transport",
+              experimental: false,
+              supports_tools_whitelist: true,
+              supports_http_transport: true,
+              run_id: context.runId,
+              run_number: context.runNumber,
+              run_attempt: process.env.GITHUB_RUN_ATTEMPT,
+              repository: context.repo.owner + '/' + context.repo.repo,
+              ref: context.ref,
+              sha: context.sha,
+              actor: context.actor,
+              event_name: context.eventName,
+              created_at: new Date().toISOString()
+            };
+            
+            // Write to /tmp directory to avoid inclusion in PR
+            const tmpPath = '/tmp/aw_info.json';
+            fs.writeFileSync(tmpPath, JSON.stringify(awInfo, null, 2));
+            console.log('Generated aw_info.json at:', tmpPath);
+            console.log(JSON.stringify(awInfo, null, 2));
+      - name: Upload agentic run info
+        if: always()
+        uses: actions/upload-artifact@v4
+        with:
+          name: aw_info.json
+          path: /tmp/aw_info.json
+          if-no-files-found: warn
+      - name: Execute Claude Code Action
+        id: agentic_execution
+        uses: anthropics/claude-code-base-action@v0.0.56
+        with:
+          # Allowed tools (sorted):
+          # - ExitPlanMode
+          # - Glob
+          # - Grep
+          # - LS
+          # - NotebookRead
+          # - Read
+          # - Task
+          # - TodoWrite
+          # - mcp__github__create_issue
+          # - mcp__github__download_workflow_run_artifact
+          # - mcp__github__get_code_scanning_alert
+          # - mcp__github__get_commit
+          # - mcp__github__get_dependabot_alert
+          # - mcp__github__get_discussion
+          # - mcp__github__get_discussion_comments
+          # - mcp__github__get_file_contents
+          # - mcp__github__get_issue
+          # - mcp__github__get_issue_comments
+          # - mcp__github__get_job_logs
+          # - mcp__github__get_me
+          # - mcp__github__get_notification_details
+          # - mcp__github__get_pull_request
+          # - mcp__github__get_pull_request_comments
+          # - mcp__github__get_pull_request_diff
+          # - mcp__github__get_pull_request_files
+          # - mcp__github__get_pull_request_reviews
+          # - mcp__github__get_pull_request_status
+          # - mcp__github__get_secret_scanning_alert
+          # - mcp__github__get_tag
+          # - mcp__github__get_workflow_run
+          # - mcp__github__get_workflow_run_logs
+          # - mcp__github__get_workflow_run_usage
+          # - mcp__github__list_branches
+          # - mcp__github__list_code_scanning_alerts
+          # - mcp__github__list_commits
+          # - mcp__github__list_dependabot_alerts
+          # - mcp__github__list_discussion_categories
+          # - mcp__github__list_discussions
+          # - mcp__github__list_issues
+          # - mcp__github__list_notifications
+          # - mcp__github__list_pull_requests
+          # - mcp__github__list_secret_scanning_alerts
+          # - mcp__github__list_tags
+          # - mcp__github__list_workflow_jobs
+          # - mcp__github__list_workflow_run_artifacts
+          # - mcp__github__list_workflow_runs
+          # - mcp__github__list_workflows
+          # - mcp__github__search_code
+          # - mcp__github__search_issues
+          # - mcp__github__search_orgs
+          # - mcp__github__search_pull_requests
+          # - mcp__github__search_repositories
+          # - mcp__github__search_users
+          allowed_tools: "ExitPlanMode,Glob,Grep,LS,NotebookRead,Read,Task,TodoWrite,mcp__github__create_issue,mcp__github__download_workflow_run_artifact,mcp__github__get_code_scanning_alert,mcp__github__get_commit,mcp__github__get_dependabot_alert,mcp__github__get_discussion,mcp__github__get_discussion_comments,mcp__github__get_file_contents,mcp__github__get_issue,mcp__github__get_issue_comments,mcp__github__get_job_logs,mcp__github__get_me,mcp__github__get_notification_details,mcp__github__get_pull_request,mcp__github__get_pull_request_comments,mcp__github__get_pull_request_diff,mcp__github__get_pull_request_files,mcp__github__get_pull_request_reviews,mcp__github__get_pull_request_status,mcp__github__get_secret_scanning_alert,mcp__github__get_tag,mcp__github__get_workflow_run,mcp__github__get_workflow_run_logs,mcp__github__get_workflow_run_usage,mcp__github__list_branches,mcp__github__list_code_scanning_alerts,mcp__github__list_commits,mcp__github__list_dependabot_alerts,mcp__github__list_discussion_categories,mcp__github__list_discussions,mcp__github__list_issues,mcp__github__list_notifications,mcp__github__list_pull_requests,mcp__github__list_secret_scanning_alerts,mcp__github__list_tags,mcp__github__list_workflow_jobs,mcp__github__list_workflow_run_artifacts,mcp__github__list_workflow_runs,mcp__github__list_workflows,mcp__github__search_code,mcp__github__search_issues,mcp__github__search_orgs,mcp__github__search_pull_requests,mcp__github__search_repositories,mcp__github__search_users"
+          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
+          mcp_config: /tmp/mcp-config/mcp-servers.json
+          prompt_file: /tmp/aw-prompts/prompt.txt
+          timeout_minutes: 5
+        env:
+          GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt
+      - name: Capture Agentic Action logs
+        if: always()
+        run: |
+          # Copy the detailed execution file from Agentic Action if available
+          if [ -n "${{ steps.agentic_execution.outputs.execution_file }}" ] && [ -f "${{ steps.agentic_execution.outputs.execution_file }}" ]; then
+            cp ${{ steps.agentic_execution.outputs.execution_file }} /tmp/test-github-mcp-http-transport.log
+          else
+            echo "No execution file output found from Agentic Action" >> /tmp/test-github-mcp-http-transport.log
+          fi
+          
+          # Ensure log file exists
+          touch /tmp/test-github-mcp-http-transport.log
+      - name: Upload engine output files
+        uses: actions/upload-artifact@v4
+        with:
+          name: agent_outputs
+          path: |
+            output.txt
+          if-no-files-found: ignore
+      - name: Clean up engine output files
+        run: |
+          rm -f output.txt
+      - name: Parse agent logs for step summary
+        if: always()
+        uses: actions/github-script@v7
+        env:
+          AGENT_LOG_FILE: /tmp/test-github-mcp-http-transport.log
+        with:
+          script: |
+            function main() {
+              const fs = require("fs");
+              try {
+                // Get the log file path from environment
+                const logFile = process.env.AGENT_LOG_FILE;
+                if (!logFile) {
+                  console.log("No agent log file specified");
+                  return;
+                }
+                if (!fs.existsSync(logFile)) {
+                  console.log(`Log file not found: ${logFile}`);
+                  return;
+                }
+                const logContent = fs.readFileSync(logFile, "utf8");
+                const markdown = parseClaudeLog(logContent);
+                // Append to GitHub step summary
+                core.summary.addRaw(markdown).write();
+              } catch (error) {
+                core.error(`Error parsing Claude log: ${error.message}`);
+                core.setFailed(error.message);
+              }
+            }
+            function parseClaudeLog(logContent) {
+              try {
+                const logEntries = JSON.parse(logContent);
+                if (!Array.isArray(logEntries)) {
+                  return "## Agent Log Summary\n\nLog format not recognized as Claude JSON array.\n";
+                }
+                let markdown = "## 🤖 Commands and Tools\n\n";
+                const toolUsePairs = new Map(); // Map tool_use_id to tool_result
+                const commandSummary = []; // For the succinct summary
+                // First pass: collect tool results by tool_use_id
+                for (const entry of logEntries) {
+                  if (entry.type === "user" && entry.message?.content) {
+                    for (const content of entry.message.content) {
+                      if (content.type === "tool_result" && content.tool_use_id) {
+                        toolUsePairs.set(content.tool_use_id, content);
+                      }
+                    }
+                  }
+                }
+                // Collect all tool uses for summary
+                for (const entry of logEntries) {
+                  if (entry.type === "assistant" && entry.message?.content) {
+                    for (const content of entry.message.content) {
+                      if (content.type === "tool_use") {
+                        const toolName = content.name;
+                        const input = content.input || {};
+                        // Skip internal tools - only show external commands and API calls
+                        if (
+                          [
+                            "Read",
+                            "Write",
+                            "Edit",
+                            "MultiEdit",
+                            "LS",
+                            "Grep",
+                            "Glob",
+                            "TodoWrite",
+                          ].includes(toolName)
+                        ) {
+                          continue; // Skip internal file operations and searches
+                        }
+                        // Find the corresponding tool result to get status
+                        const toolResult = toolUsePairs.get(content.id);
+                        let statusIcon = "❓";
+                        if (toolResult) {
+                          statusIcon = toolResult.is_error === true ? "❌" : "✅";
+                        }
+                        // Add to command summary (only external tools)
+                        if (toolName === "Bash") {
+                          const formattedCommand = formatBashCommand(input.command || "");
+                          commandSummary.push(`* ${statusIcon} \`${formattedCommand}\``);
+                        } else if (toolName.startsWith("mcp__")) {
+                          const mcpName = formatMcpName(toolName);
+                          commandSummary.push(`* ${statusIcon} \`${mcpName}(...)\``);
+                        } else {
+                          // Handle other external tools (if any)
+                          commandSummary.push(`* ${statusIcon} ${toolName}`);
+                        }
+                      }
+                    }
+                  }
+                }
+                // Add command summary
+                if (commandSummary.length > 0) {
+                  for (const cmd of commandSummary) {
+                    markdown += `${cmd}\n`;
+                  }
+                } else {
+                  markdown += "No commands or tools used.\n";
+                }
+                // Add Information section from the last entry with result metadata
+                markdown += "\n## 📊 Information\n\n";
+                // Find the last entry with metadata
+                const lastEntry = logEntries[logEntries.length - 1];
+                if (
+                  lastEntry &&
+                  (lastEntry.num_turns ||
+                    lastEntry.duration_ms ||
+                    lastEntry.total_cost_usd ||
+                    lastEntry.usage)
+                ) {
+                  if (lastEntry.num_turns) {
+                    markdown += `**Turns:** ${lastEntry.num_turns}\n\n`;
+                  }
+                  if (lastEntry.duration_ms) {
+                    const durationSec = Math.round(lastEntry.duration_ms / 1000);
+                    const minutes = Math.floor(durationSec / 60);
+                    const seconds = durationSec % 60;
+                    markdown += `**Duration:** ${minutes}m ${seconds}s\n\n`;
+                  }
+                  if (lastEntry.total_cost_usd) {
+                    markdown += `**Total Cost:** $${lastEntry.total_cost_usd.toFixed(4)}\n\n`;
+                  }
+                  if (lastEntry.usage) {
+                    const usage = lastEntry.usage;
+                    if (usage.input_tokens || usage.output_tokens) {
+                      markdown += `**Token Usage:**\n`;
+                      if (usage.input_tokens)
+                        markdown += `- Input: ${usage.input_tokens.toLocaleString()}\n`;
+                      if (usage.cache_creation_input_tokens)
+                        markdown += `- Cache Creation: ${usage.cache_creation_input_tokens.toLocaleString()}\n`;
+                      if (usage.cache_read_input_tokens)
+                        markdown += `- Cache Read: ${usage.cache_read_input_tokens.toLocaleString()}\n`;
+                      if (usage.output_tokens)
+                        markdown += `- Output: ${usage.output_tokens.toLocaleString()}\n`;
+                      markdown += "\n";
+                    }
+                  }
+                  if (
+                    lastEntry.permission_denials &&
+                    lastEntry.permission_denials.length > 0
+                  ) {
+                    markdown += `**Permission Denials:** ${lastEntry.permission_denials.length}\n\n`;
+                  }
+                }
+                markdown += "\n## 🤖 Reasoning\n\n";
+                // Second pass: process assistant messages in sequence
+                for (const entry of logEntries) {
+                  if (entry.type === "assistant" && entry.message?.content) {
+                    for (const content of entry.message.content) {
+                      if (content.type === "text" && content.text) {
+                        // Add reasoning text directly (no header)
+                        const text = content.text.trim();
+                        if (text && text.length > 0) {
+                          markdown += text + "\n\n";
+                        }
+                      } else if (content.type === "tool_use") {
+                        // Process tool use with its result
+                        const toolResult = toolUsePairs.get(content.id);
+                        const toolMarkdown = formatToolUse(content, toolResult);
+                        if (toolMarkdown) {
+                          markdown += toolMarkdown;
+                        }
+                      }
+                    }
+                  }
+                }
+                return markdown;
+              } catch (error) {
+                return `## Agent Log Summary\n\nError parsing Claude log: ${error.message}\n`;
+              }
+            }
+            function formatToolUse(toolUse, toolResult) {
+              const toolName = toolUse.name;
+              const input = toolUse.input || {};
+              // Skip TodoWrite except the very last one (we'll handle this separately)
+              if (toolName === "TodoWrite") {
+                return ""; // Skip for now, would need global context to find the last one
+              }
+              // Helper function to determine status icon
+              function getStatusIcon() {
+                if (toolResult) {
+                  return toolResult.is_error === true ? "❌" : "✅";
+                }
+                return "❓"; // Unknown by default
+              }
+              let markdown = "";
+              const statusIcon = getStatusIcon();
+              switch (toolName) {
+                case "Bash":
+                  const command = input.command || "";
+                  const description = input.description || "";
+                  // Format the command to be single line
+                  const formattedCommand = formatBashCommand(command);
+                  if (description) {
+                    markdown += `${description}:\n\n`;
+                  }
+                  markdown += `${statusIcon} \`${formattedCommand}\`\n\n`;
+                  break;
+                case "Read":
+                  const filePath = input.file_path || input.path || "";
+                  const relativePath = filePath.replace(
+                    /^\/[^\/]*\/[^\/]*\/[^\/]*\/[^\/]*\//,
+                    ""
+                  ); // Remove /home/runner/work/repo/repo/ prefix
+                  markdown += `${statusIcon} Read \`${relativePath}\`\n\n`;
+                  break;
+                case "Write":
+                case "Edit":
+                case "MultiEdit":
+                  const writeFilePath = input.file_path || input.path || "";
+                  const writeRelativePath = writeFilePath.replace(
+                    /^\/[^\/]*\/[^\/]*\/[^\/]*\/[^\/]*\//,
+                    ""
+                  );
+                  markdown += `${statusIcon} Write \`${writeRelativePath}\`\n\n`;
+                  break;
+                case "Grep":
+                case "Glob":
+                  const query = input.query || input.pattern || "";
+                  markdown += `${statusIcon} Search for \`${truncateString(query, 80)}\`\n\n`;
+                  break;
+                case "LS":
+                  const lsPath = input.path || "";
+                  const lsRelativePath = lsPath.replace(
+                    /^\/[^\/]*\/[^\/]*\/[^\/]*\/[^\/]*\//,
+                    ""
+                  );
+                  markdown += `${statusIcon} LS: ${lsRelativePath || lsPath}\n\n`;
+                  break;
+                default:
+                  // Handle MCP calls and other tools
+                  if (toolName.startsWith("mcp__")) {
+                    const mcpName = formatMcpName(toolName);
+                    const params = formatMcpParameters(input);
+                    markdown += `${statusIcon} ${mcpName}(${params})\n\n`;
+                  } else {
+                    // Generic tool formatting - show the tool name and main parameters
+                    const keys = Object.keys(input);
+                    if (keys.length > 0) {
+                      // Try to find the most important parameter
+                      const mainParam =
+                        keys.find(k =>
+                          ["query", "command", "path", "file_path", "content"].includes(k)
+                        ) || keys[0];
+                      const value = String(input[mainParam] || "");
+                      if (value) {
+                        markdown += `${statusIcon} ${toolName}: ${truncateString(value, 100)}\n\n`;
+                      } else {
+                        markdown += `${statusIcon} ${toolName}\n\n`;
+                      }
+                    } else {
+                      markdown += `${statusIcon} ${toolName}\n\n`;
+                    }
+                  }
+              }
+              return markdown;
+            }
+            function formatMcpName(toolName) {
+              // Convert mcp__github__search_issues to github::search_issues
+              if (toolName.startsWith("mcp__")) {
+                const parts = toolName.split("__");
+                if (parts.length >= 3) {
+                  const provider = parts[1]; // github, etc.
+                  const method = parts.slice(2).join("_"); // search_issues, etc.
+                  return `${provider}::${method}`;
+                }
+              }
+              return toolName;
+            }
+            function formatMcpParameters(input) {
+              const keys = Object.keys(input);
+              if (keys.length === 0) return "";
+              const paramStrs = [];
+              for (const key of keys.slice(0, 4)) {
+                // Show up to 4 parameters
+                const value = String(input[key] || "");
+                paramStrs.push(`${key}: ${truncateString(value, 40)}`);
+              }
+              if (keys.length > 4) {
+                paramStrs.push("...");
+              }
+              return paramStrs.join(", ");
+            }
+            function formatBashCommand(command) {
+              if (!command) return "";
+              // Convert multi-line commands to single line by replacing newlines with spaces
+              // and collapsing multiple spaces
+              let formatted = command
+                .replace(/\n/g, " ") // Replace newlines with spaces
+                .replace(/\r/g, " ") // Replace carriage returns with spaces
+                .replace(/\t/g, " ") // Replace tabs with spaces
+                .replace(/\s+/g, " ") // Collapse multiple spaces into one
+                .trim(); // Remove leading/trailing whitespace
+              // Escape backticks to prevent markdown issues
+              formatted = formatted.replace(/`/g, "\\`");
+              // Truncate if too long (keep reasonable length for summary)
+              const maxLength = 80;
+              if (formatted.length > maxLength) {
+                formatted = formatted.substring(0, maxLength) + "...";
+              }
+              return formatted;
+            }
+            function truncateString(str, maxLength) {
+              if (!str) return "";
+              if (str.length <= maxLength) return str;
+              return str.substring(0, maxLength) + "...";
+            }
+            // Export for testing
+            if (typeof module !== "undefined" && module.exports) {
+              module.exports = {
+                parseClaudeLog,
+                formatToolUse,
+                formatBashCommand,
+                truncateString,
+              };
+            }
+            main();
+      - name: Upload agent logs
+        if: always()
+        uses: actions/upload-artifact@v4
+        with:
+          name: test-github-mcp-http-transport.log
+          path: /tmp/test-github-mcp-http-transport.log
+          if-no-files-found: warn
+
diff --git a/.github/workflows/test-github-mcp.md b/.github/workflows/test-github-mcp.md
new file mode 100644
index 00000000000..ed525e61c05
--- /dev/null
+++ b/.github/workflows/test-github-mcp.md
@@ -0,0 +1,9 @@
+---
+tools:
+  github:
+    allowed: [list_issues, get_issue, create_issue]
+---
+
+# Test GitHub MCP HTTP Transport
+
+This is a test workflow that uses GitHub MCP with HTTP transport.
\ No newline at end of file
diff --git a/.github/workflows/test-proxy.lock.yml b/.github/workflows/test-proxy.lock.yml
index 0df0c3d3a2a..35126b0b243 100644
--- a/.github/workflows/test-proxy.lock.yml
+++ b/.github/workflows/test-proxy.lock.yml
@@ -383,17 +383,11 @@ jobs:
                 ]
               },
               "github": {
-                "command": "docker",
-                "args": [
-                  "run",
-                  "-i",
-                  "--rm",
-                  "-e",
-                  "GITHUB_PERSONAL_ACCESS_TOKEN",
-                  "ghcr.io/github/github-mcp-server:sha-09deac4"
-                ],
-                "env": {
-                  "GITHUB_PERSONAL_ACCESS_TOKEN": "${{ secrets.GITHUB_TOKEN }}"
+                "type": "http",
+                "url": "https://api.github.com/mcp",
+                "headers": {
+                  "Authorization": "Bearer ${{ secrets.GITHUB_TOKEN }}",
+                  "Content-Type": "application/json"
                 }
               }
             }
diff --git a/pkg/workflow/claude_engine.go b/pkg/workflow/claude_engine.go
index d75552292c0..39b60539e53 100644
--- a/pkg/workflow/claude_engine.go
+++ b/pkg/workflow/claude_engine.go
@@ -552,24 +552,18 @@ func (e *ClaudeEngine) RenderMCPConfig(yaml *strings.Builder, tools map[string]a
 }
 
 // renderGitHubClaudeMCPConfig generates the GitHub MCP server configuration
-// Always uses Docker MCP as the default
+// Always uses HTTP MCP as the default for remote GitHub MCP server
 func (e *ClaudeEngine) renderGitHubClaudeMCPConfig(yaml *strings.Builder, githubTool any, isLast bool) {
-	githubDockerImageVersion := getGitHubDockerImageVersion(githubTool)
+	githubURL := getGitHubMCPURL(githubTool)
 
 	yaml.WriteString("              \"github\": {\n")
 
-	// Always use Docker-based GitHub MCP server (services mode has been removed)
-	yaml.WriteString("                \"command\": \"docker\",\n")
-	yaml.WriteString("                \"args\": [\n")
-	yaml.WriteString("                  \"run\",\n")
-	yaml.WriteString("                  \"-i\",\n")
-	yaml.WriteString("                  \"--rm\",\n")
-	yaml.WriteString("                  \"-e\",\n")
-	yaml.WriteString("                  \"GITHUB_PERSONAL_ACCESS_TOKEN\",\n")
-	yaml.WriteString("                  \"ghcr.io/github/github-mcp-server:" + githubDockerImageVersion + "\"\n")
-	yaml.WriteString("                ],\n")
-	yaml.WriteString("                \"env\": {\n")
-	yaml.WriteString("                  \"GITHUB_PERSONAL_ACCESS_TOKEN\": \"${{ secrets.GITHUB_TOKEN }}\"\n")
+	// Use HTTP-based GitHub MCP server (remote service)
+	yaml.WriteString("                \"type\": \"http\",\n")
+	yaml.WriteString("                \"url\": \"" + githubURL + "\",\n")
+	yaml.WriteString("                \"headers\": {\n")
+	yaml.WriteString("                  \"Authorization\": \"Bearer ${{ secrets.GITHUB_TOKEN }}\",\n")
+	yaml.WriteString("                  \"Content-Type\": \"application/json\"\n")
 	yaml.WriteString("                }\n")
 
 	if isLast {
diff --git a/pkg/workflow/codex_test.go b/pkg/workflow/codex_test.go
index f20b2e2f62f..547bbf3ecd3 100644
--- a/pkg/workflow/codex_test.go
+++ b/pkg/workflow/codex_test.go
@@ -395,8 +395,31 @@ This is a test workflow for MCP configuration with different AI engines.
 					t.Errorf("Expected github section in JSON but didn't find it in:\n%s", lockContent)
 				}
 
-				if !strings.Contains(lockContent, "\"command\": \"docker\"") {
-					t.Errorf("Expected docker command in mcp-servers.json but didn't find it in:\n%s", lockContent)
+				// For Claude engine, expect HTTP configuration; for others, expect Docker
+				if tt.expectedAI == "claude" {
+					// Claude should use HTTP transport for GitHub MCP
+					if !strings.Contains(lockContent, "\"type\": \"http\"") {
+						t.Errorf("Expected HTTP type in Claude mcp-servers.json but didn't find it in:\n%s", lockContent)
+					}
+					if !strings.Contains(lockContent, "\"url\": \"https://api.github.com/mcp\"") {
+						t.Errorf("Expected GitHub MCP URL in Claude mcp-servers.json but didn't find it in:\n%s", lockContent)
+					}
+					if !strings.Contains(lockContent, "\"Authorization\": \"Bearer ${{ secrets.GITHUB_TOKEN }}\"") {
+						t.Errorf("Expected Authorization header in Claude mcp-servers.json but didn't find it in:\n%s", lockContent)
+					}
+					// Should NOT have Docker command
+					if strings.Contains(lockContent, "\"command\": \"docker\"") {
+						t.Errorf("Expected NO docker command in Claude mcp-servers.json but found it in:\n%s", lockContent)
+					}
+				} else {
+					// Non-Claude engines should still use Docker transport
+					if !strings.Contains(lockContent, "\"command\": \"docker\"") {
+						t.Errorf("Expected docker command in mcp-servers.json but didn't find it in:\n%s", lockContent)
+					}
+					// Should NOT have HTTP type
+					if strings.Contains(lockContent, "\"type\": \"http\"") {
+						t.Errorf("Expected NO HTTP type in non-Claude mcp-servers.json but found it in:\n%s", lockContent)
+					}
 				}
 				// Should NOT have services section (services mode removed)
 				if strings.Contains(lockContent, "services:") {
diff --git a/pkg/workflow/compiler.go b/pkg/workflow/compiler.go
index 55b560de8f4..0d56ee1a524 100644
--- a/pkg/workflow/compiler.go
+++ b/pkg/workflow/compiler.go
@@ -2845,6 +2845,20 @@ func getGitHubDockerImageVersion(githubTool any) string {
 	return githubDockerImageVersion
 }
 
+// getGitHubMCPURL returns the GitHub MCP server URL, with support for custom URLs
+func getGitHubMCPURL(githubTool any) string {
+	githubURL := "https://api.github.com/mcp" // Default GitHub MCP server URL
+	// Extract mcp_url setting from tool properties
+	if toolConfig, ok := githubTool.(map[string]any); ok {
+		if urlSetting, exists := toolConfig["mcp_url"]; exists {
+			if stringValue, ok := urlSetting.(string); ok {
+				githubURL = stringValue
+			}
+		}
+	}
+	return githubURL
+}
+
 // generateMainJobSteps generates the steps section for the main job
 func (c *Compiler) generateMainJobSteps(yaml *strings.Builder, data *WorkflowData) {
 	// Add custom steps or default checkout step
diff --git a/pkg/workflow/js/collect_ndjson_output.test.cjs b/pkg/workflow/js/collect_ndjson_output.test.cjs
index 50aa970599c..d7924369738 100644
--- a/pkg/workflow/js/collect_ndjson_output.test.cjs
+++ b/pkg/workflow/js/collect_ndjson_output.test.cjs
@@ -154,7 +154,7 @@ describe("collect_ndjson_output.cjs", () => {
     const failedMessage = mockCore.setFailed.mock.calls[0][0];
     expect(failedMessage).toContain("requires a 'body' string field");
     expect(failedMessage).toContain("requires a 'title' string field");
-    
+
     // setOutput should not be called because of early return
     const setOutputCalls = mockCore.setOutput.mock.calls;
     const outputCall = setOutputCalls.find(call => call[0] === "output");
@@ -650,7 +650,7 @@ Line 3"}
       expect(mockCore.setFailed).toHaveBeenCalledTimes(1);
       const failedMessage = mockCore.setFailed.mock.calls[0][0];
       expect(failedMessage).toContain("JSON parsing failed");
-      
+
       // setOutput should not be called because of early return
       const setOutputCalls = mockCore.setOutput.mock.calls;
       const outputCall = setOutputCalls.find(call => call[0] === "output");
@@ -736,7 +736,7 @@ Line 3"}
       // Check if repair succeeded by looking at mock calls
       const setOutputCalls = mockCore.setOutput.mock.calls;
       const outputCall = setOutputCalls.find(call => call[0] === "output");
-      
+
       if (outputCall) {
         // Repair succeeded
         const parsedOutput = JSON.parse(outputCall[1]);
@@ -830,7 +830,7 @@ Line 3"}
       expect(mockCore.setFailed).toHaveBeenCalledTimes(1);
       const failedMessage = mockCore.setFailed.mock.calls[0][0];
       expect(failedMessage).toContain("JSON parsing failed");
-      
+
       // setOutput should not be called because of early return
       const setOutputCalls = mockCore.setOutput.mock.calls;
       const outputCall = setOutputCalls.find(call => call[0] === "output");
@@ -949,7 +949,7 @@ Line 3"}
       expect(mockCore.setFailed).toHaveBeenCalledTimes(1);
       const failedMessage = mockCore.setFailed.mock.calls[0][0];
       expect(failedMessage).toContain("JSON parsing failed");
-      
+
       // setOutput should not be called because of early return
       const setOutputCalls = mockCore.setOutput.mock.calls;
       const outputCall = setOutputCalls.find(call => call[0] === "output");
@@ -970,7 +970,7 @@ Line 3"}
       expect(mockCore.setFailed).toHaveBeenCalledTimes(1);
       const failedMessage = mockCore.setFailed.mock.calls[0][0];
       expect(failedMessage).toContain("JSON parsing failed");
-      
+
       // setOutput should not be called because of early return
       const setOutputCalls = mockCore.setOutput.mock.calls;
       const outputCall = setOutputCalls.find(call => call[0] === "output");
@@ -1015,7 +1015,7 @@ Line 3"}
       // Check if repair succeeded by looking at mock calls
       const setOutputCalls = mockCore.setOutput.mock.calls;
       const outputCall = setOutputCalls.find(call => call[0] === "output");
-      
+
       if (outputCall) {
         // Repair succeeded
         const parsedOutput = JSON.parse(outputCall[1]);
diff --git a/pkg/workflow/mcp_config_test.go b/pkg/workflow/mcp_config_test.go
index c71e261928b..312f32f47af 100644
--- a/pkg/workflow/mcp_config_test.go
+++ b/pkg/workflow/mcp_config_test.go
@@ -26,55 +26,45 @@ func TestGitHubMCPConfiguration(t *testing.T) {
 		expectedDockerImage string
 	}{
 		{
-			name: "default Docker server",
+			name: "default HTTP server",
 			frontmatter: `---
 tools:
   github:
     allowed: [list_issues, create_issue]
 ---`,
-			// With Docker MCP always enabled, default is docker (not services)
-			expectedType:        "docker",
-			expectedCommand:     "docker",
-			expectedDockerImage: "ghcr.io/github/github-mcp-server:sha-09deac4",
+			// With HTTP MCP enabled by default for Claude engine
+			expectedType: "http",
+			expectedURL:  "https://api.github.com/mcp",
 		},
 		{
-			name: "custom docker image version",
+			name: "default HTTP server with list_issues",
 			frontmatter: `---
 tools:
   github:
-    use_docker_mcp: true
-    docker_image_version: "v1.2.3"
-    allowed: [list_issues, create_issue]
+    allowed: [list_issues]
 ---`,
-			expectedType:        "docker",
-			expectedCommand:     "docker",
-			expectedDockerImage: "ghcr.io/github/github-mcp-server:v1.2.3",
+			expectedType: "http",
+			expectedURL:  "https://api.github.com/mcp",
 		},
 		{
-			name: "custom docker image SHA",
+			name: "default HTTP server with multiple tools",
 			frontmatter: `---
 tools:
   github:
-    use_docker_mcp: true
-    docker_image_version: "sha-abcd1234"
-    allowed: [list_issues, create_issue]
+    allowed: [get_issue, list_pull_requests, search_issues]
 ---`,
-			expectedType:        "docker",
-			expectedCommand:     "docker",
-			expectedDockerImage: "ghcr.io/github/github-mcp-server:sha-abcd1234",
+			expectedType: "http",
+			expectedURL:  "https://api.github.com/mcp",
 		},
 		{
-			name: "custom docker image version with services disabled",
+			name: "default HTTP server with different allowed tools",
 			frontmatter: `---
 tools:
   github:
-    use_docker_mcp: true
-    docker_image_version: "latest"
-    allowed: [list_issues, create_issue]
+    allowed: [get_issue, list_pull_requests]
 ---`,
-			expectedType:        "docker",
-			expectedCommand:     "docker",
-			expectedDockerImage: "ghcr.io/github/github-mcp-server:latest",
+			expectedType: "http",
+			expectedURL:  "https://api.github.com/mcp",
 		},
 	}
 
@@ -163,30 +153,30 @@ func TestGenerateGitHubMCPConfig(t *testing.T) {
 		{
 			name:       "nil github tool",
 			githubTool: nil,
-			// With new defaults, nil tool defaults to docker (not services)
-			expectedType: "docker",
+			// With new defaults, nil tool defaults to http (remote MCP server)
+			expectedType: "http",
 		},
 		{
 			name: "empty github tool config",
 			githubTool: map[string]any{
 				"allowed": []any{"list_issues"},
 			},
-			// With Docker always enabled, empty config defaults to docker (not services)
-			expectedType: "docker",
+			// With HTTP always enabled, empty config defaults to http (remote MCP server)
+			expectedType: "http",
 		},
 		{
-			name: "explicit docker config (redundant)",
+			name: "explicit github tool config",
 			githubTool: map[string]any{
 				"allowed": []any{"list_issues"},
 			},
-			// Docker is always enabled now
-			expectedType: "docker",
+			// HTTP is always enabled now for Claude engine
+			expectedType: "http",
 		},
 		{
 			name:       "non-map github tool",
 			githubTool: "invalid",
-			// With Docker always enabled, invalid tool config defaults to docker (not services)
-			expectedType: "docker",
+			// With HTTP always enabled, invalid tool config defaults to http (remote MCP server)
+			expectedType: "http",
 		},
 	}
 
@@ -201,6 +191,19 @@ func TestGenerateGitHubMCPConfig(t *testing.T) {
 			result := yamlBuilder.String()
 
 			switch tt.expectedType {
+			case "http":
+				if !strings.Contains(result, `"type": "http"`) {
+					t.Errorf("Expected HTTP type but got:\n%s", result)
+				}
+				if !strings.Contains(result, `"url": "https://api.github.com/mcp"`) {
+					t.Errorf("Expected HTTP URL but got:\n%s", result)
+				}
+				if !strings.Contains(result, `"Authorization": "Bearer ${{ secrets.GITHUB_TOKEN }}"`) {
+					t.Errorf("Expected Authorization header but got:\n%s", result)
+				}
+				if strings.Contains(result, `"command": "docker"`) {
+					t.Errorf("Expected no Docker command but found it in:\n%s", result)
+				}
 			case "docker":
 				if !strings.Contains(result, `"command": "docker"`) {
 					t.Errorf("Expected Docker command but got:\n%s", result)
@@ -224,7 +227,7 @@ func TestMCPConfigurationEdgeCases(t *testing.T) {
 		expected   string
 	}{
 		{
-			name: "last server with docker config",
+			name: "last server with http config",
 			githubTool: map[string]any{
 				"allowed": []any{"list_issues"},
 			},
@@ -232,7 +235,7 @@ func TestMCPConfigurationEdgeCases(t *testing.T) {
 			expected: `              }`,
 		},
 		{
-			name: "not last server with docker config",
+			name: "not last server with http config",
 			githubTool: map[string]any{
 				"allowed": []any{"list_issues"},
 			},
@@ -275,7 +278,7 @@ func TestCustomDockerMCPConfiguration(t *testing.T) {
 		expectedDockerImage string // Expected Docker image version
 	}{
 		{
-			name: "custom docker MCP with default settings",
+			name: "custom docker MCP with default Claude HTTP settings",
 			frontmatter: `---
 tools:
   github:
@@ -287,11 +290,10 @@ tools:
       command: "docker"
       args: ["run", "-i", "--rm", "custom/mcp-server:latest"]
 ---`,
-			expectedType:        "docker",      // GitHub always uses docker now
-			expectedDockerImage: "sha-09deac4", // Default version
+			expectedType: "http", // Claude engine now uses HTTP transport for GitHub
 		},
 		{
-			name: "custom docker MCP with default settings",
+			name: "custom docker MCP with default Claude HTTP settings",
 			frontmatter: `---
 tools:
   github:
@@ -302,8 +304,7 @@ tools:
       command: "docker"
       args: ["run", "-i", "--rm", "custom/mcp-server:latest"]
 ---`,
-			expectedType:        "docker",      // Services mode removed - always Docker
-			expectedDockerImage: "sha-09deac4", // Default version
+			expectedType: "http", // Claude engine now uses HTTP transport for GitHub
 		},
 		{
 			name: "custom docker MCP with different settings",
@@ -317,8 +318,7 @@ tools:
       command: "docker"
       args: ["run", "-i", "--rm", "custom/mcp-server:latest"]
 ---`,
-			expectedType:        "docker",
-			expectedDockerImage: "sha-09deac4", // Default version
+			expectedType: "http", // Claude engine now uses HTTP transport for GitHub
 		},
 		{
 			name: "mixed MCP configuration with defaults",
@@ -337,8 +337,7 @@ tools:
       command: "docker"
       args: ["run", "-i", "--rm", "-v", "/tmp:/workspace", "custom/tool:latest"]
 ---`,
-			expectedType:        "docker",      // GitHub should now use docker by default (not services)
-			expectedDockerImage: "sha-09deac4", // Default version
+			expectedType: "http", // Claude engine now uses HTTP transport for GitHub
 		},
 		{
 			name: "custom docker MCP with custom Docker image version",
@@ -353,8 +352,7 @@ tools:
       command: "docker"
       args: ["run", "-i", "--rm", "custom/mcp-server:latest"]
 ---`,
-			expectedType:        "docker", // GitHub always uses docker now
-			expectedDockerImage: "v2.0.0", // Custom version
+			expectedType: "http", // Claude engine now uses HTTP transport for GitHub
 		},
 	}
 
@@ -389,6 +387,26 @@ This is a test workflow for custom Docker MCP configuration with different scena
 
 			// Check the GitHub MCP configuration based on expected type
 			switch tt.expectedType {
+			case "http":
+				// Should contain HTTP configuration for GitHub (Claude engine)
+				if !strings.Contains(lockContent, `"type": "http"`) {
+					t.Errorf("Expected HTTP type but didn't find it in:\n%s", lockContent)
+				}
+				if !strings.Contains(lockContent, `"url": "https://api.github.com/mcp"`) {
+					t.Errorf("Expected GitHub MCP URL but didn't find it in:\n%s", lockContent)
+				}
+				if !strings.Contains(lockContent, `"Authorization": "Bearer ${{ secrets.GITHUB_TOKEN }}"`) {
+					t.Errorf("Expected Authorization header but didn't find it in:\n%s", lockContent)
+				}
+				// Should NOT contain Docker configuration in the GitHub server section
+				githubSection := extractGitHubSection(lockContent)
+				if githubSection != "" && strings.Contains(githubSection, `"command": "docker"`) {
+					t.Errorf("Expected no Docker command in GitHub MCP section but found it in:\n%s", githubSection)
+				}
+				// Should NOT contain services configuration
+				if strings.Contains(lockContent, `services:`) {
+					t.Errorf("Expected no services configuration but found it in:\n%s", lockContent)
+				}
 			case "docker":
 				// Should contain Docker configuration for GitHub
 				if !strings.Contains(lockContent, `"command": "docker"`) {
@@ -435,3 +453,30 @@ This is a test workflow for custom Docker MCP configuration with different scena
 		})
 	}
 }
+
+// extractGitHubSection extracts just the GitHub MCP server section from the workflow content
+func extractGitHubSection(content string) string {
+	// Find the start of the github section
+	startIdx := strings.Index(content, `"github": {`)
+	if startIdx == -1 {
+		return ""
+	}
+
+	// Find the matching closing brace
+	braceCount := 0
+	inBraces := false
+	for i := startIdx; i < len(content); i++ {
+		char := content[i]
+		if char == '{' {
+			braceCount++
+			inBraces = true
+		} else if char == '}' {
+			braceCount--
+			if inBraces && braceCount == 0 {
+				return content[startIdx : i+1]
+			}
+		}
+	}
+
+	return ""
+}
