1+ // filepath: c:\Users\ddelimarsky\source\csharp-sdk-anm\samples\SecureWeatherClient\Program.cs
2+ using System . Net . Http ;
3+ using System . Threading . Tasks ;
4+ using ModelContextProtocol . Auth ;
5+ using ModelContextProtocol . Client ;
6+ using ModelContextProtocol . Protocol . Transport ;
7+
8+ namespace SecureWeatherClient ;
9+
10+ class Program
11+ {
12+ // The URI for our OAuth redirect - in a real app, this would be a registered URI or a local server
13+ private static readonly Uri RedirectUri = new ( "http://localhost:8888/oauth-callback" ) ;
14+
15+ static async Task Main ( string [ ] args )
16+ {
17+ Console . WriteLine ( "MCP Secure Weather Client with OAuth Authentication" ) ;
18+ Console . WriteLine ( "==================================================" ) ;
19+ Console . WriteLine ( ) ;
20+
21+ // Create an HTTP client with OAuth handling
22+ var oauthHandler = new OAuthDelegatingHandler (
23+ redirectUri : RedirectUri ,
24+ clientName : "SecureWeatherClient" ,
25+ scopes : new [ ] { "weather.read" } ,
26+ authorizationHandler : HandleAuthorizationRequestAsync ) ;
27+
28+ var httpClient = new HttpClient ( oauthHandler ) ;
29+ var serverUrl = "http://localhost:5000" ; // Default server URL
30+
31+ // Allow the user to specify a different server URL
32+ Console . WriteLine ( $ "Server URL (press Enter for default: { serverUrl } ):") ;
33+ var userInput = Console . ReadLine ( ) ;
34+ if ( ! string . IsNullOrWhiteSpace ( userInput ) )
35+ {
36+ serverUrl = userInput ;
37+ }
38+
39+ Console . WriteLine ( ) ;
40+ Console . WriteLine ( $ "Connecting to weather server at { serverUrl } ...") ;
41+
42+ // Create an MCP client with the server URL
43+ var client = new McpClient ( new Uri ( serverUrl ) , httpClient ) ;
44+
45+ try
46+ {
47+ // Get the list of available tools
48+ var tools = await client . GetToolsAsync ( ) ;
49+ if ( tools . Count == 0 )
50+ {
51+ Console . WriteLine ( "No tools available on the server." ) ;
52+ return ;
53+ }
54+
55+ Console . WriteLine ( $ "Found { tools . Count } tools on the server.") ;
56+ Console . WriteLine ( ) ;
57+
58+ // Find the weather tool
59+ var weatherTool = tools . FirstOrDefault ( t => t . Name == "get_weather" ) ;
60+ if ( weatherTool == null )
61+ {
62+ Console . WriteLine ( "The server does not provide a weather tool." ) ;
63+ return ;
64+ }
65+
66+ // Get the weather for different locations
67+ string [ ] locations = { "New York" , "London" , "Tokyo" , "Sydney" , "Moscow" } ;
68+
69+ foreach ( var location in locations )
70+ {
71+ try
72+ {
73+ Console . WriteLine ( $ "Getting weather for { location } ...") ;
74+ var result = await client . InvokeToolAsync ( weatherTool . Name , new Dictionary < string , object >
75+ {
76+ [ "location" ] = location
77+ } ) ;
78+
79+ if ( result . TryGetValue ( "temperature" , out var temperature ) &&
80+ result . TryGetValue ( "conditions" , out var conditions ) &&
81+ result . TryGetValue ( "humidity" , out var humidity ) &&
82+ result . TryGetValue ( "windSpeed" , out var windSpeed ) )
83+ {
84+ Console . WriteLine ( $ "Weather in { location } :") ;
85+ Console . WriteLine ( $ " Temperature: { temperature } °C") ;
86+ Console . WriteLine ( $ " Conditions: { conditions } ") ;
87+ Console . WriteLine ( $ " Humidity: { humidity } %") ;
88+ Console . WriteLine ( $ " Wind speed: { windSpeed } km/h") ;
89+ }
90+ else
91+ {
92+ Console . WriteLine ( $ "Invalid response format for { location } ") ;
93+ }
94+ }
95+ catch ( Exception ex )
96+ {
97+ Console . WriteLine ( $ "Error getting weather for { location } : { ex . Message } ") ;
98+ }
99+
100+ Console . WriteLine ( ) ;
101+ }
102+ }
103+ catch ( Exception ex )
104+ {
105+ Console . WriteLine ( $ "Error: { ex . Message } ") ;
106+ }
107+
108+ Console . WriteLine ( "Press any key to exit..." ) ;
109+ Console . ReadKey ( ) ;
110+ }
111+
112+ /// <summary>
113+ /// Handles the OAuth authorization request by showing the URL to the user and getting the authorization code.
114+ /// In a real application, this would launch a browser and listen for the callback.
115+ /// </summary>
116+ private static Task < string > HandleAuthorizationRequestAsync ( Uri authorizationUri )
117+ {
118+ Console . WriteLine ( ) ;
119+ Console . WriteLine ( "Authentication Required" ) ;
120+ Console . WriteLine ( "======================" ) ;
121+ Console . WriteLine ( ) ;
122+ Console . WriteLine ( "Please open the following URL in your browser to authenticate:" ) ;
123+ Console . WriteLine ( authorizationUri ) ;
124+ Console . WriteLine ( ) ;
125+ Console . WriteLine ( "After authentication, you will be redirected to a page with a code." ) ;
126+ Console . WriteLine ( "Please enter the code parameter from the URL:" ) ;
127+
128+ var authorizationCode = Console . ReadLine ( ) ;
129+ if ( string . IsNullOrWhiteSpace ( authorizationCode ) )
130+ {
131+ throw new InvalidOperationException ( "Authorization code is required." ) ;
132+ }
133+
134+ return Task . FromResult ( authorizationCode ) ;
135+ }
136+ }
0 commit comments