Skip to content

Commit 0446a9b

Browse files
gfraiteurclaude
andcommitted
MCP server: add local build rules and documentation
- Add command rules requiring manual approval for local build operations (dotnet build, msbuild, build.ps1, build.sh) - Create CLAUDE.md for MCP server with architecture and approval flow docs - Update root CLAUDE.md with MCP server source location and description Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 0c4933e commit 0446a9b

3 files changed

Lines changed: 166 additions & 1 deletion

File tree

CLAUDE.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,19 @@ Build orchestration SDK for PostSharp/Metalama repositories.
1919

2020
When running inside a Docker container, you have access to the `host-approval` MCP server for executing privileged commands on the host machine. These commands require human approval before execution.
2121

22+
**Source code**: `src/PostSharp.Engineering.McpApprovalServer/`
23+
24+
The MCP Approval Server is a WPF GUI application that:
25+
- Receives command execution requests from Claude in Docker via MCP protocol
26+
- Analyzes risk using both regex rules and AI (Claude CLI with Haiku/Opus)
27+
- Prompts the human for approval via a GUI dialog
28+
- Executes approved commands via PowerShell on the host
29+
30+
See `src/PostSharp.Engineering.McpApprovalServer/CLAUDE.md` for architecture details and how to add command rules.
31+
2232
### Starting the MCP Approval Server
2333

24-
The MCP Approval Server is now a standalone GUI application with system tray integration. Before running Claude in Docker mode, start the server:
34+
The MCP Approval Server is a standalone GUI application with system tray integration. Before running Claude in Docker mode, start the server:
2535

2636
1. Build the solution: `dotnet build`
2737
2. Run the GUI application: `.\src\PostSharp.Engineering.McpApprovalServer\bin\Debug\net8.0-windows\PostSharp.Engineering.McpApprovalServer.exe`
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# MCP Approval Server
2+
3+
A WPF GUI application that provides an MCP (Model Context Protocol) server for executing privileged commands on the host machine with human approval. Used when Claude runs inside a Docker container and needs to perform operations requiring host credentials or external access.
4+
5+
## Architecture
6+
7+
### Approval Flow
8+
9+
1. **Request Reception**: Claude in Docker calls `ExecuteCommand` via MCP
10+
2. **Parallel Risk Analysis**: Two analyzers run concurrently:
11+
- **Regex Rule Engine** (`RegexRuleEngine.cs`): Fast pattern matching against predefined rules
12+
- **AI Risk Analyzer** (`RiskAnalyzer.cs`): Uses Claude CLI (Haiku, escalating to Opus if uncertain)
13+
3. **Risk Combination** (`RiskCombiner.cs`): Takes the maximum (most restrictive) of both assessments
14+
4. **Human Approval** (`GuiApprovalPrompter.cs`): Shows approval dialog with risk assessment
15+
5. **Execution** (`CommandExecutor.cs`): If approved, executes via PowerShell on host
16+
6. **History Recording** (`CommandHistoryService.cs`): Records for session-based auto-approval
17+
18+
### Risk Levels
19+
20+
| Level | Description |
21+
|-------|-------------|
22+
| `Low` | Safe operations, recommendation shown |
23+
| `Medium` | Requires attention, manual review expected |
24+
| `High` | Potentially dangerous, careful review required |
25+
| `Critical` | Very dangerous, default recommendation is reject |
26+
| `Uncertain` | AI couldn't determine - escalates to Opus, then human |
27+
28+
### Key Components
29+
30+
```
31+
Mcp/
32+
├── Models/
33+
│ ├── CommandContext.cs # Git context for rule evaluation
34+
│ ├── CommandRecord.cs # History entry
35+
│ ├── CommandResult.cs # Execution result
36+
│ ├── CommandRule.cs # Rule definition
37+
│ └── RiskAssessment.cs # Risk analysis result
38+
├── Services/
39+
│ ├── CommandRules.cs # Predefined regex rules
40+
│ ├── CommandExecutor.cs # PowerShell execution
41+
│ ├── CommandHistoryService.cs # Session history
42+
│ ├── RegexRuleEngine.cs # Pattern-based risk evaluation
43+
│ ├── RiskAnalyzer.cs # AI-based risk analysis
44+
│ └── RiskCombiner.cs # Combines AI + regex assessments
45+
└── Tools/
46+
└── ExecuteCommandTool.cs # MCP tool entry point
47+
48+
Services/
49+
├── ApprovalRequest.cs # Approval request model
50+
├── ApprovalRequestQueue.cs # Concurrent request queue
51+
├── GitHelper.cs # Git operations helper
52+
├── GuiApprovalPrompter.cs # WPF approval dialog integration
53+
├── McpHttpServer.cs # HTTP server for MCP
54+
├── TraceLogger.cs # File-based logging
55+
└── TrayIconService.cs # System tray integration
56+
57+
Views/
58+
├── ApprovalWindow.xaml # Approval dialog
59+
├── HistoryWindow.xaml # Command history viewer
60+
└── MainWindow.xaml # Main window (hidden, tray-based)
61+
```
62+
63+
## Adding Command Rules
64+
65+
Rules are defined in `Mcp/Services/CommandRules.cs`. Each rule has:
66+
67+
- `Name`: Unique identifier for logging
68+
- `Pattern`: Regex to match against the command
69+
- `RiskLevel`: Low, Medium, High, or Critical
70+
- `Recommendation`: Approve, Reject, or None (defer to AI)
71+
- `Reason`: Human-readable explanation
72+
- `Condition`: Optional function for context-aware matching (e.g., branch checks)
73+
74+
Example:
75+
```csharp
76+
new CommandRule
77+
{
78+
Name = "git-push-to-feature",
79+
Pattern = new Regex( @"git\s+push", RegexOptions.IgnoreCase ),
80+
RiskLevel = RiskLevel.Low,
81+
Recommendation = Recommendation.Approve,
82+
Reason = "Pushing to feature/topic branch"
83+
}
84+
```
85+
86+
Rules are evaluated in order - first match wins. Place more specific rules before general ones.
87+
88+
## AI Risk Analysis
89+
90+
The `RiskAnalyzer` uses Claude CLI with a two-tier approach:
91+
92+
1. **Haiku first**: Fast, cheap analysis for most requests
93+
2. **Opus escalation**: If Haiku returns `UNCERTAIN`, escalates to Opus
94+
3. **Human fallback**: If Opus is also uncertain, defaults to Medium risk
95+
96+
The AI receives:
97+
- Command and claimed purpose
98+
- Working directory and git branch
99+
- Session history (last 10 commands)
100+
- For `git push`: Full commit diff for secrets/content analysis
101+
102+
## Session Auto-Approval
103+
104+
Commands that were previously approved in the same session can be auto-approved:
105+
- Same command text
106+
- Same working directory
107+
- Recorded in `CommandHistoryService`
108+
109+
This allows repetitive operations (like multiple pushes) without repeated approval dialogs.
110+
111+
## Security Considerations
112+
113+
- Server binds to `localhost:9847` only (not network-exposed)
114+
- Docker accesses via host gateway IP
115+
- All commands require human approval (no automatic execution)
116+
- Critical operations (nuget push, repo delete, force push) default to reject
117+
- AI analyzes commit diffs for secrets, credentials, inappropriate content
118+
- File operations on host are forbidden (must be done in container)

