Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Annotazioni
Il supporto per lo strumento MCP per l’hosting autonomo in .NET sarà presto disponibile.
Go espone un agente come strumento MCP combinando tool/agenttool, tool/mcptoole MCP Go SDK ufficiale. Eseguire il wrapping dell'agente con agenttool.New, registrarlo con mcptool.AddTool e pubblicarlo con un trasporto MCP.
L'esempio di Foundry mantenuto usa stdio. Richiede un endpoint del progetto Foundry, una distribuzione del modello e una credenziale Azure:
// 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)
}
}
Per istruzioni sull'esecuzione, vedere Integrazione degli strumenti MCP per i modelli client e server e l'esempio completo del server MCP .
Usare agent-framework-hosting-mcp per esporre un agente o un flusso di lavoro di Agent Framework come strumento nell'SDK del protocollo di contesto del modello nativo. Il pacchetto non sceglie un framework Web o esegue il wrapping del ciclo di vita del server MCP SDK. L'applicazione possiede ancora il server MCP, la registrazione del gestore, il trasporto, i criteri della chiave di sessione, l'autenticazione, l'autorizzazione e la distribuzione.
pip install --pre agent-framework-hosting-mcp
Convertire al limite del protocollo
mcp_to_run(...) converte gli argomenti dello strumento MCP convalidati in messaggi di Agent Framework e le opzioni di chat selezionate e mcp_from_run(...) converte una risposta completata in valori MCP ContentBlock nativi. Usare queste due funzioni direttamente quando il contratto degli strumenti di un'applicazione richiede uno schema e un gestore nativi completamente personalizzati:
"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()
Solo i nomi degli argomenti elencati in vengono copiati in chat_option_argumentsrun["options"]. Gli altri argomenti MCP rimangono disponibili nella rappresentazione non elaborata del messaggio, ma non vengono inoltrati al client del modello.
Host con MCPServer
Per le applicazioni MCP SDK 2.x, usare MCPServer per derivare uno schema dello strumento MCP nativo da una funzione decorata. Restituisci CallToolResult in modo esplicito dopo la conversione della risposta completata di Agent Framework:
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."""
L'esempio usa HTTP streamabile senza stato. Aggiungere l'autenticazione, l'autorizzazione e la persistenza della sessione gestite dall'applicazione prima di esporre il server oltre un ambiente locale attendibile.
Ospitare un agente come singolo strumento generato
AgentMCPTool ricava da un agente il nome, la descrizione e lo schema dello strumento nativo e mantiene allineati la visualizzazione nell'elenco, il parsing, l'esecuzione e la conversione dei risultati, impedendo che i due si disallineino:
) -> 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 usa il nome e la descrizione dell'agente a meno che non venga eseguito l'override.
parameters aggiunge proprietà dello schema JSON di proprietà dell'app che rimangono disponibili negli argomenti MCP non elaborati e chat_option_parameters aggiunge proprietà i cui valori vengono copiati in modo esplicito nelle opzioni di chat di Agent Framework.
Mantenere una sessione per ogni chiamata
Passa un AgentState esistente e un session_id_parameter per consentire a chiamate ripetute con lo stesso session_id opaco definito dall'app di continuare una conversazione:
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 esegue solo la sequenza get/run/set della sessione AgentState; l'applicazione deve autenticare o autorizzare l'identificatore di sessione e serializzare le chiamate concorrenti per la stessa sessione, come fa l'esempio con un asyncio.Lock per sessione. Non si tratta di una ramificazione in stile previous_response_id: un'applicazione che deve diramare una conversazione dovrebbe accettare ID di origine e di destinazione separati, copiare la sessione di origine e memorizzare il risultato con la chiave di destinazione.
Ospitare un flusso di lavoro come strumento
WorkflowMCPTool ricava uno strumento MCP nativo dal tipo di input dell'esecutore di avvio di un flusso di lavoro e converte gli output dei flussi di lavoro completati. Dataclass, Pydantic e altri input a forma di oggetto diventano argomenti MCP di primo livello; gli input primitivi vengono inclusi in un nome di argomento configurabile:
async def list_tools(
_ctx: ServerRequestContext[dict[str, Any]], params: types.PaginatedRequestParams | None
) -> types.ListToolsResult:
Le istanze del flusso di lavoro mantengono lo stato di esecuzione, quindi le applicazioni che necessitano di chiamate indipendenti devono fornire una WorkflowState factory con cache_target=False, come illustrato in precedenza. Il ripristino dei checkpoint, le risposte human-in-the-loop e gli identificatori di continuazione rimangono gestiti dall'applicazione; se un workflow richiede input esterno, l'adattatore genera un'eccezione anziché restituire un risultato vuoto dello strumento con esito positivo.
Per il set completo di server eseguibili, inclusa la MCPServer variante, vedere gli esempi di hosting MCP.
Importante
Considera l'identificatore di sessione MCP e qualsiasi argomento session_id specificato dall'app come input non attendibile. Autenticare e autorizzare il chiamante prima di utilizzare uno dei due per caricare o salvare lo stato della sessione e derivare il partizionamento durevole dal tenant, dall'utente o dall'area di lavoro autenticati anziché dal valore grezzo.
Passaggi successivi
Approfondimento: