Remove mcp_config input in favor of --mcp-config in claude_args (#485)

* Remove mcp_config input in favor of --mcp-config in claude_args

BREAKING CHANGE: The mcp_config input has been removed. Users should now use --mcp-config flag in claude_args instead.

This simplifies the action's input surface area and aligns better with the Claude Code CLI interface. Users can still add multiple MCP configurations by using multiple --mcp-config flags.

Migration:
- Before: mcp_config: '{"mcpServers": {...}}'
- After: claude_args: '--mcp-config {"mcpServers": {...}}'

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Add outer action MCP tests to workflow

- Add test-outer-action-inline-mcp job to test inline MCP config via claude_args
- Add test-outer-action-file-mcp job to test file-based MCP config via claude_args
- Keep base-action tests unchanged (they still use mcp_config parameter)
- Test that MCP tools are properly discovered and can be executed through the outer action

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix: Add Bun setup to outer action MCP test jobs

The test jobs for the outer action were failing because Bun wasn't installed.
Added Setup Bun step to both test-outer-action-inline-mcp and test-outer-action-file-mcp jobs.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Add id-token permission to outer action MCP test jobs

The outer action needs id-token: write permission for OIDC authentication
when using the GitHub App. Added full permissions block to both
test-outer-action-inline-mcp and test-outer-action-file-mcp jobs.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Use github_token parameter instead of id-token permission

Replace id-token: write permission with explicit github_token parameter
for both outer action MCP test jobs. This simplifies authentication by
using the provided GitHub token directly.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Use RUNNER_TEMP environment variable consistently

Changed from GitHub Actions expression syntax to environment variable
for consistency with the rest of the workflow file.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Use execution_file output from action instead of hardcoded path

Updated outer action test jobs to:
- Add step IDs (claude-inline-test, claude-file-test)
- Use the execution_file output from the action steps
- This is more reliable than hardcoding the output file path

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* tmp

* Fix MCP test assertions to match actual output format

Updated the test assertions to match the actual JSON structure:
- Tool calls are in assistant messages with type='tool_use'
- Tool results are in user messages with type='tool_result'
- The test tool returns 'Test tool response' not 'Hello from test tool'

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Make inline MCP test actually use the tool instead of just listing

Changed the inline MCP test to:
- Request that Claude uses the test tool (not just list it)
- Add --allowedTools to ensure the tool can be used
- Check that the tool was actually called and returned expected result
- Output the full JSON for debugging

This makes both tests (inline and file-based) consistent in their approach.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Ashwin Bhat
2025-08-26 09:43:18 -07:00
committed by GitHub
parent ada5bc42eb
commit e6f32c8321
9 changed files with 249 additions and 75 deletions

View File

@@ -101,7 +101,8 @@ jobs:
with: with:
prompt_file: /tmp/claude-prompts/triage-prompt.txt prompt_file: /tmp/claude-prompts/triage-prompt.txt
allowed_tools: "Bash(gh label list),mcp__github__get_issue,mcp__github__get_issue_comments,mcp__github__update_issue,mcp__github__search_issues,mcp__github__list_issues" allowed_tools: "Bash(gh label list),mcp__github__get_issue,mcp__github__get_issue_comments,mcp__github__update_issue,mcp__github__search_issues,mcp__github__list_issues"
mcp_config: /tmp/mcp-config/mcp-servers.json claude_args: |
--mcp-config /tmp/mcp-config/mcp-servers.json
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
env: env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -158,3 +158,134 @@ jobs:
fi fi
echo "✓ All MCP server checks passed with --mcp-config flag!" echo "✓ All MCP server checks passed with --mcp-config flag!"
# Test the outer action with inline MCP config
test-outer-action-inline-mcp:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4
- name: Setup Bun
uses: oven-sh/setup-bun@735343b667d3e6f658f44d0eca948eb6282f2b76 #v2
- name: Install test MCP server dependencies
run: |
cd base-action/test/mcp-test
bun install
- name: Test outer action with inline MCP config
uses: ./
id: claude-inline-test
with:
prompt: "Use the mcp__test-server__test_tool to test the MCP integration"
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
github_token: ${{ secrets.GITHUB_TOKEN }}
claude_args: |
--mcp-config '{"mcpServers":{"test-server":{"type":"stdio","command":"bun","args":["base-action/test/mcp-test/simple-mcp-server.ts"],"env":{}}}}'
--allowedTools mcp__test-server__test_tool
- name: Check execution output
run: |
echo "Checking if MCP test tool was used..."
OUTPUT_FILE="${{ steps.claude-inline-test.outputs.execution_file }}"
if [ ! -f "$OUTPUT_FILE" ]; then
echo "Error: Output file not found!"
exit 1
fi
cat $OUTPUT_FILE
# Check if the tool was actually called - looking in assistant messages
if jq -e '.[] | select(.type == "assistant" and .message.content) | .message.content[] | select(.type == "tool_use" and .name == "mcp__test-server__test_tool")' "$OUTPUT_FILE" > /dev/null; then
echo "✓ MCP test tool was called"
# Check the tool result - looking for the user message with tool_result
if jq -e '.[] | select(.type == "user" and .message.content[0].type == "tool_result") | .message.content[0].content[0].text | contains("Test tool response")' "$OUTPUT_FILE" > /dev/null; then
echo "✓ MCP test tool returned expected result"
else
echo "✗ MCP test tool result not as expected"
echo "Tool results in output:"
jq '.[] | select(.type == "user") | .message.content[]? | select(.type == "tool_result")' "$OUTPUT_FILE"
exit 1
fi
else
echo "✗ MCP test tool was not called"
echo "Tools used:"
jq '.[] | select(.type == "assistant" and .message.content) | .message.content[] | select(.type == "tool_use") | .name' "$OUTPUT_FILE"
exit 1
fi
# Test the outer action with file-based MCP config
test-outer-action-file-mcp:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4
- name: Setup Bun
uses: oven-sh/setup-bun@735343b667d3e6f658f44d0eca948eb6282f2b76 #v2
- name: Install test MCP server dependencies
run: |
cd base-action/test/mcp-test
bun install
- name: Create MCP config file
run: |
cat > /tmp/test-mcp-config.json << 'EOF'
{
"mcpServers": {
"test-server": {
"type": "stdio",
"command": "bun",
"args": ["base-action/test/mcp-test/simple-mcp-server.ts"],
"env": {}
}
}
}
EOF
- name: Test outer action with file-based MCP config
uses: ./
id: claude-file-test
with:
prompt: "Use the mcp__test-server__test_tool to test the MCP integration"
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
github_token: ${{ secrets.GITHUB_TOKEN }}
claude_args: |
--mcp-config /tmp/test-mcp-config.json
--allowedTools mcp__test-server__test_tool
- name: Check tool usage
run: |
echo "Checking if MCP test tool was used..."
OUTPUT_FILE="${{ steps.claude-file-test.outputs.execution_file }}"
if [ ! -f "$OUTPUT_FILE" ]; then
echo "Error: Output file not found!"
exit 1
fi
cat $OUTPUT_FILE
# Check if the tool was actually called - looking in assistant messages
if jq -e '.[] | select(.type == "assistant" and .message.content) | .message.content[] | select(.type == "tool_use" and .name == "mcp__test-server__test_tool")' "$OUTPUT_FILE" > /dev/null; then
echo "✓ MCP test tool was called"
# Check the tool result - looking for the user message with tool_result
if jq -e '.[] | select(.type == "user" and .message.content[0].type == "tool_result") | .message.content[0].content[0].text | contains("Test tool response")' "$OUTPUT_FILE" > /dev/null; then
echo "✓ MCP test tool returned expected result"
else
echo "✗ MCP test tool result not as expected"
echo "Tool results in output:"
jq '.[] | select(.type == "user") | .message.content[]? | select(.type == "tool_result")' "$OUTPUT_FILE"
exit 1
fi
else
echo "✗ MCP test tool was not called"
echo "Tools used:"
jq '.[] | select(.type == "tool") | .name' "$OUTPUT_FILE"
exit 1
fi

View File

@@ -61,10 +61,6 @@ inputs:
description: "Additional arguments to pass directly to Claude CLI" description: "Additional arguments to pass directly to Claude CLI"
required: false required: false
default: "" default: ""
mcp_config:
description: "Additional MCP configuration (JSON string) that merges with built-in GitHub MCP servers"
required: false
default: ""
additional_permissions: additional_permissions:
description: "Additional GitHub permissions to request (e.g., 'actions: read')" description: "Additional GitHub permissions to request (e.g., 'actions: read')"
required: false required: false
@@ -146,7 +142,6 @@ runs:
USE_COMMIT_SIGNING: ${{ inputs.use_commit_signing }} USE_COMMIT_SIGNING: ${{ inputs.use_commit_signing }}
ADDITIONAL_PERMISSIONS: ${{ inputs.additional_permissions }} ADDITIONAL_PERMISSIONS: ${{ inputs.additional_permissions }}
CLAUDE_ARGS: ${{ inputs.claude_args }} CLAUDE_ARGS: ${{ inputs.claude_args }}
MCP_CONFIG: ${{ inputs.mcp_config }}
ALL_INPUTS: ${{ toJson(inputs) }} ALL_INPUTS: ${{ toJson(inputs) }}
- name: Install Base Action Dependencies - name: Install Base Action Dependencies

View File

@@ -103,5 +103,6 @@ jobs:
with: with:
prompt_file: /tmp/claude-prompts/triage-prompt.txt prompt_file: /tmp/claude-prompts/triage-prompt.txt
allowed_tools: "Bash(gh label list),mcp__github__get_issue,mcp__github__get_issue_comments,mcp__github__update_issue,mcp__github__search_issues,mcp__github__list_issues" allowed_tools: "Bash(gh label list),mcp__github__get_issue,mcp__github__get_issue_comments,mcp__github__update_issue,mcp__github__search_issues,mcp__github__list_issues"
mcp_config: /tmp/mcp-config/mcp-servers.json claude_args: |
--mcp-config /tmp/mcp-config/mcp-servers.json
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}

