Skip to content

Commit 839d153

Browse files
ElanHassonclaude
andauthored
feat: Add NuGet package support and Docker volume mounting (#9)
* feat: Add NuGet package support and Docker volume mounting for .csx files - Added NuGet package resolver to support #r directives - Updated Dockerfile to use SDK image for NuGet resolution - Added Docker volume mounting in .mcp.json for file access - Added --pull=always to ensure latest image is used - Enhanced ScriptOptions with source and metadata resolvers - Added test scripts and examples 🤖 Generated with Claude Code Co-Authored-By: Claude <[email protected]> * refactor: Move example scripts to examples folder - Organized all .csx example files into dedicated examples directory - Cleaner project root structure 🤖 Generated with Claude Code Co-Authored-By: Claude <[email protected]> * feat: Add comprehensive examples with tests - Organized examples into categorized directories - Added README and expected output for each example - Created test suite to validate all examples - Examples cover: basic execution, Fibonacci, data processing, NuGet packages 🤖 Generated with Claude Code Co-Authored-By: Claude <[email protected]> * fix: Update CSX_ALLOWED_PATH to only apply outside Docker - CSX_ALLOWED_PATH restriction now only applies when NOT in Docker - Docker containers use volume mounts for file access control - Fixed example tests to handle dynamic content and ordering - NuGet test properly skips when packages can't be resolved 🤖 Generated with Claude Code Co-Authored-By: Claude <[email protected]> * fix: Improve NuGet package error handling - Return detailed errors when NuGet packages fail to resolve - Validate #r directive syntax and report malformed directives - Handle both missing packages and invalid versions gracefully - Update tool description to mention NuGet support 🤖 Generated with Claude Code Co-Authored-By: Claude <[email protected]> * feat: Add NUnit testing example demonstrating programmatic test execution - Create comprehensive NUnit example with Calculator and StringUtils tests - Demonstrate test fixtures, setup methods, and assertions - Show programmatic test execution without external test runner - Include expected output for test validation - Update ExamplesTests to dynamically discover example directories 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * docs: Update README with NuGet support and examples documentation - Add NuGet package support to features list - Document #r directive usage with examples - Include links to all example directories - Update Claude Code configuration with volume mounting - Expand project structure to show NuGetPackageResolver - Add all newly supported namespaces to documentation 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * refactor: Clean up code formatting and remove unnecessary blank lines * fix: Fix Docker test failure and syntax error - Skip path restriction test when running in Docker container - Fix syntax error in CSharpEvalTools async task creation - Docker sets DOTNET_RUNNING_IN_CONTAINER=true which bypasses path checks 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> --------- Co-authored-by: Claude <[email protected]>
1 parent 498fc13 commit 839d153

File tree

26 files changed

+1189
-22
lines changed

26 files changed

+1189
-22
lines changed

.mcp.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@
77
"run",
88
"-i",
99
"--rm",
10+
"--pull=always",
11+
"-v", "${HOME}:${HOME}",
12+
"-w", "${PWD}",
1013
"ghcr.io/infinityflowapp/csharp-mcp:latest"
1114
],
1215
"env": {}
1316
}
1417
}
15-
}

.vscode/settings.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"cSpell.words": [
3+
"infinityflow"
4+
]
5+
}

Directory.Packages.props

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
<!-- Roslyn Scripting -->
1111
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.14.0" />
1212

13+
<!-- NuGet Client Libraries -->
14+
<PackageVersion Include="NuGet.Protocol" Version="6.12.1" />
15+
<PackageVersion Include="NuGet.Resolver" Version="6.12.1" />
16+
1317
<!-- Testing -->
1418
<PackageVersion Include="NUnit" Version="4.4.0" />
1519
<PackageVersion Include="NUnit.Analyzers" Version="4.10.0" />

Dockerfile

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ RUN dotnet test -c Release --no-build --verbosity normal
2222
# Publish
2323
RUN dotnet publish src/InfinityFlow.CSharp.Eval/InfinityFlow.CSharp.Eval.csproj -c Release -o /app/publish --no-restore
2424

