Skip to main content
Glama

DotnetFastMCP — Enterprise Security & Governance Gateway for MCP Servers

CI .NET 8.0 .NET 10.0 NuGet License GitHub

Enterprise security, governance, and observability layer for Model Context Protocol (MCP) servers in .NET — OAuth 2.0/OIDC authentication, per-tool MFA enforcement, OpenTelemetry instrumentation, and zero-config health checks. Built on ASP.NET Core.

🎯 Overview

DotnetFastMCP adds enterprise-grade security, governance, and observability to your MCP servers. While the core protocol is simple, running MCP tools in production requires OAuth 2.0/OIDC authentication, per-tool MFA enforcement, distributed tracing, and health monitoring — none of which the base protocol provides. DotnetFastMCP handles all of this with a clean attribute-based API on ASP.NET Core, plus a native .NET client library for consuming MCP servers.

⭐ Key Features

⚡ Zero-Boilerplate MCP Servers (NEW! v2.1.0)

  • ✅ Automatic DI Registration - Non-static tool, resource, and prompt classes scanned via WithComponentsFrom() are automatically registered as Transient services in the DI container. Zero manual builder.Services.AddTransient<T>() boilerplate.

  • ✅ Preserves Custom Lifetimes - Built on TryAddTransient semantics to honor custom Singleton or Scoped registrations without collision.

  • ✅ [McpDescription] Parameter Attributes - Annotate method parameters with rich descriptions emitted directly into JSON Schema inputSchema (tools/list), significantly enhancing LLM tool-calling accuracy.

  • ✅ Smart Schema Filtering - Automatically hides framework-injected types (McpContext, CancellationToken, ClaimsPrincipal, IMcpSession) from schema exposure so LLMs only see valid user inputs.

🚀 .NET 10 LTS & .NET 8 LTS Dual Support (v2.0.0)

  • ✅ Dual-Targeting - Ships both net8.0 and net10.0 binaries in a single package

  • ✅ Zero Breaking Changes - 100% backward compatible for existing .NET 8 applications

  • ✅ Modern Non-Blocking Async Streams - High-performance SSE parsing compliant with .NET 10 CA2024 rules

  • ✅ Comprehensive Test Matrix - Dual-targeted unit & in-memory integration tests covering positive & negative scenarios

Core Framework

  • ✅ Simple Attribute-Based API - Declare tools and resources with [McpTool] and [McpResource] attributes

  • ✅ First-Class Prompts Support - Define prompts with [McpPrompt] for LLM interaction templates

  • ✅ Automatic Component Discovery - Reflection-based scanning of assemblies

  • ✅ JSON-RPC 2.0 Compliant - Full protocol compliance with proper error handling

  • ✅ Flexible Parameter Binding - Supports both array and named parameters

  • ✅ Built on ASP.NET Core - Leverage the powerful ASP.NET Core hosting model

  • ✅ Production Ready - Comprehensive error handling and logging

  • ✅ Type-Safe - Full C# type system integration

🔐 Enterprise Authentication

  • ✅ 6 OAuth Providers Supported - Azure AD, Google, GitHub, Auth0, Okta, AWS Cognito

  • ✅ OAuth Proxy Built-In - Automatic Dynamic Client Registration (DCR) for non-DCR providers

  • ✅ JWT Token Verification - Automatic token validation with JWKS caching

  • ✅ Zero Configuration - Set environment variables and go

  • ✅ Sensible Defaults - Pre-configured scopes for common use cases

  • ✅ Fine-Grained Authorization - Protect tools with [Authorize] attribute

  • ✅ Claims-Based Access - Access user information from authenticated requests

  • ✅ MFA Support - Enforce Multi-Factor Authentication for sensitive tools

🔌 Native Client Library

  • ✅ McpClient - Type-safe .NET client for consuming any MCP server

  • ✅ Transport Agnostic - Support for both Stdio and SSE connections

  • ✅ Notification Handling - Events for real-time logs and progress

  • ✅ Tool Invocation - Clean CallToolAsync<T> API

🤖 LLM Integration

  • ✅ 8 LLM Providers - Ollama, OpenAI, Azure OpenAI, Anthropic Claude, Google Gemini, Cohere, Hugging Face, Deepseek

  • ✅ Latest Models (Feb 2026) - Claude Opus 4.6, Gemini 3 Pro/Flash, Command A, DeepSeek V3.2

  • ✅ Unified Interface - Single ILLMProvider API for all providers

  • ✅ Streaming Support - Real-time token streaming with IAsyncEnumerable<string>

  • ✅ Production-Ready - HttpClientFactory, Polly retry policies, connection pooling

  • ✅ Plug-and-Play - Simple extension methods: builder.AddAnthropicProvider()

📡 Observability

  • ✅ OpenTelemetry Integration - First-class metrics and distributed tracing

  • ✅ 5 Auto-Tracked Metrics - Tool invocations, duration, errors, prompt requests, resource reads

  • ✅ One-Line Setup - builder.WithTelemetry() — zero boilerplate

  • ✅ Exporter Agnostic - Plug in Prometheus, Application Insights, Grafana, Jaeger, or any OTLP backend

  • ✅ OTel Semantic Conventions - Standard tag names, exception events, span status

  • ✅ Zero Overhead When Disabled - Fully opt-in, no performance cost if unused

  • ✅ Stdio + HTTP - Metrics work across both transports

🏥 Health Checks & Diagnostics

  • ✅ Built-In Health Endpoint - GET /mcp/health exposed automatically

  • ✅ One-Line Setup - builder.WithHealthChecks() — no configuration required

  • ✅ Plug-In Custom Checks - Add any check as a simple lambda (no interfaces needed)

  • ✅ Parallel Execution - All checks run concurrently with per-check timeout

  • ✅ Standard HTTP Status Codes - 200 Healthy / 207 Degraded / 503 Unhealthy

  • ✅ Kubernetes & Docker Ready - Drop-in for liveness/readiness probes

  • ✅ Auto Server Diagnostics - Tool count, uptime, framework version included

  • ✅ Zero Overhead When Disabled - Fully opt-in, endpoint not registered unless configured

Related MCP server: MCPAuth

🚀 Quick Start

Installation

Install via NuGet Package Manager:

dotnet add package DotnetFastMCP --version 2.1.1

Or clone the repository:

git clone https://github.com/tekspry/DotnetFastMCP.git
cd DotnetFastMCP
dotnet build -c Release

