Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Note
Die Self-Hosting-MCP-Toolunterstützung in .NET wird in Kürze verfügbar sein.
Go stellt einen Agenten als MCP-Tool bereit, indem tool/agenttool, tool/mcptool und das offizielle MCP Go SDK kombiniert werden. Schließen Sie den Agent mit agenttool.New ein, registrieren Sie ihn bei mcptool.AddTool, und stellen Sie ihn über einen MCP-Transport bereit.
Das gepflegte Foundry-Beispiel verwendet stdio. Es erfordert einen Foundry-Projektendpunkt, Modellbereitstellung und Azure Anmeldeinformationen:
// 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)
}
}
Siehe MCP-Toolintegration für Client- und Servermuster sowie das vollständige MCP-Serverbeispiel für Anweisungen zur Ausführung.
Verwenden Sie agent-framework-hosting-mcp, um einen Agent Framework-Agenten oder Workflow als Werkzeug im nativen Model Context Protocol-SDK verfügbar zu machen. Das Paket wählt kein Webframework aus oder kapselt den Lebenszyklus des MCP-SDK-Servers. Ihre Anwendung verwaltet weiterhin den MCP-Server, die Handlerregistrierung, den Transport, die Sitzungsschlüssel-Richtlinie, Authentifizierung, Autorisierung und Bereitstellung.
pip install --pre agent-framework-hosting-mcp
An der Protokollgrenze konvertieren
mcp_to_run(...) konvertiert überprüfte MCP-Toolargumente in Agent Framework-Nachrichten und ausgewählte Chatoptionen und mcp_from_run(...) konvertiert eine abgeschlossene Antwort in systemeigene MCP-Werte ContentBlock . Verwenden Sie diese beiden Funktionen direkt, wenn der Toolvertrag einer Anwendung ein vollständig benutzerdefiniertes systemeigenes Schema und einen Handler benötigt:
"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()
Nur die in chat_option_arguments aufgeführten Argumentnamen werden in run["options"] kopiert; andere MCP-Argumente bleiben in der Rohdarstellung der Nachricht verfügbar, werden jedoch nicht an den Modellclient weitergeleitet.
Host mit MCPServer
Verwenden Sie MCPServer, um für MCP SDK 2.x-Anwendungen ein systemeigenes MCP-Toolschema von einer dekorierten Funktion abzuleiten. Geben Sie CallToolResult explizit zurück, nachdem die abgeschlossene Agent Framework-Antwort konvertiert wurde:
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."""
Im Beispiel wird zustandsloses streambares HTTP verwendet. Fügen Sie anwendungseigene Authentifizierung, Autorisierung und Sitzungspersistenz hinzu, bevor Sie den Server über eine vertrauenswürdige lokale Umgebung hinaus verfügbar machen.
Hosten eines Agents als ein generiertes Tool
AgentMCPTool leitet den nativen Toolnamen, die Beschreibung sowie das Schema von einem Agenten ab und hält Auflistung, Parsing, Ausführung und Ergebniskonvertierung aufeinander abgestimmt, sodass sie nicht auseinanderlaufen können:
) -> 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 verwendet den Namen und die Beschreibung des Agenten, es sei denn, diese werden außer Kraft gesetzt.
parameters Fügt appeigene JSON-Schemaeigenschaften hinzu, die in den unformatierten MCP-Argumenten verfügbar bleiben, und chat_option_parameters fügt Eigenschaften hinzu, deren Werte explizit in Agent Framework-Chatoptionen kopiert werden.
Beibehalten einer Sitzung pro Anruf
Übergeben Sie einen vorhandenen AgentState und einen session_id_parameter, damit wiederholte Aufrufe mit derselben opaken, von der App definierten session_id dieselbe Unterhaltung fortsetzen:
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 führt nur die AgentState Abfolge „get/run/set“ für Sitzungen aus; Ihre Anwendung muss die Sitzungskennung authentifizieren oder autorisieren und gleichzeitige Aufrufe für dieselbe Sitzung serialisieren, wie es das Beispiel mit einem asyncio.Lock pro Sitzung tut. Dies ist keine previous_response_id-Stil-Verzweigung – eine Anwendung, die eine Konversation verzweigen muss, sollte getrennte Quell- und Ziel-IDs akzeptieren, die Quellsitzung kopieren und das Ergebnis unter dem Zielschlüssel speichern.
Hosten eines Workflows als Tool
WorkflowMCPTool erstellt ein natives MCP-Tool aus dem Eingabetyp des Start-Executors eines Workflows und konvertiert die Ausgaben abgeschlossener Workflows. Datenklassen-, Pydantische und andere objektförmige Eingaben werden zu MCP-Argumenten der obersten Ebene; Primitive Eingaben werden in einen konfigurierbaren Argumentnamen eingeschlossen:
async def list_tools(
_ctx: ServerRequestContext[dict[str, Any]], params: types.PaginatedRequestParams | None
) -> types.ListToolsResult:
Workflowinstanzen behalten ihren Ausführungszustand bei, sodass Anwendungen, die unabhängige Aufrufe benötigen, wie oben gezeigt eine WorkflowStateFactory mit cache_target=False bereitstellen sollten. Prüfpunktwiederherstellung, Human-in-the-Loop-Antworten und Fortsetzungs-IDs bleiben anwendungseigene. Wenn ein Workflow externe Eingaben anfordert, löst der Adapter aus, anstatt ein leeres erfolgreiches Toolergebnis zurückzugeben.
Eine vollständige Liste ausführbarer Server, einschließlich der Variante MCPServer, finden Sie in den MCP-Hostingbeispielen.
Important
Behandeln Sie den MCP-Sitzungsbezeichner und jedes app-definierte session_id Argument als nicht vertrauenswürdige Eingabe. Authentifizieren und autorisieren Sie den Aufrufer, bevor Sie ihn zum Laden oder Speichern des Sitzungszustands verwenden, und leiten Sie die persistente Partitionierung aus dem authentifizierten Mandanten, Benutzer oder Arbeitsbereich ab statt aus dem Rohwert.
Nächste Schritte
Gehen Sie tiefer: