---
url: https://weboost-at.github.io/Typeshift/guide/mcp.md
description: >-
  Offer the tools of MCP servers to an agent, connected by your app's own MCP
  client or by the model's provider.
---

# MCP servers

An agent can offer an MCP server's tools next to its toolsets. Typeshift takes no MCP dependency, so you pick the
client.

## Servers your app connects

`UseMcpServer` names a server in the agent's constructor. The name is a key you choose, and your app decides which
server it stands for:

```cs
UseMcpServer("status_page")
    .ReadOnly();
```

Your app connects the server by implementing `IMcpToolProvider`. Its `GetToolsAsync` receives the name and returns
that server's tools. This provider uses the official `ModelContextProtocol.Core` client and builds the server's URL
from the name:

```cs
internal sealed class McpToolProvider : IMcpToolProvider, IAsyncDisposable
{
    private readonly Dictionary<string, McpClient> _clients = [];

    public async ValueTask<IReadOnlyList<AITool>> GetToolsAsync(string server, CancellationToken ct)
    {
        if (!_clients.TryGetValue(server, out var client))
        {
            var transport = new HttpClientTransport(new() { Endpoint = new Uri($"https://mcp.example.com/{server}") });
            _clients[server] = client = await McpClient.CreateAsync(transport, cancellationToken: ct);
        }

        return [.. await client.ListToolsAsync(cancellationToken: ct)];
    }

    // The scope that resolved the provider disposes it, and its connections with it
    public async ValueTask DisposeAsync()
    {
        foreach (var client in _clients.Values)
        {
            await client.DisposeAsync();
        }
    }
}
```

## Registering the provider

Register the provider with `WithMcpToolProvider<T>()`:

```cs
services.AddTypeshift()
    .WithMcpToolProvider<McpToolProvider>();
```

The provider is scoped, and Typeshift resolves it from the run's services, so each scope, such as a web request, gets
its own. That lets it connect each customer with their own credentials. When the scope ends, it disposes the provider
along with its connections, so the provider above opens one connection per server for each scope.

## How the agent offers the tools

In the tool list the model receives, the servers' tools come after the agent's own.
`UseMcpServer(...).RequiresApproval()` makes every call of the server's tools need approval, as
[Approval and modes](./tool-approval.md) describes. `ReadOnly()` marks every tool of the server as reading only, so
[plan mode](./tool-approval.md#plan-mode) offers them all. Use it only for a server whose tools change nothing.

The run fails when a server's tool is named like one of the agent's own tools or like a tool of another server it
uses, because the model would otherwise see only one of them. The error names the server and the tool. An agent that
uses servers also fails its run when no provider is registered.

::: danger A server's tools are untrusted
Treat a server's tool descriptions and results as untrusted text, never as instructions. The model reads both, so a
server you do not control puts its words into the model's context.
:::

## Servers the model provider connects

Some model providers call MCP servers themselves. For those, put Microsoft.Extensions.AI's `HostedMcpServerTool` in
the chat options:

```cs
WithChatOptions()
    .WithModel("anthropic", "claude-sonnet-5-5")
    .WithTools(new HostedMcpServerTool("status_page", new Uri("https://mcp.example.com/status")));
```

The model provider then connects to the server itself, and your `IMcpToolProvider` takes no part. A hosted tool
carries no `ReadOnly()` mark, so plan mode hides it.

## Related

* [Approval and modes](./tool-approval.md): asking before a server's tools run.
* [Plan mode](./tool-approval.md#plan-mode): which tools plan mode offers.
* [Agents](./defining-agents.md#selecting-tools): offering toolsets next to servers.
* [Builders](./builders.md): `UseMcpServer` among the other calls of an agent's constructor.