Create Your First MCP Server

1. Define Your Tools

Tools can be written as instance classes with constructor dependency injection (auto-registered!) or static methods:

using FastMCP.Attributes;
using Microsoft.Extensions.Logging;

// Instance-based tool with constructor injection (automatically registered into DI via WithComponentsFrom!)
public class CalculatorTools
{
    private readonly ILogger<CalculatorTools> _logger;

    public CalculatorTools(ILogger<CalculatorTools> logger)
    {
        _logger = logger;
    }

    [McpTool(Description = "Performs mathematical addition")]
    public int Add(
        [McpDescription("The first number to add")] int a,
        [McpDescription("The second number to add")] int b)
    {
        _logger.LogInformation("Adding {A} + {B}", a, b);
        return a + b;
    }
}

// Static tools are also supported out of the box
public static class EchoTools
{
    [McpTool(Description = "Returns an echo of the input message")]
    public static string Echo(
        [McpDescription("Text message to echo back")] string message) => message;
}

2. Create Program.cs

using FastMCP.Hosting;
using FastMCP.Server;
using System.Reflection;

var server = new FastMCPServer("MyMcpServer");
var builder = McpServerBuilder.Create(server, args);
builder.WithComponentsFrom(Assembly.GetExecutingAssembly());

var app = builder.Build();
await app.RunMcpAsync(args);

Running the Example Server

cd examples/BasicServer
dotnet run

The server will start on http://localhost:5000.

🏆 Built With DotnetFastMCP

Real-world enterprise projects that demonstrate DotnetFastMCP in production:

👗 Fashion Accessory AI Marketing Pipeline

GitHub .NET 10.0 Google A2A

An enterprise-grade, distributed multimodal AI pipeline on .NET 10 LTS that automates the transformation of raw fashion accessory photographs into commercial marketing visuals and video content.

Architecture highlights:

  • 🏗️ Two-Dimensional AI Architecture — DotnetFastMCP (vertical MCP tool layer) + Google A2A Protocol (horizontal agent communication)

  • 🤖 5 DotnetFastMCP Servers — VisionMcpServer, PromptMcpServer, ImageMcpServer, InpaintingMcpServer, VideoMcpServer

  • 🎨 Multimodal AI — Gemini 3.1 Flash Image for dual-conditioning image synthesis, Kling AI for video generation

  • 🛡️ Multi-Tenant SaaS — Entity Framework Core global query filters with tenant isolation

  • ⏱️ Async Background Jobs — Hangfire with exponential backoff and rate-limit protection

OrchestratorAgent (A2A)
    ├── VisionAgent → VisionMcpServer  :5100  (extract_accessory_features)
    ├── CreativeAgent → PromptMcpServer :5200  (generate_image_prompts)
    ├── ImageAgent → ImageMcpServer    :5300  (generate_accessory_image)
    ├── InpaintingAgent → InpaintingMcpServer :5500  (inpaint_accessory)
    └── VideoAgent → VideoMcpServer    :5400  (generate_accessory_video)

🔗 View Repository →


📚 Architecture

Core Components

DotnetFastMCP/
├── src/
│   ├── FastMCP/
│   │   ├── Attributes/          # Component declaration attributes
│   │   ├── Client/              # 🔌 Client library implementation
│   │   ├── Hosting/             # Server hosting and middleware
│   │   ├── Protocol/            # JSON-RPC protocol implementation
│   │   ├── Server/              # FastMCPServer core class
│   │   └── FastMCP.csproj
│   └── FastMCP.CLI/             # Command-line utilities
├── examples/
│   └── BasicServer/             # Example MCP server implementation
├── tests/
│   └── McpIntegrationTest/      # Integration tests
├── LAUNCH_TESTS.ps1             # PowerShell test suite launcher
└── RUN_AND_TEST.ps1             # PowerShell integration test script

Project Structure

Project

Purpose

FastMCP

Core framework library

FastMCP.CLI

Command-line interface tools

BasicServer

Example MCP server implementation

McpIntegrationTest

Integration tests

ClientDemo

Example Client consuming BasicServer

🔧 Creating an MCP Server

1. Define Components

For better organization, split your components into multiple files (e.g., Tools.cs, Resources.cs). The framework will discover them automatically.

File: Tools.cs

using FastMCP.Attributes;
using Microsoft.AspNetCore.Authorization;
using System.Security.Claims;

public static class MyTools
{
    /// <summary>
    /// Public tool - no authentication required
    /// </summary>
    [McpTool]
    public static int Add(int a, int b) => a + b;

public static class Resources
{
    /// <summary>
    /// Protected tool - requires authentication
    /// </summary>
    [McpTool]
    [Authorize]
    public static object GetUserProfile(ClaimsPrincipal user)
    {
        return new
        {
            Name = user.Identity?.Name,
            Email = user.FindFirst("email")?.Value,
            IsAuthenticated = user.Identity?.IsAuthenticated
        };
    }
}

2. Configure Server with Authentication

using FastMCP.Hosting;
using FastMCP.Server;
using System.Reflection;

var mcpServer = new FastMCPServer(name: "My Secure MCP Server");
var builder = McpServerBuilder.Create(mcpServer, args);

// Add authentication (choose your provider)
builder.AddAzureAdTokenVerifier();  // or AddGoogleTokenVerifier(), AddGitHubTokenVerifier(), etc.

// Register tools
builder.WithComponentsFrom(Assembly.GetExecutingAssembly());

var app = builder.Build();
app.Urls.Add("http://localhost:5002");
await app.RunAsync();

3. Set Environment Variables

# Windows PowerShell
$env:FASTMCP_SERVER_AUTH_AZUREAD_TENANT_ID="your-tenant-id"
$env:FASTMCP_SERVER_AUTH_AZUREAD_CLIENT_ID="your-client-id"
$env:FASTMCP_SERVER_AUTH_AZUREAD_CLIENT_SECRET="your-client-secret"
# Linux/Mac
export FASTMCP_SERVER_AUTH_AZUREAD_TENANT_ID="your-tenant-id"
export FASTMCP_SERVER_AUTH_AZUREAD_CLIENT_ID="your-client-id"
export FASTMCP_SERVER_AUTH_AZUREAD_CLIENT_SECRET="your-client-secret"

4. Run and Test

dotnet run

Your server is now running with OAuth Proxy endpoints:

  • MCP endpoint: http://localhost:5002/mcp

  • OAuth authorization: http://localhost:5002/oauth/authorize

