Claude Agent SDK for .NET
January 14, 2026 ยท View on GitHub
A modern .NET library for interacting with the Claude Code CLI, providing both a simple one-shot QueryAsync() API and a full bidirectional client with control-protocol support.
Disclaimer: This is an independent, unofficial port and is not affiliated with or endorsed by Anthropic, PBC.
Features
- Simple
Claude.QueryAsync()API for one-shot requests ClaudeSDKClientfor multi-turn, bidirectional conversations- Control protocol support (interrupts, modes, dynamic model switching)
- Hook system (PreToolUse, PostToolUse, UserPromptSubmit)
- Tool permission callbacks with allow/deny control
- In-process MCP server support (tools, prompts, resources)
- Cross-platform: Windows, Linux, macOS
- Source-generated JSON models for message types
- Well-tested: 109 tests (90 unit + 19 integration; integration tests are disabled by default)
Prerequisites
- .NET 8.0 or .NET 9.0
- Claude Code CLI >= 2.0.0:
npm install -g @anthropic-ai/claude-code
CLI Path Resolution
The SDK discovers the Claude Code CLI in this order:
ClaudeAgentOptions.CliPath(explicit path)CLAUDE_CLI_PATHenvironment variablePATHsearch forclaude(orclaude.cmdon Windows)
Quick Start
One-Shot Query
using Claude.AgentSdk;
await foreach (var msg in Claude.QueryAsync("What is 2+2?"))
{
if (msg is AssistantMessage am)
foreach (var block in am.Content)
if (block is TextBlock tb)
Console.Write(tb.Text);
}
Multi-Turn Conversation
using Claude.AgentSdk;
await using var client = new ClaudeSDKClient();
await client.ConnectAsync();
await client.QueryAsync("Write a Python hello world");
await foreach (var msg in client.ReceiveResponseAsync())
{
if (msg is AssistantMessage am)
foreach (var block in am.Content)
if (block is TextBlock tb)
Console.Write(tb.Text);
}
With Options
var options = Claude.Options()
.SystemPrompt("You are a helpful coding assistant.")
.MaxTurns(5)
.Model("claude-sonnet-4-20250514")
.AcceptEdits()
.Build();
await foreach (var msg in Claude.QueryAsync("Explain async/await", options))
{
// handle messages
}
Tool Permission Callback
var options = Claude.Options()
.CanUseTool(async (toolName, input, context, ct) =>
{
if (toolName == "Bash" && input.GetProperty("command").GetString()?.Contains("rm") == true)
return new PermissionResultDeny("Destructive commands not allowed");
return new PermissionResultAllow();
})
.Build();
Hooks
var options = Claude.Options()
.AllowTools("Bash")
.Hooks(h => h
.PreToolUse("Bash", (input, toolUseId, ctx, ct) =>
{
Console.WriteLine($"[Hook] Bash: {input}");
return Task.FromResult(new HookOutput { Continue = true });
}))
.Build();
MCP Tools (In-Process)
using Claude.AgentSdk;
using Claude.AgentSdk.Mcp;
var options = Claude.Options()
.McpServers(m => m.AddSdk("calculator", s => s
.Tool("add", (double a, double b) => a + b, "Add two numbers")))
.AllowAllTools()
.Build();
Custom Agents
var options = Claude.Options()
.Agents(a => a
.Add("reviewer", "Reviews code", "You are a code reviewer.", "Read", "Grep")
.Add("writer", "Writes code", "You are a clean coder.", tools: ["Read", "Write"]))
.Build();
Sandbox Configuration
var options = Claude.Options()
.Sandbox(s => s
.Enable()
.AutoAllowBash()
.ExcludeCommands("rm", "sudo")
.Network(n => n.AllowLocalBinding()))
.Build();
Configuration
ClaudeAgentOptions mirrors the Python SDK's options:
| Property | Type | Description |
|---|---|---|
SystemPrompt | string? | Custom system prompt |
MaxTurns | int? | Maximum conversation turns |
MaxBudgetUsd | decimal? | Spending limit in USD |
Model | string? | Model to use |
FallbackModel | string? | Fallback model |
PermissionMode | PermissionMode? | Default, AcceptEdits, BypassPermissions |
McpServers | object? | MCP server configurations |
CanUseTool | CanUseToolCallback? | Tool permission callback |
Hooks | IReadOnlyDictionary<...>? | Event hooks |
AllowedTools | IReadOnlyList<string> | Whitelist tools |
DisallowedTools | IReadOnlyList<string> | Blacklist tools |
Cwd | string? | Working directory |
CliPath | string? | Explicit CLI path |
Message Types
AssistantMessage- Claude's response withContentblocksUserMessage- User inputSystemMessage- System notificationsResultMessage- Query completion with cost/duration info
Content Blocks
TextBlock- Text contentThinkingBlock- Extended thinking (with signature)ToolUseBlock- Tool invocationToolResultBlock- Tool output
Examples
See the examples/ directory:
| Example | Description |
|---|---|
BasicQuery | Simple one-shot query |
StreamingMode | Interactive bidirectional client |
SystemPrompt | Custom system prompts |
McpCalculator | In-process MCP tools |
McpPrompts | MCP prompt templates |
Hooks | Pre/post tool use hooks |
ToolPermissionCallback | Permission control |
Agents | Agent configurations |
MaxBudget | Spending limits |
Status & Parity
- Current version: 0.1.0
- Status: Preview (API and behavior may change)
- Parity: Designed to match the Python Claude Agent SDK API, behavior, and ergonomics
- Tests: 109 tests (90 unit + 19 integration; integration tests are disabled by default)
Known Limitations
control_cancel_requestis currently ignored (cancellation of in-flight control requests is not implemented yet; matches Python SDK TODO).
Running Integration Tests
Integration tests require a working Claude Code CLI and are disabled by default.
- Enable them with:
CLAUDE_AGENT_SDK_RUN_INTEGRATION_TESTS=1 dotnet test
Canonical rule: The Python claude-agent-sdk is the canonical reference. This .NET port tracks its behavior and API.
Installation
NuGet Package (Coming Soon)
dotnet add package Claude.AgentSdk
From Source
git clone https://github.com/anthropics/claude-agent-sdk-dotnet.git
cd claude-agent-sdk-dotnet
dotnet build
Related Projects
| Project | Language | Description |
|---|---|---|
| claude-agent-sdk-python | Python | Official Python SDK (canonical reference) |
| claude-agent-sdk-cpp | C++ | C++ port with full feature parity |
License
Licensed under the MIT License. See LICENSE for details.
This is a .NET port of claude-agent-sdk-python by Anthropic, PBC.
Support
- Issues: Use the GitHub issue tracker
- Examples: See
examples/ - Tests: See
tests/