1- // filepath: c:\Users\ddelimarsky\source\csharp-sdk-anm\samples\SecureWeatherServer\Program.cs
2- using Microsoft . AspNetCore . Builder ;
3- using Microsoft . Extensions . DependencyInjection ;
4- using ModelContextProtocol . AspNetCore . Auth ;
5- using ModelContextProtocol . Protocol . Messages ;
6- using ModelContextProtocol . Server ;
1+ using SecureWeatherServer . Tools ;
2+ using System . Net . Http . Headers ;
73
84var builder = WebApplication . CreateBuilder ( args ) ;
95
10- // Add MCP server with OAuth authorization
116builder . Services . AddMcpServer ( )
127 . WithHttpTransport ( )
13- . WithOAuthAuthorization ( metadata =>
8+ . WithTools < WeatherTools > ( )
9+ . WithAuthorization ( metadata =>
1410 {
15- // Configure the resource metadata
1611 metadata . AuthorizationServers . Add ( new Uri ( "https://auth.example.com" ) ) ;
17- metadata . ScopesSupported . AddRange ( new [ ] { "weather.read" , "weather.write" } ) ;
12+ metadata . ScopesSupported . AddRange ( [ "weather.read" , "weather.write" ] ) ;
1813 metadata . ResourceDocumentation = new Uri ( "https://docs.example.com/api/weather" ) ;
1914 } ) ;
2015
21- // Build the app
16+ builder . Services . AddSingleton ( _ =>
17+ {
18+ var client = new HttpClient ( ) { BaseAddress = new Uri ( "https://api.weather.gov" ) } ;
19+ client . DefaultRequestHeaders . UserAgent . Add ( new ProductInfoHeaderValue ( "weather-tool" , "1.0" ) ) ;
20+ return client ;
21+ } ) ;
22+
2223var app = builder . Build ( ) ;
2324
24- // Enable CORS for development
2525app . UseCors ( policy => policy
2626 . AllowAnyOrigin ( )
2727 . AllowAnyMethod ( )
2828 . AllowAnyHeader ( ) ) ;
2929
30- // Configure the HTTP request pipeline
3130app . UseAuthentication ( ) ;
3231app . UseAuthorization ( ) ;
3332
34- // Map MCP endpoints with authorization
35- app . MapMcpWithAuthorization ( ) ;
36-
37- // Define weather tool
38- var weatherTool = new McpTool ( "get_weather" , "Get the current weather for a location" )
39- . WithParameter ( "location" , "The location to get the weather for" , typeof ( string ) , required : true ) ;
40-
41- // Define weather server logic
42- app . UseMiddleware < ServerInvokeMiddleware > ( options =>
43- {
44- options . RegisterTool ( weatherTool , async ( McpToolInvokeParameters parameters , CancellationToken ct ) =>
45- {
46- if ( ! parameters . TryGetParameterValue < string > ( "location" , out var location ) )
47- {
48- return McpToolResult . Error ( "Location parameter is required" ) ;
49- }
50-
51- // In a real implementation, you would get the weather for the location
52- // For this example, we'll just return a random weather
53- var weather = GetRandomWeather ( location ) ;
54-
55- return McpToolResult . Success ( new
56- {
57- location ,
58- temperature = weather . Temperature ,
59- conditions = weather . Conditions ,
60- humidity = weather . Humidity ,
61- windSpeed = weather . WindSpeed
62- } ) ;
63- } ) ;
64- } ) ;
65-
66- // Run the app
6733app . Run ( ) ;
68-
69- // Helper method to generate random weather
70- ( double Temperature , string Conditions , int Humidity , double WindSpeed ) GetRandomWeather ( string location )
71- {
72- var random = new Random ( ) ;
73- var conditions = new [ ] { "Sunny" , "Cloudy" , "Rainy" , "Snowy" , "Foggy" , "Windy" } ;
74-
75- return (
76- Temperature : Math . Round ( random . NextDouble ( ) * 40 - 10 , 1 ) , // -10 to 30 degrees
77- Conditions : conditions [ random . Next ( conditions . Length ) ] ,
78- Humidity : random . Next ( 30 , 95 ) ,
79- WindSpeed : Math . Round ( random . NextDouble ( ) * 30 , 1 )
80- ) ;
81- }
82-
83- // Middleware to handle server invocations
84- public class ServerInvokeMiddleware
85- {
86- private readonly RequestDelegate _next ;
87- private readonly McpServerInvokeOptions _options ;
88-
89- public ServerInvokeMiddleware ( RequestDelegate next , McpServerInvokeOptions options )
90- {
91- _next = next ;
92- _options = options ;
93- }
94-
95- public ServerInvokeMiddleware ( RequestDelegate next , Action < McpServerInvokeOptions > configureOptions )
96- : this ( next , new McpServerInvokeOptions ( configureOptions ) )
97- {
98- }
99-
100- public async Task InvokeAsync ( HttpContext context )
101- {
102- // Set up the MCP server with the registered tools
103- if ( context . Features . Get < IMcpServer > ( ) is McpServer server )
104- {
105- foreach ( var registration in _options . ToolRegistrations )
106- {
107- server . RegisterToolHandler ( registration . Tool . Definition , registration . Handler ) ;
108- }
109- }
110-
111- await _next ( context ) ;
112- }
113- }
114-
115- // Helper classes for tool registration
116- public class McpServerInvokeOptions
117- {
118- public List < ToolRegistration > ToolRegistrations { get ; } = new ( ) ;
119-
120- public McpServerInvokeOptions ( ) { }
121-
122- public McpServerInvokeOptions ( Action < McpServerInvokeOptions > configure )
123- {
124- configure ( this ) ;
125- }
126-
127- public void RegisterTool ( McpTool tool , Func < McpToolInvokeParameters , CancellationToken , Task < McpToolResult > > handler )
128- {
129- ToolRegistrations . Add ( new ToolRegistration ( tool , handler ) ) ;
130- }
131- }
132-
133- public class ToolRegistration
134- {
135- public McpTool Tool { get ; }
136- public Func < McpToolInvokeParameters , CancellationToken , Task < McpToolResult > > Handler { get ; }
137-
138- public ToolRegistration (
139- McpTool tool ,
140- Func < McpToolInvokeParameters , CancellationToken , Task < McpToolResult > > handler )
141- {
142- Tool = tool ;
143- Handler = handler ;
144- }
145- }
146-
147- // Helper class to simplify tool registration and parameter handling
148- public class McpTool
149- {
150- public ToolDefinition Definition { get ; }
151-
152- public McpTool ( string name , string description )
153- {
154- Definition = new ToolDefinition
155- {
156- Name = name ,
157- Description = description ,
158- Parameters = new ToolParameterDefinition
159- {
160- Properties = { } ,
161- Required = new List < string > ( )
162- }
163- } ;
164- }
165-
166- public McpTool WithParameter ( string name , string description , Type type , bool required = false )
167- {
168- Definition . Parameters . Properties [ name ] = new ToolPropertyDefinition
169- {
170- Description = description ,
171- Type = GetJsonSchemaType ( type )
172- } ;
173-
174- if ( required )
175- {
176- Definition . Parameters . Required . Add ( name ) ;
177- }
178-
179- return this ;
180- }
181-
182- private static string GetJsonSchemaType ( Type type )
183- {
184- return type . Name . ToLowerInvariant ( ) switch
185- {
186- "string" => "string" ,
187- "int32" or "int64" or "int" or "long" or "double" or "float" or "decimal" => "number" ,
188- "boolean" => "boolean" ,
189- _ => "object"
190- } ;
191- }
192- }
193-
194- // Helper class for the tool invocation parameters
195- public class McpToolInvokeParameters
196- {
197- private readonly Dictionary < string , object ? > _parameters ;
198-
199- public McpToolInvokeParameters ( Dictionary < string , object ? > parameters )
200- {
201- _parameters = parameters ;
202- }
203-
204- public bool TryGetParameterValue < T > ( string name , out T value )
205- {
206- if ( _parameters . TryGetValue ( name , out var objValue ) && objValue is T typedValue )
207- {
208- value = typedValue ;
209- return true ;
210- }
211-
212- value = default ! ;
213- return false ;
214- }
215-
216- public T ? GetParameterValue < T > ( string name )
217- {
218- if ( _parameters . TryGetValue ( name , out var value ) && value is T typedValue )
219- {
220- return typedValue ;
221- }
222-
223- return default ;
224- }
225- }
226-
227- // Helper class for the tool result
228- public class McpToolResult
229- {
230- public object ? Result { get ; }
231- public string ? Error { get ; }
232- public bool IsError => Error != null ;
233-
234- private McpToolResult ( object ? result , string ? error )
235- {
236- Result = result ;
237- Error = error ;
238- }
239-
240- public static McpToolResult Success ( object ? result = null ) => new McpToolResult ( result , null ) ;
241- public static McpToolResult Error ( string error ) => new McpToolResult ( null , error ) ;
242- }
0 commit comments