src/PostSharp.Engineering.McpApprovalServer/Mcp/Services/CommandRules.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,43 @@ public static class CommandRules
133133
Reason = "Creating pull request"
134134
},
135135

136+
// ============================================
137+
// Local Build Operations - Require Manual Approval
138+
// ============================================
139+
140+
new CommandRule
141+
{
142+
Name = "local-build-dotnet",
143+
Pattern = new Regex( @"dotnet\s+build", RegexOptions.IgnoreCase ),
144+
RiskLevel = RiskLevel.Medium,
145+
Recommendation = Recommendation.Approve,
146+
Reason = "Local build operation - should normally be done in the container"
147+
},
148+
new CommandRule
149+
{
150+
Name = "local-build-msbuild",
151+
Pattern = new Regex( @"msbuild", RegexOptions.IgnoreCase ),
152+
RiskLevel = RiskLevel.Medium,
153+
Recommendation = Recommendation.Approve,
154+
Reason = "Local build operation - should normally be done in the container"
155+
},
156+
new CommandRule
157+
{
158+
Name = "local-build-ps1",
159+
Pattern = new Regex( @"[Bb]uild\.ps1", RegexOptions.IgnoreCase ),
160+
RiskLevel = RiskLevel.Medium,
161+
Recommendation = Recommendation.Approve,
162+
Reason = "Local build script - should normally be done in the container"
163+
},
164+
new CommandRule
165+
{
166+
Name = "local-build-sh",
167+
Pattern = new Regex( @"build\.sh", RegexOptions.IgnoreCase ),
168+
RiskLevel = RiskLevel.Medium,
169+
Recommendation = Recommendation.Approve,
170+
Reason = "Local build script - should normally be done in the container"
171+
},
172+
136173
// ============================================
137174
// File Operations - ALL FORBIDDEN
138175
// ============================================

0 commit comments

Comments
 (0)