  • OAuth token: http://localhost:5002/oauth/token

  • Discovery: http://localhost:5002/.well-known/oauth-authorization-server

Stdio Mode

You can also run the server in Stdio mode (for local LLM clients):

dotnet run -- --stdio

Create an MCP Client

Connect to any MCP server using the C# Client Library:

using FastMCP.Client;
using FastMCP.Client.Transports;

// 1. Connect (via Stdio or SSE)
var transport = new StdioClientTransport("dotnet", "run --project examples/BasicServer -- --stdio");
await using var client = new McpClient(transport);
await client.ConnectAsync();

// 2. List & Call Tools
var tools = await client.ListToolsAsync();
var result = await client.CallToolAsync<int>("add_numbers", new { a = 10, b = 20 });

🔐 Authentication Providers

DotnetFastMCP supports 6 enterprise-grade OAuth providers out of the box:

Provider

Method

Use Case

Default Scopes

Azure AD

AddAzureAdTokenVerifier()

Enterprise apps, Microsoft 365

openid, profile, email, offline_access

Google

AddGoogleTokenVerifier()

Consumer apps, Google Workspace

openid, profile, email, userinfo.profile

GitHub

AddGitHubTokenVerifier()

Developer tools, repositories

read:user, user:email

Auth0

AddAuth0TokenVerifier()

Multi-tenant SaaS, custom identity

openid, profile, email, offline_access

Okta

AddOktaTokenVerifier()

Enterprise SSO, workforce identity

openid, profile, email, offline_access

AWS Cognito

AddAwsCognitoTokenVerifier()

AWS-native apps, user pools

openid, profile, email

Quick Setup Examples

builder.AddAzureAdTokenVerifier();

Environment Variables:

FASTMCP_SERVER_AUTH_AZUREAD_TENANT_ID=your-tenant-id
FASTMCP_SERVER_AUTH_AZUREAD_CLIENT_ID=your-client-id
FASTMCP_SERVER_AUTH_AZUREAD_CLIENT_SECRET=your-client-secret

Example: examples/Auth/AzureAdOAuth

builder.AddGoogleTokenVerifier();

Environment Variables:

FASTMCP_SERVER_AUTH_GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com
FASTMCP_SERVER_AUTH_GOOGLE_CLIENT_SECRET=your-client-secret

Example: examples/Auth/GoogleOAuth

builder.AddGitHubTokenVerifier();

Environment Variables:

FASTMCP_SERVER_AUTH_GITHUB_CLIENT_ID=your-github-client-id
FASTMCP_SERVER_AUTH_GITHUB_CLIENT_SECRET=your-github-client-secret

Example: examples/Auth/GitHubOAuth

The project includes a comprehensive PowerShell-based integration test suite that validates a running server end-to-end.

  1. Publish the server (from the root of the DotnetFastMCP project):

    dotnet publish -c Release -o ..\publish examples\BasicServer
  2. Run the tests: Open a PowerShell terminal and run the launcher script from the project root:

    .\LAUNCH_TESTS.ps1

This will open a new window, start the BasicServer, and run a series of tests covering all tools and resources, including error handling.

Example Manual Test

builder.AddAuth0TokenVerifier();

Environment Variables:

FASTMCP_SERVER_AUTH_AUTH0_DOMAIN=your-tenant.auth0.com
FASTMCP_SERVER_AUTH_AUTH0_AUDIENCE=https://your-api-identifier
FASTMCP_SERVER_AUTH_AUTH0_CLIENT_ID=your-client-id
FASTMCP_SERVER_AUTH_AUTH0_CLIENT_SECRET=your-client-secret

Example: examples/Auth/Auth0OAuth

builder.AddOktaTokenVerifier();

Environment Variables:

FASTMCP_SERVER_AUTH_OKTA_DOMAIN=dev-123456.okta.com
FASTMCP_SERVER_AUTH_OKTA_AUDIENCE=api://default
FASTMCP_SERVER_AUTH_OKTA_CLIENT_ID=your-client-id
FASTMCP_SERVER_AUTH_OKTA_CLIENT_SECRET=your-client-secret

Example: examples/Auth/OktaOAuth

builder.AddAwsCognitoTokenVerifier();

Environment Variables:

FASTMCP_SERVER_AUTH_AWSCOGNITO_USER_POOL_ID=us-east-1_XXXXXXXXX
FASTMCP_SERVER_AUTH_AWSCOGNITO_REGION=us-east-1
FASTMCP_SERVER_AUTH_AWSCOGNITO_CLIENT_ID=your-app-client-id
FASTMCP_SERVER_AUTH_AWSCOGNITO_CLIENT_SECRET=your-app-client-secret
FASTMCP_SERVER_AUTH_AWSCOGNITO_DOMAIN=myapp.auth.us-east-1.amazoncognito.com

Example: examples/Auth/AwsCognitoOAuth

📚 Architecture

Project Structure

DotnetFastMCP/
├── src/
│   └── FastMCP/
│       ├── Attributes/              # Component declaration attributes
│       ├── Authentication/          # 🔐 OAuth providers & token verification
│       │   ├── Providers/          # Azure AD, Google, GitHub, Auth0, Okta, AWS
│       │   ├── Proxy/              # OAuth Proxy for DCR
│       │   └── Verification/       # JWT token validation
│       ├── Hosting/                 # Server hosting and middleware
│       ├── Protocol/                # JSON-RPC protocol implementation
│       └── Server/                  # FastMCPServer core class
├── examples/
│   ├── BasicServer/                 # Simple MCP server
│   └── Auth/                        # 🔐 Authentication examples
│       ├── AzureAdOAuth/           # Azure AD example
│       ├── GoogleOAuth/            # Google OAuth example
│       ├── GitHubOAuth/            # GitHub OAuth example
│       ├── Auth0OAuth/             # Auth0 example
│       ├── OktaOAuth/              # Okta example
│       └── AwsCognitoOAuth/        # AWS Cognito example
└── tests/
    └── McpIntegrationTest/          # Integration tests

Project Structure (Client)

The FastMCP framework now includes a complete client implementation in src/FastMCP/Client.

graph TD
    App[Your App] -->|Uses| Client[McpClient]
    Client -->|IClientTransport| Trans[Transport Layer]
    Trans -->|Stdio| Local[Local Process]
    Trans -->|SSE/HTTP| Remote[Remote Server]

Authentication Flow

sequenceDiagram
    participant Client
    participant MCP Server
    participant OAuth Provider
    
    Client->>MCP Server: Request with Bearer Token
    MCP Server->>Token Verifier: Validate Token
    Token Verifier->>OAuth Provider: Fetch JWKS (if needed)
    OAuth Provider-->>Token Verifier: Public Keys
    Token Verifier-->>MCP Server: Validated Claims
    MCP Server-->>Client: Protected Resource

🔧 Creating an MCP Server

Basic Server (No Authentication)

using FastMCP.Hosting;
using FastMCP.Server;
using System.Reflection;

var mcpServer = new FastMCPServer(name: "My MCP Server");
var builder = McpServerBuilder.Create(mcpServer, args);

builder.WithComponentsFrom(Assembly.GetExecutingAssembly());

var app = builder.Build();
await app.RunAsync();

Secure Server (With Authentication)

using FastMCP.Hosting;
using FastMCP.Server;
using System.Reflection;

var mcpServer = new FastMCPServer(name: "My Secure MCP Server");
var builder = McpServerBuilder.Create(mcpServer, args);

// Add authentication - automatically configures OAuth Proxy
builder.AddAzureAdTokenVerifier();  // or any other provider

builder.WithComponentsFrom(Assembly.GetExecutingAssembly());

var app = builder.Build();
app.Urls.Add("http://localhost:5002");
await app.RunMcpAsync(args);

Protected Tools

using FastMCP.Attributes;
using Microsoft.AspNetCore.Authorization;
using System.Security.Claims;

public static class SecureTools
{
    /// <summary>
    /// Public tool - anyone can call
    /// </summary>
    [McpTool]
    public static string Echo(string message) => message;

    /// <summary>
    /// Protected tool - requires valid OAuth token
    /// </summary>
    [McpTool]
    [Authorize]
    public static object GetUserInfo(ClaimsPrincipal user)
    {
        return new
        {
            Name = user.Identity?.Name ?? "Unknown",
            Email = user.FindFirst("email")?.Value ?? "Not available",
            IsAuthenticated = user.Identity?.IsAuthenticated ?? false,
            Claims = user.Claims.Select(c => new { c.Type, c.Value }).ToList()
        };
    }

    /// <summary>
    /// Role-based authorization
    /// </summary>
    [McpTool]
    [Authorize(Roles = "Admin")]
    public static string AdminOnly() => "Admin access granted";
}

📡 JSON-RPC Protocol

Prompts

Prompts allow servers to provide templates that LLMs can use.

using FastMCP.Attributes;
using FastMCP.Protocol;

public static class MyPrompts
{
    [McpPrompt("analyze_code")]
    public static GetPromptResult Analyze(string code)
    {
        return new GetPromptResult
        {
            Description = "Analyze the given code",
            Messages = new List<PromptMessage>
            {
                new PromptMessage 
                { 
                    Role = "user", 
                    Content = new { type = "text", text = $"Please analyze this code:\n{code}" } 
                }
            }
        };
    }
}

Calling Tools

Public Tool (No Auth):

POST /mcp
{
  "jsonrpc": "2.0",
  "method": "Echo",
  "params": ["Hello World"],
  "id": 1
}

Protected Tool (With Auth):

POST /mcp
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGc...

{
  "jsonrpc": "2.0",
  "method": "GetUserInfo",
  "params": [],
  "id": 2
}

🧪 Testing

Run All Tests

dotnet test

Test Authentication Flow

Each authentication example includes a comprehensive .rest file for testing:

# Open in VS Code with REST Client extension
code examples/Auth/AzureAdOAuth/azure-ad-auth-tests.rest

Test files include:

  • ✅ Discovery endpoints

  • ✅ Public tool tests

  • ✅ Protected tool tests (should fail without auth)

  • ✅ OAuth authorization flow

  • ✅ Token exchange

  • ✅ Provider-specific API calls

📖 Documentation

Guides & Features

Complete Authentication Guide

See MFA Support Guide for enforcing Multi-Factor Authentication on sensitive tools, and the individual provider README files under examples/Auth/ for detailed OAuth setup instructions.

Example Projects

Example

Description

Port

BasicServer

Simple MCP server with Auto-DI & [McpDescription]

5000

HealthChecksDemo

🏥 Health monitoring & diagnostics demo

5000

TelemetryDemo

📡 OpenTelemetry metrics & tracing demo

5000

AzureAdOAuth

Azure AD authentication example

5002

GoogleOAuth

Google OAuth example

5000

GitHubOAuth

GitHub OAuth example

5001

Auth0OAuth

Auth0 authentication example

5005

OktaOAuth

Okta authentication example

5007

AwsCognitoOAuth

AWS Cognito example

5006

🏗️ Advanced Features

⚡ Automatic DI Registration & [McpDescription] (NEW! v2.1.0)

DotnetFastMCP 2.1 makes authoring production MCP servers completely zero-boilerplate by pairing automatic Dependency Injection with LLM-grade parameter schemas:

  1. Zero-Config DI: Non-static tool, resource, and prompt classes scanned with WithComponentsFrom() are automatically registered as Transient into ASP.NET Core DI. No more manual builder.Services.AddTransient<OrderTools>() lines.

  2. Preserves Custom Lifetimes: Built on TryAddTransient semantics, so any class explicitly registered as Singleton or Scoped in builder.Services retains its desired lifetime.

  3. [McpDescription] for Parameters: Annotate tool parameters with descriptions that are exposed directly in the JSON Schema inputSchema (tools/list), giving LLMs exact semantic context and eliminating hallucinated arguments.

  4. Framework Parameter Exclusion: Types such as McpContext, CancellationToken, ClaimsPrincipal, and IMcpSession are automatically filtered out from the public schema.

public class OrderTools
{
    private readonly IOrderRepository _repository;
    private readonly ILogger<OrderTools> _logger;

    // Injected automatically via ASP.NET Core DI
    public OrderTools(IOrderRepository repository, ILogger<OrderTools> logger)
    {
        _repository = repository;
        _logger = logger;
    }

