feat: mount MCP servers as local CLIs after gateway starts#25928
feat: mount MCP servers as local CLIs after gateway starts#25928
Conversation
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/f6e50b8d-7b6d-4cef-a64b-c7b0f9f8878d Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Adds automatic mounting of MCP servers as local CLI tools in agentic workflows. This behavior is opt-in via a new `tools.mount-as-clis: true` flag (default `false`). When enabled, all user-facing MCP servers are exposed as standalone shell commands and excluded from the agent's final MCP config so the agent uses the CLI wrappers exclusively. Reconstructs the feature from PR #24503. Agent-Logs-Url: https://github.com/github/gh-aw/sessions/f6e50b8d-7b6d-4cef-a64b-c7b0f9f8878d Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
|
@copilot ignore the github MCP server, it is handled differently. |
The github MCP server is handled differently and should not be mounted as a CLI tool. Added it to the exclusion lists in both Go and JavaScript code, updated prompt template examples, and restored smoke test instructions to use github as a normal MCP tool. Agent-Logs-Url: https://github.com/github/gh-aw/sessions/35a490ef-753b-4f4e-8ab3-0d10a2d44b21 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Excluded the Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
@copilot enable flag for smoke-copilot |
|
@copilot always enabled for safeoutputs, mcpscripts. Update the built prompt generator to reflect this change too. |
The |
Removed safeoutputs, mcp-scripts, and mcpscripts from the internalMCPServerNames exclusion list in both Go and JavaScript. Added explicit logic to always include safeoutputs and mcpscripts in getMCPCLIServerNames() when they are enabled. Updated the prompt template with safeoutputs/mcpscripts examples and updated smoke-copilot test instructions accordingly. Agent-Logs-Url: https://github.com/github/gh-aw/sessions/20bf245a-f76f-48bb-9b17-8597b84ee941 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Done in Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
✅ All tools validated successfully! Agent Container Smoke Test confirms agent container is ready. |
|
|
|
✨ The prophecy is fulfilled... Smoke Codex has completed its mystical journey. The stars align. 🌟 |
|
📰 BREAKING: Smoke Copilot is now investigating this pull request. Sources say the story is developing... |
|
🎬 THE END — Smoke Claude MISSION: ACCOMPLISHED! The hero saves the day! ✨ |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
@copilot guard the entire feature with a feature-flag (MCP-CLI) so that without the feature-flag, code generation remains unchanged. |
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/215f7f0c-ba81-4e1c-b4df-0c37f50916b4 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/215f7f0c-ba81-4e1c-b4df-0c37f50916b4 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Done in Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
| export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.2.19' | ||
|
|
||
| cat << GH_AW_MCP_CONFIG_459cdec802576905_EOF | bash "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh" | ||
| cat << GH_AW_MCP_CONFIG_459cdec802576905_EOF | node "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" |
There was a problem hiding this comment.
@copilot add code to resolve node binary location and inline it here
There was a problem hiding this comment.
Done in 532cacc. Added GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node) before the gateway pipe, and the heredoc now uses "$GH_AW_NODE" instead of bare node. Updated test expectations and golden files.
… of workflows Agent-Logs-Url: https://github.com/github/gh-aw/sessions/dbb3ff1b-b380-40ce-88bd-9fd174e7118e Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Done in Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
@copilot merge main and recompile |
…eature-24503 # Conflicts: # .github/workflows/api-consumption-report.lock.yml # .github/workflows/audit-workflows.lock.yml # .github/workflows/copilot-pr-nlp-analysis.lock.yml # .github/workflows/copilot-token-audit.lock.yml # .github/workflows/daily-code-metrics.lock.yml # .github/workflows/daily-firewall-report.lock.yml # .github/workflows/daily-integrity-analysis.lock.yml # .github/workflows/daily-issues-report.lock.yml # .github/workflows/daily-performance-summary.lock.yml # .github/workflows/github-mcp-structural-analysis.lock.yml # .github/workflows/org-health-report.lock.yml # .github/workflows/portfolio-analyst.lock.yml # .github/workflows/prompt-clustering-analysis.lock.yml # .github/workflows/release.lock.yml # .github/workflows/stale-repo-identifier.lock.yml # .github/workflows/super-linter.lock.yml Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
…recompile all 191 lock files Agent-Logs-Url: https://github.com/github/gh-aw/sessions/0dce577d-d975-466a-8535-7898264c40ff Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Merged main, resolved 16 lock file conflicts (api-consumption-report, audit-workflows, copilot-pr-nlp-analysis, copilot-token-audit, daily-code-metrics, daily-firewall-report, daily-integrity-analysis, daily-issues-report, daily-performance-summary, github-mcp-structural-analysis, org-health-report, portfolio-analyst, prompt-clustering-analysis, release, stale-repo-identifier, super-linter), fixed Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
@copilot merge main and recompile |
…eature-24503 # Conflicts: # .github/workflows/agentic-observability-kit.lock.yml # .github/workflows/api-consumption-report.lock.yml # .github/workflows/artifacts-summary.lock.yml # .github/workflows/audit-workflows.lock.yml # .github/workflows/breaking-change-checker.lock.yml # .github/workflows/code-simplifier.lock.yml # .github/workflows/constraint-solving-potd.lock.yml # .github/workflows/copilot-cli-deep-research.lock.yml # .github/workflows/copilot-pr-nlp-analysis.lock.yml # .github/workflows/copilot-pr-prompt-analysis.lock.yml # .github/workflows/copilot-session-insights.lock.yml # .github/workflows/copilot-token-audit.lock.yml # .github/workflows/copilot-token-optimizer.lock.yml # .github/workflows/daily-assign-issue-to-user.lock.yml # .github/workflows/daily-cli-tools-tester.lock.yml # .github/workflows/daily-code-metrics.lock.yml # .github/workflows/daily-compiler-quality.lock.yml # .github/workflows/daily-firewall-report.lock.yml # .github/workflows/daily-integrity-analysis.lock.yml # .github/workflows/daily-issues-report.lock.yml # .github/workflows/daily-performance-summary.lock.yml # .github/workflows/daily-repo-chronicle.lock.yml # .github/workflows/daily-workflow-updater.lock.yml # .github/workflows/delight.lock.yml # .github/workflows/docs-noob-tester.lock.yml # .github/workflows/github-mcp-structural-analysis.lock.yml # .github/workflows/gpclean.lock.yml # .github/workflows/issue-triage-agent.lock.yml # .github/workflows/org-health-report.lock.yml # .github/workflows/pdf-summary.lock.yml # .github/workflows/portfolio-analyst.lock.yml # .github/workflows/prompt-clustering-analysis.lock.yml # .github/workflows/refactoring-cadence.lock.yml # .github/workflows/repo-audit-analyzer.lock.yml # .github/workflows/research.lock.yml # .github/workflows/security-review.lock.yml # .github/workflows/slide-deck-maintainer.lock.yml # .github/workflows/smoke-copilot-arm.lock.yml # .github/workflows/smoke-copilot.lock.yml # .github/workflows/smoke-multi-pr.lock.yml # .github/workflows/smoke-temporary-id.lock.yml # .github/workflows/smoke-workflow-call-with-inputs.lock.yml # .github/workflows/spec-extractor.lock.yml # .github/workflows/super-linter.lock.yml # .github/workflows/test-quality-sentinel.lock.yml # .github/workflows/unbloat-docs.lock.yml # .github/workflows/update-astro.lock.yml # .github/workflows/weekly-editors-health-check.lock.yml # .github/workflows/weekly-issue-summary.lock.yml # .github/workflows/workflow-generator.lock.yml # .github/workflows/workflow-skill-extractor.lock.yml Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Merged main, resolved 51 lock file conflicts, and recompiled all 191 lock files in
Merged main, resolved 51 lock file conflicts, and recompiled all 191 lock files in Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
📰 BREAKING: Smoke Copilot is now investigating this pull request. Sources say the story is developing... |
|
✅ All tools validated successfully! Agent Container Smoke Test confirms agent container is ready. |
|
🎬 THE END — Smoke Claude MISSION: ACCOMPLISHED! The hero saves the day! ✨ |
|
|
|
🌑 The shadows whisper... Smoke Codex failed. The oracle requires further meditation... |
Agent Container Tool Check
Result: 12/12 tools available ✅ Overall Status: PASS
|
There was a problem hiding this comment.
💥 Automated smoke test review - all systems nominal!
💥 [THE END] — Illustrated by Smoke Claude · ● 144.3K
| "gh-aw": patch | ||
| --- | ||
|
|
||
| Added opt-in MCP CLI mounting via `tools.mount-as-clis: true`, which exposes eligible MCP servers as local CLI wrappers on `PATH` and updates prompt/config wiring so agents use those wrappers. The `github` MCP server remains a normal MCP tool, while `safeoutputs` and `mcpscripts` are included in CLI mounting when enabled. |
There was a problem hiding this comment.
✅ Smoke test review comment #1 — The changeset description is clear and concise, good work documenting the opt-in MCP CLI mounting feature.
| issue_number: prNumber, | ||
| body: `👋 Hey @${actor}! Here's your ACE editor session link for this pull request:\n\n🔗 **${aceUrl}**\n\nCopy and paste this link into Slack to invite your teammates into the session! 🚀`, | ||
| }); | ||
| features: |
There was a problem hiding this comment.
✅ Smoke test review comment #2 — The mcp-cli: true feature flag is correctly placed in the frontmatter features section.
|
Smoke Test: Copilot - 24484587552 — PR #25928
Overall: ✅ PASS cc
|
There was a problem hiding this comment.
🤖 Smoke Test Review — PR #25928 adds MCP CLI mounting (mount-as-clis: true). Confirmed: safeoutputs and mcpscripts are accessible as CLI commands in this smoke run. Changeset doc is clear. The ace-editor.md feature flag addition looks correct. No blocking issues found.
📰 BREAKING: Report filed by Smoke Copilot · ● 1.2M
| "gh-aw": patch | ||
| --- | ||
|
|
||
| Added opt-in MCP CLI mounting via `tools.mount-as-clis: true`, which exposes eligible MCP servers as local CLI wrappers on `PATH` and updates prompt/config wiring so agents use those wrappers. The `github` MCP server remains a normal MCP tool, while `safeoutputs` and `mcpscripts` are included in CLI mounting when enabled. |
There was a problem hiding this comment.
🔍 Smoke Test: Changeset description is clear and concise. Confirming that safeoutputs and mcpscripts are now accessible as CLI commands in this smoke run via mount-as-clis: true — working as expected.
| @@ -35,6 +35,8 @@ jobs: | |||
| issue_number: prNumber, | |||
| body: `👋 Hey @${actor}! Here's your ACE editor session link for this pull request:\n\n🔗 **${aceUrl}**\n\nCopy and paste this link into Slack to invite your teammates into the session! 🚀`, | |||
| }); | |||
There was a problem hiding this comment.
🔍 Smoke Test: The features: mcp-cli: true flag added here enables MCP CLI mounting for this workflow — worth verifying that the generated CLI wrappers are functional end-to-end (tool list discovery, not just navigation).
|
📰 VERDICT: Smoke Copilot has concluded. All systems operational. This is a developing story. 🎤 |
Reconstructs the feature from #24503. Adds opt-in mounting of MCP servers as standalone CLI tools on
PATHviatools.mount-as-clis: true(defaultfalse). When enabled, user-facing MCP servers are exposed as shell commands and excluded from the agent's final MCP config, forcing the agent to use CLI wrappers exclusively. ThegithubMCP server is excluded from CLI mounting as it is handled differently and remains available as a normal MCP tool.The
safeoutputsandmcpscriptsservers are always CLI-mounted when enabled — regardless of themount-as-clissetting — and remain available as MCP tools too (dual access). The injected prompt instructs the agent to prefer the CLI wrappers over the MCP tools for these servers.The entire feature is gated behind the
mcp-clifeature flag. Withoutfeatures: mcp-cli: truein the workflow frontmatter, code generation remains completely unchanged — no MCP CLI mount step, no CLI server filtering, no prompt injection, and no PATH setup. This ensures zero impact on existing workflows. The feature is currently enabled for ~34% (65/191) of agentic workflows in this repo for gradual rollout.How it works
The gateway starts containers for all configured servers (so they're reachable), then filtering happens in two stages:
${RUNNER_TEMP}/gh-aw/mcp-cli/manifest.jsonGH_AW_MCP_CLI_SERVERSenv var in eachconvert_gateway_config_*.cjsscript — exceptsafeoutputsandmcpscripts, which stay in the agent MCP config for dual accessAfter the gateway starts,
mount_mcp_as_cli.cjsreads the manifest, queries each server'stools/listvia the full MCP session protocol (initialize→notifications/initialized→tools/list), and generates locked-down CLI wrappers under${RUNNER_TEMP}/gh-aw/mcp-cli/bin/.Note: The
githubMCP server is not CLI-mounted — it is handled differently and remains available as a normal MCP tool even whenmount-as-clis: trueis set.Changes
Feature flag guard
pkg/constants/feature_constants.go— newMCPCLIFeatureFlag FeatureFlag = "mcp-cli"constantpkg/workflow/mcp_cli_mount.go—getMCPCLIServerNames()checksconfig.HasFeatureEnabled(constants.MCPCLIFeatureFlag)and returnsnilearly when the flag is not set, which cascades to disable all downstream behavior: no mount step generation, no CLI server exclusion from agent config, no prompt section injection, and no PATH setupgenerateMCPCLIMountStep,getMCPCLIExcludeFromAgentConfig,buildMCPCLIPromptSection,GetMCPCLIPathSetup) depend ongetMCPCLIServerNames()returning a non-empty list, so the single guard point disables the entire featureGradual rollout
.mdfiles in.github/workflows/havefeatures: mcp-cli: trueadded to their frontmatter for gradual rollout testingNode binary resolution for gateway
mcp_renderer.go— gateway start command now resolves the node binary path viaGH_AW_NODE=$(which node)and uses"$GH_AW_NODE"for thestart_mcp_gateway.cjsinvocation, ensuring correct node resolution even in environments wherenodemay not be on the default PATHNew files
pkg/workflow/mcp_cli_mount.go—getMCPCLIServerNames(),getMCPCLIExcludeFromAgentConfig(),generateMCPCLIMountStep(),buildMCPCLIPromptSection(),GetMCPCLIPathSetup()actions/setup/js/mount_mcp_as_cli.cjs— manifest reader, MCP handshake, CLI wrapper generator; generates thin bash stubs thatexecinto the Node.js bridgeactions/setup/js/mcp_cli_bridge.cjs— Node.js CLI-to-MCP bridge handling full MCP session protocol (initialize→notifications/initialized→tools/call), argument parsing,--helpdisplay, response formatting, and JSONL audit logging; usesshim.cjsandcore.*for consistent GitHub Actions loggingactions/setup/md/mcp_cli_tools_prompt.md—<mcp-clis>prompt section templateactions/setup/js/convert_gateway_config_copilot.cjs— JavaScript gateway config converter for Copilot (filters CLI servers, addstools:["*"], rewrites URLs)actions/setup/js/convert_gateway_config_claude.cjs— JavaScript gateway config converter for Claude (filters CLI servers, setstype:"http", rewrites URLs)actions/setup/js/convert_gateway_config_codex.cjs— JavaScript gateway config converter for Codex (filters CLI servers, resolveshost.docker.internalto172.30.0.1, generates TOML)actions/setup/js/convert_gateway_config_gemini.cjs— JavaScript gateway config converter for Gemini (filters CLI servers, removestypefield for transport auto-detection, rewrites URLs, addscontext.includeDirectories)actions/setup/js/start_mcp_gateway.cjs— JavaScript gateway startup script (reads MCP config from stdin, launches Docker container, health check polling, engine-specific converter dispatch, CLI manifest creation, GitHub Actions outputs)CLI wrapper architecture (bash → Node.js bridge)
exec node mcp_cli_bridge.cjswith server config passed as arguments — no jq/curl/awk dependenciesmcp_cli_bridge.cjshandles all MCP protocol logic in Node.js:initialize→notifications/initialized→tools/callwith proper session ID tracking--key valueand--key=valuestyles, with--jsonflag for raw JSON output--help/-hsupport: displays available tools with parameter schemasshim.cjsandcore.*for all logging (consistent GitHub Actions annotation output)/tmp/gh-aw/mcp-cli-audit/<server>.jsonlwith timestamps, duration, request/response details, and error tracking — audit directory/file failures logged as warnings without blocking tool executionGo pipeline integration
ToolsConfig.MountAsCLIsfield + parser + schema + validationcompiler_yaml_main_job.gocallsgenerateMCPCLIMountStep()after gateway setupmcp_setup_generator.goexportsGH_AW_MCP_CLI_SERVERSJSON array to$GITHUB_ENVusinggetMCPCLIExcludeFromAgentConfig()(excludessafeoutputs/mcpscriptsso they remain as MCP tools)unified_prompt_step.goinjects CLI tools prompt section (8a, after safe outputs)mcp_rendering.godocuments why CLI servers stay in gateway configmcp_renderer.goinvokesnode start_mcp_gateway.cjs(converted frombash start_mcp_gateway.sh)getMCPCLIServerNames()always includessafeoutputsandmcpscriptswhen they are enabled (HasSafeOutputsEnabled/IsMCPScriptsEnabled), regardless ofmount-as-clissettinggetMCPCLIExcludeFromAgentConfig()returns only servers that should be removed from agent MCP config (does not includesafeoutputs/mcpscripts— they get dual access)MCP CLI bin directory on PATH inside AWF container
GetMCPCLIPathSetup()inmcp_cli_mount.goreturns theexport PATH=snippet that prepends${RUNNER_TEMP}/gh-aw/mcp-cli/binto$PATHcopilot_engine_execution.go,claude_engine.go,codex_engine.go,gemini_engine.go) inject this PATH setup into the AWF container's environment so CLI wrappers are discoverable without manualexportby the agentDual access for safeoutputs and mcpscripts
safeoutputsandmcpscriptsare always CLI-mounted when enabled, even withoutmount-as-clis: truealwaysCLIMountedServersmap in Go controls which servers get this treatmentGateway scripts (bash → JavaScript)
start_mcp_gateway.cjs— full JavaScript port of the gateway startup script usingchild_process.spawnfor Docker container management, Node.jshttpmodule for health checks, andchild_process.execSyncfor converter/checker dispatch. Maintains all security controls (umask, symlink attack prevention, 0o600 file permissions)convert_gateway_config_{copilot,claude,codex,gemini}.cjs— all four engine converters are JavaScript for CLI server filtering, URL rewriting, and engine-specific config generationvalidate_prompt_placeholders.sh— strips backtick code spans before checking for unreplaced__GH_AW_*__placeholdersConfig storage hardening (
/tmp→RUNNER_TEMP)mcp-config/) and CLI manifest (mcp-cli/) moved from/tmp/gh-aw/to${RUNNER_TEMP}/gh-aw/to prevent tampering —/tmpis world-writable,RUNNER_TEMPis per-runner and not world-accessiblestart_mcp_gateway.cjs, converter scripts,mount_mcp_as_cli.cjs,redact_secrets.cjs) and Go engine code (claude_engine.go,codex_engine.go,codex_mcp.go,claude_mcp.go,gemini_mcp.go,mcp_setup_generator.go,threat_detection.go,step_order_validation.go)/tmp/gh-aw/mcp-logs/since the Docker gateway container writes there via-v /tmp:/tmp:rwSecurity hardening (shell injection, input validation)
shellEscapeDoubleQuoted()inmount_mcp_as_cli.cjs— escapes$ `` \ " !and strips\r\nfor all values embedded in generated CLI wrapper bash scripts (server name, URL, tools file path, API key), preventing shell injection and line injection attacksisValidServerName()inmount_mcp_as_cli.cjs— validates server names against[a-zA-Z0-9_-]with 64-char max length, preventing path traversal and shell metacharacter injection via malicious server names; servers failing validation are skipped with a warningnew URL()before processinggatewayPortverified to be strictly numeric before interpolation intoexecSyncshell commands instart_mcp_gateway.cjscheck_mcp_servers.shcall uses$MCP_GATEWAY_API_KEYenv var reference instead of direct JS string interpolation to avoid shell metacharacter risksstart_mcp_gateway.cjsfilters invalid server names when generating the CLI manifestObservability improvements
core.*logging viashim.cjs(core.info,core.error,core.warning) instead ofconsole.*, ensuring consistent GitHub Actions annotation outputstart_mcp_gateway.cjslogs startup banner (engine, port, domain, runner temp), server names in CLI manifest; top-level error handler preserves stack traces viacore.error(err.stack)beforecore.setFailed()mount_mcp_as_cli.cjslogs manifest server count after internal filtering, skipped servers with validation error reasonsmcp_cli_bridge.cjslogs every tool invocation with timing, arguments, and response status; appends JSONL audit entries to/tmp/gh-aw/mcp-cli-audit/<server>.jsonlfor post-run analysisServer exclusions
githubMCP server is excluded from CLI mounting in both Go (internalMCPServerNames) and JavaScript (INTERNAL_SERVERS) — it is handled differently and remains a normal MCP toolsafeoutputsandmcpscriptsare always CLI-mounted when enabled (dual access with MCP), with usage examples and preference guidance in the prompt templateSmoke test
smoke-copilot.mdenables bothfeatures: mcp-cli: trueandmount-as-clis: true, and updates test instructions to use CLI syntax for playwright/serena/safeoutputs/mcpscripts while keeping github as a normal MCP tool✨ PR Review Safe Output Test - Run 24484587539