Skip to content

Commit af4ca83

Browse files
mcp usage sample (#490)
* mcp usage sample * simplified dependencies of ToMessage * cleaned up usings
1 parent b8d4d6d commit af4ca83

File tree

1 file changed

+89
-0
lines changed

1 file changed

+89
-0
lines changed

docs/guides/mcp/chat_with_mcp.cs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
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

Comments
 (0)