MCP & AI

MCP + Claude Desktop for Windows Operations

What the Model Context Protocol actually is, why ops + AI is finally interesting, and how to wire Claude Desktop into a fleet of Windows hosts in under an hour.

For about three years now, the AI conversation in operations has had a hole in the middle. LLMs were great at explaining log lines, debugging stack traces in chat, and writing PowerShell. But to actually do anything in your environment they needed a human operator copying output back and forth. The friction killed most workflows before they got useful.

The Model Context Protocol (MCP) is the spec that closes that loop. Released by Anthropic in late 2024, MCP gives LLMs a standard, tool-typed way to read context from and act on external systems. For Windows operations, the implication is huge: you can now expose your fleet's capabilities to Claude Desktop (or any MCP-compatible client) and have natural-language ops actually run end-to-end.

This post is what we wish someone had handed us six months ago. What MCP is, why it matters for Windows ops specifically, how to wire it up, and where it falls short.

What is MCP, in one paragraph

MCP is a JSON-RPC protocol that lets an MCP client (Claude Desktop, Cursor, etc.) connect to an MCP server (something you write) and discover three things: tools (functions the client can call), resources (read-only data the client can fetch), and prompts (named templates). The tools are JSON-Schema-typed, so the LLM on the client side knows exactly what each tool takes and returns. Transport is either STDIO (the client spawns the server as a child process) or HTTP. That's the whole spec, and that's why it works.

Why ops + AI is finally interesting

Three things changed at once:

1. The LLM can finally read and act

Previously, integrating an LLM into ops meant either (a) custom function-calling with awkward JSON schemas, or (b) ChatOps via Slack with command-prefix bots. MCP gives you typed tools that the model can chain — read state, decide, act, observe, act again — without you writing glue per tool.

2. The desktop client is good enough

Claude Desktop runs locally, sees your local environment, and (with MCP) reaches whatever you tell it to. It's effectively a personal ops console that happens to be an AI. The UX of "ask, get answer, take action" matters more than benchmarks here.

3. Windows finally has a sane agent runtime

.NET 9 produces single-file binaries with no install required, runs as a tray app or a Windows Service, talks HTTPS to your server, and starts up in milliseconds. Building the agent half of the equation is a weekend job, not a quarter.

What a Windows-ops MCP server looks like

Concretely, you want to expose a handful of tools that map to "things an operator does on the fleet." From experience, the high-value ones are:

Six tools is enough to drive 80% of fleet operations from natural language. You can add more as needs emerge.

Minimal C# implementation

The official C# SDK (ModelContextProtocol NuGet) takes care of the protocol. Your tool is a method with attributes:

using System.ComponentModel;
using ModelContextProtocol.Server;

[McpServerToolType]
public static class FleetTools
{
    [McpServerTool(Name = "list_clients"),
     Description("List all hosts in the fleet with their status and tags.")]
    public static async Task<object> ListClients(
        [Description("Optional tag filter, e.g. 'prod' or 'customer:acme'")] string? tag = null)
    {
        // Call your server's REST API
        var clients = await PwaApi.GetClientsAsync(tag);
        return clients.Select(c => new {
            id = c.Id, name = c.Name, status = c.IsOnline ? "online" : "offline",
            lastSeen = c.LastSeenAt, tags = c.Tags
        });
    }

    [McpServerTool(Name = "dispatch_task"),
     Description("Dispatch a diagnostic or remediation task to a specific host.")]
    public static async Task<object> DispatchTask(
        [Description("Target host ID")] string clientId,
        [Description("Tool name, e.g. 'DiskSpace', 'TopProcesses', 'TempCleaner'")] string toolName,
        [Description("Optional JSON parameters for the tool")] string? paramsJson = null)
    {
        var task = await PwaApi.CreateTaskAsync(clientId, toolName, paramsJson);
        return new { taskId = task.Id, status = "queued", eta = "~30s" };
    }
}

Register the server in Program.cs:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddMcpServer()
    .WithStdioServerTransport()      // STDIO for Claude Desktop
    .WithHttpServerTransport()       // HTTP for everything else
    .WithToolsFromAssembly();        // auto-discovers [McpServerTool]
var app = builder.Build();
app.MapMcp();
app.Run();

Build it as a single-file executable and you've got an MCP server. The WithToolsFromAssembly() reflection bit means adding a new tool is exactly one new method — no manifest, no registration code.

Wiring Claude Desktop

Claude Desktop reads claude_desktop_config.json. On Windows it lives at %APPDATA%\Claude\claude_desktop_config.json. Add your server:

{
  "mcpServers": {
    "windows-ops": {
      "command": "C:\\Program Files\\MyOpsAgent\\McpServer.exe",
      "args": ["--stdio"],
      "env": {
        "OPS_API_BASE": "https://ops.internal.example.com",
        "OPS_API_KEY": "..."
      }
    }
  }
}

Restart Claude Desktop. The tools show up under the plug icon. Ask Claude "what's the disk usage across all production hosts?" — it calls list_clients with tag=prod, then dispatches DiskSpace to each, waits for results, and synthesizes the answer.

What this unlocks in practice

A few real examples from our own operations:

None of these are revolutionary, individually. The win is that the bar to do them dropped from "remember the exact CLI syntax" to "describe what you want." For operators who don't live in the CLI daily, this is the difference between using the tooling and dreading it.

Where it falls short (be honest)

Latency. A round-trip through Claude with one tool call is ~3–8 seconds. A chained workflow with 4–5 tool calls is 20–40 seconds. That's fine for triage and ad-hoc work. It's wrong for time-critical incident response — for that, keep your dashboard and CLI close.

Confirmation and safety. Mutating tools (kill process, restart service, run script) should default to asking before doing, especially in production. MCP doesn't enforce this — your tool implementation must. We add a requireConfirmation flag per tool and gate Claude's calls behind a "really?" prompt for the dangerous ones.

Audit trail. When the operator runs restart_service from the dashboard, you log who did it. When Claude does it on the operator's behalf, the same audit needs to capture "operator X asked Claude, Claude called restart_service on host Y at time Z". Build this into your MCP server from day one. Retrofitting is painful.

Context window discipline. If you naively return giant JSON blobs (full process lists, full event logs), you'll blow Claude's context fast. Return summaries by default; let Claude ask for the detail when it needs it.

What's next

MCP is still young — the spec hits major versions every few months — but the basic shape is stable enough to build on. The pattern of typed tools + a smart client is a real shift in how ops gets done. If you operate Windows infrastructure and you haven't tried wiring MCP into your tooling yet, an afternoon experiment will probably surprise you.

If you don't want to build the server half: PeopleWorks Agent ships an MCP Server with 20 fleet-ops tools out of the box. Drop it in your claude_desktop_config.json and you're in business in five minutes.

Try MCP-powered Windows ops in 5 minutes

PWA's MCP Server is part of the free Starter tier. Connect Claude Desktop, drive your fleet in natural language.

Start Free