Agentes de auto-hospedagem como ferramentas MCP

Observação

O suporte para autoalojamento de ferramentas MCP em .NET estará disponível em breve.

O Go expõe um agente como uma ferramenta MCP ao combinar tool/agenttool, tool/mcptool, e o SDK oficial do MCP Go. Envolve o agente com agenttool.New, regista-o com mcptool.AddTool, e serve-o através de um transporte MCP.

A amostra mantida do Foundry utiliza stdio. Requer um endpoint de projeto Foundry, implementação de modelos e credencial Azure:

// Copyright (c) Microsoft. All rights reserved.

// This sample shows how to expose an Agent as an MCP tool.

package main

import (
    "context"

    "github.com/microsoft/agent-framework-go/agent"
    "github.com/microsoft/agent-framework-go/examples/internal/demo"
    "github.com/microsoft/agent-framework-go/provider/foundryprovider"
    "github.com/microsoft/agent-framework-go/tool/agenttool"
    "github.com/microsoft/agent-framework-go/tool/mcptool"
    "github.com/modelcontextprotocol/go-sdk/mcp"
)

// Run "npx @modelcontextprotocol/inspector go run ." to connect to this MCP server.

func main() {
    token := demo.FoundryTokenCredential()

    // Create Microsoft Foundry agent with the same configuration as the C# example.
    agent := foundryprovider.NewAgent(
        demo.FoundryProjectEndpoint,
        token,
        foundryprovider.ModelDeployment(demo.FoundryModel),
        foundryprovider.AgentConfig{
            Instructions: "You are good at telling jokes, and you always start each joke with 'Aye aye, captain!'.",
            Config: agent.Config{
                Name:        "Joker",
                Description: "An agent that tells jokes.",
            },
        },
    )

    // Create an MCP server with the agent exposed as a tool.
    srv := mcp.NewServer(&mcp.Implementation{
        Name:    "agent-mcp-server",
        Version: "1.0.0",
    }, nil)

    // Register the agent as an MCP tool.
    mcptool.AddTool(srv, agenttool.New(agent, agenttool.Config{}))

    // Run the MCP server with StdIO transport.
    if err := srv.Run(context.Background(), &mcp.StdioTransport{}); err != nil {
        demo.Panic(err)
    }
}

Consulte integração com a ferramenta MCP para padrões cliente e servidor, e o exemplo completo do servidor MCP para instruções de execução.

Utilize agent-framework-hosting-mcp para expor um agente ou fluxo de trabalho do Agent Framework como uma ferramenta no SDK nativo Model Context Protocol. O pacote não escolhe um framework web nem envolve o ciclo de vida do servidor MCP SDK. A sua aplicação ainda detém o servidor MCP, o registo do handler, o transporte, a política de chave de sessão, a autenticação, a autorização e a implantação.

pip install --pre agent-framework-hosting-mcp

Converter no limite do protocolo

mcp_to_run(...) converte argumentos validados da ferramenta MCP em mensagens do Agent Framework e opções de chat selecionadas, e mcp_from_run(...) converte uma resposta completa em valores nativos do MCP ContentBlock . Use estas duas funções diretamente quando o contrato de ferramenta de uma aplicação necessita de um esquema e gestor nativos totalmente personalizados:

                    "properties": {
                        TASK_ARGUMENT: {
                            "type": "string",
                            "description": "The request for the hosted agent.",
                        },
                        **CHAT_OPTION_ARGUMENTS,
                    },
                    "required": [TASK_ARGUMENT],
                    "additionalProperties": False,
                },
            )
        ]
    )


async def call_tool(
    _ctx: ServerRequestContext[dict[str, Any]], params: types.CallToolRequestParams
) -> types.CallToolResult:
    """Convert, run, and render without the agent-backed adapter."""
    name = params.name
    arguments = params.arguments or {}

    if name != "run_agent_manually":
        raise MCPError(types.INVALID_PARAMS, f"Unknown MCP tool: {name}")
    run = mcp_to_run(
        arguments,
        argument_name=TASK_ARGUMENT,
        chat_option_arguments=CHAT_OPTION_ARGUMENTS,
    )
    result = await agent.run(run["messages"], options=run["options"])
    return types.CallToolResult(content=mcp_from_run(result))


server = Server("agent-framework-hosting-mcp-manual-sample", on_list_tools=list_tools, on_call_tool=call_tool)
credential = DefaultAzureCredential()

Apenas os nomes dos argumentos listados em chat_option_arguments são copiados para run["options"]; outros argumentos MCP permanecem disponíveis na representação bruta da mensagem, mas não são encaminhados para o cliente modelo.

Anfitrião com MCPServer

Para aplicações MCP SDK 2.x, utilize-se MCPServer para derivar um esquema nativo de ferramenta MCP a partir de uma função decorada. Retorne CallToolResult explicitamente após converter a resposta completa do Agent Framework:

from contextlib import asynccontextmanager
from typing import Literal

from agent_framework import Agent
from agent_framework.foundry import FoundryChatClient
from agent_framework_hosting_mcp import mcp_from_run, mcp_to_run
from azure.identity.aio import DefaultAzureCredential
from mcp import types
from mcp.server.mcpserver import MCPServer

credential = DefaultAzureCredential()
agent = Agent(
    client=FoundryChatClient(
        project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
        model=os.environ["FOUNDRY_MODEL"],
        credential=credential,
    ),
    name="MCPHostedAgent",
    description="Answer a request with the hosted Agent Framework agent.",
    instructions="Answer the user's request clearly and concisely.",
)


@asynccontextmanager
async def lifespan(_server: MCPServer[None]) -> AsyncGenerator[None]:
    """Close the model credential when the MCP server stops."""
    async with credential:
        yield


server = MCPServer(
    name="agent-framework-hosting-mcpserver-sample",
    instructions="Expose an Agent Framework agent as an MCP tool.",
    lifespan=lifespan,
)


@server.tool(
    name="run_agent",
    description="Run the hosted Agent Framework agent.",
    structured_output=False,
)
async def run_agent(
    task: str,
    reasoning_effort: Literal["low", "medium", "high"] | None = None,
) -> types.CallToolResult:
    """Run the agent with MCPServer-validated arguments."""

A amostra utiliza HTTP transmissível sem estado. Adicione autenticação gerida pela aplicação, autorização e persistência de sessão antes de expor o servidor para além de um ambiente local de confiança.

Hospedar um agente como uma ferramenta gerada

AgentMCPTool obtém de um agente o nome nativo da ferramenta, a descrição e o esquema, e mantém alinhadas a listagem, a interpretação, a execução e a conversão de resultados, evitando que ambos se desalinhem:

) -> types.CallToolResult:
    """Run the app-owned tool with native MCP and Agent Framework values."""
    return await agent_tool.call_tool(params.name, params.arguments)


server = Server("agent-framework-hosting-mcp-sample", on_list_tools=list_tools, on_call_tool=call_tool)
credential = DefaultAzureCredential()
agent = Agent(
    client=FoundryChatClient(
        project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
        model=os.environ["FOUNDRY_MODEL"],
        credential=credential,
    ),
    name="MCPHostedAgent",
    description="Answer a request with the hosted Agent Framework agent.",
    instructions="Answer the user's request clearly and concisely.",
)
agent_tool = AgentMCPTool(
    agent,
    name="run_agent",
    argument_description="The request for the hosted agent.",
    chat_option_parameters={
        "reasoning_effort": {
            "type": "string",

AgentMCPTool usa o nome e a descrição do agente, salvo indicação em contrário. parameters adiciona propriedades do schema JSON pertencentes à aplicação que permanecem disponíveis nos argumentos MCP em bruto, e chat_option_parameters adiciona propriedades cujos valores são explicitamente copiados para as opções de chat do Agent Framework.

Manter sessão por chamada

Passe um AgentState existente e um session_id_parameter para permitir que chamadas repetidas com o mesmo session_id opaco definido pela aplicação continuem a mesma conversa:

state = AgentState(agent)
agent_tool = AgentMCPTool(
    state,
    name="run_agent",
    argument_description="The request for the hosted agent.",
    parameters={
        "session_id": {
            "type": "string",
            "minLength": 1,
            "description": (
                "Opaque, app-defined conversation key. Reuse the same value to continue and update one conversation."
            ),
        }
    },
    required_parameters={"session_id"},
    chat_option_parameters={
        "reasoning_effort": {
            "type": "string",

AgentMCPTool apenas executa a sequência AgentState get/run/set da sessão; a sua aplicação tem de autenticar ou autorizar o identificador da sessão e serializar chamadas concorrentes para a mesma sessão, tal como o exemplo faz com um asyncio.Lock por sessão. Isto não é uma ramificação no estilo previous_response_id — uma aplicação que precise de bifurcar uma conversa deve aceitar IDs de origem e de destino separados, copiar a sessão de origem e armazenar o resultado sob a chave de destino.

Hospedar um fluxo de trabalho como ferramenta

WorkflowMCPTool gera uma ferramenta nativa de MCP a partir do tipo de entrada start-executor de um fluxo de trabalho e converte os resultados de saída de fluxos de trabalho concluídos. Dataclass, Pydantic e outras entradas em forma de objeto tornam-se argumentos MCP de topo; As entradas primitivas são envoltas num nome de argumento configurável:



async def list_tools(
    _ctx: ServerRequestContext[dict[str, Any]], params: types.PaginatedRequestParams | None
) -> types.ListToolsResult:

As instâncias de fluxo de trabalho mantêm o estado de execução, pelo que as aplicações que necessitam de chamadas independentes devem fornecer uma fábrica WorkflowState com cache_target=False, como mostrado acima. A restauração de pontos de controlo, as respostas humanas no ciclo e os identificadores de continuação continuam a ser propriedade da aplicação; Se um fluxo de trabalho solicitar entrada externa, o adaptador gera em vez de devolver um resultado vazio e bem-sucedido da ferramenta.

Para o conjunto completo de servidores executáveis, incluindo a MCPServer variante, consulte os exemplos de alojamento MCP.

Importante

Trate o identificador de sessão MCP e qualquer argumento definido session_id pela aplicação como entrada não confiável. Autentique e autorize o autor da chamada antes de utilizar qualquer um deles para carregar ou guardar o estado da sessão, e obtenha um particionamento persistente a partir do tenant, utilizador ou espaço de trabalho autenticados, em vez do valor em bruto.

Passos seguintes

Vai mais fundo: