Agentes de auto-host como ferramentas do MCP

Note

O suporte à ferramenta MCP de auto-hospedagem no .NET estará disponível em breve.

Note

O suporte à ferramenta MCP de auto-hospedagem não está disponível no momento para o Go.

Use agent-framework-hosting-mcp para expor um agente ou fluxo de trabalho do Agent Framework como ferramenta no SDK nativo do Model Context Protocol. O pacote não escolhe um framework web nem encapsula o ciclo de vida do servidor no SDK do MCP; seu aplicativo continua responsável por Server, o registro de manipuladores, 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 de ferramenta MCP validados em mensagens do Agent Framework e opções de chat selecionadas e mcp_from_run(...) converte uma resposta concluída em valores mcp ContentBlock nativos. Use essas duas funções diretamente quando o contrato de ferramenta de um aplicativo precisar de um esquema e manipulador nativo totalmente personalizados:

@server.list_tools()
async def list_tools() -> list[types.Tool]:
    """Return the app-owned native MCP tool definition."""
    return [
        types.Tool(
            name="run_agent_manually",
            description=agent.description or "",
            inputSchema={
                "type": "object",
                "properties": {
                    TASK_ARGUMENT: {
                        "type": "string",
                        "description": "The request for the hosted agent.",
                    },
                    **CHAT_OPTION_ARGUMENTS,
                },
                "required": [TASK_ARGUMENT],
                "additionalProperties": False,
            },
        )
    ]


@server.call_tool()
async def call_tool(name: str, arguments: dict[str, object] | None) -> list[types.ContentBlock]:
    """Convert, run, and render without the agent-backed adapter."""
    if name != "run_agent_manually":
        raise ValueError(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 mcp_from_run(result)

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

Hospedar um agente como uma ferramenta gerada

AgentMCPTool extrai de um agente o nome, a descrição e o schema da ferramenta nativa, e mantém a listagem, o parseamento, a execução e a conversão de resultados alinhados para que não se desalinhem entre si:

agent_tool = AgentMCPTool(
    agent,
    name="run_agent",
    argument_description="The request for the hosted agent.",
    chat_option_parameters={
        "reasoning_effort": {
            "type": "string",
            "enum": ["low", "medium", "high"],
            "description": "Optional reasoning effort for models that support it.",
        }
    },
)


@server.list_tools()
async def list_tools() -> list[types.Tool]:
    """Describe the app-owned MCP tool schema."""
    return await agent_tool.list_tools()


@server.call_tool()
async def call_tool(name: str, arguments: dict[str, object] | None) -> list[types.ContentBlock]:
    """Run the app-owned tool with native MCP and Agent Framework values."""
    return await agent_tool.call_tool(name, arguments)

AgentMCPTool usa o nome e a descrição do agente, a menos que seja substituído. parameters adiciona propriedades de esquema JSON de propriedade do aplicativo que permanecem disponíveis nos argumentos MCP brutos e chat_option_parameters adiciona propriedades cujos valores são explicitamente copiados em opções de chat do Agent Framework.

Manter uma 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 pelo aplicativo continuem a mesma conversa:

session_locks: dict[str, asyncio.Lock] = {}


@server.list_tools()
async def list_tools() -> list[types.Tool]:
    """Return the agent-derived MCP tool definition."""
    return await agent_tool.list_tools()


@server.call_tool()
async def call_tool(name: str, arguments: dict[str, object] | None) -> list[types.ContentBlock]:
    """Serialize calls per app-owned session before using ``AgentState``."""
    session_id = arguments.get("session_id") if arguments else None
    if not isinstance(session_id, str) or not session_id:
        raise ValueError("MCP tool argument 'session_id' must be a non-empty string.")
    lock = session_locks.setdefault(session_id, asyncio.Lock())
    async with lock:
        return await agent_tool.call_tool(name, arguments)

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

Hospedar um fluxo de trabalho como uma ferramenta

WorkflowMCPTool gera uma ferramenta MCP nativa a partir do tipo de entrada do start-executor de um fluxo de trabalho e converte as saídas de um fluxo de trabalho concluído. As entradas dataclass, Pydantic e outras entradas em forma de objeto tornam-se argumentos MCP de nível superior; as entradas primitivas são encapsuladas em um nome de argumento configurável:

server = Server("agent-framework-hosting-mcp-workflow-sample")
workflow_tool = WorkflowMCPTool(
    WorkflowState(create_workflow, cache_target=False),
    name="draft_content",
)

As instâncias de fluxo de trabalho preservam o estado de execução, portanto os aplicativos que precisam de chamadas independentes devem fornecer uma fábrica WorkflowState com cache_target=False, conforme mostrado acima. A restauração do ponto de verificação, as respostas humanas no loop e os identificadores de continuação permanecem de propriedade do aplicativo; se um fluxo de trabalho solicitar entrada externa, o adaptador será gerado em vez de retornar um resultado de ferramenta de êxito vazio.

Para obter o conjunto completo de servidores executáveis , incluindo a variante FastMCP que deriva seu esquema de uma função decorada, consulte os exemplos de hospedagem do MCP.

Importante

Trate o identificador de sessão MCP e qualquer argumento definido pelo session_id aplicativo como entrada não confiável. Autentique e autorize o chamador antes de usar qualquer uma das duas operações para carregar ou salvar o estado da sessão e derive o particionamento durável do locatário, usuário ou workspace autenticado, em vez de usar o valor bruto.

Próximas Etapas 

Vá mais fundo: