MCP and Microsoft Agent Framework

tl;dr

  • MCP (Model Context Protocol) is an open protocol that standardizes how AI hosts (models/ or agents) discover and call external “tools” and contextual data sources. Instead of building bespoke integrations for every service, an AI host can discover tools exposed by MCP servers and invoke them using a single, consistent API (tool list + function invocation/streaming).
  • MCP server: a service that publishes tools (callable functions, data endpoints, long-running operations) via MCP over supported transports (stdio for local child processes, HTTP + SSE for remote/streamable). Servers are the canonical place to register capabilities agents can discover. *SSE is an HTTP‑based streaming mechanism where the server keeps an HTTP connection open and continuously pushes events to the client
  • MCP client: the client-side runtime your agent uses to discover and call tools exposed by one or more MCP servers. The MCP C# SDK provides transports and helpers to produce AIFunctions that integrate with Microsoft’s Agent Framework function-calling model.

This post explains what MCP is, how servers and clients work, and how to connect MCP tools into the Microsoft Agent Framework with short, practical C# examples (stdio client, converting tools to AIFunctions, and a minimal ASP.NET Core MCP server). It assumes you already know the Microsoft Agent Framework and are familiar with adding AIFunctions to an agent.

Why MCP matters for Agent Framework users

  • Decoupling: your agent doesn’t need every skill embedded. Publish skills centrally on MCP servers and let agents discover them at runtime.
  • Reuse & governance: maintain a canonical set of tools, centralize auth, logging, quotas, and policy.
  • Transport flexibility: local tools as child processes (stdio) during development, HTTP + SSE for remote production services with streaming and sessions.
  • Function-calling integration: the MCP C# SDK exposes helpers that translate MCP tools to AIFunction instances you can pass directly to the Agent Framework. That means the model’s function-calling flow can choose and invoke remote MCP tools as if they were local functions.

Core concepts

  • Tool: a callable capability. Each tool includes metadata (name, description, JSON schema for arguments, and optional streaming semantics). LLMs use this metadata to select and call appropriate tools.
  • Transport: how a client talks to a server. Common transports: stdio (spawned child), HTTP + SSE (remote streaming).
  • Session & long-running tasks: MCP supports sessions and resumable/streamable operations so agents can work with long-running processes.
  • Security: MCP servers are APIs—protect them with OAuth, validate scopes/claims, and apply standard API hardening.

C# examples — preface and dependencies

  • The examples use the Model Context Protocol C# SDK and the Agent Framework integration helpers. Replace placeholders (endpoints, credentials, model clients) with your configuration.
  • NuGet packages you’ll typically use (check exact package names/versions for your environment): ModelContextProtocol.Client, ModelContextProtocol.AspNetCore (server-side), Microsoft.Extensions.AI (AIFunction types), and your Agent Framework package (the one you already use). The exact package names and APIs may evolve; consult the MCP C# SDK docs and Agent Framework docs for up-to-date guidance.

Example 1 — Minimal MCP client (stdio) that lists tools
Purpose: quickly launch a local MCP server as a child process and list the tools it exposes. Useful for local dev or verifying a server.

C# (minimal)

using System;
using System.Threading.Tasks;
using ModelContextProtocol.Client;
using ModelContextProtocol.Client.Transports;

class Program
{
    static async Task Main()
    {
        // Start a local MCP server as a child process. Adjust command/arguments.
        var transport = new StdioClientTransport(new StdioClientTransportOptions
        {
            Command = "dotnet",
            Arguments = new[] { "run", "--project", "../MyMcpServer" },
            Name = "LocalMcp"
        });

        using var mcpClient = await McpClient.CreateAsync(transport);

        var tools = await mcpClient.ListToolsAsync();
        Console.WriteLine("Tools available from MCP server:");
        foreach (var t in tools)
        {
            Console.WriteLine($"- {t.Name}: {t.Description}");
        }
    }
}

What this does

  • It spawns your server project (via dotnet run) and uses the stdio transport to speak MCP to it.
  • ListToolsAsync fetches the catalog of published tools (names, descriptions, and parameter schemas).

Notes

  • Use stdio for development, local tooling, or launching untrusted tools in a sandboxed child process. For production remote servers use HTTP + SSE.
  • Always handle cancellation tokens and process lifecycle (timeouts, crashes) robustly in production code.

