Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Замечание
Поддержка самостоятельного размещения инструментов MCP в .NET скоро появится.
Go предоставляет агент как инструмент MCP, объединяя tool/agenttool, tool/mcptool и официальный пакет SDK MCP Go. Оберните агента с помощью agenttool.New, зарегистрируйте его в mcptool.AddTool и предоставляйте его через транспорт MCP.
В актуальном примере Foundry используется stdio. Для этого требуется конечная точка проекта Foundry, развертывание модели и 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)
}
}
См. сведения об интеграции средств MCP для шаблонов клиента и сервера, а также полный пример сервера MCP с инструкциями по выполнению.
Используйте agent-framework-hosting-mcp, чтобы предоставить агент Agent Framework или рабочий процесс как инструмент в собственном SDK Model Context Protocol. Пакет не выбирает веб-фреймворк и не оборачивает жизненный цикл сервера MCP SDK. Приложение по-прежнему владеет сервером MCP, регистрацией обработчика, транспортом, политикой ключа сеанса, проверкой подлинности, авторизацией и развертыванием.
pip install --pre agent-framework-hosting-mcp
Преобразование по границе протокола
mcp_to_run(...) преобразует проверенные аргументы инструментов MCP в сообщения Agent Framework и выбранные параметры чата и mcp_from_run(...) преобразует завершенный ответ в собственные значения MCP ContentBlock . Используйте эти две функции непосредственно, когда контракт средства приложения требует полностью настраиваемой собственной схемы и обработчика:
"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()
Только имена аргументов, перечисленные в chat_option_arguments, копируются в run["options"]; другие аргументы MCP остаются доступными в необработанном представлении сообщения, но не пересылаются клиенту модели.
Хост с MCPServer
Для приложений MCP SDK 2.x используйте MCPServer для получения собственной схемы инструмента MCP из украшенной функции. Верните CallToolResult явным образом после преобразования завершенного ответа 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."""
В этом примере используется потоковый HTTP без сохранения состояния. Добавьте проверку подлинности, авторизацию и сохранение сеансов на уровне приложения, прежде чем открывать сервер за пределами доверенной локальной среды.
Разместить агента как единый сгенерированный инструмент
AgentMCPTool извлекает имя, описание и схему встроенного инструмента из агента и поддерживает согласованность списка, разбора, выполнения и преобразования результатов, чтобы они не расходились:
) -> 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 использует имя и описание агента, если эти значения не переопределены.
parameters добавляет свойства схемы JSON, принадлежащие приложению, которые остаются доступными в необработанных аргументах MCP, и chat_option_parameters добавляет свойства, значения которых явно копируются в параметры чата Agent Framework.
Сохранять сеанс для каждого вызова
Передайте существующий AgentState и session_id_parameter, чтобы повторные вызовы с одним и тем же непрозрачным идентификатором session_id, определяемым приложением, продолжали один и тот же диалог:
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 выполняет только последовательность get/run/set для сеанса AgentState; ваше приложение должно аутентифицировать или авторизовать идентификатор сеанса и сериализовать одновременные вызовы для одного и того же сеанса, как это показано в примере с отдельным asyncio.Lock для каждого сеанса. Это не ветвление в стиле previous_response_id — приложение, которому нужно разветвить диалог, должно принимать отдельные идентификаторы источника и назначения, копировать исходный сеанс и сохранять результат по ключу назначения.
Размещение рабочего процесса в качестве инструмента
WorkflowMCPTool формирует собственный инструмент MCP на основе типа входных данных стартового исполнителя процесса и преобразует выходные данные завершённого процесса. Dataclass, Pydantic и другие входные данные, формируемые объектом, становятся аргументами MCP верхнего уровня; примитивные входные данные упаковываются в настраиваемое имя аргумента:
async def list_tools(
_ctx: ServerRequestContext[dict[str, Any]], params: types.PaginatedRequestParams | None
) -> types.ListToolsResult:
Экземпляры рабочего процесса сохраняют состояние исполнения, поэтому приложения, которым требуются независимые вызовы, должны предоставлять фабрику WorkflowState с cache_target=False, как показано выше. Восстановление контрольных точек, ответы с участием человека и идентификаторы продолжения остаются в ведении приложения; если рабочий процесс запрашивает внешний ввод, адаптер генерирует исключение вместо возврата пустого успешного результата инструмента.
Полный набор исполняемых серверов, включая вариант MCPServer, см. в примерах размещения MCP.
Это важно
Обработайте идентификатор сеанса MCP и любой аргумент, определенный session_id приложением, как ненадежные входные данные. Проверяйте подлинность и авторизуйте инициатора запроса перед тем, как использовать любой из этих механизмов для загрузки или сохранения состояния сеанса, и определяйте устойчивое разбиение на основе аутентифицированного арендатора, пользователя или рабочей области, а не исходного значения.
Дальнейшие действия
Вернитесь глубже: