Agenti hostovaní ve vlastní režii jako nástroje MCP

Poznámka:

Podpora samoobslužného nástroje MCP v .NET bude brzy k dispozici.

Go zpřístupňuje agenta jako nástroj MCP kombinací tool/agenttool, tool/mcptool a oficiálního MCP Go SDK. Zabalte agenta agenttool.New, zaregistrujte ho pomocí mcptool.AddTool a zpřístupněte jej přes transport MCP.

Udržovaná ukázka Foundry používá stdio. Vyžaduje koncový bod projektu Foundry, nasazení modelu a Azure přihlašovací údaje:

// 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)
    }
}

Viz integraci nástrojů MCP pro vzory klientů a serverů a kompletní ukázku serveru MCP pro pokyny ke spuštění.

Pomocí agent-framework-hosting-mcp můžete zpřístupnit agenta nebo pracovní postup platformy Agent Framework jako nástroj v nativní sadě SDK Model Context Protocol. Balíček nevybere webový framework ani nezabalí životní cyklus serveru MCP SDK. Vaše aplikace stále vlastní server MCP, registraci obslužné rutiny, přenos, zásady klíče relace, ověřování, autorizaci a nasazení.

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

Převést na rozhraní protokolu

mcp_to_run(...) převede ověřené argumenty nástroje MCP na zprávy agenta Framework a vybrané možnosti chatu a mcp_from_run(...) převede dokončenou odpověď na nativní hodnoty MCP ContentBlock . Tyto dvě funkce použijte přímo, když kontrakt nástrojů aplikace potřebuje plně vlastní nativní schéma a obslužnou rutinu:

                    "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()

Do chat_option_arguments se kopírují pouze názvy argumentů uvedené v run["options"]; ostatní argumenty MCP zůstávají dostupné v nezpracované reprezentaci zprávy, ale klientovi modelu se nepřeposílají.

Hostování pomocí MCPServeru

Pro aplikace MCP SDK 2.x použijte MCPServer k odvození nativního schématu nástrojů MCP z dekorované funkce. Po převodu dokončené odpovědi rozhraní Agent Framework vraťte CallToolResult explicitně:

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."""

Ukázka používá bezstavové streamovatelné HTTP. Před zveřejněním serveru mimo důvěryhodné místní prostředí přidejte ověřování, autorizaci a trvalost relací spravované aplikací.

Hostování agenta jako jednoho vygenerovaného nástroje

AgentMCPTool přebírá od agenta nativní název nástroje, popis a schéma a udržuje jejich výpis, parsování, spouštění a převod výsledků ve vzájemném souladu, takže se tyto dvě části nemohou rozejít:

) -> 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 použije název a popis agenta, pokud není zadáno jinak. parameters přidá vlastnosti schématu JSON vlastněné aplikací, které zůstanou dostupné v nezpracovaných argumentech MCP, a chat_option_parameters přidá vlastnosti, jejichž hodnoty se explicitně zkopírují do možností chatu v rozhraní Agent Framework.

Zachovat relaci pro každé volání

Předejte existující AgentState a session_id_parameter, aby opakovaná volání se stejným neprůhledným identifikátorem session_id, definovaným aplikací, mohla pokračovat v jedné konverzaci:

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 provádí pouze sekvenci get/run/set pro relaci; vaše aplikace musí ověřit nebo autorizovat identifikátor relace a serializovat souběžná volání pro stejnou relaci, jak to ukázka dělá pomocí AgentState pro každou relaci. Nejedná se o větvení ve stylu previous_response_id – aplikace, která potřebuje rozdělit konverzaci do větví, by měla přijímat samostatná zdrojová a cílová ID, zkopírovat zdrojovou relaci a uložit výsledek pod cílovým klíčem.

Hostovat workflow jako nástroj

WorkflowMCPTool vytváří jeden nativní nástroj MCP ze vstupního typu spouštěcího vykonavatele pracovního postupu a převádí výstupy dokončeného pracovního postupu. Dataclass, Pydantic a další vstupy tvarované objekty se stanou argumenty MCP nejvyšší úrovně; primitivní vstupy jsou zabalené do konfigurovatelného názvu argumentu:



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

Instance workflow zachovávají stav provádění, takže aplikace, které vyžadují nezávislá volání, by měly poskytnout továrnu WorkflowState s cache_target=False, jak je znázorněno výše. Obnovení kontrolního bodu, odpovědi v režimu human-in-the-loop a identifikátory pokračování zůstávají na straně aplikace; pokud pracovní postup vyžaduje externí vstup, adaptér místo vrácení prázdného úspěšného výsledku nástroje vyvolá výjimku.

Kompletní sadu spustitelných serverů, včetně MCPServer varianty, najdete v ukázkách hostování MCP.

Důležité

Považovat identifikátor relace MCP a libovolný argument definovaný session_id aplikací za nedůvěryhodný vstup. Před použitím kteréhokoli z nich k načtení nebo uložení stavu relace ověřte a autorizujte volajícího a trvalé rozdělení odvoďte od ověřeného tenanta, uživatele nebo pracovního prostoru, nikoli od nezpracované hodnoty.

Další kroky

Jděte hlouběji: