Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion ModelContextProtocol.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@
<Project Path="samples/AspNetCoreMcpPerSessionTools/AspNetCoreMcpPerSessionTools.csproj" />
<Project Path="samples/AspNetCoreMcpServer/AspNetCoreMcpServer.csproj" />
<Project Path="samples/ChatWithTools/ChatWithTools.csproj" />
<Project Path="samples/EverythingServer/EverythingServer.csproj" />
<Project Path="samples/EverythingServer.Core/EverythingServer.Core.csproj" />
<Project Path="samples/EverythingServer.Http/EverythingServer.Http.csproj" />
<Project Path="samples/EverythingServer.Stdio/EverythingServer.Stdio.csproj" />
<Project Path="samples/InMemoryTransport/InMemoryTransport.csproj" />
<Project Path="samples/ProtectedMcpClient/ProtectedMcpClient.csproj" />
<Project Path="samples/ProtectedMcpServer/ProtectedMcpServer.csproj" />
Expand Down
13 changes: 13 additions & 0 deletions samples/EverythingServer.Core/EverythingServer.Core.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\ModelContextProtocol\ModelContextProtocol.csproj" />
</ItemGroup>

</Project>
149 changes: 149 additions & 0 deletions samples/EverythingServer.Core/EverythingServerExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
using EverythingServer.Core.Prompts;
using EverythingServer.Core.Resources;
using EverythingServer.Core.Tools;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
using ModelContextProtocol;
using ModelContextProtocol.Protocol;
using ModelContextProtocol.Server;
using System.Collections.Concurrent;

namespace EverythingServer.Core;

