Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Note
La prise en charge de l’auto-hébergement des outils MCP dans .NET sera bientôt disponible.
Go expose un agent en tant qu’outil MCP en combinant tool/agenttool, tool/mcptoolet le SDK Go MCP officiel. Encapsulez l’agent avec agenttool.New, enregistrez-le avec mcptool.AddTool et servez-le sur un transport MCP.
L’exemple Foundry maintenu utilise stdio. Il nécessite un point de terminaison de projet Foundry, un déploiement de modèle et des informations d’identification 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)
}
}
Consultez l’intégration de l’outil MCP pour les modèles client et serveur, ainsi que l’exemple complet de serveur MCP pour obtenir des instructions d’exécution.
Utilisez agent-framework-hosting-mcp pour exposer un agent du framework Agent Framework ou un flux de travail en tant qu’outil dans le SDK natif Model Context Protocol. Le package ne choisit pas d’infrastructure web et n’encapsule pas le cycle de vie du serveur du SDK MCP. Votre application possède toujours le serveur MCP, l’enregistrement du gestionnaire, le transport, la politique de clé de session, l’authentification, l’autorisation et le déploiement.
pip install --pre agent-framework-hosting-mcp
Effectuer la conversion à la limite du protocole
mcp_to_run(...) convertit les arguments de l’outil MCP validés en messages Agent Framework et les options de conversation sélectionnées et mcp_from_run(...) convertit une réponse terminée en valeurs MCP ContentBlock natives. Utilisez ces deux fonctions directement quand le contrat d’outil d’une application a besoin d’un schéma et d’un gestionnaire natifs entièrement personnalisés :
"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()
Seuls les noms d’arguments répertoriés dans chat_option_arguments sont copiés run["options"]; les autres arguments MCP restent disponibles sur la représentation brute du message, mais ne sont pas transférés au client de modèle.
Héberger avec MCPServer
Pour les applications MCP SDK 2.x, utilisez MCPServer pour dériver un schéma d’outil MCP natif à partir d’une fonction décorée. Retournez CallToolResult explicitement après la conversion de la réponse d’Agent Framework terminée :
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’exemple utilise HTTP diffusable sans état. Ajoutez l’authentification, l’autorisation et la persistance de session appartenant à l’application avant d’exposer le serveur au-delà d’un environnement local approuvé.
Héberger un agent sous la forme d’un seul outil généré
AgentMCPTool extrait d’un agent le nom, la description et le schéma de l’outil natif, et maintient alignés l’énumération, l’analyse syntaxique, l’exécution et la conversion des résultats afin d’éviter toute divergence entre les deux :
) -> 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 utilise le nom et la description de l’agent, sauf s’ils sont remplacés.
parameters ajoute des propriétés de schéma JSON appartenant à l’application qui restent disponibles dans les arguments MCP bruts et chat_option_parameters ajoute des propriétés dont les valeurs sont explicitement copiées dans les options de conversation Agent Framework.
Conserver une session par appel
Transmettez un AgentState existant et un session_id_parameter pour permettre à des appels répétés avec le même session_id opaque défini par l’application de poursuivre une même conversation :
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 effectue uniquement la séquence get/run/set de session AgentState ; votre application doit authentifier ou autoriser l’identificateur de session et sérialiser les appels simultanés pour la même session, comme l’exemple le fait avec une session par session asyncio.Lock. Il ne s’agit pas d’un embranchement de type previous_response_id : une application qui doit dupliquer une conversation devrait accepter des identifiants source et destination distincts, copier la session source et stocker le résultat sous la clé de destination.
Héberger un flux de travail en tant qu’outil
WorkflowMCPTool génère un outil MCP natif à partir du type d’entrée de l’exécuteur de démarrage d’un flux de travail et convertit les sorties d’un flux de travail terminé. Dataclass, Pydantic et d’autres entrées en forme d’objet deviennent des arguments MCP de niveau supérieur ; les entrées primitives sont encapsulées dans un nom d’argument configurable :
async def list_tools(
_ctx: ServerRequestContext[dict[str, Any]], params: types.PaginatedRequestParams | None
) -> types.ListToolsResult:
Les instances de workflow conservent l’état d’exécution. Les applications qui nécessitent des appels indépendants doivent donc fournir une fabrique WorkflowState avec cache_target=False, comme indiqué précédemment. La restauration des points de contrôle, les réponses d’intervention humaine et les identifiants de reprise restent gérés par l’application. Si un workflow demande une entrée externe, l’adaptateur déclenche une exception au lieu de renvoyer un résultat d’outil vide considéré comme réussi.
Pour obtenir l’ensemble complet de serveurs exécutables, y compris la MCPServer variante, consultez les exemples d’hébergement MCP.
Important
Traitez l’identificateur de session MCP et tout argument défini par session_id l’application comme une entrée non approuvée. Authentifiez et autorisez l’appelant avant de charger ou d’enregistrer l’état de session, et dérivez le partitionnement durable du locataire authentifié, de l’utilisateur ou de l’espace de travail plutôt que de la valeur brute.
Étapes suivantes
Aller plus loin :