Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
bb5af77
Revert "Remove unstable public APIs from SDK (#151)"
ashwin-ant Sep 7, 2025
9a8216b
fix: Make SDK MCP servers work with streaming client
ashwin-ant Sep 7, 2025
297206c
Fix tool duplication bug in MCP calculator example
km-anthropic Sep 7, 2025
ff3fbf3
Add e2e tests for MCP calculator with real Claude API
ashwin-ant Sep 8, 2025
eb0e46f
Rename e2e workflow to test-examples and remove main-only restriction
ashwin-ant Sep 8, 2025
15b58a7
Add Claude Code installation and multi-Python testing to e2e workflow
ashwin-ant Sep 8, 2025
ca651ed
rename
ashwin-ant Sep 8, 2025
85485df
lint
ashwin-ant Sep 8, 2025
0a3a680
tests
ashwin-ant Sep 8, 2025
e9b18e8
tests
ashwin-ant Sep 8, 2025
60b309a
lint
ashwin-ant Sep 8, 2025
c0cf97d
log
ashwin-ant Sep 8, 2025
6cce491
Refactor e2e tests to focus on SDK MCP tool mechanics
ashwin-ant Sep 8, 2025
ac0ef4b
log
ashwin-ant Sep 8, 2025
ac1de11
Track actual tool function execution in e2e tests
ashwin-ant Sep 8, 2025
6bea47e
Fix mypy type error in subprocess_cli.py
ashwin-ant Sep 8, 2025
fdbe188
Fix remaining mypy type error in subprocess_cli.py
ashwin-ant Sep 8, 2025
3b207a6
Add e2e tests for tool permission callbacks
ashwin-ant Sep 8, 2025
70d140a
Simplify tool permission callback tests to single focused test
ashwin-ant Sep 8, 2025
5f4c0b3
tmp
ashwin-ant Sep 8, 2025
f93b327
Add debug logging to permission callback test
ashwin-ant Sep 8, 2025
a470e1c
wite
ashwin-ant Sep 8, 2025
6f47853
Fix tool permission callbacks by auto-setting stdio mode
ashwin-ant Sep 8, 2025
1434cf8
lint
ashwin-ant Sep 8, 2025
9abc015
lint
ashwin-ant Sep 8, 2025
bb5405d
rm script
ashwin-ant Sep 8, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 0 additions & 45 deletions .github/workflows/test-e2e.yml

This file was deleted.

117 changes: 93 additions & 24 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,103 @@ on:
pull_request:
push:
branches:
- 'main'
- "main"

jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.10', '3.11', '3.12', '3.13']

python-version: ["3.10", "3.11", "3.12", "3.13"]

steps:
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e ".[dev]"

- name: Run tests
run: |
python -m pytest tests/ -v --cov=claude_code_sdk --cov-report=xml

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
file: ./coverage.xml
fail_ci_if_error: false

test-e2e:
runs-on: ubuntu-latest
needs: test # Run after unit tests pass
strategy:
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]

steps:
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e ".[dev]"

- name: Run tests
run: |
python -m pytest tests/ -v --cov=claude_code_sdk --cov-report=xml

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
file: ./coverage.xml
fail_ci_if_error: false
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install Claude Code
run: |
curl -fsSL https://claude.ai/install.sh | bash
echo "$HOME/.local/bin" >> $GITHUB_PATH

- name: Verify Claude Code installation
run: claude -v

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e ".[dev]"

- name: Run end-to-end tests with real API
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
python -m pytest e2e-tests/ -v -m e2e

test-examples:
runs-on: ubuntu-latest
needs: test-e2e # Run after e2e tests
strategy:
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]

steps:
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install Claude Code
run: |
curl -fsSL https://claude.ai/install.sh | bash
echo "$HOME/.local/bin" >> $GITHUB_PATH

- name: Verify Claude Code installation
run: claude -v

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e .

- name: Run example scripts
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
python examples/quick_start.py
timeout 120 python examples/streaming_mode.py all
84 changes: 84 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,90 @@ options = ClaudeCodeOptions(
)
```

### SDK MCP Servers (In-Process)

The SDK now supports in-process MCP servers that run directly within your Python application, eliminating the need for separate processes.

#### Creating a Simple Tool

```python
from claude_code_sdk import tool, create_sdk_mcp_server