Example 2 — Convert MCP tools to AIFunctions and add them to an Agent
Purpose: let your agent use discovered remote tools via the Agent Framework’s function-calling mechanism (the model sees tools as functions it can call).

C# (sketch)

using System;
using System.Threading;
using System.Threading.Tasks;
using ModelContextProtocol.Client;
using ModelContextProtocol.Client.Transports;
using Microsoft.Extensions.AI;                // AIFunction types
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Agents.AI;                    // your Agent Framework types

class Program
{
    static async Task Main()
    {
        // 1) Create an MCP client (stdio example)
        var transport = new StdioClientTransport(new StdioClientTransportOptions
        {
            Command = "dotnet",
            Arguments = new[] { "run", "--project", "../MyMcpServer" }
        });

        using var mcpClient = await McpClient.CreateAsync(transport);

        // 2) Convert discovered tools to AIFunctions using the SDK helper
        // The SDK exposes an extension/method that returns IEnumerable<AIFunction>
        var aiFunctions = await mcpClient.GetAIFunctionsAsync(cancellationToken: CancellationToken.None);
        // aiFunctions are ready to pass into the Agent Framework.

        // 3) Build your ChatClient (your existing model client). Pseudocode below.
        IChatClient chatClient = BuildYourChatClientWithFunctionInvocation(); // use OpenAI/AzureOpenAI etc.

        // 4) Create an agent with the discovered functions available to the model
        var agent = chatClient.AsAIAgent(instructions: "You may call MCP tools as needed.", tools: aiFunctions);

        var result = await agent.RunAsync("Check invoice 12345 and return the payment date.");
        Console.WriteLine(result.Text);
    }

    static IChatClient BuildYourChatClientWithFunctionInvocation()
    {
        // Build your model client with function-calling enabled. This is highly dependent
        // on which model SDK you use; use the Agent Framework pattern you already have.
        throw new NotImplementedException();
    }
}

Key points and gotchas

  • The MCP SDK returns AIFunction-compatible objects (or adapters) for MCP tools; you can pass them straight into the agent constructor/options used by the Agent Framework. No manual JSON schema translation usually required.
  • Pay attention to parameter schemas: MCP tool parameter schemas are JSON Schema-based. The AIFunction adapter will present these to the model, but ensure you validate arguments server-side as well.
  • Streaming/long-running tools: if a tool supports streaming or sessions, the adapter may offer streaming bindings or expose session tokens that the Agent Framework can handle. Check the SDK docs for streaming APIs and how they map to your chat client’s streaming model.

Example 3 — Minimal ASP.NET Core MCP server (HTTP + SSE)
Purpose: expose tools over HTTP + SSE so remote agents can discover and invoke them. This is a minimal Program.cs sketch; register and implement your tools separately.

Program.cs

using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using ModelContextProtocol.AspNetCore; // server integration

var builder = WebApplication.CreateBuilder(args);

// Add MCP server services (package provides extension methods)
builder.Services.AddModelContextProtocol();

var app = builder.Build();

// Map the MCP endpoints. This registers the endpoints the MCP HTTP transport expects (e.g. /sse, /messages).
app.MapMcp(); // extension method from ModelContextProtocol.AspNetCore

app.Run();

Registering tools

  • The SDK provides APIs to register tools (stateless tools, session-aware tools, or long-running handlers). Implement each tool as a class or function and register it with the MCP server service registration API (see SDK docs for registration patterns). Tools are described with name, description, and input schema.

Security

  • Protect MCP endpoints with OAuth 2.1 / bearer tokens (Microsoft Entra ID recommended). Validate scopes and claims before allowing tool invocation. Don’t expose privileged tools without strict auth checks.
  • Apply standard API hardening: CORS restrictions, host filtering, rate limiting, input validation, logging/auditing, and parameter sanitization. Treat tool execution as code execution—apply sandboxing, denylisting, and runtime quotas where appropriate.

Example: minimal tool registration sketch (pseudocode)

// Pseudocode - consult the SDK for exact API names
builder.Services.AddModelContextProtocol()
    .AddTool<MyTool>("CheckInvoice", options => { /* metadata, schema */ });

Practical notes when connecting MCP and Agent Framework

  1. Discovery vs. shipping tools
    • You can ship a few “core” tools inside the agent and discover more via MCP at startup or dynamically during a session. Consider caching the tool catalog to avoid repeated network calls.
  2. Function invocation flow
    • The Agent Framework’s function-calling flow is typically: model chooses a function, agent runtime serializes arguments according to the function schema, calls the function, and returns results to the model. MCP adapters wire that call to an MCP server invocation. Handle timeouts and partial results for long-running operations.
  3. Streaming & sessions
    • For streaming outputs (SSE), ensure your chat client and agent can accept streamed partial results or forward them as incremental responses to the model. For session-based tools (long-running jobs), the server will usually hand back a session ID or event stream you can poll or subscribe to. Map session lifecycle into your agent’s state model.
  4. Error handling & observability
    • Log tool discovery, invocation arguments, responses, and errors. Capture correlation IDs. Consider returning sanitized error messages to the model while logging full details internally.
  5. Security & governance checklist
    • Require OAuth bearer tokens and validate tokens on every request.
    • Use scoped permissions: separate discovery (tool list) vs. execution scopes.
    • Limit which apps/users can call elevated tools.
    • Rate-limit and quota tools to reduce abuse.
    • Validate input against declared JSON schema server-side (never trust client input).
    • Sanitize logs to avoid leaking sensitive data.
    • Audit tool invocations with user identity and request context.
    • Consider a per-tool approval workflow for sensitive operations (human-in-the-loop).

Debugging tips

  • If ListToolsAsync returns nothing: check transport connectivity, server process logs (stdio), firewall/CORS (HTTP), and version compatibility between client/server SDKs.
  • For JSON schema mismatches: ensure server-published tool schemas are valid JSON Schema and that the client SDK version understands the schema features used.
  • For streaming issues: check that the server pushes SSE frames and that the client transport is configured to read/forward events incrementally.
  • For auth issues: inspect token audience (resource indicator), scopes, and clock skew. Entra ID configuration examples are in Microsoft docs.

Real-world use cases (short)

  • Integrating Teams / Copilot: expose an MCP server that can send messages, create approvals, or read group context—agents discover these tools to orchestrate workflows.
  • Enterprise services: expose CRM, ERP, or Dynamics 365 actions via MCP so Copilot/agents can act on domain data without embedding connectors in every agent.
  • IDE tooling: expose project or infra operations (build, deploy, ticket lookup) as MCP tools so in-editor agents can perform actions safely and auditable.

Where to go from here

  • Official docs and samples:
    • Model Context Protocol (overview): Microsoft Learn MCP overview.
    • MCP C# SDK repo and samples: modelcontextprotocol/csharp-sdk on GitHub.

Appendix — runnable minimal project tips and csproj hints

  • Minimal dependencies you’ll likely need (adjust exact package IDs to match the SDK versions you pick):
    • ModelContextProtocol.Client
    • ModelContextProtocol.AspNetCore (server)
    • Microsoft.Extensions.AI
    • Your Agent Framework package (the one you already use)

Example csproj snippet (replace versions and package names with exact ones you choose)

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="ModelContextProtocol.Client" Version="x.y.z" />
    <PackageReference Include="ModelContextProtocol.AspNetCore" Version="x.y.z" />
    <PackageReference Include="Microsoft.Extensions.AI" Version="x.y.z" />
    <!-- Add your Agent Framework package here -->
  </ItemGroup>
</Project>

Note: The initial draft of this post was written by BlogWriter and then
edited by Jesse Liberty.
Illustrations by Copilot. Caution: LLMs make mistakes; this post is offered as is.

Unknown's avatar

About Jesse Liberty

Jesse Liberty has three decades of experience writing and delivering software projects and is the author of 2 dozen books and a couple dozen online courses. Liberty is a Senior AI Engineer at the University of Pittsburgh Medical Center, and was a Team Lead and Senior Software Engineer for various corporations, a Senior Technical Evangelist for Microsoft, a Distinguished Software Engineer for AT&T, a VP for Information Services for Citibank and a Software Architect for PBS. He is a 21 year Microsoft MVP.
This entry was posted in AI. Bookmark the permalink.