diff --git a/actions/setup/js/mount_mcp_as_cli.cjs b/actions/setup/js/mount_mcp_as_cli.cjs index 81702623441..ffaeba68818 100644 --- a/actions/setup/js/mount_mcp_as_cli.cjs +++ b/actions/setup/js/mount_mcp_as_cli.cjs @@ -311,6 +311,16 @@ exec node "${safeBridge}" \\ `; } +/** + * Format mounted server names into prompt-ready bullet lines. + * + * @param {string[]} mountedServers - Successfully mounted server names + * @returns {string} + */ +function formatMountedServersPromptList(mountedServers) { + return mountedServers.map(name => `- \`${name}\` — run \`${name} --help\` to see available tools`).join("\n"); +} + /** * Mount MCP servers as CLI tools by reading the manifest and generating wrapper scripts. * @@ -445,6 +455,7 @@ async function main() { } core.info(`CLI bin directory added to PATH: ${CLI_BIN_DIR}`); core.setOutput("mounted-servers", mountedServers.join(",")); + core.setOutput("mounted-servers-list", formatMountedServersPromptList(mountedServers)); } -module.exports = { main, fetchMCPTools, generateCLIWrapperScript, isValidServerName, shellEscapeDoubleQuoted, parseMCPResponseBody }; +module.exports = { main, fetchMCPTools, generateCLIWrapperScript, isValidServerName, shellEscapeDoubleQuoted, parseMCPResponseBody, formatMountedServersPromptList }; diff --git a/actions/setup/js/mount_mcp_as_cli.test.cjs b/actions/setup/js/mount_mcp_as_cli.test.cjs index cd86c1f53be..233858cce08 100644 --- a/actions/setup/js/mount_mcp_as_cli.test.cjs +++ b/actions/setup/js/mount_mcp_as_cli.test.cjs @@ -1,7 +1,7 @@ // @ts-check import { describe, expect, it } from "vitest"; -import { parseMCPResponseBody } from "./mount_mcp_as_cli.cjs"; +import { formatMountedServersPromptList, parseMCPResponseBody } from "./mount_mcp_as_cli.cjs"; describe("mount_mcp_as_cli.cjs", () => { it("parses JSON object responses unchanged", () => { @@ -38,4 +38,9 @@ describe("mount_mcp_as_cli.cjs", () => { }, }); }); + + it("formats mounted servers for prompt rendering", () => { + expect(formatMountedServersPromptList(["safeoutputs", "playwright"])).toBe("- `safeoutputs` — run `safeoutputs --help` to see available tools\n- `playwright` — run `playwright --help` to see available tools"); + expect(formatMountedServersPromptList([])).toBe(""); + }); }); diff --git a/pkg/workflow/mcp_cli_mount.go b/pkg/workflow/mcp_cli_mount.go index 92008009f34..260bed34349 100644 --- a/pkg/workflow/mcp_cli_mount.go +++ b/pkg/workflow/mcp_cli_mount.go @@ -297,28 +297,22 @@ func GetMCPCLIPathSetup(data *WorkflowData) string { return `export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH"` } -// buildMCPCLIPromptSection returns a PromptSection describing the CLI tools available -// to the agent, or nil if there are no servers to mount. -// The prompt is loaded from actions/setup/md/mcp_cli_tools_prompt.md at runtime, -// with the __GH_AW_MCP_CLI_SERVERS_LIST__ placeholder substituted by the substitution step. +// buildMCPCLIPromptSection returns a PromptSection describing CLI wrappers available +// to the agent, or nil if no servers are configured for mounting. +// The prompt content is loaded from actions/setup/md/mcp_cli_tools_prompt.md at runtime. +// The server list comes from the mount step output so only successfully mounted wrappers +// are advertised to the model. func buildMCPCLIPromptSection(data *WorkflowData) *PromptSection { servers := getMCPCLIServerNames(data) if len(servers) == 0 { return nil } - // Build the human-readable list of servers with example usage - var listLines []string - for _, name := range servers { - listLines = append(listLines, fmt.Sprintf("- `%s` — run `%s --help` to see available tools", name, name)) - } - serversList := strings.Join(listLines, "\n") - return &PromptSection{ Content: mcpCLIToolsPromptFile, IsFile: true, EnvVars: map[string]string{ - "GH_AW_MCP_CLI_SERVERS_LIST": serversList, + "GH_AW_MCP_CLI_SERVERS_LIST": "${{ steps.mount-mcp-clis.outputs.mounted-servers-list }}", }, } } diff --git a/pkg/workflow/mcp_cli_mount_test.go b/pkg/workflow/mcp_cli_mount_test.go index 205cfa178b5..207ca774742 100644 --- a/pkg/workflow/mcp_cli_mount_test.go +++ b/pkg/workflow/mcp_cli_mount_test.go @@ -226,4 +226,5 @@ func TestBuildMCPCLIPromptSection_PromptFileUsesNonHeadingLabels(t *testing.T) { assert.NotRegexp(t, `(?m)^\s*(>\s*)?##\s+`, prompt, "prompt must not contain H2 Markdown headings") assert.NotRegexp(t, `(?m)^\s*(>\s*)?###\s+`, prompt, "prompt must not contain H3 Markdown headings") assert.Contains(t, prompt, "Use ` --help` for tool names, parameters, and examples before calling any command.") + assert.Equal(t, "${{ steps.mount-mcp-clis.outputs.mounted-servers-list }}", section.EnvVars["GH_AW_MCP_CLI_SERVERS_LIST"]) }