View File

@@ -2,39 +2,28 @@
## Using Custom MCP Configuration ## Using Custom MCP Configuration
The `mcp_config` input allows you to add custom MCP (Model Context Protocol) servers to extend Claude's capabilities. These servers merge with the built-in GitHub MCP servers. You can add custom MCP (Model Context Protocol) servers to extend Claude's capabilities using the `--mcp-config` flag in `claude_args`. These servers merge with the built-in GitHub MCP servers.
### Basic Example: Adding a Sequential Thinking Server ### Basic Example: Adding a Sequential Thinking Server
```yaml ```yaml
- uses: anthropics/claude-code-action@beta - uses: anthropics/claude-code-action@v1
with: with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
mcp_config: | claude_args: |
{ --mcp-config '{"mcpServers": {"sequential-thinking": {"command": "npx", "args": ["-y", "@modelcontextprotocol/server-sequential-thinking"]}}}'
"mcpServers": { --allowedTools mcp__sequential-thinking__sequentialthinking
"sequential-thinking": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-sequential-thinking"
]
}
}
}
allowed_tools: "mcp__sequential-thinking__sequentialthinking" # Important: Each MCP tool from your server must be listed here, comma-separated
# ... other inputs # ... other inputs
``` ```
### Passing Secrets to MCP Servers ### Passing Secrets to MCP Servers
For MCP servers that require sensitive information like API keys or tokens, use GitHub Secrets in the environment variables: For MCP servers that require sensitive information like API keys or tokens, you can create a configuration file with GitHub Secrets:
```yaml ```yaml
- uses: anthropics/claude-code-action@beta - name: Create MCP Config
with: run: |
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} cat > /tmp/mcp-config.json << 'EOF'
mcp_config: |
{ {
"mcpServers": { "mcpServers": {
"custom-api-server": { "custom-api-server": {
@@ -47,6 +36,13 @@ For MCP servers that require sensitive information like API keys or tokens, use
} }
} }
} }
EOF
- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
claude_args: |
--mcp-config /tmp/mcp-config.json
# ... other inputs # ... other inputs
``` ```
@@ -55,10 +51,9 @@ For MCP servers that require sensitive information like API keys or tokens, use
For Python-based MCP servers managed with `uv`, you need to specify the directory containing your server: For Python-based MCP servers managed with `uv`, you need to specify the directory containing your server:
```yaml ```yaml
- uses: anthropics/claude-code-action@beta - name: Create MCP Config for Python Server
with: run: |
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} cat > /tmp/mcp-config.json << 'EOF'
mcp_config: |
{ {
"mcpServers": { "mcpServers": {
"my-python-server": { "my-python-server": {
@@ -73,7 +68,14 @@ For Python-based MCP servers managed with `uv`, you need to specify the director
} }
} }
} }
allowed_tools: "my-python-server__<tool_name>" # Replace <tool_name> with your server's tool names EOF
- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
claude_args: |
--mcp-config /tmp/mcp-config.json
--allowedTools my-python-server__<tool_name> # Replace <tool_name> with your server's tool names
# ... other inputs # ... other inputs
``` ```
@@ -84,10 +86,26 @@ For example, if your Python MCP server is at `mcp_servers/weather.py`, you would
["--directory", "${{ github.workspace }}/mcp_servers/", "run", "weather.py"] ["--directory", "${{ github.workspace }}/mcp_servers/", "run", "weather.py"]
``` ```
### Multiple MCP Servers
You can add multiple MCP servers by using multiple `--mcp-config` flags:
```yaml
- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
claude_args: |
--mcp-config /tmp/config1.json
--mcp-config /tmp/config2.json
--mcp-config '{"mcpServers": {"inline-server": {"command": "npx", "args": ["@example/server"]}}}'
# ... other inputs
```
**Important**: **Important**:
- Always use GitHub Secrets (`${{ secrets.SECRET_NAME }}`) for sensitive values like API keys, tokens, or passwords. Never hardcode secrets directly in the workflow file. - Always use GitHub Secrets (`${{ secrets.SECRET_NAME }}`) for sensitive values like API keys, tokens, or passwords. Never hardcode secrets directly in the workflow file.
- Your custom servers will override any built-in servers with the same name. - Your custom servers will override any built-in servers with the same name.
- The `claude_args` supports multiple `--mcp-config` flags that will be merged together.
## Additional Permissions for CI/CD Integration ## Additional Permissions for CI/CD Integration
@@ -322,5 +340,6 @@ Many individual input parameters have been consolidated into `claude_args` or `s
| `model` | Use `claude_args: "--model claude-4-0-sonnet-20250805"` | | `model` | Use `claude_args: "--model claude-4-0-sonnet-20250805"` |
| `claude_env` | Use `settings` with `"env"` object | | `claude_env` | Use `settings` with `"env"` object |
| `custom_instructions` | Use `claude_args: "--system-prompt 'Your instructions'"` | | `custom_instructions` | Use `claude_args: "--system-prompt 'Your instructions'"` |
| `mcp_config` | Use `claude_args: "--mcp-config '{...}'"` |
| `direct_prompt` | Use `prompt` input instead | | `direct_prompt` | Use `prompt` input instead |
| `override_prompt` | Use `prompt` with GitHub context variables | | `override_prompt` | Use `prompt` with GitHub context variables |

View File

@@ -25,6 +25,7 @@ The following inputs have been deprecated and replaced:
| `allowed_tools` | `claude_args: --allowedTools` | Use CLI format | | `allowed_tools` | `claude_args: --allowedTools` | Use CLI format |
| `disallowed_tools` | `claude_args: --disallowedTools` | Use CLI format | | `disallowed_tools` | `claude_args: --disallowedTools` | Use CLI format |
| `claude_env` | `settings` with env object | Use settings JSON | | `claude_env` | `settings` with env object | Use settings JSON |
| `mcp_config` | `claude_args: --mcp-config` | Pass MCP config via CLI arguments |
## Migration Examples ## Migration Examples
@@ -156,17 +157,19 @@ claude_args: |
--allowedTools Edit,Read,Write,Bash --allowedTools Edit,Read,Write,Bash
--disallowedTools WebSearch --disallowedTools WebSearch
--system-prompt "You are a senior engineer focused on code quality" --system-prompt "You are a senior engineer focused on code quality"
--mcp-config '{"mcpServers": {"custom": {"command": "npx", "args": ["-y", "@example/server"]}}}'
``` ```
### Common claude_args Options ### Common claude_args Options
| Option | Description | Example | | Option | Description | Example |
| ------------------- | ------------------------ | ------------------------------------- | | ------------------- | ------------------------ | -------------------------------------- |
| `--max-turns` | Limit conversation turns | `--max-turns 10` | | `--max-turns` | Limit conversation turns | `--max-turns 10` |
| `--model` | Specify Claude model | `--model claude-4-0-sonnet-20250805` | | `--model` | Specify Claude model | `--model claude-4-0-sonnet-20250805` |
| `--allowedTools` | Enable specific tools | `--allowedTools Edit,Read,Write` | | `--allowedTools` | Enable specific tools | `--allowedTools Edit,Read,Write` |
| `--disallowedTools` | Disable specific tools | `--disallowedTools WebSearch` | | `--disallowedTools` | Disable specific tools | `--disallowedTools WebSearch` |
| `--system-prompt` | Add system instructions | `--system-prompt "Focus on security"` | | `--system-prompt` | Add system instructions | `--system-prompt "Focus on security"` |
| `--mcp-config` | Add MCP server config | `--mcp-config '{"mcpServers": {...}}'` |
## Provider-Specific Updates ## Provider-Specific Updates
@@ -190,6 +193,44 @@ claude_args: |
--model claude-4-0-sonnet@20250805 --model claude-4-0-sonnet@20250805
``` ```
## MCP Configuration Migration
### Adding Custom MCP Servers
**Before (v0.x):**
```yaml
- uses: anthropics/claude-code-action@beta
with:
mcp_config: |
{
"mcpServers": {
"custom-server": {
"command": "npx",
"args": ["-y", "@example/server"]
}
}
}
```
**After (v1.0):**
```yaml
- uses: anthropics/claude-code-action@v1
with:
claude_args: |
--mcp-config '{"mcpServers": {"custom-server": {"command": "npx", "args": ["-y", "@example/server"]}}}'
```
You can also pass MCP configuration from a file:
```yaml
- uses: anthropics/claude-code-action@v1
with:
claude_args: |
--mcp-config /path/to/mcp-config.json
```
## Step-by-Step Migration Checklist ## Step-by-Step Migration Checklist
- [ ] Update action version from `@beta` to `@v1` - [ ] Update action version from `@beta` to `@v1`
@@ -202,6 +243,7 @@ claude_args: |
- [ ] Convert `allowed_tools` to `claude_args` with `--allowedTools` - [ ] Convert `allowed_tools` to `claude_args` with `--allowedTools`
- [ ] Convert `disallowed_tools` to `claude_args` with `--disallowedTools` - [ ] Convert `disallowed_tools` to `claude_args` with `--disallowedTools`
- [ ] Move `claude_env` to `settings` JSON format - [ ] Move `claude_env` to `settings` JSON format
- [ ] Move `mcp_config` to `claude_args` with `--mcp-config`
- [ ] Test workflow in a non-production environment - [ ] Test workflow in a non-production environment
## Getting Help ## Getting Help

View File

@@ -17,7 +17,6 @@ export function collectActionInputsPresence(): void {
custom_instructions: "", custom_instructions: "",
direct_prompt: "", direct_prompt: "",
override_prompt: "", override_prompt: "",
mcp_config: "",
additional_permissions: "", additional_permissions: "",
claude_env: "", claude_env: "",
settings: "", settings: "",

View File

@@ -119,13 +119,6 @@ export const agentMode: Mode = {
claudeArgs = `--mcp-config '${escapedOurConfig}'`; claudeArgs = `--mcp-config '${escapedOurConfig}'`;
} }
// Add user's MCP_CONFIG env var as separate --mcp-config
const userMcpConfig = process.env.MCP_CONFIG;
if (userMcpConfig?.trim()) {
const escapedUserConfig = userMcpConfig.replace(/'/g, "'\\''");
claudeArgs = `${claudeArgs} --mcp-config '${escapedUserConfig}'`.trim();
}
// Append user's claude_args (which may have more --mcp-config flags) // Append user's claude_args (which may have more --mcp-config flags)
claudeArgs = `${claudeArgs} ${userClaudeArgs}`.trim(); claudeArgs = `${claudeArgs} ${userClaudeArgs}`.trim();

View File

@@ -155,13 +155,6 @@ export const tagMode: Mode = {
const escapedOurConfig = ourMcpConfig.replace(/'/g, "'\\''"); const escapedOurConfig = ourMcpConfig.replace(/'/g, "'\\''");
claudeArgs = `--mcp-config '${escapedOurConfig}'`; claudeArgs = `--mcp-config '${escapedOurConfig}'`;
// Add user's MCP_CONFIG env var as separate --mcp-config
const userMcpConfig = process.env.MCP_CONFIG;
if (userMcpConfig?.trim()) {
const escapedUserConfig = userMcpConfig.replace(/'/g, "'\\''");
claudeArgs = `${claudeArgs} --mcp-config '${escapedUserConfig}'`;
}
// Add required tools for tag mode // Add required tools for tag mode
claudeArgs += ` --allowedTools "${tagModeTools.join(",")}"`; claudeArgs += ` --allowedTools "${tagModeTools.join(",")}"`;