Skip to content

Commit e667b1d

Browse files
committed
added webscoket support to MCP
1 parent 968970b commit e667b1d

File tree

7 files changed

+882
-0
lines changed

7 files changed

+882
-0
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net8.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<ProjectReference Include="../../src/SuperSocket.WebSocket.Server/SuperSocket.WebSocket.Server.csproj" />
12+
<ProjectReference Include="../../src/SuperSocket.MCP/SuperSocket.MCP.csproj" />
13+
<ProjectReference Include="../../src/SuperSocket.Server/SuperSocket.Server.csproj" />
14+
</ItemGroup>
15+
16+
</Project>
Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
using Microsoft.Extensions.DependencyInjection;
2+
using Microsoft.Extensions.Hosting;
3+
using Microsoft.Extensions.Logging;
4+
using SuperSocket.MCP;
5+
using SuperSocket.MCP.Abstractions;
6+
using SuperSocket.MCP.Extensions;
7+
using SuperSocket.MCP.Models;
8+
using SuperSocket.WebSocket.Server;
9+
10+
namespace McpWebSocketServer
11+
{
12+
/// <summary>
13+
/// MCP Server implementation that communicates over WebSocket connections
14+
/// This uses the SuperSocket.MCP library's command system for proper MCP protocol handling
15+
/// </summary>
16+
class Program
17+
{
18+
static async Task Main(string[] args)
19+
{
20+
Console.WriteLine("Starting MCP WebSocket Server...");
21+
Console.WriteLine("This server provides MCP functionality over WebSocket connections.");
22+
Console.WriteLine("Connect using: ws://localhost:8080 with sub-protocol 'mcp'");
23+
Console.WriteLine("----------------------------------------");
24+
25+
var host = WebSocketHostBuilder.Create(args)
26+
.ConfigureServices((hostCtx, services) =>
27+
{
28+
// Register MCP services
29+
services.AddSingleton<IMcpHandlerRegistry, McpHandlerRegistry>();
30+
services.AddSingleton<McpServerInfo>(new McpServerInfo
31+
{
32+
Name = "SuperSocket MCP WebSocket Server",
33+
Version = "1.0.0",
34+
ProtocolVersion = "2024-11-05"
35+
});
36+
37+
// Register sample tools
38+
services.AddSingleton<IMcpToolHandler, EchoToolHandler>();
39+
services.AddSingleton<IMcpToolHandler, MathToolHandler>();
40+
services.AddSingleton<IMcpToolHandler, TimeToolHandler>();
41+
services.AddSingleton<IMcpToolHandler, WebInfoToolHandler>();
42+
})
43+
.UseMcp("mcp") // Use MCP with "mcp" sub-protocol - this handles all the command routing
44+
.ConfigureLogging((hostCtx, loggingBuilder) =>
45+
{
46+
loggingBuilder.AddConsole();
47+
loggingBuilder.SetMinimumLevel(LogLevel.Information);
48+
})
49+
.Build();
50+
51+
await host.RunAsync();
52+
}
53+
}
54+
55+
/// <summary>
56+
/// Simple echo tool that returns the input message
57+
/// </summary>
58+
public class EchoToolHandler : IMcpToolHandler
59+
{
60+
public Task<McpTool> GetToolDefinitionAsync()
61+
{
62+
return Task.FromResult(new McpTool
63+
{
64+
Name = "echo",
65+
Description = "Echo back the input message via WebSocket",
66+
InputSchema = new
67+
{
68+
type = "object",
69+
properties = new
70+
{
71+
message = new { type = "string", description = "Message to echo back" }
72+
},
73+
required = new[] { "message" }
74+
}
75+
});
76+
}
77+
78+
public Task<McpToolResult> ExecuteAsync(Dictionary<string, object> arguments)
79+
{
80+
var message = arguments.TryGetValue("message", out var msg) ? msg.ToString() : "Hello WebSocket!";
81+
return Task.FromResult(new McpToolResult
82+
{
83+
Content = new List<McpContent>
84+
{
85+
new McpContent { Type = "text", Text = $"WebSocket Echo: {message}" }
86+
}
87+
});
88+
}
89+
}
90+
91+
/// <summary>
92+
/// Math tool that performs basic arithmetic operations
93+
/// </summary>
94+
public class MathToolHandler : IMcpToolHandler
95+
{
96+
public Task<McpTool> GetToolDefinitionAsync()
97+
{
98+
return Task.FromResult(new McpTool
99+
{
100+
Name = "math",
101+
Description = "Perform basic math operations (add, subtract, multiply, divide)",
102+
InputSchema = new
103+
{
104+
type = "object",
105+
properties = new
106+
{
107+
operation = new { type = "string", description = "The operation to perform", @enum = new[] { "add", "subtract", "multiply", "divide" } },
108+
a = new { type = "number", description = "First number" },
109+
b = new { type = "number", description = "Second number" }
110+
},
111+
required = new[] { "operation", "a", "b" }
112+
}
113+
});
114+
}
115+
116+
public Task<McpToolResult> ExecuteAsync(Dictionary<string, object> arguments)
117+
{
118+
try
119+
{
120+
var operation = arguments.TryGetValue("operation", out var op) ? op.ToString() : "";
121+
var a = Convert.ToDouble(arguments.TryGetValue("a", out var aVal) ? aVal : 0);
122+
var b = Convert.ToDouble(arguments.TryGetValue("b", out var bVal) ? bVal : 0);
123+
124+
double result = operation switch
125+
{
126+
"add" => a + b,
127+
"subtract" => a - b,
128+
"multiply" => a * b,
129+
"divide" => b != 0 ? a / b : throw new DivideByZeroException("Cannot divide by zero"),
130+
_ => throw new ArgumentException($"Unknown operation: {operation}")
131+
};
132+
133+
return Task.FromResult(new McpToolResult
134+
{
135+
Content = new List<McpContent>
136+
{
137+
new McpContent { Type = "text", Text = $"Result: {a} {operation} {b} = {result}" }
138+
}
139+
});
140+
}
141+
catch (Exception ex)
142+
{
143+
return Task.FromResult(new McpToolResult
144+
{
145+
Content = new List<McpContent>
146+
{
147+
new McpContent { Type = "text", Text = $"Error: {ex.Message}" }
148+
},
149+
IsError = true
150+
});
151+
}
152+
}
153+
}
154+
155+
/// <summary>
156+
/// Time tool that provides current server time
157+
/// </summary>
158+
public class TimeToolHandler : IMcpToolHandler
159+
{
160+
public Task<McpTool> GetToolDefinitionAsync()
161+
{
162+
return Task.FromResult(new McpTool
163+
{
164+
Name = "time",
165+
Description = "Get the current server time in various formats",
166+
InputSchema = new
167+
{
168+
type = "object",
169+
properties = new
170+
{
171+
format = new { type = "string", description = "Time format", @enum = new[] { "iso", "local", "utc", "unix" } }
172+
}
173+
}
174+
});
175+
}
176+
177+
public Task<McpToolResult> ExecuteAsync(Dictionary<string, object> arguments)
178+
{
179+
var format = arguments.TryGetValue("format", out var fmt) ? fmt.ToString() : "iso";
180+
var now = DateTime.Now;
181+
var utcNow = DateTime.UtcNow;
182+
183+
var timeString = format switch
184+
{
185+
"iso" => utcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"),
186+
"local" => now.ToString("yyyy-MM-dd HH:mm:ss"),
187+
"utc" => utcNow.ToString("yyyy-MM-dd HH:mm:ss UTC"),
188+
"unix" => ((DateTimeOffset)utcNow).ToUnixTimeSeconds().ToString(),
189+
_ => utcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ")
190+
};
191+
192+
return Task.FromResult(new McpToolResult
193+
{
194+
Content = new List<McpContent>
195+
{
196+
new McpContent { Type = "text", Text = $"Current time ({format}): {timeString}" }
197+
}
198+
});
199+
}
200+
}
201+
202+
/// <summary>
203+
/// Web information tool that provides details about the WebSocket connection
204+
/// </summary>
205+
public class WebInfoToolHandler : IMcpToolHandler
206+
{
207+
public Task<McpTool> GetToolDefinitionAsync()
208+
{
209+
return Task.FromResult(new McpTool
210+
{
211+
Name = "webinfo",
212+
Description = "Get information about the WebSocket connection and server",
213+
InputSchema = new
214+
{
215+
type = "object",
216+
properties = new { }
217+
}
218+
});
219+
}
220+
221+
public Task<McpToolResult> ExecuteAsync(Dictionary<string, object> arguments)
222+
{
223+
var info = new
224+
{
225+
Protocol = "WebSocket",
226+
SubProtocol = "mcp",
227+
Server = "SuperSocket MCP WebSocket Server",
228+
Framework = ".NET 8.0",
229+
Transport = "WebSocket over TCP",
230+
Features = new[] { "Binary frames", "Text frames", "Ping/Pong", "Sub-protocols", "Extensions" }
231+
};
232+
233+
var infoText = $"""
234+
WebSocket MCP Server Information:
235+
- Protocol: {info.Protocol}
236+
- Sub-Protocol: {info.SubProtocol}
237+
- Server: {info.Server}
238+
- Framework: {info.Framework}
239+
- Transport: {info.Transport}
240+
- Features: {string.Join(", ", info.Features)}
241+
""";
242+
243+
return Task.FromResult(new McpToolResult
244+
{
245+
Content = new List<McpContent>
246+
{
247+
new McpContent { Type = "text", Text = infoText }
248+
}
249+
});
250+
}
251+
}
252+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"serverOptions": {
3+
"name": "McpWebSocketServer",
4+
"listeners": [
5+
{
6+
"ip": "Any",
7+
"port": 8080
8+
}
9+
]
10+
},
11+
"Logging": {
12+
"LogLevel": {
13+
"Default": "Information",
14+
"Microsoft": "Warning",
15+
"Microsoft.Hosting.Lifetime": "Information",
16+
"SuperSocket": "Information"
17+
}
18+
}
19+
}

0 commit comments

Comments
 (0)