Skip to content

Commit 0736960

Browse files
MCP
1 parent 04e0415 commit 0736960

File tree

4 files changed

+1161
-569
lines changed

4 files changed

+1161
-569
lines changed

RestClient.Net.McpGenerator/McpToolGenerator.cs

Lines changed: 52 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,12 @@ string extensionsNamespace
5959
#nullable enable
6060
using System.ComponentModel;
6161
using System.Text.Json;
62-
using ModelContextProtocol;
6362
using Outcome;
6463
using {{extensionsNamespace}};
6564
6665
namespace {{@namespace}};
6766
6867
/// <summary>MCP server tools for {{serverName}} API.</summary>
69-
[McpServerToolType]
7068
public class {{serverName}}Tools(IHttpClientFactory httpClientFactory)
7169
{
7270
private static readonly JsonSerializerOptions JsonOptions = new()
@@ -109,8 +107,16 @@ Dictionary<string, int> methodNameCounts
109107
var hasBody = GetRequestBodyType(operation) != null;
110108
var bodyType = GetRequestBodyType(operation) ?? "object";
111109
var responseType = GetResponseType(operation);
110+
var errorType = GetErrorType(operation);
112111
var isDelete = operationType == HttpMethod.Delete;
113112
var resultResponseType = isDelete ? "Unit" : responseType;
113+
114+
// Build the full response type name for alias lookup
115+
// When error type is not "string", append it to response type (e.g., "KnowledgeBoxObjHTTPValidationError")
116+
var fullResponseType = errorType != "string"
117+
? $"{resultResponseType}{errorType}"
118+
: resultResponseType;
119+
114120
var summary = operation.Description ?? operation.Summary ?? $"{mcpToolName} operation";
115121

116122
return GenerateToolMethod(
@@ -120,7 +126,8 @@ Dictionary<string, int> methodNameCounts
120126
parameters,
121127
hasBody,
122128
bodyType,
123-
resultResponseType
129+
fullResponseType,
130+
errorType
124131
);
125132
}
126133

