Lokalt installerade agenter som MCP-verktyg

Anmärkning

Stöd för att självhantera MCP-verktyg i .NET kommer snart.

Go gör en agent till ett MCP-verktyg genom att kombinera tool/agenttool, tool/mcptool och den officiella MCP Go SDK. Omslut agenten med agenttool.New, registrera den med mcptool.AddTool, och exponera den via en MCP-transport.

Det aktivt underhållna Foundry-exemplet använder stdio. Det kräver en slutpunkt för Foundry-projektet, modelldistribution och Azure autentiseringsuppgifter:

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

Se MCP-verktygsintegrering för klient- och servermönster och det fullständiga MCP-serverexemplet för körningsinstruktioner.

Använd agent-framework-hosting-mcp för att exponera en Agent Framework-agent eller ett arbetsflöde som ett verktyg i det interna SDK:t för Model Context Protocol . Paketet väljer inte ett webbramverk eller omsluter MCP SDK-serverns livscykel. Din applikation äger fortfarande MCP-servern, hanterarregistrering, transport, sessionsnyckelprincip, autentisering, auktorisering och driftsättning.

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

Konvertera vid protokollgränsen

mcp_to_run(...) konverterar verifierade MCP-verktygsargument till Agent Framework-meddelanden och valda chattalternativ och mcp_from_run(...) konverterar ett slutfört svar till inbyggda MCP-värden ContentBlock . Använd dessa två funktioner direkt när ett programs verktygskontrakt behöver ett helt anpassat internt schema och en hanterare:

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

Endast argumentnamn som anges i chat_option_arguments kopieras till run["options"]; andra MCP-argument förblir tillgängliga i meddelandets rårepresentation men vidarebefordras inte till modellklienten.

Host med MCPServer

För MCP SDK 2.x-program använder du MCPServer för att härleda ett inbyggt MCP-verktygsschema från en dekorerad funktion. Returnera CallToolResult uttryckligen när du har konverterat det slutförda Agent Framework-svaret:

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

Exempelkoden använder tillståndslös strömmande HTTP. Lägg till programägd autentisering, auktorisering och sessionspersistens innan du exponerar servern utanför en betrodd lokal miljö.

Använd en agent som ett genererat verktyg

AgentMCPTool härleder verktygets egna namn, beskrivning och schema från en agent och håller listning, parsning, körning och resultatkonvertering i linje med varandra så att de inte kan glida isär:

) -> 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 använder agentens namn och beskrivning om inget annat anges. parameters lägger till appägda JSON-schemaegenskaper som förblir tillgängliga i de råa MCP-argumenten och chat_option_parameters lägger till egenskaper vars värden uttryckligen kopieras till Agent Framework-chattalternativ.

Behåll en session per samtal

Skicka en befintlig AgentState och en session_id_parameter så att upprepade anrop med samma opaka, appdefinierade session_id kan fortsätta samma konversation:

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 utför endast sessionens get/run/set-sekvens. Programmet måste autentisera AgentState eller auktorisera sessionsidentifieraren och serialisera samtidiga anrop för samma session, som exemplet gör med en per session asyncio.Lock. Det här är inte previous_response_id-style branching – ett program som behöver förgrena en konversation bör acceptera separata käll- och mål-ID: er, kopiera källsessionen och lagra resultatet under målnyckeln.

Publicera ett arbetsflöde som verktyg

WorkflowMCPTool härleder ett inbyggt MCP-verktyg från ett arbetsflödes start-executor-indatatyp och konverterar slutförda arbetsflödesutdata. Dataklass, Pydantic och andra objektformade indata blir MCP-argument på toppnivå. primitiva indata omsluts i ett konfigurerbart argumentnamn:



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

Arbetsflödesinstanser bevarar exekveringstillståndet, så applikationer som behöver oberoende anrop bör tillhandahålla en WorkflowState-fabrik med cache_target=False, som visas ovan. Kontrollpunktsåterställning, human-in-the-loop-svar och fortsättningsidentifierare förblir programägda. Om ett arbetsflöde begär externa indata genereras adaptern i stället för att returnera ett tomt lyckat verktygsresultat.

Den fullständiga uppsättningen runnable-servrar, inklusive varianten MCPServer, se MCP-hostingexemplen.

Important

Behandla MCP-sessionsidentifieraren och alla appdefinierade session_id argument som ej betrodda indata. Autentisera och auktorisera anroparen innan du använder någon av dem för att ladda eller spara sessionstillstånd, och härled varaktig partitionering från den autentiserade klientorganisationen, användaren eller arbetsytan i stället för det ursprungliga värdet.

Nästa steg

Gå djupare: