Bundle platform-specific Claude Code CLI binaries directly in the Python
package, eliminating the need for separate CLI installation.
## Changes
### Build System
- Created `scripts/download_cli.py` to fetch CLI during build
- Created `scripts/build_wheel.py` for building platform-specific wheels
- Created `scripts/update_cli_version.py` to track bundled CLI version
- Updated `pyproject.toml` to properly bundle CLI without duplicate file
warnings
- Made twine check non-blocking (License-File warnings are false
positives)
### Runtime
- Modified `subprocess_cli.py` to check for bundled CLI first
- Added `_cli_version.py` to track which CLI version is bundled
- SDK automatically uses bundled CLI, falling back to system
installation if not found
- Users can still override with `cli_path` option
### Release Workflow
- Updated GitHub workflow to build separate wheels per platform (macOS,
Linux, Windows)
- Workflow now accepts two inputs:
- `version`: Package version to publish (e.g., `0.1.5`)
- `claude_code_version`: CLI version to bundle (e.g., `2.0.0` or
`latest`)
- Workflow builds platform-specific wheels with bundled CLI
- Creates release PR that updates:
- `pyproject.toml` version
- `src/claude_agent_sdk/_version.py`
- `src/claude_agent_sdk/_cli_version.py` with bundled CLI version
- `CHANGELOG.md` with auto-generated release notes
### Documentation
- Updated README to reflect bundled CLI (removed Node.js requirement)
- Added release workflow documentation
- Added local wheel building instructions
## Benefits
- **Zero external dependencies**: No need for Node.js or npm
- **Easier installation**: Single `pip install` gets everything
- **Version control**: Track exactly which CLI version is bundled
- **Flexible releases**: Can release new package versions with updated
CLI without code changes
- **Better user experience**: Works out of the box with no setup
Platform-specific wheels are automatically selected by pip during
installation based on the user's OS and architecture.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
Adds a committable pre-push hook that runs ruff checks before pushing,
matching the CI lint workflow. Developers run ./scripts/initial-setup.sh
to install the hook locally.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
- Add version check in subprocess transport that runs `claude -v` on
connect
- Display warning to stderr if version is below 2.0.0
- Update README prerequisites to specify Claude Code 2.0.0+
- Version check is non-blocking (warns but continues execution)
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-authored-by: Claude <noreply@anthropic.com>
## Summary
This PR adds support for custom tool callbacks and comprehensive e2e
testing for MCP calculator functionality.
## Key Features Added
- **Custom tool permission callbacks** - Allow dynamic tool permission
control via `can_use_tool` callback
- **E2E test suite** - Real Claude API tests validating MCP tool
execution end-to-end
- **Fixed MCP calculator example** - Now properly uses `allowed_tools`
for permission management
## Changes
### Custom Callbacks
- Added `ToolPermissionContext` and `PermissionResult` types for tool
permission handling
- Implemented `can_use_tool` callback support in SDK client
- Added comprehensive tests in `tests/test_tool_callbacks.py`
### E2E Testing Infrastructure
- Created `e2e-tests/` directory with pytest-based test suite
- `test_mcp_calculator.py` - Tests all calculator operations with real
API calls
- `conftest.py` - Pytest config with mandatory API key validation
- GitHub Actions workflow for automated e2e testing on main branch
- Comprehensive documentation in `e2e-tests/README.md`
### Bug Fixes
- Fixed MCP calculator example to use `allowed_tools` instead of
incorrect `permission_mode`
- Resolved tool permission issues preventing MCP tools from executing
## Testing
E2E tests require `ANTHROPIC_API_KEY` environment variable and will fail
without it.
Run locally:
```bash
export ANTHROPIC_API_KEY=your-key
python -m pytest e2e-tests/ -v -m e2e
```
Run unit tests including callback tests:
```bash
python -m pytest tests/test_tool_callbacks.py -v
```
🤖 Generated with [Claude Code](https://claude.ai/code)
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Kashyap Murali <kashyap@anthropic.com>
Hide hooks, tool permission callbacks, and SDK MCP server APIs from
public interface while keeping implementation code intact. These
features are not yet stable and should not be documented or exposed to
users.
Changes:
- Remove hook-related exports (HookCallback, HookContext, HookMatcher)
from __all__
- Remove tool permission exports (CanUseTool, ToolPermissionContext)
from __all__
- Remove SDK MCP exports (tool, create_sdk_mcp_server, SdkMcpTool) from
__all__
- Delete examples using unstable APIs (tool_permission_callback.py,
mcp_calculator.py)
- Remove SDK MCP server documentation from README
🤖 Generated with [Claude Code](https://claude.ai/code)
---------
Co-authored-by: Claude <noreply@anthropic.com>
## Summary
Adds in-process SDK MCP server support to the Python SDK, building on
the control protocol from #139.
**Note: Targets `dickson/control` branch (PR #139), not `main`.**
## Key Changes
- Added `@tool` decorator and `create_sdk_mcp_server()` API for defining
in-process MCP servers
- SDK MCP servers run directly in the Python process (no subprocess
overhead)
- Moved SDK MCP handling from Transport to Query class for proper
architectural layering
- Added `McpSdkServerConfig` type and integrated with control protocol
## Example
```python
from claude_code_sdk import tool, create_sdk_mcp_server
@tool("greet", "Greet a user", {"name": str})
async def greet_user(args):
return {"content": [{"type": "text", "text": f"Hello, {args['name']}!"}]}
server = create_sdk_mcp_server(name="my-tools", tools=[greet_user])
options = ClaudeCodeOptions(mcp_servers={"tools": server})
```
## Testing
- Added integration tests in `test_sdk_mcp_integration.py`
- Added example calculator server in `examples/mcp_calculator.py`
---------
Co-authored-by: Dickson Tsai <dickson@anthropic.com>
Co-authored-by: Ashwin Bhat <ashwin@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>