Table of Contents

Can I Connect to Existing MCP Servers Like Filesystem or GitHub?


TL;DR

Yes. LM-Kit.NET connects to any MCP-compatible server using either stdio (for local servers running as subprocesses) or HTTP+SSE (for remote servers). Most community MCP servers are npm or Python packages that run via stdio. Once connected, the server's tools appear as standard ITool instances that your agents can call. Authentication is handled through bearer tokens (HTTP) or environment variables (stdio).


Connecting to a Local MCP Server (Stdio)

Most MCP servers in the ecosystem are npm packages that run as local subprocesses. LM-Kit.NET manages the subprocess lifecycle automatically:

Filesystem Server

using LMKit.Mcp;

// Start the official filesystem MCP server
var client = McpClientBuilder.ForStdio(
        "npx", "@modelcontextprotocol/server-filesystem /home/user/project")
    .WithStderrHandler(line => Console.WriteLine($"[Server] {line}"))
    .Build();

await client.ConnectAsync();

// Register tools: read_file, write_file, list_directory, search_files, etc.
chat.Tools.Register(client);

string response = chat.Submit("List all C# files in the src directory");

Python-Based Server

// Connect to a Python MCP server
var client = McpClientBuilder.ForStdio(
        "uvx", "mcp-server-sqlite --db-path /data/mydb.sqlite")
    .Build();

await client.ConnectAsync();
chat.Tools.Register(client);

string response = chat.Submit("Show me the schema of the users table");

Subprocess Configuration

var client = McpClientBuilder.ForStdio("npx", "@modelcontextprotocol/server-github")
    .WithWorkingDirectory("/path/to/project")
    .WithEnvironment("GITHUB_TOKEN", Environment.GetEnvironmentVariable("GITHUB_TOKEN"))
    .WithAutoRestart(maxAttempts: 3)       // Restart on crash
    .WithStderrHandler(line => Log(line))   // Capture server logs
    .Build();

Connecting to a Remote MCP Server (HTTP+SSE)

For cloud-hosted MCP servers, use HTTP transport with optional authentication:

// Connect to a remote MCP server with bearer token auth
var client = McpClientBuilder.ForHttp("https://mcp.example.com")
    .WithBearerToken("your-api-token")
    .WithTimeout(TimeSpan.FromMinutes(2))
    .WithClientInfo("MyApp", "My Application", "1.0.0")
    .Build();

await client.ConnectAsync();
chat.Tools.Register(client);

Discovering Available Tools

After connecting, list the tools the server provides:

await client.ConnectAsync();

var tools = await client.GetToolsAsync();
foreach (var tool in tools)
{
    Console.WriteLine($"  {tool.Name}: {tool.Description}");
    // Example output:
    //   read_file: Read the contents of a file
    //   list_directory: List files in a directory
    //   search_files: Search for files matching a pattern
}

Selective Tool Registration

Register only the tools you need:

// Register all tools
chat.Tools.Register(client);

// Or register with a filter
chat.Tools.Register(client, filter: tool => tool.Name.StartsWith("read_"));

// MCP tools work alongside built-in tools and custom tools
chat.Tools.Register(BuiltInTools.Calculator);
chat.Tools.Register(new MyCustomTool());

Handling Authentication

Transport Authentication Method
HTTP Bearer token via WithBearerToken()
Stdio Environment variables via WithEnvironment()
// HTTP: Bearer token
var httpClient = McpClientBuilder.ForHttp("https://api.example.com/mcp")
    .WithBearerToken("sk-your-token")
    .Build();

// Stdio: Pass API key as environment variable
var stdioClient = McpClientBuilder.ForStdio("npx", "@modelcontextprotocol/server-github")
    .WithEnvironment("GITHUB_PERSONAL_ACCESS_TOKEN", ghToken)
    .Build();

Monitor authentication failures:

client.AuthFailed += (sender, args) =>
{
    Console.WriteLine($"Authentication failed: {args.StatusCode}");
};

Lifecycle Management

// Connect
await client.ConnectAsync();

// Use the client...
chat.Tools.Register(client);

// Disconnect when done
await client.DisconnectAsync();

// Or use IDisposable pattern
using var client = McpClientBuilder.ForStdio("npx", "server-name").Build();
await client.ConnectAsync();
// Automatically disconnects and stops subprocess on dispose

Share