    [McpTool(Description = "Retrieves order status by order identifier and country")]
    public async Task<string> GetOrderStatus(
        [McpDescription("Unique order ID, e.g. ORD-98765")] string orderId,
        [McpDescription("Two-letter country code, e.g. US, UK")] string countryCode = "US",
        CancellationToken ct = default) // Framework types are automatically excluded from the tool schema
    {
        _logger.LogInformation("Fetching order {OrderId} in {Country}", orderId, countryCode);
        return await _repository.GetStatusAsync(orderId, countryCode, ct);
    }
}
// Program.cs - Zero boilerplate registration!
var server = new FastMCPServer("OrderServer");
var builder = McpServerBuilder.Create(server, args);

// Automatically registers OrderTools as Transient, discovers [McpTool], and configures schemas!
builder.WithComponentsFrom(Assembly.GetExecutingAssembly());

var app = builder.Build();
await app.RunMcpAsync(args);

🏥 Health Checks & Diagnostics (v1.15.0)

FastMCP ships with a built-in production health check endpoint. Enable with one line and plug in any custom check as a simple lambda.

using FastMCP.Health;

// Zero-config — exposes GET /mcp/health automatically
builder.WithHealthChecks();

// With custom checks (database, LLM provider, memory, etc.)
builder.WithHealthChecks(checks =>
{
    checks.AddCheck("memory", () =>
        GC.GetTotalMemory(false) < 500_000_000L); // sync: < 500 MB

    checks.AddAsyncCheck("database", async ct =>
        await dbContext.Database.CanConnectAsync(ct));

    checks.AddAsyncCheck("llm_provider", async ct =>
        await llmProvider.IsHealthyAsync(ct));
});

Response JSON (HTTP 200 — Healthy):

{
  "status": "Healthy",
  "timestamp": "2026-04-19T20:00:00Z",
  "checks": [
    { "name": "mcp_server",   "status": "Healthy", "durationMs": 0 },
    { "name": "memory",       "status": "Healthy", "durationMs": 0.1 },
    { "name": "database",     "status": "Healthy", "durationMs": 4.9 },
    { "name": "llm_provider", "status": "Healthy", "durationMs": 22.3 }
  ],
  "diagnostics": {
    "serverName": "my-mcp-server",
    "frameworkVersion": "1.15.0.0",
    "toolCount": 12,
    "uptimeSeconds": 3721.4
  }
}

HTTP status code mapping:

Status

HTTP Code

Meaning

Healthy

200

All checks passed

Degraded

207

Server up, ≥1 check timed out

Unhealthy

503

≥1 check failed or threw

Kubernetes liveness / readiness probe:

livenessProbe:
  httpGet:
    path: /mcp/health
    port: 5000
  initialDelaySeconds: 15
  periodSeconds: 30
readinessProbe:
  httpGet:
    path: /mcp/health
    port: 5000
  periodSeconds: 10

See Health Checks Guide for full documentation, including Docker Compose, Azure Container Apps, per-check timeout configuration, unit testing patterns, and complete validation examples.


📡 Observability — OpenTelemetry (v1.14.0)

FastMCP ships with built-in OpenTelemetry instrumentation. Enable with one line and connect to any backend.

using FastMCP.Telemetry;
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;

// 1. Enable FastMCP telemetry (one line)
builder.WithTelemetry(t =>
{
    t.ServiceName    = "my-mcp-server";
    t.EnableMetrics  = true;
    t.EnableTracing  = true;
});

// 2. Configure your exporter of choice
builder.Services.AddOpenTelemetry()
    .WithMetrics(m =>
    {
        m.AddMcpInstrumentation();  // FastMCP extension method
        m.AddPrometheusExporter();  // or AddConsoleExporter(), AddOtlpExporter()
    })
    .WithTracing(t =>
    {
        t.AddMcpInstrumentation();  // FastMCP extension method
        t.AddOtlpExporter();        // or AddJaeger(), AddZipkin()
    });

Metrics automatically tracked:

Metric

Type

Tag

Description

mcp.tool.invocations

Counter

tool.name

Total tool calls

mcp.tool.duration

Histogram (ms)

tool.name

Tool execution time

mcp.tool.errors

Counter

tool.name

Failed tool calls

mcp.prompt.requests

Counter

—

Prompt template requests

mcp.resource.reads

Counter

—

Resource read requests

Validate with dotnet-counters (no exporter needed):

dotnet-counters monitor -n YourAppName --counters FastMCP

See Observability Guide for full documentation, including production exporter setup, distributed tracing details, and real request/response validation examples.


Middleware Interception

Middleware allows you to intercept and modify JSON-RPC messages (requests and responses) flowing through the server pipeline. This is useful for logging, validation, modification, or custom monitoring.

  1. Define Middleware: Implement IMcpMiddleware.

  2. Register Middleware: Use builder.AddMcpMiddleware<T>().

public class LoggingMiddleware : IMcpMiddleware
{
    public async Task<JsonRpcResponse> InvokeAsync(McpMiddlewareContext context, McpMiddlewareDelegate next, CancellationToken ct)
    {
        Console.Error.WriteLine($"[LOG] Incoming: {context.Request.Method}");
        
        // Pass to next handler
        var response = await next(context, ct);
        
        Console.Error.WriteLine($"[LOG] Completed. Error: {response.Error != null}");
        return response;
    }
}

// In Program.cs:
builder.AddMcpMiddleware<LoggingMiddleware>();

Server Composition (NEW!)

Mount other MCP servers into your main server instantiation. This supports a "Micro-MCP" architecture where you can compose a robust agent from smaller, focused modules.

// 1. Create Sub-Server (e.g. GitHub Tools)
var githubServer = new FastMCPServer("GitHub");
// ... register tools ...

// 2. Import into Main Server with "gh" prefix
builder.AddServer(githubServer, prefix: "gh");

// Result:
// The client sees tools named: "gh_create_issue", "gh_get_repo", etc.

MFA Support (NEW!)

Enforce Multi-Factor Authentication for sensitive tools.

[McpTool("transfer_funds")]
[AuthorizeMcpTool(RequireMfa = true)]
public static string TransferFunds()
{
    return "Transferred!";
}
  • MFA Check: Verifies amr claim contains mfa.

