Zelf-gehoste agents als MCP-hulpmiddelen

Opmerking

Ondersteuning voor self-hosting van MCP-hulpprogramma’s in .NET is binnenkort beschikbaar.

Go maakt een agent beschikbaar als een MCP-hulpprogramma door tool/agenttool, tool/mcptool en de officiële MCP Go SDK te combineren. Wikkel de agent met agenttool.New, registreer deze bij mcptool.AddTool en serveer deze via een MCP-transport.

Het onderhouden Foundry-voorbeeld maakt gebruik van stdio. Hiervoor is een Foundry-projecteindpunt, modeldeployment en Azure-referentiegegevens vereist:

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

Zie MCP-toolintegratie voor client- en serverpatronen en het volledige VOORBEELD van de MCP-server voor uitvoeringsinstructies.

Gebruik agent-framework-hosting-mcp dit om een Agent Framework-agent of -werkstroom beschikbaar te maken als een hulpprogramma in de systeemeigen Model Context Protocol SDK. Het pakket kiest geen webframework en beheert de levenscyclus van de MCP SDK-server niet. Uw toepassing is nog steeds eigenaar van de MCP-server, handlerregistratie, transport, sessiesleutelbeleid, verificatie, autorisatie en implementatie.

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

Converteren op de protocolgrens

mcp_to_run(...) converteert gevalideerde MCP-hulpprogrammaargumenten naar Agent Framework-berichten en geselecteerde chatopties en mcp_from_run(...) converteert een voltooid antwoord naar systeemeigen MCP-waarden ContentBlock . Gebruik deze twee functies rechtstreeks wanneer het hulpprogrammacontract van een toepassing een volledig aangepast systeemeigen schema en handler nodig heeft:

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

Alleen argumentnamen die in chat_option_arguments staan vermeld, worden naar run["options"] gekopieerd; andere MCP-argumenten blijven beschikbaar in de ruwe weergave van het bericht, maar worden niet doorgestuurd naar de modelclient.

Host met MCPServer

Voor MCP SDK 2.x-toepassingen gebruikt u MCPServer om een systeemeigen MCP-hulpprogrammaschema af te leiden van een gedecoreerde functie. Retourneer CallToolResult expliciet na het converteren van het voltooide Agent Framework-antwoord:

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

In de sample wordt stateless, streambare HTTP gebruikt. Voeg door de toepassing beheerde verificatie, autorisatie en sessiepersistentie toe voordat de server buiten een vertrouwde lokale omgeving wordt blootgesteld.

Een agent hosten als één gegenereerd hulpprogramma

AgentMCPTool leidt de oorspronkelijke toolnaam, beschrijving en het schema af van een agent, en houdt weergave, parsing, uitvoering en resultaatconversie op elkaar afgestemd, zodat beide niet uit elkaar kunnen gaan lopen:

) -> 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 gebruikt de naam en beschrijving van de agent, tenzij anders ingesteld. parameters voegt eigenschappen toe die eigendom zijn van het JSON-schema die beschikbaar blijven in de onbewerkte MCP-argumenten en chat_option_parameters voegt eigenschappen toe waarvan de waarden expliciet worden gekopieerd naar chatopties van Agent Framework.

Een sessie per gesprek behouden

Geef een bestaande AgentState en een session_id_parameter door, zodat herhaalde aanroepen met hetzelfde ondoorzichtige, door de app gedefinieerde session_id dezelfde conversatie voortzetten:

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 voert alleen de AgentState sessie get/run/set-reeks uit; uw toepassing moet de sessie-id verifiëren of autoriseren en gelijktijdige aanroepen voor dezelfde sessie serialiseren, zoals het voorbeeld doet met een sessie per sessie asyncio.Lock. Dit is geen previous_response_idvertakking in stijl. Een toepassing die een gesprek moet vertakken, moet afzonderlijke bron- en doel-id's accepteren, de bronsessie kopiëren en het resultaat opslaan onder de doelsleutel.

Een werkstroom hosten als hulpprogramma

WorkflowMCPTool leidt één native MCP-tool af uit het start-executor-invoertype van een workflow en converteert de uitvoer van voltooide workflows. Dataclass, Pydantic en andere objectvormige invoer worden MCP-argumenten op het hoogste niveau; primitieve invoer wordt verpakt in een configureerbare argumentnaam:



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

Workflowinstanties behouden hun uitvoeringsstatus, dus toepassingen die onafhankelijke oproepen vereisen, moeten een WorkflowState-factory met cache_target=False opgeven, zoals hierboven is weergegeven. Herstel van controlepunten, antwoorden met menselijke tussenkomst en vervolgidentificatoren blijven eigendom van de applicatie; als een workflow externe invoer aanvraagt, genereert de adapter een fout in plaats van een leeg, succesvol toolresultaat te retourneren.

Zie de MCPServer voor de volledige set runnable servers, inclusief de variant.

Belangrijk

Behandel de MCP-sessie-id en elk door de app gedefinieerd session_id argument als niet-vertrouwde invoer. Verifieer en autoriseer de aanroeper voordat u deze gebruikt om de sessiestatus te laden of op te slaan, en leid duurzame partitionering af van de geauthenticeerde tenant, gebruiker of werkruimte in plaats van van de ruwe waarde.

Volgende stappen 

Ga dieper in: