Skip to content

Commit 498fc13

Browse files
ElanHassonclaude
andauthored
Add Cursor and Claude Code MCP configuration support (#8)
* docs: Add Cursor and Claude Code MCP configuration instructions - Add Cursor configuration for both Docker and dotnet tool installation - Add Claude Code configuration with platform-specific paths - Include CSX_ALLOWED_PATH environment variable examples for security - Reorganize MCP configuration section with Cursor and Claude Code first * docs: Add Cursor and Claude Code MCP configuration instructions - Add .mcp.json configuration file for MCP client support - Make CSharpEvalTools public and add McpServerToolType attribute for proper MCP registration - Enable csharp-mcp server to work with Cursor IDE and Claude Code 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> --------- Co-authored-by: Claude <[email protected]>
1 parent 40e0893 commit 498fc13

File tree

2 files changed

+40
-23
lines changed

2 files changed

+40
-23
lines changed

.mcp.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"mcpServers": {
3+
"csharp-mcp": {
4+
"type": "stdio",
5+
"command": "docker",
6+
"args": [
7+
"run",
8+
"-i",
9+
"--rm",
10+
"ghcr.io/infinityflowapp/csharp-mcp:latest"
11+
],
12+
"env": {}
13+
}
14+
}
15+
}

src/InfinityFlow.CSharp.Eval/Tools/CSharpEvalTools.cs

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ namespace InfinityFlow.CSharp.Eval.Tools;
99
/// <summary>
1010
/// MCP tool for evaluating and executing C# scripts using Roslyn.
1111
/// </summary>
12-
internal class CSharpEvalTools
12+
13+
[McpServerToolType]
14+
public class CSharpEvalTools
1315
{
1416
[McpServerTool]
1517
[Description("Evaluates and executes C# script code and returns the output. Can either execute code directly or from a file.")]
@@ -29,7 +31,7 @@ public async Task<string> EvalCSharp(
2931
}
3032

3133
string scriptCode;
32-
34+
3335
try
3436
{
3537
if (!string.IsNullOrWhiteSpace(csxFile))
@@ -38,13 +40,13 @@ public async Task<string> EvalCSharp(
3840
try
3941
{
4042
var fullPath = Path.GetFullPath(csxFile);
41-
43+
4244
// Ensure the file has .csx extension
4345
if (!fullPath.EndsWith(".csx", StringComparison.OrdinalIgnoreCase))
4446
{
4547
return $"Error: Only .csx files are allowed. Provided: {csxFile}";
4648
}
47-
49+
4850
// Optional: Restrict to specific directories for additional security
4951
// This can be configured via environment variable
5052
var allowedPath = Environment.GetEnvironmentVariable("CSX_ALLOWED_PATH");
@@ -56,12 +58,12 @@ public async Task<string> EvalCSharp(
5658
return $"Error: File access is restricted to {normalizedAllowedPath}";
5759
}
5860
}
59-
61+
6062
if (!File.Exists(fullPath))
6163
{
6264
return $"Error: File not found: {fullPath}";
6365
}
64-
66+
6567
scriptCode = await File.ReadAllTextAsync(fullPath);
6668
}
6769
catch (Exception ex)
@@ -101,29 +103,29 @@ public async Task<string> EvalCSharp(
101103
// Capture console output
102104
var originalOut = Console.Out;
103105
var outputBuilder = new StringBuilder();
104-
106+
105107
try
106108
{
107109
using var stringWriter = new StringWriter(outputBuilder);
108110
Console.SetOut(stringWriter);
109111

110112
// Execute the script with timeout
111113
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(timeoutSeconds));
112-
114+
113115
// Run script in a task so we can properly handle timeout
114-
var scriptTask = Task.Run(async () =>
115-
await CSharpScript.EvaluateAsync(scriptCode, scriptOptions, cancellationToken: cts.Token),
116+
var scriptTask = Task.Run(async () =>
117+
await CSharpScript.EvaluateAsync(scriptCode, scriptOptions, cancellationToken: cts.Token),
116118
cts.Token);
117-
119+
118120
var timeoutTask = Task.Delay(TimeSpan.FromSeconds(timeoutSeconds));
119121
var completedTask = await Task.WhenAny(scriptTask, timeoutTask);
120-
122+
121123
if (completedTask == timeoutTask)
122124
{
123125
cts.Cancel();
124126
throw new OperationCanceledException();
125127
}
126-
128+
127129
var result = await scriptTask;
128130

129131
// Add the result value if it's not null
@@ -149,26 +151,26 @@ await CSharpScript.EvaluateAsync(scriptCode, scriptOptions, cancellationToken: c
149151
var errorBuilder = new StringBuilder();
150152
errorBuilder.AppendLine("Compilation Error(s):");
151153
errorBuilder.AppendLine();
152-
154+
153155
foreach (var diagnostic in e.Diagnostics)
154156
{
155157
var lineSpan = diagnostic.Location.GetLineSpan();
156158
var line = lineSpan.StartLinePosition.Line + 1; // Convert to 1-based
157159
var column = lineSpan.StartLinePosition.Character + 1;
158-
160+
159161
errorBuilder.AppendLine($" Line {line}, Column {column}: {diagnostic.Id} - {diagnostic.GetMessage()}");
160-
162+
161163
// Try to show the problematic code if available
162164
if (!diagnostic.Location.IsInSource) continue;
163-
165+
164166
var sourceText = diagnostic.Location.SourceTree?.GetText();
165167
if (sourceText != null)
166168
{
167169
var lineText = sourceText.Lines[lineSpan.StartLinePosition.Line].ToString();
168170
if (!string.IsNullOrWhiteSpace(lineText))
169171
{
170172
errorBuilder.AppendLine($" Code: {lineText.Trim()}");
171-
173+
172174
// Add a pointer to the error position
173175
if (column > 0 && column <= lineText.Length)
174176
{
@@ -179,7 +181,7 @@ await CSharpScript.EvaluateAsync(scriptCode, scriptOptions, cancellationToken: c
179181
}
180182
errorBuilder.AppendLine();
181183
}
182-
184+
183185
return errorBuilder.ToString().TrimEnd();
184186
}
185187
catch (OperationCanceledException)
@@ -191,7 +193,7 @@ await CSharpScript.EvaluateAsync(scriptCode, scriptOptions, cancellationToken: c
191193
var errorBuilder = new StringBuilder();
192194
errorBuilder.AppendLine($"Runtime Error: {e.GetType().Name}");
193195
errorBuilder.AppendLine($"Message: {e.Message}");
194-
196+
195197
// Try to extract the line number from the stack trace if it's a script error
196198
if (e.StackTrace != null && e.StackTrace.Contains("Submission#0"))
197199
{
@@ -209,16 +211,16 @@ await CSharpScript.EvaluateAsync(scriptCode, scriptOptions, cancellationToken: c
209211
}
210212
}
211213
}
212-
214+
213215
if (e.InnerException != null)
214216
{
215217
errorBuilder.AppendLine($"Inner Exception: {e.InnerException.GetType().Name}: {e.InnerException.Message}");
216218
}
217-
219+
218220
errorBuilder.AppendLine();
219221
errorBuilder.AppendLine("Stack Trace:");
220222
errorBuilder.AppendLine(e.StackTrace);
221-
223+
222224
return errorBuilder.ToString().TrimEnd();
223225
}
224226
}

0 commit comments

Comments
 (0)