25-
# Runtime stage
26-
FROM mcr.microsoft.com/dotnet/runtime:9.0 AS runtime
25+
# Runtime stage - Use SDK for NuGet package resolution
26+
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS runtime
2727
WORKDIR /app
2828

2929
# Install required dependencies for Roslyn scripting
@@ -34,11 +34,21 @@ RUN apt-get update && apt-get install -y \
3434
# Copy published app
3535
COPY --from=build /app/publish .
3636

37+
# Create directories for NuGet packages
38+
RUN mkdir -p /tmp/csharp-mcp-packages && \
39+
chmod 777 /tmp/csharp-mcp-packages
40+
3741
# Create non-root user
3842
RUN useradd -m -s /bin/bash mcpuser && \
3943
chown -R mcpuser:mcpuser /app
4044

4145
USER mcpuser
4246

47+
# Set NuGet package cache directory
48+
ENV NUGET_PACKAGES=/tmp/csharp-mcp-packages
49+
50+
# Indicate we're running in a container
51+
ENV DOTNET_RUNNING_IN_CONTAINER=true
52+
4353
# The MCP server uses stdio for communication
4454
ENTRYPOINT ["dotnet", "InfinityFlow.CSharp.Eval.dll"]

README.md

Lines changed: 63 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ An MCP (Model Context Protocol) server that evaluates and executes C# scripts us
66

77
- 🚀 Execute C# scripts directly or from files
88
- 📦 Full Roslyn scripting support with common namespaces pre-imported
9+
- 📚 NuGet package support via `#r "nuget: PackageName, Version"` directives
910
- 🔒 Console output capture (safe for MCP stdio protocol)
1011
- ⚡ Comprehensive error handling for compilation and runtime errors
11-
- 🐳 Available as both Docker container and dotnet tool
12+
- 🐳 Available as both Docker container and dotnet tool with volume mounting support
1213
- ✅ Full test coverage with NUnit and FluentAssertions
1314

1415
## Installation
@@ -56,12 +57,21 @@ The MCP server exposes a single tool: `EvalCSharp`
5657

5758
- `csxFile` (optional): Full path to a .csx file to execute
5859
- `csx` (optional): C# script code to execute directly
60+
- `timeoutSeconds` (optional): Maximum execution time in seconds (default: 30)
5961

6062
Either `csxFile` or `csx` must be provided, but not both.
6163

6264
### Examples
6365

66+
For comprehensive examples, see the [examples directory](examples/):
67+
- [Basic Execution](examples/basic-execution/) - Simple C# script execution
68+
- [Fibonacci Sequence](examples/fibonacci-sequence/) - Generating number sequences
69+
- [Data Processing](examples/data-processing/) - LINQ and data manipulation
70+
- [NuGet Packages](examples/nuget-packages/) - Using external NuGet packages
71+
- [NUnit Testing](examples/nunit-testing/) - Running tests programmatically
72+
6473
#### Direct code execution
74+
6575
```json
6676
{
6777
"tool": "EvalCSharp",
@@ -72,12 +82,14 @@ Either `csxFile` or `csx` must be provided, but not both.
7282
```
7383

