1+ using Anthropic . SDK ;
2+ using Microsoft . Extensions . AI ;
3+ using Microsoft . Extensions . Configuration ;
4+ using Microsoft . Extensions . Hosting ;
5+ using ModelContextProtocol . Client ;
6+ using ModelContextProtocol . Protocol . Transport ;
7+
8+ var builder = Host . CreateEmptyApplicationBuilder ( settings : null ) ;
9+
10+ builder . Configuration
11+ . AddEnvironmentVariables ( )
12+ . AddUserSecrets < Program > ( ) ;
13+
14+ var ( command , arguments ) = GetCommandAndArguments ( args ) ;
15+
16+ await using var mcpClient = await McpClientFactory . CreateAsync ( new ( )
17+ {
18+ Id = "demo-server" ,
19+ Name = "Demo Server" ,
20+ TransportType = TransportTypes . StdIo ,
21+ TransportOptions = new ( )
22+ {
23+ [ "command" ] = command ,
24+ [ "arguments" ] = arguments ,
25+ }
26+ } ) ;
27+
28+ var tools = await mcpClient . ListToolsAsync ( ) ;
29+ foreach ( var tool in tools )
30+ {
31+ Console . WriteLine ( $ "Connected to server with tools: { tool . Name } ") ;
32+ }
33+
34+ using var anthropicClient = new AnthropicClient ( new APIAuthentication ( builder . Configuration [ "ANTHROPIC_API_KEY" ] ) )
35+ . Messages
36+ . AsBuilder ( )
37+ . UseFunctionInvocation ( )
38+ . Build ( ) ;
39+
40+ var options = new ChatOptions
41+ {
42+ MaxOutputTokens = 1000 ,
43+ ModelId = "claude-3-5-sonnet-20241022" ,
44+ Tools = [ .. tools ]
45+ } ;
46+
47+ Console . ForegroundColor = ConsoleColor . Green ;
48+ Console . WriteLine ( "MCP Client Started!" ) ;
49+ Console . ResetColor ( ) ;
50+
51+ PromptForInput ( ) ;
52+ while ( Console . ReadLine ( ) is string query && ! "exit" . Equals ( query , StringComparison . OrdinalIgnoreCase ) )
53+ {
54+ if ( string . IsNullOrWhiteSpace ( query ) )
55+ {
56+ PromptForInput ( ) ;
57+ continue ;
58+ }
59+
60+ await foreach ( var message in anthropicClient . GetStreamingResponseAsync ( query , options ) )
61+ {
62+ Console . Write ( message ) ;
63+ }
64+ Console . WriteLine ( ) ;
65+
66+ PromptForInput ( ) ;
67+ }
68+
69+ static void PromptForInput ( )
70+ {
71+ Console . WriteLine ( "Enter a command (or 'exit' to quit):" ) ;
72+ Console . ForegroundColor = ConsoleColor . Cyan ;
73+ Console . Write ( "> " ) ;
74+ Console . ResetColor ( ) ;
75+ }
76+
77+ /// <summary>
78+ /// Determines the command (executable) to run and the script/path to pass to it. This allows different
79+ /// languages/runtime environments to be used as the MCP server.
80+ /// </summary>
81+ /// <remarks>
82+ /// This method uses the file extension of the first argument to determine the command, if it's py, it'll run python,
83+ /// if it's js, it'll run node, if it's a directory or a csproj file, it'll run dotnet.
84+ ///
85+ /// If no arguments are provided, it defaults to running the QuickstartWeatherServer project from the current repo.
86+ ///
87+ /// This method would only be required if you're creating a generic client, such as we use for the quickstart.
88+ /// </remarks>
89+ static ( string command , string arguments ) GetCommandAndArguments ( string [ ] args )
90+ {
91+ return args switch
92+ {
93+ [ var script ] when script . EndsWith ( ".py" ) => ( "python" , script ) ,
94+ [ var script ] when script . EndsWith ( ".js" ) => ( "node" , script ) ,
95+ [ var script ] when Directory . Exists ( script ) || ( File . Exists ( script ) && script . EndsWith ( ".csproj" ) ) => ( "dotnet" , $ "run --project { script } --no-build") ,
96+ _ => ( "dotnet" , "run --project ../../../../QuickstartWeatherServer --no-build" )
97+ } ;
98+ }
0 commit comments