# Define a tool using the @tool decorator
@tool("greet", "Greet a user", {"name": str})
async def greet_user(args):
return {
"content": [
{"type": "text", "text": f"Hello, {args['name']}!"}
]
}

# Create an SDK MCP server
server = create_sdk_mcp_server(
name="my-tools",
version="1.0.0",
tools=[greet_user]
)

# Use it with Claude
options = ClaudeCodeOptions(
mcp_servers={"tools": server}
)

async for message in query(prompt="Greet Alice", options=options):
print(message)
```

#### Benefits Over External MCP Servers

- **No subprocess management** - Runs in the same process as your application
- **Better performance** - No IPC overhead for tool calls
- **Simpler deployment** - Single Python process instead of multiple
- **Easier debugging** - All code runs in the same process
- **Type safety** - Direct Python function calls with type hints

#### Migration from External Servers

```python
# BEFORE: External MCP server (separate process)
options = ClaudeCodeOptions(
mcp_servers={
"calculator": {
"type": "stdio",
"command": "python",
"args": ["-m", "calculator_server"]
}
}
)

# AFTER: SDK MCP server (in-process)
from my_tools import add, subtract # Your tool functions

calculator = create_sdk_mcp_server(
name="calculator",
tools=[add, subtract]
)

options = ClaudeCodeOptions(
mcp_servers={"calculator": calculator}
)
```

#### Mixed Server Support

You can use both SDK and external MCP servers together:

```python
options = ClaudeCodeOptions(
mcp_servers={
"internal": sdk_server, # In-process SDK server
"external": { # External subprocess server
"type": "stdio",
"command": "external-server"
}
}
)
```

## API Reference

Expand Down
102 changes: 102 additions & 0 deletions e2e-tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# End-to-End Tests for Claude Code SDK

This directory contains end-to-end tests that run against the actual Claude API to verify real-world functionality.

## Requirements

### API Key (REQUIRED)

These tests require a valid Anthropic API key. The tests will **fail** if `ANTHROPIC_API_KEY` is not set.

Set your API key before running tests:

```bash
export ANTHROPIC_API_KEY="your-api-key-here"
```

### Dependencies

Install the development dependencies:

```bash
pip install -e ".[dev]"
```

## Running the Tests

### Run all e2e tests:

```bash
python -m pytest e2e-tests/ -v
```

### Run with e2e marker only:

```bash
python -m pytest e2e-tests/ -v -m e2e
```

### Run a specific test:

```bash
python -m pytest e2e-tests/test_mcp_calculator.py::test_basic_addition -v
```

## Cost Considerations

⚠️ **Important**: These tests make actual API calls to Claude, which incur costs based on your Anthropic pricing plan.

- Each test typically uses 1-3 API calls
- Tests use simple prompts to minimize token usage
- The complete test suite should cost less than $0.10 to run

## Test Coverage

### MCP Calculator Tests (`test_mcp_calculator.py`)

Tests the MCP (Model Context Protocol) integration with calculator tools:

- **test_basic_addition**: Verifies the add tool executes correctly
- **test_division**: Tests division with decimal results
- **test_square_root**: Validates square root calculations
- **test_power**: Tests exponentiation
- **test_multi_step_calculation**: Verifies multiple tools can be used in sequence
- **test_tool_permissions_enforced**: Ensures permission system works correctly

Each test validates:
1. Tools are actually called (ToolUseBlock present in response)
2. Correct tool inputs are provided
3. Expected results are returned
4. Permission system is enforced

## CI/CD Integration

These tests run automatically on:
- Pushes to `main` branch (via GitHub Actions)
- Manual workflow dispatch

The workflow uses `ANTHROPIC_API_KEY` from GitHub Secrets.

## Troubleshooting

### "ANTHROPIC_API_KEY environment variable is required" error
- Set your API key: `export ANTHROPIC_API_KEY=sk-ant-...`
- The tests will not skip - they require the key to run

### Tests timing out
- Check your API key is valid and has quota available
- Ensure network connectivity to api.anthropic.com

### Permission denied errors
- Verify the `allowed_tools` parameter includes the necessary MCP tools
- Check that tool names match the expected format (e.g., `mcp__calc__add`)

## Adding New E2E Tests

When adding new e2e tests:

1. Mark tests with `@pytest.mark.e2e` decorator
2. Use the `api_key` fixture to ensure API key is available
3. Keep prompts simple to minimize costs
4. Verify actual tool execution, not just mocked responses
5. Document any special setup requirements in this README
Loading