Skip to content

Commit cfdf95d

Browse files
authored
Merge pull request #207 from StefH/stef-ModelContextProtocol
Change dependency on mcpdotnet to ModelContextProtocol
2 parents 1106f54 + 9518d8f commit cfdf95d

File tree

11 files changed

+205
-135
lines changed

11 files changed

+205
-135
lines changed

Directory.Packages.props

+1-2
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,9 @@
22
<PropertyGroup>
33
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
44
</PropertyGroup>
5-
65
<ItemGroup>
76
<PackageVersion Include="coverlet.collector" Version="6.0.3" />
87
<PackageVersion Include="coverlet.collector" Version="6.0.3" />
9-
<PackageVersion Include="mcpdotnet" Version="1.0.1.3" />
108
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.0" />
119
<PackageVersion Include="Microsoft.CodeAnalysis.Common" Version="4.12.0" />
1210
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.12.0" />
@@ -23,5 +21,6 @@
2321
<PackageVersion Include="Spectre.Console.ImageSharp" Version="0.49.1" />
2422
<PackageVersion Include="Spectre.Console" Version="0.49.1" />
2523
<PackageVersion Include="System.Linq.Async" Version="6.0.1" />
24+
<PackageVersion Include="ModelContextProtocol" Version="0.1.0-preview.7" />
2625
</ItemGroup>
2726
</Project>

OllamaSharp.slnx

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<Solution>
22
<Folder Name="/Solution Items/">
33
<File Path=".editorconfig" />
4+
<File Path="Directory.Packages.props" />
45
</Folder>
56
<Project Path="demo/OllamaApiConsole.csproj" />
67
<Project Path="src/OllamaSharp.ModelContextProtocol/OllamaSharp.ModelContextProtocol.csproj" />

src/OllamaSharp.ModelContextProtocol/McpClientOptions.cs

+5-11
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
using McpDotNet.Client;
2-
using McpDotNet.Configuration;
3-
using McpDotNet.Protocol.Transport;
4-
using McpDotNet.Protocol.Types;
51
using Microsoft.Extensions.Logging;
2+
using ModelContextProtocol.Protocol.Transport;
3+
using ModelContextProtocol.Protocol.Types;
4+
using OllamaSharp.ModelContextProtocol.Server;
65

76
namespace OllamaSharp.ModelContextProtocol;
87

@@ -19,12 +18,7 @@ public class McpClientOptions
1918
/// <summary>
2019
/// An optional factory method which returns transport implementations based on a server configuration.
2120
/// </summary>
22-
public Func<McpServerConfig, IClientTransport>? TransportFactoryMethod { get; set; }
23-
24-
/// <summary>
25-
/// An optional factory method which creates a client based on client options and transport implementation.
26-
/// </summary>
27-
public Func<IClientTransport, McpServerConfig, McpDotNet.Client.McpClientOptions, IMcpClient>? ClientFactoryMethod { get; set; }
21+
public Func<McpServerConfiguration, ILoggerFactory?, IClientTransport>? ClientTransportFactoryMethod { get; set; }
2822

2923
/// <summary>
3024
/// Client capabilities to advertise to the server.
@@ -35,4 +29,4 @@ public class McpClientOptions
3529
/// Timeout for initialization sequence.
3630
/// </summary>
3731
public TimeSpan InitializationTimeout { get; init; } = TimeSpan.FromSeconds(60);
38-
}
32+
}

src/OllamaSharp.ModelContextProtocol/OllamaSharp.ModelContextProtocol.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
</ItemGroup>
3737

3838
<ItemGroup>
39-
<PackageReference Include="mcpdotnet" />
39+
<PackageReference Include="ModelContextProtocol" />
4040
</ItemGroup>
4141

4242
<ItemGroup>

src/OllamaSharp.ModelContextProtocol/Server/McpClientTool.cs

+15-9
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
using McpDotNet.Client;
1+
using System.Text.Json;
2+
using ModelContextProtocol.Client;
3+
using OllamaSharp.ModelContextProtocol.Server.Types;
4+
using ModelContextProtocolClient = ModelContextProtocol.Client;
25

36
namespace OllamaSharp.ModelContextProtocol.Server;
47

@@ -12,36 +15,39 @@ public class McpClientTool : OllamaSharp.Models.Chat.Tool, OllamaSharp.Tools.IAs
1215
/// <summary>
1316
/// Initializes a new instance with metadata about the original method.
1417
/// </summary>
15-
public McpClientTool(McpDotNet.Protocol.Types.Tool mcpTool, IMcpClient client)
18+
public McpClientTool(ModelContextProtocolClient.McpClientTool mcpTool, IMcpClient client)
1619
{
1720
_client = client;
1821

19-
this.Function = new OllamaSharp.Models.Chat.Function
22+
Function = new OllamaSharp.Models.Chat.Function
2023
{
2124
Name = mcpTool.Name,
2225
Description = mcpTool.Description
2326
};
2427

25-
var properties = mcpTool.InputSchema?.Properties;
28+
var inputSchema = mcpTool.JsonSchema.Deserialize<JsonSchema>();
29+
var properties = inputSchema?.Properties;
2630
if (properties == null)
31+
{
2732
return;
33+
}
2834

29-
this.Function.Parameters = new OllamaSharp.Models.Chat.Parameters
35+
Function.Parameters = new OllamaSharp.Models.Chat.Parameters
3036
{
31-
Type = mcpTool.InputSchema!.Type,
37+
Type = inputSchema!.Type,
3238
Properties = properties.ToDictionary(kvp => kvp.Key, kvp => new OllamaSharp.Models.Chat.Property
3339
{
3440
Type = kvp.Value.Type,
3541
Description = kvp.Value.Description
3642
}),
37-
Required = mcpTool.InputSchema?.Required ?? []
43+
Required = inputSchema.Required ?? []
3844
};
3945
}
4046

4147
/// <inheritdoc />
4248
public async Task<object?> InvokeMethodAsync(IDictionary<string, object?>? args)
4349
{
44-
var arguments = args?.ToDictionary(a => a.Key, a => a.Value ?? string.Empty) ?? [];
50+
var arguments = args?.ToDictionary(a => a.Key, a => (object?) (a.Value ?? string.Empty)) ?? [];
4551

4652
try
4753
{
@@ -57,4 +63,4 @@ public McpClientTool(McpDotNet.Protocol.Types.Tool mcpTool, IMcpClient client)
5763
return ex.Message;
5864
}
5965
}
60-
}
66+
}

src/OllamaSharp.ModelContextProtocol/Tools.cs

+41-45
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
using System.Reflection;
22
using System.Text.Json;
33
using System.Text.Json.Serialization;
4-
using McpDotNet.Client;
5-
using McpDotNet.Configuration;
4+
using Microsoft.Extensions.Logging;
65
using Microsoft.Extensions.Logging.Abstractions;
6+
using ModelContextProtocol.Protocol.Transport;
77
using OllamaSharp.ModelContextProtocol.Server;
8+
using ModelContextProtocolClient = ModelContextProtocol.Client;
89

910
namespace OllamaSharp.ModelContextProtocol;
1011

@@ -68,65 +69,64 @@ public static async Task<object[]> GetFromMcpServers(McpClientOptions? clientOpt
6869
if (mcpServers == null || mcpServers.Length == 0)
6970
throw new ArgumentNullException(nameof(mcpServers));
7071

72+
var loggerFactory = clientOptions?.LoggerFactory ?? NullLoggerFactory.Instance;
7173
var options = CreateMcpClientOptions(clientOptions);
72-
var servers = ConvertServerConfigurations(mcpServers);
73-
74-
var factory = new McpClientFactory(
75-
servers,
76-
options,
77-
clientOptions?.LoggerFactory ?? NullLoggerFactory.Instance, clientOptions?.TransportFactoryMethod, clientOptions?.ClientFactoryMethod
78-
);
7974

8075
var result = new List<object>();
81-
82-
foreach (var server in servers)
76+
foreach (var server in mcpServers)
8377
{
84-
var client = await factory.GetClientAsync(server.Id);
85-
86-
var tools = await client.ListToolsAsync();
78+
var clientTransport = clientOptions?.ClientTransportFactoryMethod != null ?
79+
clientOptions.ClientTransportFactoryMethod(server, loggerFactory) :
80+
ConvertServerConfigurations(server, loggerFactory);
8781

88-
if (tools != null)
82+
var client = await ModelContextProtocolClient.McpClientFactory.CreateAsync(clientTransport, options, loggerFactory);
83+
foreach (var tool in await ModelContextProtocolClient.McpClientExtensions.ListToolsAsync(client))
8984
{
90-
foreach (var tool in tools.Tools)
91-
result.Add(new McpClientTool(tool, client));
85+
result.Add(new McpClientTool(tool, client));
9286
}
9387
}
9488

9589
return result.ToArray();
9690
}
9791

98-
private static List<McpServerConfig> ConvertServerConfigurations(McpServerConfiguration[] mcpServers)
92+
private static IClientTransport ConvertServerConfigurations(McpServerConfiguration server, ILoggerFactory loggerFactory)
9993
{
100-
var result = new List<McpServerConfig>();
101-
102-
foreach (var server in mcpServers)
94+
if (server.TransportType == McpServerTransportType.Stdio)
10395
{
104-
var config = new McpServerConfig
96+
var stdioOptions = new StdioClientTransportOptions
10597
{
106-
Id = server.Name ?? Guid.NewGuid().ToString("n"),
107-
Name = server.Name ?? Guid.NewGuid().ToString("n"),
108-
TransportType = server.TransportType.ToString(),
109-
Arguments = ResolveVariables(server.Arguments),
110-
Location = server.Command,
111-
TransportOptions = server.Options ?? []
98+
Command = server.Command,
99+
Name = server.Name
112100
};
113101

102+
if (server.Arguments != null)
103+
{
104+
stdioOptions.Arguments = ResolveVariables(server.Arguments);
105+
}
106+
114107
if (server.Environment != null)
115108
{
109+
stdioOptions.EnvironmentVariables = [];
116110
foreach (var kvp in server.Environment)
117-
config.TransportOptions[$"env:{kvp.Key}"] = Environment.GetEnvironmentVariable(GetEnvironmentVariableName(kvp.Value)) ?? kvp.Value;
111+
{
112+
stdioOptions.EnvironmentVariables[kvp.Key] = Environment.GetEnvironmentVariable(GetEnvironmentVariableName(kvp.Value)) ?? kvp.Value;
113+
}
118114
}
119115

120-
if (config.Arguments != null)
121-
config.TransportOptions["arguments"] = string.Join(' ', config.Arguments);
122-
123-
if (config.TransportOptions?.TryGetValue("workingDirectory", out var dir) == true)
124-
config.TransportOptions["workingDirectory"] = ResolveVariables(dir);
116+
if (server.Options?.TryGetValue("workingDirectory", out var workingDirectory) == true)
117+
{
118+
stdioOptions.WorkingDirectory = workingDirectory;
119+
}
125120

126-
result.Add(config);
121+
return new StdioClientTransport(stdioOptions, loggerFactory);
127122
}
128123

129-
return result;
124+
var sseOptions = new SseClientTransportOptions
125+
{
126+
Endpoint = new Uri(server.Command),
127+
Name = server.Name
128+
};
129+
return new SseClientTransport(sseOptions, loggerFactory);
130130
}
131131

132132
private static string GetEnvironmentVariableName(string name)
@@ -137,22 +137,19 @@ private static string GetEnvironmentVariableName(string name)
137137
return name;
138138
}
139139

140-
private static string[]? ResolveVariables(string[]? arguments)
140+
private static string[] ResolveVariables(string[] arguments)
141141
{
142-
if (arguments == null)
143-
return null;
144-
145-
return arguments.Select(a => ResolveVariables(a)).ToArray();
142+
return arguments.Select(ResolveVariables).ToArray();
146143
}
147144

148145
private static string ResolveVariables(string argument)
149146
{
150147
return Environment.ExpandEnvironmentVariables(argument);
151148
}
152149

153-
private static McpDotNet.Client.McpClientOptions CreateMcpClientOptions(McpClientOptions? clientOptions)
150+
private static ModelContextProtocolClient.McpClientOptions CreateMcpClientOptions(McpClientOptions? clientOptions)
154151
{
155-
return new McpDotNet.Client.McpClientOptions
152+
return new ModelContextProtocolClient.McpClientOptions
156153
{
157154
Capabilities = clientOptions?.Capabilities,
158155
InitializationTimeout = clientOptions?.InitializationTimeout ?? TimeSpan.FromSeconds(60),
@@ -169,5 +166,4 @@ private sealed class McpServerConfigurationFile
169166
[JsonPropertyName("mcpServers")]
170167
public Dictionary<string, McpServerConfiguration> Servers { get; set; } = [];
171168
}
172-
}
173-
169+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System.Text.Json.Serialization;
2+
3+
namespace OllamaSharp.ModelContextProtocol.Server.Types;
4+
5+
/// <summary>
6+
/// Represents a JSON schema for a tool's input arguments.
7+
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see>
8+
/// </summary>
9+
internal class JsonSchema
10+
{
11+
/// <summary>
12+
/// The type of the schema, should be "object".
13+
/// </summary>
14+
[JsonPropertyName("type")]
15+
public string Type { get; set; } = "object";
16+
17+
/// <summary>
18+
/// Map of property names to property definitions.
19+
/// </summary>
20+
[JsonPropertyName("properties")]
21+
public Dictionary<string, JsonSchemaProperty>? Properties { get; set; }
22+
23+
/// <summary>
24+
/// List of required property names.
25+
/// </summary>
26+
[JsonPropertyName("required")]
27+
public List<string>? Required { get; set; }
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System.Text.Json.Serialization;
2+
3+
namespace OllamaSharp.ModelContextProtocol.Server.Types;
4+
5+
/// <summary>
6+
/// Represents a property in a JSON schema.
7+
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see>
8+
/// </summary>
9+
internal class JsonSchemaProperty
10+
{
11+
/// <summary>
12+
/// The type of the property. Should be a JSON Schema type and is required.
13+
/// </summary>
14+
[JsonPropertyName("type")]
15+
public string Type { get; set; } = string.Empty;
16+
17+
/// <summary>
18+
/// A human-readable description of the property.
19+
/// </summary>
20+
[JsonPropertyName("description")]
21+
public string? Description { get; set; } = string.Empty;
22+
}

0 commit comments

Comments
 (0)