عوامل المضيف الذاتي كأدوات MCP

Note

سيتوفر دعم أداة MCP ذاتية الاستضافة في .NET قريبا.

يعرض Go وكيلا كأداة MCP من خلال الجمع tool/agenttoolبين و tool/mcptoolو و MCP Go SDK الرسمي. التفاف العامل مع 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 لعرض عامل إطار عمل العامل أو سير العمل كأداة على SDK بروتوكول سياق النموذج الأصلي. لا تختار الحزمة إطار عمل ويب أو التفاف دورة حياة خادم MCP SDK. لا يزال التطبيق الخاص بك يمتلك خادم MCP وتسجيل المعالج والنقل ونهج مفتاح الجلسة والمصادقة والتخويل والنشر.

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

التحويل عند حد البروتوكول

mcp_to_run(...) يحول وسيطات أداة MCP التي تم التحقق من صحتها إلى رسائل إطار عمل العامل وخيارات الدردشة المحددة، ويحول 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 بشكل صريح بعد تحويل استجابة إطار عمل العامل المكتملة:

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 خصائص يتم نسخ قيمها بشكل صريح إلى خيارات دردشة إطار عمل العامل.

استمرار جلسة عمل لكل مكالمة

قم بتمرير قائمة 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 ينفذ 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.

Important

تعامل مع معرف جلسة MCP وأي وسيطة معرفة session_id من قبل التطبيق كإدخل غير موثوق به. قم بمصادقة المتصل وتخويله قبل استخدام إما لتحميل حالة جلسة العمل أو حفظها، واشتقاق التقسيم الدائم من المستأجر أو المستخدم أو مساحة العمل المصادق عليها بدلا من القيمة الأولية.

الخطوات التالية

انتقل إلى أبعد من ذلك: