-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Using stdio transport for custom mcp config isn't working #130
Description
Describe the bug
I've written a custom mcp server in python using fastmcp>=2.6.1 and uv as the python project manager. I've tested it multiple ways locally and everything works as intended. However, when trying to get it to work in claude-code-action, it doesn't work. The only helpful message I can find in my Github workflow output is:
"mcp_servers": [
{
"name": "current_time_test_server",
"status": "failed"
},
{
"name": "github_file_ops",
"status": "connected"
},
{
"name": "sequential-thinking",
"status": "connected"
},
{
"name": "github",
"status": "connected"
}
]
I'm using AWS Bedrock and have verified that's working correctly (with the connection to custom MCP failing). I even added a debug step and can successfully start the mcp server using uv within the runner. Is there something I'm missing or is this a bug?
To Reproduce
Steps to reproduce the behavior:
- Install Claude App in your repo
- Add mcp server python code as listed in the additional context section
- Add workflow yaml file that's listed (uses aws bedrock and a personal Github app)
- Observe that the current_time_test_server fails to connect in the Github action output.
Expected behavior
Expect claude-code-action to successfully connect to custom mcp server using stdio and be able to use the tools (get_current_time) in this case.
Screenshots
Workflow yml file
name: Claude PR Action
permissions:
contents: write
pull-requests: write
issues: write
id-token: write
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
jobs:
claude-pr:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Generate GitHub App token
id: app-token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
- name: Configure AWS Credentials (OIDC)
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_IAM_ROLE_ARN }}
aws-region: ${{ secrets.AWS_REGION }}
- name: Install uv
uses: astral-sh/setup-uv@v5
with:
version: "0.7.10"
- name: Sync uv Project
run: |
uv sync
- name: Debug
run: |
pwd
ls -la
uv run time_test_mcp.py &
- name: Claude Code Action Official
uses: anthropics/claude-code-action@beta
with:
timeout_minutes: "10"
use_bedrock: "true"
model: us.anthropic.claude-sonnet-4-20250514-v1:0
github_token: ${{ steps.app-token.outputs.token }}
mcp_config: |
{
"mcpServers": {
"current_time_test_server": {
"command": "uv",
"args": [
"run",
"time_test_mcp.py"
]
},
"sequential-thinking": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-sequential-thinking"
]
}
}
}
allowed_tools: "test_time_server___get_current_time"
API Provider
[ ] Anthropic First-Party API (default)
[ x] AWS Bedrock
[ ] GCP Vertex
Additional context
python code for mcp server:
from datetime import datetime, timezone
from typing import Any
from fastmcp import FastMCP
mcp = FastMCP(
name="Time Test MCP",
instructions="""This server provides a simple tool to get the current time.
Use the `get_current_time` tool to retrieve the current UTC time regardless of timezone.
""",
)
@mcp.tool(
name="get_current_time",
description="Get the current UTC time regardless of timezone.",
)
async def get_current_time() -> dict[str, Any]:
"""
Get the current UTC time.
Returns:
dict[str, Any]: A dictionary containing:
- utc_time: Current UTC time in ISO format
- timestamp: Unix timestamp
- formatted_time: Human-readable UTC time string
"""
try:
# Get current UTC time
now_utc = datetime.now(timezone.utc)
# Format the response
time_info = {
"utc_time": now_utc.isoformat(),
"timestamp": now_utc.timestamp(),
"formatted_time": now_utc.strftime("%Y-%m-%d %H:%M:%S UTC"),
}
return time_info
except Exception as e:
# Handle any unexpected errors
return {
"error": f"Failed to get current time: {str(e)}",
"utc_time": None,
"timestamp": None,
"formatted_time": None,
}
def main():
# Run the MCP server using stdio transport
mcp.run(transport="stdio")
if __name__ == "__main__":
main()