7484
Output:
75-
```
85+
86+
```text
7687
Hello World!
7788
Result: 4
7889
```
7990

8091
#### Execute from file
92+
8193
```json
8294
{
8395
"tool": "EvalCSharp",
@@ -88,6 +100,7 @@ Result: 4
88100
```
89101

90102
#### Complex example with LINQ
103+
91104
```csharp
92105
var numbers = Enumerable.Range(1, 10);
93106
var evenSum = numbers.Where(n => n % 2 == 0).Sum();
@@ -96,20 +109,47 @@ evenSum * 2
96109
```
97110

98111
Output:
99-
```
112+
113+
```text
100114
Sum of even numbers: 30
101115
Result: 60
102116
```
103117

104118
### Pre-imported namespaces
105119

106120
The following namespaces are automatically available:
121+
107122
- `System`
108123
- `System.IO`
109124
- `System.Linq`
110125
- `System.Text`
111126
- `System.Collections.Generic`
112127
- `System.Threading.Tasks`
128+
- `System.Net.Http`
129+
- `System.Text.Json`
130+
- `System.Text.RegularExpressions`
131+
132+
### NuGet Package Support
133+
134+
You can reference NuGet packages directly in your scripts using the `#r` directive:
135+
136+
```csharp
137+
#r "nuget: Newtonsoft.Json, 13.0.3"
138+
#r "nuget: Humanizer, 2.14.1"
139+
140+
using Newtonsoft.Json;
141+
using Humanizer;
142+
143+
var json = JsonConvert.SerializeObject(new { Message = "Hello World" });
144+
Console.WriteLine(json);
145+
Console.WriteLine("5 days".Humanize());
146+
```
147+
148+
The tool will automatically:
149+
- Download the specified packages from NuGet.org
150+
- Resolve and download dependencies
151+
- Cache packages for faster subsequent runs
152+
- Provide detailed error messages for invalid package specifications
113153

114154
## MCP Configuration
115155

@@ -159,15 +199,19 @@ Add to your Claude Code configuration (`claude_desktop_config.json`):
159199
"mcpServers": {
160200
"csharp-eval": {
161201
"command": "docker",
162-
"args": ["run", "-i", "--rm", "ghcr.io/infinityflowapp/csharp-mcp:latest"],
163-
"env": {
164-
"CSX_ALLOWED_PATH": "/scripts"
165-
}
202+
"args": [
203+
"run", "-i", "--rm", "--pull=always",
204+
"-v", "${HOME}:${HOME}",
205+
"-w", "${PWD}",
206+
"ghcr.io/infinityflowapp/csharp-mcp:latest"
207+
]
166208
}
167209
}
168210
}
169211
```
170212

213+
Note: The volume mounting (`-v ${HOME}:${HOME}`) allows the tool to access .csx files from your filesystem.
214+
171215
Or if installed as a dotnet tool:
172216

173217
```json
@@ -262,18 +306,26 @@ docker run -it infinityflow/csharp-eval-mcp
262306

263307
## Project Structure
264308

265-
```
309+
```text
266310
csharp-mcp/
267311
├── src/
268312
│ └── InfinityFlow.CSharp.Eval/ # Main MCP server implementation
269313
│ ├── Tools/
270-
│ │ └── CSharpEvalTools.cs # Roslyn script evaluation tool
314+
│ │ ├── CSharpEvalTools.cs # Roslyn script evaluation tool
315+
│ │ └── NuGetPackageResolver.cs # NuGet package resolution
271316
│ ├── Program.cs # MCP server entry point
272317
│ └── .mcp/
273318
│ └── server.json # MCP server configuration
274319
├── tests/
275320
│ └── InfinityFlow.CSharp.Eval.Tests/ # Unit tests
276-
│ └── CSharpEvalToolsTests.cs # Comprehensive test suite
321+
│ ├── CSharpEvalToolsTests.cs # Core functionality tests
322+
│ └── ExamplesTests.cs # Example validation tests
323+
├── examples/ # Example scripts with documentation
324+
│ ├── basic-execution/ # Simple C# script examples
325+
│ ├── fibonacci-sequence/ # Algorithm demonstrations
326+
│ ├── data-processing/ # LINQ and data manipulation
327+
│ ├── nuget-packages/ # External package usage
328+
│ └── nunit-testing/ # Programmatic test execution
277329
├── Directory.Packages.props # Central package management
278330
├── Dockerfile # Docker containerization
279331
├── docker-compose.yml # Docker compose configuration
@@ -303,6 +355,7 @@ git push origin v1.0.0
303355
```
304356

305357
This will:
358+
306359
1. Build and test the project
307360
2. Publish Docker image to GitHub Container Registry
308361
3. Publish NuGet package to NuGet.org

examples/README.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# C# MCP Examples
2+
3+
This directory contains example C# scripts demonstrating various features of the C# MCP server.
4+
5+
## Examples
6+
7+
### 1. [Basic Execution](./basic-execution)
8+
Simple script demonstrating console output, variables, loops, and return values.
9+
10+
### 2. [Fibonacci Sequence](./fibonacci-sequence)
11+
Recursive functions and LINQ operations for calculating Fibonacci numbers.
12+
13+
### 3. [Data Processing](./data-processing)
14+
Complex data manipulation with custom classes, LINQ queries, and JSON serialization.
15+
16+
### 4. [NuGet Packages](./nuget-packages)
17+
Using external NuGet packages with the `#r` directive (requires SDK runtime).
18+
19+
## Running Examples
20+
21+
Each example can be run in several ways:
22+
23+
### Using the MCP Tool Directly
24+
```bash
25+
cd examples/basic-execution
26+
dotnet run --project ../../src/InfinityFlow.CSharp.Eval -- eval-csharp --csx-file script.csx
27+
```
28+
29+
### Using Docker
30+
```bash
31+
docker run -i --rm -v $(pwd):/scripts ghcr.io/infinityflowapp/csharp-mcp:latest \
32+
eval-csharp --csx-file /scripts/examples/basic-execution/script.csx
33+
```
34+
35+
### Via MCP Client
36+
When using an MCP client like Claude or Cursor, provide the full path to the script file.
37+
38+
## Testing Examples
39+
40+
All examples are automatically tested to ensure they produce the expected output:
41+
42+
```bash
43+
dotnet test --filter "FullyQualifiedName~ExamplesTests"
44+
```
45+
46+
## Structure
47+
48+
Each example directory contains:
49+
- `script.csx` - The C# script to execute
50+
- `README.md` - Documentation for the example
51+
- `expected-output.txt` - Expected output for validation
52+
53+
The test suite validates that each example:
54+
1. Executes without errors
55+
2. Produces output matching the expected output
56+
3. Contains all required files

