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
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Platforms>AnyCPU;x64</Platforms>
<ProduceReferenceAssembly>False</ProduceReferenceAssembly>
</PropertyGroup>

<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebugType>embedded</DebugType>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<DebugType>embedded</DebugType>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DebugType>embedded</DebugType>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<DebugType>embedded</DebugType>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\MCPSharp\MCPSharp.csproj" />
</ItemGroup>


<Target Name="PreBuild" BeforeTargets="PreBuildEvent">

</Target>

</Project>
40 changes: 40 additions & 0 deletions MCPSharp.Example.BackgroundServer/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System;
using System.Threading.Tasks;
using MCPSharp;
using MCPSharp.Model;
using MCPSharp.Model.Schemas;

namespace MCPSharp.Example.BackgroundServer;

/// <summary>
/// This example demonstrates how to run an MCP server in a background thread using MCPServerHost.
/// The server is started asynchronously and will continue to run even after the main thread exits.
/// </summary>
public class Program
{
/// <summary>
/// The main entry point for the MCP server example.
/// </summary>
public static async Task Main()
{
// Start server in background thread
await using var server = await MCPServerHost.StartAsync("BackgroundServer", "1.0.0");

// Add a sample tool
MCPServer.AddToolHandler(new Tool()
{
Name = "greet",
Description = "A simple greeting tool",
InputSchema = new InputSchema
{
Type = "object",
Required = ["name"],
Properties = new Dictionary<string, ParameterSchema>{
{"name", new ParameterSchema{Type="string", Description="Name to greet"}}
}
}
}, (string name) => $"Hello, {name}! (from background server)");

await Task.Delay(-1);
}
}
38 changes: 37 additions & 1 deletion MCPSharp.sln
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@


Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.12.35707.178
Expand All @@ -13,54 +13,90 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MCPSharp.Example.Import", "
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MCPSharp.Example.OllamaChatCLI", "MCPSharp.Example.OllamaChatCLI\MCPSharp.Example.OllamaChatCLI.csproj", "{73FD6F85-CCEE-4D80-8E8B-154F94511DD2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MCPSharp.Example.BackgroundServer", "MCPSharp.Example.BackgroundServer\MCPSharp.Example.BackgroundServer.csproj", "{DD4ABB3D-89CF-4C9C-AF62-94CEC22B779D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1A4D1BB7-973C-49AD-9564-F45D5B7703EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1A4D1BB7-973C-49AD-9564-F45D5B7703EF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1A4D1BB7-973C-49AD-9564-F45D5B7703EF}.Debug|x64.ActiveCfg = Debug|x64
{1A4D1BB7-973C-49AD-9564-F45D5B7703EF}.Debug|x64.Build.0 = Debug|x64
{1A4D1BB7-973C-49AD-9564-F45D5B7703EF}.Debug|x86.ActiveCfg = Debug|Any CPU
{1A4D1BB7-973C-49AD-9564-F45D5B7703EF}.Debug|x86.Build.0 = Debug|Any CPU
{1A4D1BB7-973C-49AD-9564-F45D5B7703EF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1A4D1BB7-973C-49AD-9564-F45D5B7703EF}.Release|Any CPU.Build.0 = Release|Any CPU
{1A4D1BB7-973C-49AD-9564-F45D5B7703EF}.Release|x64.ActiveCfg = Release|x64
{1A4D1BB7-973C-49AD-9564-F45D5B7703EF}.Release|x64.Build.0 = Release|x64
{1A4D1BB7-973C-49AD-9564-F45D5B7703EF}.Release|x86.ActiveCfg = Release|Any CPU
{1A4D1BB7-973C-49AD-9564-F45D5B7703EF}.Release|x86.Build.0 = Release|Any CPU
{7FF8D00E-9DBA-435D-80E4-4F1F7E860CDA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7FF8D00E-9DBA-435D-80E4-4F1F7E860CDA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7FF8D00E-9DBA-435D-80E4-4F1F7E860CDA}.Debug|x64.ActiveCfg = Debug|Any CPU
{7FF8D00E-9DBA-435D-80E4-4F1F7E860CDA}.Debug|x64.Build.0 = Debug|Any CPU
{7FF8D00E-9DBA-435D-80E4-4F1F7E860CDA}.Debug|x86.ActiveCfg = Debug|Any CPU
{7FF8D00E-9DBA-435D-80E4-4F1F7E860CDA}.Debug|x86.Build.0 = Debug|Any CPU
{7FF8D00E-9DBA-435D-80E4-4F1F7E860CDA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7FF8D00E-9DBA-435D-80E4-4F1F7E860CDA}.Release|Any CPU.Build.0 = Release|Any CPU
{7FF8D00E-9DBA-435D-80E4-4F1F7E860CDA}.Release|x64.ActiveCfg = Release|Any CPU
{7FF8D00E-9DBA-435D-80E4-4F1F7E860CDA}.Release|x64.Build.0 = Release|Any CPU
{7FF8D00E-9DBA-435D-80E4-4F1F7E860CDA}.Release|x86.ActiveCfg = Release|Any CPU
{7FF8D00E-9DBA-435D-80E4-4F1F7E860CDA}.Release|x86.Build.0 = Release|Any CPU
{EAAC2C18-8A35-4CED-B407-582170A7A0F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EAAC2C18-8A35-4CED-B407-582170A7A0F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EAAC2C18-8A35-4CED-B407-582170A7A0F9}.Debug|x64.ActiveCfg = Debug|Any CPU
{EAAC2C18-8A35-4CED-B407-582170A7A0F9}.Debug|x64.Build.0 = Debug|Any CPU
{EAAC2C18-8A35-4CED-B407-582170A7A0F9}.Debug|x86.ActiveCfg = Debug|Any CPU
{EAAC2C18-8A35-4CED-B407-582170A7A0F9}.Debug|x86.Build.0 = Debug|Any CPU
{EAAC2C18-8A35-4CED-B407-582170A7A0F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EAAC2C18-8A35-4CED-B407-582170A7A0F9}.Release|Any CPU.Build.0 = Release|Any CPU
{EAAC2C18-8A35-4CED-B407-582170A7A0F9}.Release|x64.ActiveCfg = Release|Any CPU
{EAAC2C18-8A35-4CED-B407-582170A7A0F9}.Release|x64.Build.0 = Release|Any CPU
{EAAC2C18-8A35-4CED-B407-582170A7A0F9}.Release|x86.ActiveCfg = Release|Any CPU
{EAAC2C18-8A35-4CED-B407-582170A7A0F9}.Release|x86.Build.0 = Release|Any CPU
{6B4E00C3-6CAF-4493-9A4D-9AE602FA9E00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6B4E00C3-6CAF-4493-9A4D-9AE602FA9E00}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6B4E00C3-6CAF-4493-9A4D-9AE602FA9E00}.Debug|x64.ActiveCfg = Debug|Any CPU
{6B4E00C3-6CAF-4493-9A4D-9AE602FA9E00}.Debug|x64.Build.0 = Debug|Any CPU
{6B4E00C3-6CAF-4493-9A4D-9AE602FA9E00}.Debug|x86.ActiveCfg = Debug|Any CPU
{6B4E00C3-6CAF-4493-9A4D-9AE602FA9E00}.Debug|x86.Build.0 = Debug|Any CPU
{6B4E00C3-6CAF-4493-9A4D-9AE602FA9E00}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6B4E00C3-6CAF-4493-9A4D-9AE602FA9E00}.Release|Any CPU.Build.0 = Release|Any CPU
{6B4E00C3-6CAF-4493-9A4D-9AE602FA9E00}.Release|x64.ActiveCfg = Release|Any CPU
{6B4E00C3-6CAF-4493-9A4D-9AE602FA9E00}.Release|x64.Build.0 = Release|Any CPU
{6B4E00C3-6CAF-4493-9A4D-9AE602FA9E00}.Release|x86.ActiveCfg = Release|Any CPU
{6B4E00C3-6CAF-4493-9A4D-9AE602FA9E00}.Release|x86.Build.0 = Release|Any CPU
{73FD6F85-CCEE-4D80-8E8B-154F94511DD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{73FD6F85-CCEE-4D80-8E8B-154F94511DD2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{73FD6F85-CCEE-4D80-8E8B-154F94511DD2}.Debug|x64.ActiveCfg = Debug|Any CPU
{73FD6F85-CCEE-4D80-8E8B-154F94511DD2}.Debug|x64.Build.0 = Debug|Any CPU
{73FD6F85-CCEE-4D80-8E8B-154F94511DD2}.Debug|x86.ActiveCfg = Debug|Any CPU
{73FD6F85-CCEE-4D80-8E8B-154F94511DD2}.Debug|x86.Build.0 = Debug|Any CPU
{73FD6F85-CCEE-4D80-8E8B-154F94511DD2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{73FD6F85-CCEE-4D80-8E8B-154F94511DD2}.Release|Any CPU.Build.0 = Release|Any CPU
{73FD6F85-CCEE-4D80-8E8B-154F94511DD2}.Release|x64.ActiveCfg = Release|Any CPU
{73FD6F85-CCEE-4D80-8E8B-154F94511DD2}.Release|x64.Build.0 = Release|Any CPU
{73FD6F85-CCEE-4D80-8E8B-154F94511DD2}.Release|x86.ActiveCfg = Release|Any CPU
{73FD6F85-CCEE-4D80-8E8B-154F94511DD2}.Release|x86.Build.0 = Release|Any CPU
{DD4ABB3D-89CF-4C9C-AF62-94CEC22B779D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DD4ABB3D-89CF-4C9C-AF62-94CEC22B779D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DD4ABB3D-89CF-4C9C-AF62-94CEC22B779D}.Debug|x64.ActiveCfg = Debug|x64
{DD4ABB3D-89CF-4C9C-AF62-94CEC22B779D}.Debug|x64.Build.0 = Debug|x64
{DD4ABB3D-89CF-4C9C-AF62-94CEC22B779D}.Debug|x86.ActiveCfg = Debug|Any CPU
{DD4ABB3D-89CF-4C9C-AF62-94CEC22B779D}.Debug|x86.Build.0 = Debug|Any CPU
{DD4ABB3D-89CF-4C9C-AF62-94CEC22B779D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DD4ABB3D-89CF-4C9C-AF62-94CEC22B779D}.Release|Any CPU.Build.0 = Release|Any CPU
{DD4ABB3D-89CF-4C9C-AF62-94CEC22B779D}.Release|x64.ActiveCfg = Release|x64
{DD4ABB3D-89CF-4C9C-AF62-94CEC22B779D}.Release|x64.Build.0 = Release|x64
{DD4ABB3D-89CF-4C9C-AF62-94CEC22B779D}.Release|x86.ActiveCfg = Release|Any CPU
{DD4ABB3D-89CF-4C9C-AF62-94CEC22B779D}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
40 changes: 27 additions & 13 deletions MCPSharp/Core/MCPServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,22 @@ namespace MCPSharp
/// </summary>
public class MCPServer
{
private static readonly MCPServer _instance = new();
private static MCPServer _instance = new();

/// <summary>
/// Gets the current server instance.
/// </summary>
public static MCPServer Instance => _instance;
private readonly JsonRpc _rpc;
private readonly Stream StandardOutput;

private readonly ToolManager _toolManager = new()
{
ToolChangeNotification = () => { if (EnableToolChangeNotification)
_= _instance._rpc.InvokeWithParameterObjectAsync("notifications/tools/list_changed", null);}
ToolChangeNotification = () =>
{
if (EnableToolChangeNotification)
_ = _instance._rpc.InvokeWithParameterObjectAsync("notifications/tools/list_changed", null);
}
};

private readonly ResourceManager _resouceManager = new();
Expand Down Expand Up @@ -53,14 +61,17 @@ public class MCPServer
private MCPServer()
{
Implementation = new();
_target = new(_toolManager, _resouceManager, Implementation);
_target = new(_toolManager, _resouceManager, Implementation);
Console.SetOut(RedirectedOutput);
_rpc = new JsonRpc(new NewLineDelimitedMessageHandler(new StdioTransportPipe(),
new SystemTextJsonFormatter() {
JsonSerializerOptions = new System.Text.Json.JsonSerializerOptions {
PropertyNameCaseInsensitive = true,
PropertyNamingPolicy = System.Text.Json.JsonNamingPolicy.CamelCase
} }), _target);
_rpc = new JsonRpc(new NewLineDelimitedMessageHandler(new StdioTransportPipe(),
new SystemTextJsonFormatter()
{
JsonSerializerOptions = new System.Text.Json.JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
PropertyNamingPolicy = System.Text.Json.JsonNamingPolicy.CamelCase
}
}), _target);

_rpc.StartListening();
}
Expand All @@ -76,7 +87,7 @@ private MCPServer()
/// Registers a tool with the server.
/// </summary>
/// <typeparam name="T"></typeparam>
public static void Register<T>() where T : class, new()=>_ = _instance.RegisterAsync<T>();
public static void Register<T>() where T : class, new() => _ = _instance.RegisterAsync<T>();
public async Task RegisterAsync<T>() where T : class, new() { _toolManager.Register<T>(); _resouceManager.Register<T>(); }
public static void AddToolHandler(Tool tool, Delegate func) => _instance._toolManager.AddToolHandler(new ToolHandler(tool, func.Method));

Expand Down Expand Up @@ -141,8 +152,11 @@ private async Task StartPingThreadAsync()
}
}
}

internal void Dispose()

/// <summary>
/// Disposes the server and releases all resources.
/// </summary>
public void Dispose()
{
_cancellationTokenSource.Cancel();
_rpc.Dispose();
Expand Down
Loading