@@ -131,7 +138,8 @@ private static string GenerateToolMethod(
131138
List<McpParameterInfo> parameters,
132139
bool hasBody,
133140
string bodyType,
134-
string responseType
141+
string responseType,
142+
string errorType
135143
)
136144
{
137145
var methodParams = new List<string>();
@@ -159,7 +167,16 @@ string responseType
159167
foreach (var param in optionalParams)
160168
{
161169
methodParams.Add(FormatParameter(param));
162-
extensionCallArgs.Add(param.Name);
170+
171+
// For optional strings with default "", use null coalescing
172+
if (param.Type == "string?" && param.DefaultValue == "")
173+
{
174+
extensionCallArgs.Add($"{param.Name} ?? \"\"");
175+
}
176+
else
177+
{
178+
extensionCallArgs.Add(param.Name);
179+
}
163180
}
164181

165182
var paramDescriptions = string.Join(
@@ -187,20 +204,25 @@ string responseType
187204
return $$"""
188205
/// <summary>{{SanitizeDescription(summary)}}</summary>
189206
{{paramDescriptions}}
190-
[McpServerTool]
191207
[Description("{{SanitizeDescription(summary)}}")]
192208
public async Task<string> {{toolName}}({{methodParamsStr}})
193209
{
194210
var httpClient = httpClientFactory.CreateClient();
195-
var result = await httpClient.{{extensionMethodName}}({{extensionCallArgsStr}}CancellationToken.None);
211+
var result = await httpClient.{{extensionMethodName}}({{extensionCallArgsStr}});
196212
197213
return result switch
198214
{
199215
{{okAlias}}(var success) =>
200216
JsonSerializer.Serialize(success, JsonOptions),
201-
{{errorAlias}}(var error) =>
202-
$"Error: {error.StatusCode} - {error.Body}",
203-
_ => "Unknown error"
217+
{{errorAlias}}(var httpError) => httpError switch
218+
{
219+
HttpError<{{errorType}}>.ErrorResponseError err =>
220+
$"Error {err.StatusCode}: {JsonSerializer.Serialize(err.Body, JsonOptions)}",
221+
HttpError<{{errorType}}>.ExceptionError err =>
222+
$"Exception: {err.Exception.Message}",
223+
_ => "Unknown error"
224+
},
225+
_ => "Unknown result"
204226
};
205227
}
206228
""";
@@ -277,6 +299,7 @@ private static List<McpParameterInfo> GetParameters(
277299
}
278300

279301
// Make nullable if not required and no default value
302+
// For strings with default "", DON'T make nullable - pass the parameter and use ?? ""
280303
var makeNullable = !required && hasNoDefault && !baseType.EndsWith('?');
281304
var type = makeNullable ? $"{baseType}?" : baseType;
282305

@@ -330,6 +353,25 @@ private static string GetResponseType(OpenApiOperation operation)
330353
: "object";
331354
}
332355

356+
private static string GetErrorType(OpenApiOperation operation)
357+
{
358+
var errorResponse = operation.Responses?.FirstOrDefault(r =>
359+
r.Key.StartsWith('4') || r.Key.StartsWith('5')
360+
);
361+
362+
if (errorResponse?.Value?.Content == null)
363+
{
364+
return "string";
365+
}
366+
367+
var content = errorResponse.Value.Value.Content.FirstOrDefault();
368+
return content.Value?.Schema is OpenApiSchemaReference schemaRef
369+
? schemaRef.Reference.Id != null
370+
? CodeGenerationHelpers.ToPascalCase(schemaRef.Reference.Id)
371+
: "string"
372+
: "string";
373+
}
374+
333375
private static string GetExtensionMethodName(
334376
OpenApiOperation operation,
335377
HttpMethod operationType,

Samples/NucliaDbClient.McpServer/NucliaDbClient.McpServer.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
<ProjectReference Include="..\NucliaDbClient\NucliaDbClient.csproj" />
1515
</ItemGroup>
1616
<ItemGroup>
17-
<!-- Include the generated MCP tools -->
17+
<!-- Include the generated MCP tools and type aliases -->
1818
<Compile Include="..\NucliaDbClient\Generated\NucliaDbMcpTools.g.cs" Link="Generated\NucliaDbMcpTools.g.cs" />
19+
<Compile Include="..\NucliaDbClient\Generated\GlobalUsings.g.cs" Link="Generated\GlobalUsings.g.cs" />
1920
</ItemGroup>
2021
</Project>
Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using Microsoft.Extensions.DependencyInjection;
22
using Microsoft.Extensions.Hosting;
33
using ModelContextProtocol;
4+
using NucliaDB.Mcp;
45

56
var builder = Host.CreateApplicationBuilder(args);
67

@@ -9,19 +10,19 @@
910
Environment.GetEnvironmentVariable("NUCLIA_BASE_URL") ?? "http://localhost:8080/api/v1";
1011

1112
// Configure HttpClient with base URL
12-
builder.Services.AddHttpClient(
13-
Options.DefaultName,
14-
client =>
15-
{
16-
client.BaseAddress = new Uri(nucleaBaseUrl);
17-
client.Timeout = TimeSpan.FromSeconds(30);
18-
}
19-
);
13+
builder.Services.AddHttpClient(client =>
14+
{
15+
client.BaseAddress = new Uri(nucleaBaseUrl);
16+
client.Timeout = TimeSpan.FromSeconds(30);
17+
});
18+
19+
// Add the NucliaDB tools to DI
20+
builder.Services.AddSingleton<NucliaDbTools>();
2021

2122
// Add MCP server with NucliaDB tools
2223
builder.Services
2324
.AddMcpServer(new ServerInfo(name: "nuclia-db-mcp-server", version: "1.0.0"))
24-
.WithToolsFromAssembly();
25+
.WithTools<NucliaDbTools>();
2526

2627
var host = builder.Build();
27-
await host.RunAsync();
28+
await host.RunAsync().ConfigureAwait(false);

0 commit comments

Comments
 (0)