  • Security: Provides granular protection for critical operations.

Storage Abstraction (NEW!)

FastMCP now includes a built-in state persistence layer. Tools can request McpContext to access IMcpStorage.

[McpTool]
public static async Task<string> SetValue(string key, string value, McpContext context)
{
    await context.Storage.SetAsync(key, value);
    return "Saved!";
}

The default implementation is In-Memory, but you can swap it for Redis, SQL, or File storage:

builder.AddMcpStorage<MyRedisStorage>();

LLM Integration (NEW!)

FastMCP includes a powerful LLM integration system with 8 providers supporting the latest models (Feb 2026).

Quick Setup

using FastMCP.AI;

// Option 1: Local (Ollama)
builder.AddOllamaProvider(options =>
{
    options.BaseUrl = "http://localhost:11434";
    options.DefaultModel = "llama3.1:8b";
});

// Option 2: Cloud (Anthropic Claude Opus 4.6 - Latest)
builder.AddAnthropicProvider(options =>
{
    options.ApiKey = Environment.GetEnvironmentVariable("ANTHROPIC_API_KEY")!;
    options.DefaultModel = "claude-opus-4.6"; // 1M context, Feb 2026
});

// Option 3: Google Gemini 3
builder.AddGeminiProvider(options =>
{
    options.ApiKey = Environment.GetEnvironmentVariable("GEMINI_API_KEY")!;
    options.DefaultModel = "gemini-3-flash"; // Fast, cost-effective
});

Use in Tools

public class AITools
{
    private readonly ILLMProvider _llm;

    public AITools(ILLMProvider llm) => _llm = llm;

    [McpTool("generate_story")]
    public async Task<string> GenerateStory(string topic)
    {
        return await _llm.GenerateAsync(
            $"Write a story about {topic}",
            new LLMGenerationOptions
            {
                SystemPrompt = "You are a creative storyteller.",
                Temperature = 0.8,
                MaxTokens = 500
            });
    }

    [McpTool("stream_response")]
    public async IAsyncEnumerable<string> StreamResponse(string prompt)
    {
        await foreach (var token in _llm.StreamAsync(prompt))
        {
            yield return token;
        }
    }
}

Supported Providers (Feb 2026)

Provider

Extension Method

Latest Model

Best For

Ollama

AddOllamaProvider()

llama3.1:8b

Local, privacy, offline

OpenAI

AddOpenAIProvider()

gpt-4-turbo

Production, function calling

Azure OpenAI

AddAzureOpenAIProvider()

gpt-4

Enterprise, compliance

Anthropic

AddAnthropicProvider()

claude-opus-4.6

Deep reasoning, 1M context

Google Gemini

AddGeminiProvider()

gemini-3-flash

Multimodal, high-volume

Cohere

AddCohereProvider()

command-a

Enterprise RAG, agents

Hugging Face

AddHuggingFaceProvider()

Any model

Open-source, flexibility

Deepseek

AddDeepseekProvider()

deepseek-v3.2

Cost-effective, reasoning

See LLM Integration Guide for complete documentation.

Background Tasks (NEW!)

FastMCP allows tools to fire-and-forget long running operations using RunInBackground.

[McpTool]
public static async Task<string> ProcessFile(string file, McpContext context)
{
    await context.RunInBackground(async (ct) => 
    {
        // This runs without blocking the client
        await HeavyProcessing(file, ct);
    });

    return "Processing started!";
}

Icons Support (NEW!)

Enhance the user interface of clients by providing icons for your server and tools.

// Server Icon
server.Icon = "https://myserver.com/logo.png";

// Tool Icon
[McpTool(Icon = "https://myserver.com/tools/calc.png")]
public static int Add(int a, int b) => a + b;

Binary Content Support (NEW!)

Return rich content like Images from your tools and prompts.

[McpTool]
public static CallToolResult GetSnapshot()
{
    return new CallToolResult 
    {
        Content = new List<ContentItem> 
        {
            new ImageContent { Data = "base64...", MimeType = "image/png" }
        }
    };
}

OAuth Proxy

DotnetFastMCP includes a built-in OAuth Proxy that provides:

  • ✅ Dynamic Client Registration (DCR) - Automatic client registration for MCP clients

  • ✅ Authorization Code Flow - Full OAuth 2.0 authorization code flow with PKCE

  • ✅ Token Management - Automatic token exchange, refresh, and revocation

  • ✅ Discovery Endpoints - RFC 8414 compliant OAuth discovery

Automatically Available Endpoints:

  • /.well-known/oauth-authorization-server - OAuth server metadata

  • /oauth/authorize - Authorization endpoint

  • /oauth/token - Token endpoint

  • /oauth/register - Dynamic client registration

  • /oauth/userinfo - User information endpoint

Custom Scopes

Override default scopes for any provider:

builder.AddAzureAdTokenVerifier(new AzureAdAuthOptions
{
    RequiredScopes = new[] { "openid", "profile", "email", "User.Read", "Calendars.Read" }
});

Multiple Authentication Schemes

// Support multiple providers simultaneously
builder.AddAzureAdTokenVerifier();
builder.AddGoogleTokenVerifier();
builder.AddGitHubTokenVerifier();

🔐 Security Best Practices

Development

  • ✅ Use environment variables for secrets

  • ✅ Never commit credentials to source control

  • ✅ Use .env files for local development

  • ✅ Test with short-lived tokens

Production

  • ✅ Use HTTPS for all communication

  • ✅ Store secrets in Azure Key Vault / AWS Secrets Manager

  • ✅ Enable MFA for OAuth providers

  • ✅ Implement rate limiting

  • ✅ Monitor authentication logs

  • ✅ Use separate app registrations per environment

  • ✅ Validate token scopes match required permissions

📦 NuGet Package

Install from NuGet (when published):

dotnet add package DotnetFastMCP

🤝 Contributing

Contributions are welcome! Please:

  1. Fork the repository

  2. Create a feature branch (git checkout -b feature/amazing-feature)

  3. Commit your changes (git commit -m 'Add amazing feature')

  4. Push to the branch (git push origin feature/amazing-feature)

  5. Open a Pull Request

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🔗 Resources

Official Documentation

Framework Documentation

Provider Documentation

🐛 Issues & Support

For bug reports and feature requests, please use GitHub Issues.

✨ What's New

v2.1.1 - Client Deserialization Patch (Latest - Sep 2026)