examples/basic-execution/README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Basic Execution Example
2+
3+
This example demonstrates basic C# script execution with console output and return values.
4+
5+
## Features
6+
7+
- Console output
8+
- Variable declarations
9+
- Simple loops
10+
- Return values
11+
12+
## Running the Example
13+
14+
```bash
15+
# Using the MCP tool directly
16+
dotnet run --project ../../src/InfinityFlow.CSharp.Eval -- eval-csharp --csx-file script.csx
17+
18+
# Or via MCP client
19+
# Provide the full path to script.csx when using the eval_c_sharp tool
20+
```
21+
22+
## Expected Output
23+
24+
The script will output:
25+
26+
- A greeting message
27+
- Current timestamp
28+
- Sum calculation result
29+
- Return value with the final sum
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Hello from C# MCP!
2+
Script is running...
3+
Sum of 1 to 10: 55
4+
5+
Result: Script completed successfully with sum = 55
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System;
2+
3+
// Basic C# script execution example
4+
Console.WriteLine("Hello from C# MCP!");
5+
Console.WriteLine($"Script is running...");
6+
7+
// Simple calculation
8+
var sum = 0;
9+
for (int i = 1; i <= 10; i++)
10+
{
11+
sum += i;
12+
}
13+
14+
Console.WriteLine($"Sum of 1 to 10: {sum}");
15+
16+
// Return a value
17+
return $"Script completed successfully with sum = {sum}";

examples/data-processing/README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Data Processing Example
2+
3+
This example demonstrates complex data processing with classes, LINQ, and JSON serialization.
4+
5+
## Features
6+
- Custom class definitions
7+
- Collection manipulation
8+
- LINQ queries and aggregations
9+
- Anonymous types
10+
- GroupBy operations
11+
- JSON serialization (System.Text.Json)
12+
13+
## Running the Example
14+
15+
```bash
16+
# Using the MCP tool directly
17+
dotnet run --project ../../src/InfinityFlow.CSharp.Eval -- eval-csharp --csx-file script.csx
18+
19+
# Or via MCP client
20+
# Provide the full path to script.csx when using the eval_c_sharp tool
21+
```
22+
23+
## Expected Output
24+
The script will output:
25+
- List of people with their hobbies
26+
- Statistical analysis
27+
- Age group distribution
28+
- Return value with processing summary

0 commit comments

Comments
 (0)