Open
Description
Is your feature request related to a problem? Please describe.
Not at all :)
Describe the solution you'd like
I realize this repo is nascent to the extreme and l genuinely appreciate all the work everyone is putting in to make this available to the .NET community. The samples are great and it's awesome you can bootstrap it so quickly from the console but it might be helpful to provide a sample that demonstrates how to best wire up clients for dependency injection. I'm more than happy to submit one if you would like a PR just let me know.
Additional context
I was thinking due to the ephemeral nature of the MCP docker containers something like this...
public abstract class DockerMcpServiceBase
{
private readonly Task<IMcpClient> _clientTask;
protected DockerMcpServiceBase(string container, string[]? flags = null,
Dictionary<string, string>? environmentVariables = null,
IReadOnlyDictionary<string, string>? parameters = null)
{
// Build the arguments array
var args = new List<string>();
if (flags is { Length: > 0 }) args.AddRange(flags);
if (environmentVariables is { Count: > 0 })
foreach (var (key, _) in environmentVariables)
{
args.Add("-e");
args.Add(key);
}
args.Add(container);
if (parameters is { Count: > 0 })
foreach (var (key, value) in parameters)
args.Add($"--{key}={value}");
_clientTask = McpClientFactory.CreateAsync(
new StdioClientTransport(new()
{
Name = container.Split('/')[1],
Command = "docker",
Arguments = ["run", "-i", "--rm", .. args],
EnvironmentVariables = environmentVariables ?? []
}));
}
public async Task<IEnumerable<McpClientTool>> GetToolsAsync(string[]? toolsToInclude = null,
CancellationToken cancellationToken = default)
{
var client = await _clientTask;
var tools = await client.ListToolsAsync(cancellationToken: cancellationToken);
return toolsToInclude is { Length: > 0 } ? tools.Where(t => toolsToInclude.Contains(t.Name)) : tools;
}
}
public class AtlassianMcpService(IConfiguration configuration) : DockerMcpServiceBase("mcp/atlassian",
parameters: new Dictionary<string, string>
{
["confluence-url"] =
$"{configuration[Secrets.AtlassianServer] ?? throw new InvalidOperationException($"{Secrets.AtlassianServer} is not set")}wiki",
["confluence-username"] =
configuration[Secrets.AtlassianEmail] ??
throw new InvalidOperationException($"{Secrets.AtlassianEmail} is not set"),
["confluence-token"] =
configuration[Secrets.AtlassianToken] ??
throw new InvalidOperationException($"{Secrets.AtlassianToken} is not set"),
["jira-url"] =
configuration[Secrets.AtlassianServer] ??
throw new InvalidOperationException($"{Secrets.AtlassianServer} is not set"),
["jira-username"] =
configuration[Secrets.AtlassianEmail] ??
throw new InvalidOperationException($"{Secrets.AtlassianEmail} is not set"),
["jira-token"] =
configuration[Secrets.AtlassianToken] ??
throw new InvalidOperationException($"{Secrets.AtlassianToken} is not set")
});
public class BraveSearchMcpService(IConfiguration configuration) : DockerMcpServiceBase("mcp/brave-search",
environmentVariables: new Dictionary<string, string>
{
["BRAVE_API_KEY"] = configuration[Secrets.BraveSearchToken] ??
throw new InvalidOperationException($"{Secrets.BraveSearchToken} is not set")
});
public class FetchMcpService() : DockerMcpServiceBase("mcp/fetch");
public class GitHubMcpService(IConfiguration configuration) : DockerMcpServiceBase("mcp/github",
environmentVariables: new Dictionary<string, string>
{
["GITHUB_PERSONAL_ACCESS_TOKEN"] = configuration[Secrets.GitHubToken] ??
throw new InvalidOperationException($"{Secrets.GitHubToken} is not set")
});
public class GoogleMapsMcpService(IConfiguration configuration) : DockerMcpServiceBase("mcp/google-maps",
environmentVariables: new Dictionary<string, string>
{
["GOOGLE_MAPS_API_KEY"] = configuration[Secrets.GoogleMapsToken] ??
throw new InvalidOperationException($"{Secrets.GoogleMapsToken} is not set")
});
public class MemoryMcpService() : DockerMcpServiceBase("mcp/memory");
public class PuppeteerMcpService() : DockerMcpServiceBase("mcp/puppeteer", ["--init"],
new Dictionary<string, string> { ["DOCKER_CONTAINER"] = "true" });
public class SequentialThinkingMcpService() : DockerMcpServiceBase("mcp/sequentialthinking");
public class TimeMcpService() : DockerMcpServiceBase("mcp/time");
Then it's simply wire up a singleton to the service collection and off you go.