  • 🐛 Fix McpClient.CallToolAsync<TResult> Deserialization - Resolved deserialization error where calling tools returning primitive types (int, bool, double, etc.), string, or custom POCO models threw JSON conversion errors (fixes #37).

  • 📦 Automatic Envelope Unwrapping - Correctly unwraps and deserializes the inner payload from CallToolResult.Content while maintaining full MCP specification compliance.

  • ⚡ Direct Envelope Overload - Added non-generic client.CallToolAsync("toolName", args) returning raw CallToolResult directly.

  • 🧪 Comprehensive Test Coverage - Added unit and integration test suites validating primitive, string, and complex model deserialization.

v2.1.0 - Zero-Boilerplate MCP Servers (Sep 2026)

  • ⚡ Automatic DI Registration - Non-static classes containing [McpTool], [McpResource], or [McpPrompt] are automatically registered as Transient during WithComponentsFrom(). No manual builder.Services.AddTransient<T>() boilerplate required.

  • 🛡️ Lifespan Safety - Implemented via TryAddTransient so custom Singleton or Scoped registrations configured in builder.Services are never overwritten.

  • 📝 [McpDescription] Parameter Attribute - Tool parameters annotated with [McpDescription] have their documentation automatically rendered into JSON Schema properties.<param>.description in tools/list.

  • 🧼 Clean Schema Generation - Framework types (McpContext, CancellationToken, ClaimsPrincipal, IMcpSession) are automatically excluded from tools/list schema definitions, preventing LLM argument errors.

  • 🧪 57 Tests Passing - Dual-targeted unit and integration test suite passing across both .NET 8 LTS and .NET 10 LTS.

  • 📖 Comprehensive Guide - Detailed documentation in docs/auto-di-registration-guide.md.

v2.0.0 - .NET 10 LTS & .NET 8 LTS Dual Support (Aug 2026)

  • 🚀 Dual-Targeting - Ships both net8.0 and net10.0 binaries in a single package.

  • 🔒 Zero Breaking Changes - 100% backward compatible for existing .NET 8 applications.

  • ⚡ High-Performance Non-Blocking Async Streams - SSE parser compliant with .NET 10 CA2024 rules.

  • 🧪 Comprehensive Test Matrix - Unit & in-memory integration tests running across both target frameworks.

v1.15.0 - Health Checks & Diagnostics (Apr 2026)

  • 🏥 Built-In Health Endpoint - GET /mcp/health exposed with a single builder.WithHealthChecks() call

  • 🔌 Lambda-Based Custom Checks - Add any check (database, llm, memory, external API) as a simple lambda with no interface to implement

  • ⚡ Parallel Execution - All checks run concurrently; a slow check never delays a fast one

  • ⏱️ Per-Check Timeout - Configurable MaxResponseTimeMs; hanging checks reported as Degraded, not left blocking

  • 🌐 Standard HTTP Status Codes - 200 Healthy / 207 Degraded / 503 Unhealthy; understood natively by Kubernetes, load balancers, and APM tools

  • 📊 Auto Server Diagnostics - Automatically includes server name, framework version, tool/resource/prompt counts, and uptime

  • 🛡️ Always Reachable - Endpoint marked AllowAnonymous() so infrastructure probes bypass authentication

  • 🎯 Zero Overhead - Fully opt-in; endpoint is not registered unless WithHealthChecks() is called

  • 📚 Comprehensive Docs - Full guide covering Kubernetes, Docker, ACA probes, validation walkthrough, and unit tests

v1.14.0 - OpenTelemetry Observability (Mar 2026)

  • 📡 OpenTelemetry Integration - First-class metrics and distributed tracing built in

  • 📊 5 Auto-Tracked Metrics - Tool invocations, duration, errors, prompt requests, resource reads

  • ✨ One-Line Setup - builder.WithTelemetry() with zero boilerplate

  • 🔌 Exporter Agnostic - Works with Prometheus, App Insights, Grafana, Jaeger, any OTLP backend

  • 🔍 Distributed Tracing - Full span support with OTel semantic convention tags

  • 🛡️ PII Safe Defaults - Tool inputs never logged unless explicitly enabled

  • 🎯 Zero Overhead - Fully opt-in, no cost when not used

  • 📚 Comprehensive Docs - Full guide with validation examples and production checklist

v1.13.0 - LLM Integration (Feb 2026)

  • 🤖 8 LLM Providers - Ollama, OpenAI, Azure OpenAI, Anthropic Claude, Google Gemini, Cohere, Hugging Face, Deepseek

  • ✨ Latest Models - Claude Opus 4.6 (1M context), Gemini 3 Pro/Flash, Command A, DeepSeek V3.2

  • 🔌 Unified Interface - Single ILLMProvider API for all providers

  • 📡 Streaming Support - Real-time token streaming with IAsyncEnumerable<string>

  • 🏗️ Production-Ready - HttpClientFactory, Polly retry policies, connection pooling

  • 🎯 Plug-and-Play - Simple registration: builder.AddAnthropicProvider()

  • 📚 Comprehensive Docs - Complete integration guide with examples

v1.12.0 - MFA Support

  • 🛡️ MFA Enforcement - Require mfa AMR claim for sensitive tools

  • ✅ Granular Control - Enable per-tool using [AuthorizeMcpTool(RequireMfa=true)]

  • 🔒 Enhanced Security - Standards-based multi-factor authentication check

v1.11.0 - Binary Content Support

  • ✅ Polymorphic Content - Support for mixed Text and Image responses

  • ✅ Image Support - Return Base64 encoded images from tools

  • ✅ Multimodal Prompts - Embbed images in prompts for LLM context

v1.10.0 - Icons Support

  • ✅ Server Icons - Define a brand icon for your MCP server

  • ✅ Tool/Resource Icons - Visually distinguish capabilities

  • ✅ UI/UX Enhancement - Enable richer client experiences

v1.9.0 - Background Tasks

  • ✅ Fire-and-Forget - Offload long-running operations from tools

  • ✅ Non-Blocking - Return immediate responses to clients

  • ✅ Hosted Service - Built-in queuing mechanism using Channels

v1.8.0 - Storage Abstractions

  • ✅ State Persistence - Tools can now persist data via McpContext.Storage

  • ✅ Pluggable Backends - Swap in Redis/SQL/File storage easily

  • ✅ In-Memory Default - Zero-config built-in storage for development

v1.7.0 - Server Composition

  • ✅ Server Composition - Mount other MCP servers as modules (Micro-MCPs)

  • ✅ Namespacing - Automatically prefix imported tools (e.g., github_createIssue)

  • ✅ Zero-Overhead - High-performance internal dictionary routing (O(1))

v1.6.0 - Middleware Interception

  • ✅ Middleware Pipeline - Intercept and modify requests/responses

  • ✅ Critical Fixes - Resolved Stdio transport initialization deadlocks

  • ✅ Builder API - Easy registration with AddMcpMiddleware<T>

v1.5.0 - Native Client Library

  • ✅ McpClient - Type-safe .NET client for consuming MCP servers

  • ✅ Transport Agnostic - Support for both Stdio and SSE connections

  • ✅ Notification Handling - Events for real-time logs and progress

v1.4.0 - Server-Sent Events (SSE)

  • ✅ SSE Transport - Real-time server-to-client streaming transport

  • ✅ Async Notifications - Push logs and progress updates to HTTP clients

v1.3.0 - Context & Interaction

  • ✅ Context System - McpContext injection for logging and progress

  • ✅ IMcpSession - Transport-agnostic interaction abstraction

v1.2.0 - Protocol Discovery

  • ✅ Dynamic Discovery - Auto-discovery of Tools, Resources, and Prompts

  • ✅ Prompts/List - Full support for prompt templates

v1.1.0 - Stdio Transport & Authentication

  • ✅ Stdio Transport - Initial support for stdio communication

  • 🔐 6 OAuth Providers - Azure AD, Google, GitHub, Auth0, Okta, AWS Cognito

  • 🔐 OAuth Proxy - Built-in DCR support

v1.0.0 - Core Framework

  • ✅ Attribute-based API

  • ✅ JSON-RPC 2.0 compliance

  • ✅ ASP.NET Core integration

Made with ❤️ by the DotnetFastMCP team

⭐ Star this repo if you find it useful!

Available Tools

3 tools
add_numbersB

Adds two integers and returns their sum

ParametersJSON Schema
NameRequiredDescriptionDefault
aYesThe first integer operand
bYesThe second integer operand

TDQS

B3.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the burden. It does disclose the return value (the sum) and the operand types, which is useful, but it says nothing about overflow behavior, non-integer input handling, or error conditions for a pure arithmetic operation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single sentence with zero filler, front-loading the action and stating the result. Nothing is wasted and nothing essential is omitted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter pure arithmetic tool with no output schema, the definition covers the action, input types, and return value adequately. Only minor gaps remain around edge-case behavior, which is likely out of scope for this simplicity level.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% – both parameters 'a' and 'b' are documented as 'first/second integer operand'. The description only restates that two integers are involved, adding no meaning beyond the schema. Baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (adds), the exact resource (two integers), and the outcome (their sum), so an agent knows precisely what it does. Sibling tools (greet_user, TestContext) are unrelated, so differentiation isn't relevant, but the definition stands on its own clearly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no guidance on when to use this tool, no prerequisites, and no mention of alternatives or edge cases. The usage is self-evident from the purpose, but nothing in the text explicitly directs the agent.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

greet_userA

Returns a personalised greeting for the given user name

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYesThe name of the user to greet, e.g. 'Alice'
styleNoThe greeting style: 'formal' or 'casual' (default: casual)

TDQS

A3.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. 'Returns' usefully implies a side-effect-free read with no auth or mutation concerns, but the description never mentions that the 'style' parameter changes the output form, nor anything about the return format.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single sentence with no filler, front-loading the return value and the input it depends on. Nothing could be trimmed without losing meaning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a trivial two-parameter tool with no output schema and full schema coverage, the description is sufficient to call it correctly. The only gap is that the effect of 'style' on the greeting is left entirely to the schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so both parameters are already documented in the schema (including the 'formal'/'casual' options and default). The description adds nothing beyond restating the 'name' input, which is the baseline 3 case.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('Returns') and resource ('a personalised greeting') scoped to an input ('the given user name'). An agent can distinguish it immediately from the unrelated siblings add_numbers and TestContext.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by the trivial nature of the tool (greet a user by name), but the description offers no explicit when-to-use, when-not, or alternative routing guidance. Nothing is misleading, but nothing is stated either.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

TestContextC

Processes input with progress reporting via McpContext

ParametersJSON Schema
NameRequiredDescriptionDefault
inputYesThe input string to process

TDQS

C2.1/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full disclosure burden. It only reveals that progress is reported via McpContext; it says nothing about whether the input is mutated, whether the call is side-effecting, whether it is safe to retry, or what the caller observes.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

It is a single front-loaded sentence with no filler, but the terseness reflects under-specification rather than economy — the one clause about McpContext is the only content and it is jargon.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no annotations, no output schema, and a generic verb, an agent cannot tell what this tool produces or when it is appropriate. For a tool whose entire contract is otherwise unstructured, the description is far too thin.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the single parameter is documented as "The input string to process." The description adds no format, constraint, or example beyond the schema, so baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose2/5

Does the description clearly state what the tool does and how it differs from similar tools?

"Processes input" restates the tool name (TestContext/input) without naming what processing actually occurs — no verb+resource specificity. "Progress reporting via McpContext" is an implementation detail rather than a description of observable behavior, and it does nothing to distinguish this tool from siblings like add_numbers or greet_user.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines1/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives no when-to-use guidance, no prerequisites, and never mentions the sibling tools or any alternative. An agent has no basis for choosing this over add_numbers or greet_user.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 3 tool updatesv0.1.0
    • First observedadd_numbers
    • First observedgreet_user
    • First observedTestContext

TDQS

C2.6/5.0

Scored across 3 tools

Disambiguation4/5

Each tool has a distinct purpose: add_numbers does addition, greet_user does greetings, and TestContext handles context-based processing. Only TestContext has a somewhat vague name, but its description makes it distinguishable.

Naming Consistency2/5

Naming is inconsistent: add_numbers and greet_user use snake_case, while TestContext uses PascalCase and lacks a verb. The mix of conventions reduces predictability.

Tool Count2/5

With only 3 tools, the server appears under-scoped for a general-purpose MCP server. This is too few to cover common operations, making the set feel thin.

Completeness1/5

The tools are trivial and unrelated, with no clear domain or CRUD operations. There is no meaningful coverage of any real-world use case, leaving significant gaps.

Maintenance

ActivityMaintained
ResponsivenessResponsive

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    A comprehensive Model Context Protocol server template that implements HTTP-based transport with OAuth proxy for third-party authorization servers like Auth0, enabling AI tools to securely connect while supporting Dynamic Application Registration.
    13 npm
    7
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    A self-hostable OAuth 2.0 server designed for the Model-Context-Protocol (MCP) that enables you to secure your MCP applications with a robust implementation you control.
    3,059 npm
    113
    ISC
  • A
    license
    Not graded
    quality
    C
    maintenance
    Easiest framework for building MCP servers with automatic discovery of tools, prompts, and resources, plus enterprise-grade authentication and telemetry.
    840
    Apache 2.0