MCP Server Generation
Generate Model Context Protocol (MCP) servers from OpenAPI specifications, enabling Claude Code to interact with your REST APIs.
What is MCP?
The Model Context Protocol allows AI assistants to:
- Call external APIs as "tools"
- Access data sources
- Perform actions on behalf of users
With RestClient.Net's MCP generator, your REST APIs become Claude Code tools automatically.
Prerequisites
- An OpenAPI 3.x specification
- Generated RestClient.Net client (see OpenAPI Generator)
- RestClient.Net.McpGenerator.Cli tool
Installation
Install the MCP generator CLI:
dotnet tool install -g RestClient.Net.McpGenerator.Cli
Quick Start
Step 1: Generate the REST Client
First, generate the RestClient.Net client from your OpenAPI spec:
restclient-gen \
--input api.yaml \
--output Generated \
--namespace MyApi.Client
Step 2: Generate MCP Server
Generate the MCP server code:
restclient-mcp \
--openapi api.yaml \
--output McpServer \
--namespace MyApi.Mcp \
--server-name MyApiServer \
--client-namespace MyApi.Client
Step 3: Create MCP Server Project
Create a new console project:
dotnet new console -n MyApi.McpServer
cd MyApi.McpServer
dotnet add package Microsoft.Extensions.Hosting
dotnet add package RestClient.Net
Add the generated files and create the host:
// Program.cs
using Microsoft.Extensions.Hosting;
using MyApi.Mcp;
var host = Host.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
services.AddHttpClient("api", client =>
{
client.BaseAddress = new Uri("https://api.example.com");
});
services.AddMcpServer<MyApiServer>();
})
.Build();
await host.RunAsync();
Step 4: Configure Claude Code
Add to your Claude Code configuration (.claude/mcp.json):
{
"mcpServers": {
"myapi": {
"command": "dotnet",
"args": ["run", "--project", "path/to/MyApi.McpServer"]
}
}
}
CLI Options
| Option | Description |
|---|---|
--openapi |
OpenAPI spec URL or file path (required) |
--output |
Output directory (default: McpServer) |
--namespace |
C# namespace for generated code (required) |
--server-name |
MCP server class name (required) |
--client-namespace |
Namespace of the generated REST client |
--tags |
Include only these operation tags (comma-separated) |
--exclude-tags |
Exclude these operation tags (comma-separated) |
Examples
Include only specific operations:
restclient-mcp \
--openapi api.yaml \
--output McpServer \
--namespace MyApi.Mcp \
--server-name MyApiServer \
--client-namespace MyApi.Client \
--tags "Users,Search"
Exclude admin operations:
restclient-mcp \
--openapi api.yaml \
--output McpServer \
--namespace MyApi.Mcp \
--server-name MyApiServer \
--client-namespace MyApi.Client \
--exclude-tags "Admin,Internal"
Generated Code Structure
McpServer/
├── Tools/
│ ├── GetUserTool.cs
│ ├── CreateUserTool.cs
│ └── ...
├── MyApiServer.cs
└── ServiceCollectionExtensions.cs
Generated Tool Example
// McpServer/Tools/GetUserTool.cs
namespace MyApi.Mcp.Tools;
public class GetUserTool(IHttpClientFactory httpClientFactory) : IMcpTool
{
public string Name => "get_user";
public string Description => "Retrieves a user by their ID";
public ToolParameters Parameters => new()
{
Properties = new Dictionary<string, ToolParameter>
{
["userId"] = new()
{
Type = "string",
Description = "The unique identifier of the user",
Required = true
}
}
};
public async Task<ToolResult> ExecuteAsync(
JsonElement arguments,
CancellationToken ct)
{
var userId = arguments.GetProperty("userId").GetString()!;
var client = httpClientFactory.CreateClient("api");
var result = await client.GetUserByIdAsync(userId, ct);
return result switch
{
OkUser(var user) => ToolResult.Success(JsonSerializer.Serialize(user)),
ErrorUser(var error) => ToolResult.Error($"Failed: {error}"),
};
}
}
Authentication
For authenticated APIs, configure the HttpClient:
services.AddHttpClient("api", client =>
{
client.BaseAddress = new Uri("https://api.example.com");
})
.AddHttpMessageHandler<AuthenticationHandler>();
services.AddTransient<AuthenticationHandler>();
Environment Variables
Use environment variables for secrets:
public class AuthenticationHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
var token = Environment.GetEnvironmentVariable("API_TOKEN");
request.Headers.Authorization =
new AuthenticationHeaderValue("Bearer", token);
return base.SendAsync(request, cancellationToken);
}
}
Configure in Claude Code:
{
"mcpServers": {
"myapi": {
"command": "dotnet",
"args": ["run", "--project", "MyApi.McpServer"],
"env": {
"API_TOKEN": "your-api-token"
}
}
}
}
Tool Naming
The generator creates tool names from operation IDs:
| Operation ID | Tool Name |
|---|---|
getUserById |
get_user_by_id |
createUser |
create_user |
deleteUserById |
delete_user_by_id |
Best Practices
- Filter operations - Only expose necessary tools to Claude
- Use descriptive operation summaries - These become tool descriptions
- Secure sensitive operations - Use authentication and authorization
- Handle errors gracefully - Return meaningful error messages
- Test tools manually - Verify behavior before Claude uses them
Debugging
Run the MCP server locally to test:
cd MyApi.McpServer
dotnet run
Use the MCP inspector to test tools:
npx @anthropic-ai/mcp-inspector
Next Steps
- Exhaustion Analyzer - Compile-time exhaustiveness
- Advanced Usage - Retry policies and middleware
- API Reference - Complete documentation