1+ // SAMPLE: call the official MCP library for .NET
2+
3+ #: package OpenAI @2.2 . * - *
4+ #: package ModelContextProtocol. Core@* - *
5+ #: property PublishAot = false
6+
7+ using ModelContextProtocol;
8+ using ModelContextProtocol . Client ;
9+ using OpenAI . Chat ;
10+
11+ string mcpCommand = Environment . GetEnvironmentVariable ( "MCP_SERVER_COMMAND" ) ! ; // path to a stdio mcp server
12+ string key = Environment . GetEnvironmentVariable ( "OPENAI_KEY" ) ! ;
13+
14+ ChatClient chatClient = new ( "gpt-4.1" , key ) ;
15+
16+ // Create MCP client to connect to the server
17+ IMcpClient mcpClient = await McpClientFactory . CreateAsync ( new StdioClientTransport ( new StdioClientTransportOptions
18+ {
19+ Name = "MyServer" ,
20+ Command = mcpCommand ,
21+ Arguments = [ ] ,
22+ } ) ) ;
23+
24+ // get avaliable tools and add them to completion options
25+ ChatCompletionOptions options = new ( ) ;
26+ await foreach ( McpClientTool chatTool in mcpClient . EnumerateToolsAsync ( ) )
27+ {
28+ options . Tools . Add ( chatTool . AsOpenAIChatTool ( ) ) ;
29+ }
30+
31+ // conversation thread
32+ List < ChatMessage > conversation = new ( )
33+ {
34+ ChatMessage . CreateUserMessage ( "Use an MCP tool" )
35+ } ;
36+
37+ start :
38+ ChatCompletion chatCompletion = chatClient . CompleteChat ( conversation , options ) ;
39+ conversation . Add ( ChatMessage . CreateAssistantMessage ( chatCompletion ) ) ;
40+ switch ( chatCompletion . FinishReason )
41+ {
42+ case ChatFinishReason . ToolCalls :
43+ foreach ( var call in chatCompletion . ToolCalls )
44+ {
45+ var mcpArguments = call . FunctionArguments . ToObjectFromJson < Dictionary < string , object > > ( ) ;
46+ Console . WriteLine ( "Tool call detected, calling MCP server..." ) ;
47+ ModelContextProtocol . Protocol . CallToolResult result = await mcpClient . CallToolAsync ( call . FunctionName , mcpArguments ! ) ;
48+ Console . WriteLine ( $ "tool call result { result . Content [ 0 ] } ") ;
49+ ChatMessage message = call . ToMessage ( result . Content . ToAIContents ( ) ) ;
50+ conversation . Add ( message ) ;
51+ }
52+ goto start ;
53+ case ChatFinishReason . Stop :
54+ Console . WriteLine ( chatCompletion . Content [ 0 ] . Text ) ;
55+ break ;
56+ default :
57+ throw new NotImplementedException ( ) ;
58+ }
59+
60+ #region TEMPORARY
61+ // this is temporary. all these APIs will endup being in one of the packages used here.
62+ public static class TemporaryExtensions
63+ {
64+ // this needs to be in the adapter package
65+ public static ChatMessage ToMessage ( this ChatToolCall openaiCall , IEnumerable < Microsoft . Extensions . AI . AIContent > contents )
66+ {
67+ List < ChatMessageContentPart > parts = new ( ) ;
68+ foreach ( Microsoft . Extensions . AI . AIContent content in contents )
69+ {
70+ string serialized = System . Text . Json . JsonSerializer . Serialize ( content . RawRepresentation ) ;
71+ using System . Text . Json . JsonDocument json = System . Text . Json . JsonDocument . Parse ( serialized ) ;
72+ System . Text . Json . JsonElement text = json . RootElement . GetProperty ( "text" ) ;
73+ string textValue = text . GetString ( ) ?? string . Empty ;
74+ parts . Add ( ChatMessageContentPart . CreateTextPart ( textValue ) ) ;
75+ }
76+ ToolChatMessage message = ChatMessage . CreateToolMessage ( openaiCall . Id , parts ) ;
77+ return message ;
78+ }
79+
80+ // this is in the adapter package
81+ public static ChatTool AsOpenAIChatTool ( this Microsoft . Extensions . AI . AIFunction mcpTool )
82+ {
83+ return ChatTool . CreateFunctionTool (
84+ mcpTool . Name ,
85+ mcpTool . Description ,
86+ BinaryData . FromString ( mcpTool . JsonSchema . GetRawText ( ) ) ) ;
87+ }
88+ }
89+ #endregion
0 commit comments