Expose Claude Code agents as MCP tools via a simple YAML config.
CCRA turns a YAML configuration file into a FastMCP stdio server where each agent becomes one MCP tool. Under the hood it spawns persistent ClaudeSDKClient instances (from the official Claude Agent SDK) at startup and bridges incoming MCP tool calls to agent queries. Responses stream back as plain text.
In practice this means you can point an agent at any directory, give it a system prompt and a set of allowed tools, and it becomes a queryable domain expert — all with a few lines of YAML. Your main Claude Code session can then call these agents as regular MCP tools, just like any other integration.
Claude Code is incredibly capable, but it's scoped to one project at a time. If you're working across multiple repositories — or you want to consult a specialized read-only expert on a large codebase — there's no built-in way to do that from a single session.
CCRA fills that gap. It lets you spin up multiple specialized agents, each anchored to its own directory with its own system prompt and tool restrictions, and expose them all as MCP tools. Your main Claude Code session can then query any of them on demand.
This enables workflows like:
- A multi-repo development session where you ask agents in different repos for context
- A domain-expert panel where each agent knows one codebase deeply
- Read-only advisors that can search and explain code but never modify it
- Read-only domain experts for large codebases — OpenWrt, Linux kernel, framework source trees. An agent with
Read,Grep,Glob, andBashcan answer deep questions about any codebase without risk of modification. - Multi-repo development — Query agents anchored to different projects from your main session. Ask the backend agent about an API while you're working on the frontend.
- Code review assistants — Set up agents with restricted tool access that can only read and analyze code, providing review feedback on demand.
- On-demand knowledge bases — Turn proprietary codebases into queryable experts that cite file paths and line numbers.
- Python 3.10 or newer
- uv package manager
- Claude Code CLI installed and authenticated
uv tool install git+https://github.com/unkier/ccraThis installs ccra as a global command. After installation, just run:
ccra path/to/config.ymlgit clone https://github.com/unkier/ccra.git && cd ccra
uv sync
uv run ccra path/to/config.yml1. Create a config file (my-experts.yml):
agents:
my_project_expert:
description: "Read-only expert for my project. Ask about architecture, APIs, and code."
cwd: /home/user/projects/my-project
allowed_tools:
- Read
- Bash
- Glob
- Grep
system_prompt: |
You are a read-only expert for this project.
Answer questions by searching and reading the source code.
Never modify any files. Cite file paths and line numbers.2. Run the server:
ccra my-experts.yml3. Integrate with Claude Code — add to your .claude/settings.json:
{
"mcpServers": {
"my-experts": {
"command": "ccra",
"args": ["/home/user/configs/my-experts.yml"]
}
}
}Now your main Claude Code session has a my_project_expert tool that you can query with natural language prompts.
Here's a full example showing all available fields:
agents:
openwrt_expert:
# Required
description: >-
Read-only OpenWrt domain expert with access to the full source tree.
Ask about build system, UCI, networking, packages, and more.
cwd: /home/user/devel/openwrt
# Optional — agent behavior
model: claude-sonnet-4-20250514 # Override default model
fallback_model: claude-haiku-4-5-20251001 # Fallback if primary unavailable
system_prompt: |
You are a read-only OpenWrt expert. Never modify files.
effort: high # low | medium | high | max
max_turns: 50 # Max conversation turns per query
max_budget_usd: 1.0 # Spending cap per query
# Optional — tool restrictions
allowed_tools: # Whitelist (empty = all tools)
- Read
- Bash
- Glob
- Grep
disallowed_tools: [] # Blacklist (takes precedence)
# Optional — environment
use_subscription: false # Use Claude subscription instead of API key
setting_sources: ["user", "project", "local"] # Settings to inherit
add_dirs: # Additional directories the agent can access
- /home/user/devel/shared-libs
# Optional — MCP servers available to the agent
mcp_servers:
my_server:
transport: stdio
command: /usr/bin/my-mcp-server
args: ["--flag"]| Field | Required | Type | Description |
|---|---|---|---|
description |
Yes | string |
Tool description shown in Claude Code |
cwd |
Yes | string |
Working directory for the agent (must exist) |
model |
No | string |
Model to use (defaults to Claude Code's default) |
system_prompt |
No | string |
System prompt prepended to every query |
allowed_tools |
No | list[string] |
Whitelist of tools the agent can use |
disallowed_tools |
No | list[string] |
Blacklist of tools (takes precedence over whitelist) |
setting_sources |
No | list[string] |
Settings sources to inherit |
use_subscription |
No | bool |
Use Claude subscription instead of API key (default: false) |
mcp_servers |
No | dict |
MCP servers available to the agent |
max_turns |
No | int |
Maximum conversation turns per query |
max_budget_usd |
No | float |
Spending cap per query in USD |
effort |
No | string |
Effort level: low, medium, high, or max |
fallback_model |
No | string |
Fallback model if primary is unavailable |
add_dirs |
No | list[string] |
Additional directories the agent can access |
Agent names must match the pattern ^[a-z][a-z0-9_]*$ (lowercase, starting with a letter, using only letters, digits, and underscores).
Each agent defined in your YAML config becomes one MCP tool. The tool name matches the agent name, it takes a single prompt string as input, and returns the agent's text response.
{
"mcpServers": {
"ccra": {
"command": "ccra",
"args": ["/home/user/configs/my-experts.yml"]
}
}
}{
"mcpServers": {
"ccra": {
"command": "uv",
"args": ["run", "--project", "/home/user/devel/ccra", "ccra", "/home/user/configs/my-experts.yml"]
}
}
}CCRA ships with a Claude Code slash-command skill that interactively generates a YAML config for a read-only expert agent pointing at the current project.
Install the skill (from the CCRA repo root):
ln -s ../../skills/ccra-expert .claude/skills/ccra-expertUse it in any Claude Code session:
/ccra-expert [output-path]
It will ask you about the project, then generate a ready-to-use CCRA config file.
CLI (cli.py)
-> load_config(path) -> CCRAConfig [config.py]
-> create_server(config) -> FastMCP [server.py]
-> AgentManager(config) [agent_manager.py]
-> registers one MCP tool per agent via Tool.from_function()
-> lifespan: spawn_all() on enter, shutdown() on exit
-> server.run(transport="stdio")
cli.py— Argparse entry point. Parses the config path and verbosity flag, sets up logging to stderr (stdout is reserved for the MCP stdio transport).config.py— Pydantic v2 models (CCRAConfig->AgentConfig->McpServerConfig). Validates agent names, working directories, and MCP server configs.agent_manager.py— Manages a pool ofClaudeSDKClientinstances.spawn_all()connects all agents concurrently.query()sends a prompt and collects response text.server.py— Builds a FastMCP server with a lifespan that manages agent startup/shutdown. Each agent is registered as an MCP tool via closure functions.
| Package | Version | Purpose |
|---|---|---|
claude-agent-sdk |
>= 0.1.45 | ClaudeSDKClient / ClaudeAgentOptions for spawning and querying agents |
fastmcp |
>= 3.0 | MCP server framework, @lifespan decorator, Tool.from_function() |
pydantic |
>= 2.0 | Configuration validation via Pydantic v2 models |
pyyaml |
>= 6.0 | YAML config file parsing |
uv sync # Install all dependencies
uv run ccra <config.yml> # Run the server
uv run ccra <config.yml> -v # Run with verbose/debug loggingNo tests or linter are configured yet — contributions welcome.
This entire project — every line of code, every config file, this README, and all documentation — was 100% created with Claude Code with zero manual file editing. It's turtles all the way down: an AI tool for orchestrating AI agents, built entirely by an AI agent.
MIT — Copyright 2026 Dmitrii Shapovalov