/// <summary>
/// Extension methods for configuring the EverythingServer MCP handlers.
/// </summary>
public static class EverythingServerExtensions
{
/// <summary>
/// Adds all the tools, prompts, resources, and handlers for the EverythingServer.
/// </summary>
/// <param name="builder">The MCP server builder.</param>
/// <param name="subscriptions">The subscriptions dictionary to use for managing resource subscriptions.</param>
/// <returns>The MCP server builder for chaining.</returns>
public static IMcpServerBuilder AddEverythingMcpHandlers(
this IMcpServerBuilder builder,
ConcurrentDictionary<string, ConcurrentDictionary<string, byte>> subscriptions)
{
return builder
.WithTools<AddTool>()
.WithTools<AnnotatedMessageTool>()
.WithTools<EchoTool>()
.WithTools<LongRunningTool>()
.WithTools<PrintEnvTool>()
.WithTools<SampleLlmTool>()
.WithTools<TinyImageTool>()
.WithPrompts<ComplexPromptType>()
.WithPrompts<SimplePromptType>()
.WithResources<SimpleResourceType>()
.WithSubscribeToResourcesHandler(async (ctx, ct) =>
{
var sessionId = ctx.Server.SessionId ?? "stdio";

if (!subscriptions.TryGetValue(sessionId, out var sessionSubscriptions))
{
sessionSubscriptions = new ConcurrentDictionary<string, byte>();
subscriptions[sessionId] = sessionSubscriptions;
}

if (ctx.Params?.Uri is { } uri)
{
sessionSubscriptions.TryAdd(uri, 0);

await ctx.Server.SampleAsync([
new ChatMessage(ChatRole.System, "You are a helpful test server"),
new ChatMessage(ChatRole.User, $"Resource {uri}, context: A new subscription was started"),
],
options: new ChatOptions
{
MaxOutputTokens = 100,
Temperature = 0.7f,
},
cancellationToken: ct);
}

return new EmptyResult();
})
.WithUnsubscribeFromResourcesHandler(async (ctx, ct) =>
{
var sessionId = ctx.Server.SessionId ?? "stdio";

if (subscriptions.TryGetValue(sessionId, out var sessionSubscriptions))
{
if (ctx.Params?.Uri is { } uri)
{
sessionSubscriptions.TryRemove(uri, out _);
}
}
return new EmptyResult();
})
.WithCompleteHandler(async (ctx, ct) =>
{
var exampleCompletions = new Dictionary<string, IEnumerable<string>>
{
{ "style", ["casual", "formal", "technical", "friendly"] },
{ "temperature", ["0", "0.5", "0.7", "1.0"] },
{ "resourceId", ["1", "2", "3", "4", "5"] }
};

if (ctx.Params is not { } @params)
{
throw new NotSupportedException($"Params are required.");
}

var @ref = @params.Ref;
var argument = @params.Argument;

if (@ref is ResourceTemplateReference rtr)
{
var resourceId = rtr.Uri?.Split("/").Last();

if (resourceId is null)
{
return new CompleteResult();
}

var values = exampleCompletions["resourceId"].Where(id => id.StartsWith(argument.Value));

return new CompleteResult
{
Completion = new Completion { Values = [.. values], HasMore = false, Total = values.Count() }
};
}

if (@ref is PromptReference pr)
{
if (!exampleCompletions.TryGetValue(argument.Name, out IEnumerable<string>? value))
{
throw new NotSupportedException($"Unknown argument name: {argument.Name}");
}

var values = value.Where(value => value.StartsWith(argument.Value));
return new CompleteResult
{
Completion = new Completion { Values = [.. values], HasMore = false, Total = values.Count() }
};
}

throw new NotSupportedException($"Unknown reference type: {@ref.Type}");
})
.WithSetLoggingLevelHandler(async (ctx, ct) =>
{
if (ctx.Params?.Level is null)
{
throw new McpProtocolException("Missing required argument 'level'", McpErrorCode.InvalidParams);
}

// The SDK updates the LoggingLevel field of the IMcpServer

await ctx.Server.SendNotificationAsync("notifications/message", new
{
Level = "debug",
Logger = "test-server",
Data = $"Logging level set to {ctx.Params.Level}",
}, cancellationToken: ct);

return new EmptyResult();
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using ModelContextProtocol.Protocol;
using ModelContextProtocol.Server;

namespace EverythingServer;
namespace EverythingServer.Core;

public class LoggingUpdateMessageSender(McpServer server) : BackgroundService
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using EverythingServer.Tools;
using EverythingServer.Core.Tools;
using Microsoft.Extensions.AI;
using ModelContextProtocol.Server;
using System.ComponentModel;

namespace EverythingServer.Prompts;
namespace EverythingServer.Core.Prompts;

[McpServerPromptType]
public class ComplexPromptType
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using ModelContextProtocol.Server;
using System.ComponentModel;

namespace EverythingServer.Prompts;
namespace EverythingServer.Core.Prompts;

[McpServerPromptType]
public class SimplePromptType
Expand Down
42 changes: 42 additions & 0 deletions samples/EverythingServer.Core/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# EverythingServer.Core

This is the core library containing all the shared MCP server handlers (tools, prompts, resources) used by both the HTTP and stdio implementations of the EverythingServer sample.

## What's Inside

This library contains:

- **Tools**: Various example tools demonstrating different MCP capabilities
- `AddTool`: Simple addition operation
- `AnnotatedMessageTool`: Returns annotated messages
- `EchoTool`: Echoes input back to the client
- `LongRunningTool`: Demonstrates long-running operations with progress reporting
- `PrintEnvTool`: Prints environment variables
- `SampleLlmTool`: Example LLM sampling integration
- `TinyImageTool`: Returns image content

- **Prompts**: Example prompts showing argument handling
- `SimplePromptType`: Basic prompt example
- `ComplexPromptType`: Prompt with multiple arguments

- **Resources**: Example resources with subscriptions
- `SimpleResourceType`: Dynamic resource with URI template matching

- **Background Services**: For managing subscriptions and logging
- `SubscriptionMessageSender`: Sends periodic updates to subscribed resources
- `LoggingUpdateMessageSender`: Sends periodic logging messages at different levels

- **Extension Method**: `AddEverythingMcpHandlers` to configure all handlers in one call

## Usage

Reference this project from your MCP server implementation (HTTP or stdio) and call the extension method:

```csharp
builder.Services
.AddMcpServer()
.WithHttpTransport() // or WithStdioServerTransport()
.AddEverythingMcpHandlers(subscriptions);
```

See the `EverythingServer.Http` and `EverythingServer.Stdio` projects for complete examples.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using ModelContextProtocol.Protocol;

namespace EverythingServer;
namespace EverythingServer.Core;

static class ResourceGenerator
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using ModelContextProtocol.Server;
using System.ComponentModel;

namespace EverythingServer.Resources;
namespace EverythingServer.Core.Resources;

[McpServerResourceType]
public class SimpleResourceType
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
using System.Collections.Concurrent;
using Microsoft.Extensions.Hosting;
using ModelContextProtocol;
using ModelContextProtocol.Server;

internal class SubscriptionMessageSender(McpServer server, ConcurrentDictionary<string, byte> subscriptions) : BackgroundService
namespace EverythingServer.Core;

public class SubscriptionMessageSender(McpServer server, ConcurrentDictionary<string, byte> subscriptions) : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using ModelContextProtocol.Server;
using System.ComponentModel;

namespace EverythingServer.Tools;
namespace EverythingServer.Core.Tools;

[McpServerToolType]
public class AddTool
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using ModelContextProtocol.Server;
using System.ComponentModel;

namespace EverythingServer.Tools;
namespace EverythingServer.Core.Tools;

[McpServerToolType]
public class AnnotatedMessageTool
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using ModelContextProtocol.Server;
using System.ComponentModel;

namespace EverythingServer.Tools;
namespace EverythingServer.Core.Tools;

[McpServerToolType]
public class EchoTool
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using ModelContextProtocol.Server;
using System.ComponentModel;

namespace EverythingServer.Tools;
namespace EverythingServer.Core.Tools;

[McpServerToolType]
public class LongRunningTool
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using System.ComponentModel;
using System.Text.Json;

namespace EverythingServer.Tools;
namespace EverythingServer.Core.Tools;

[McpServerToolType]
public class PrintEnvTool
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using ModelContextProtocol.Server;
using System.ComponentModel;

namespace EverythingServer.Tools;
namespace EverythingServer.Core.Tools;

[McpServerToolType]
public class SampleLlmTool
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using ModelContextProtocol.Server;
using System.ComponentModel;

namespace EverythingServer.Tools;
namespace EverythingServer.Core.Tools;

[McpServerToolType]
public class TinyImageTool
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

<ItemGroup>
<ProjectReference Include="..\..\src\ModelContextProtocol.AspNetCore\ModelContextProtocol.AspNetCore.csproj" />
<ProjectReference Include="..\EverythingServer.Core\EverythingServer.Core.csproj" />
</ItemGroup>

</Project>
Loading
Loading