Azure Functions 的 MCP 工具触发器

使用 MCP 工具触发器在 模型内容协议 (MCP) 服务器中定义工具终结点,这些服务器由客户端语言模型和代理访问以执行特定任务,例如存储或访问代码片段。 MCP 客户端还可以订阅函数应用,以接收有关公开工具更改的通知。

重要

Azure Functions MCP 扩展目前以预览版提供。 在扩展正式发布之前,你可能需要对触发器和绑定 API 进行更改。
应避免在生产应用中使用预览版扩展。

有关设置和配置详细信息,请参阅概述

示例:

注释

Azure Functions MCP 扩展仅支持 隔离的辅助角色模型

此代码创建一个终结点,用于公开一个名为 GetSnippet 的工具,该工具尝试按名称从 Blob 存储检索代码片段。

    private const string BlobPath = "snippets/{mcptoolargs." + SnippetNamePropertyName + "}.json";

    [Function(nameof(GetSnippet))]
    public object GetSnippet(
        [McpToolTrigger(GetSnippetToolName, GetSnippetToolDescription)]
            ToolInvocationContext context,
        [BlobInput(BlobPath)] string snippetContent
    )
    {
        return snippetContent;
    }

此代码创建一个终结点,用于公开一个名为将命名 SaveSnippet 代码片段保存到 Blob 存储的工具。

private const string BlobPath = "snippets/{mcptoolargs." + SnippetNamePropertyName + "}.json";

[Function(nameof(GetSnippet))]
public object GetSnippet(
    [McpToolTrigger(GetSnippetToolName, GetSnippetToolDescription)]
        ToolInvocationContext context,
    [BlobInput(BlobPath)] string snippetContent
)
{
    return snippetContent;
}

有关完整的代码示例,请参阅 SnippetTool.cs

此代码创建一个终结点,用于公开一个名为 GetSnippets 的工具,该工具尝试按名称从 Blob 存储检索代码片段。

@FunctionName("GetSnippets")
@StorageAccount("AzureWebJobsStorage")
public void getSnippet(
        @McpToolTrigger(
                toolName = "getSnippets",
                description = "Gets a text snippet from your snippets collection.",
                toolProperties = GET_SNIPPET_ARGUMENTS
        )
        String toolArguments,
        @BlobInput(name = "inputBlob", path = BLOB_PATH)
        String inputBlob,
        final ExecutionContext context
) {
    // Log the entire incoming JSON for debugging
    context.getLogger().info(toolArguments);

    // Parse the JSON and get the snippetName field
    String snippetName = JsonParser.parseString(toolArguments)
            .getAsJsonObject()
            .getAsJsonObject("arguments")
            .get(SNIPPET_NAME_PROPERTY_NAME)
            .getAsString();

    // Log the snippet name and the fetched snippet content from the blob
    context.getLogger().info("Retrieving snippet with name: " + snippetName);
    context.getLogger().info("Snippet content:");
    context.getLogger().info(inputBlob);
}

此代码创建一个终结点,用于公开一个名为将命名 SaveSnippets 代码片段保存到 Blob 存储的工具。

@FunctionName("SaveSnippets")
@StorageAccount("AzureWebJobsStorage")
public void saveSnippet(
        @McpToolTrigger(
                toolName = "saveSnippets",
                description = "Saves a text snippet to your snippets collection.",
                toolProperties = SAVE_SNIPPET_ARGUMENTS
        )
        String toolArguments,
        @BlobOutput(name = "outputBlob", path = BLOB_PATH)
        OutputBinding<String> outputBlob,
        final ExecutionContext context
) {
    // Log the entire incoming JSON for debugging
    context.getLogger().info(toolArguments);

    // Parse the JSON and extract the snippetName/snippet fields
    JsonObject arguments = JsonParser.parseString(toolArguments)
            .getAsJsonObject()
            .getAsJsonObject("arguments");
    String snippetName = arguments.get(SNIPPET_NAME_PROPERTY_NAME).getAsString();
    String snippet = arguments.get(SNIPPET_PROPERTY_NAME).getAsString();

    // Log the snippet name and content
    context.getLogger().info("Saving snippet with name: " + snippetName);
    context.getLogger().info("Snippet content:\n" + snippet);

    // Write the snippet content to the output blob
    outputBlob.setValue(snippet);
}

有关完整的代码示例,请参阅 Snippets.java

JavaScript 的示例代码当前不可用。 有关使用 Node.js的常规指南,请参阅 TypeScript 示例。

此代码创建一个终结点,用于公开一个名为 getsnippet 的工具,该工具尝试按名称从 Blob 存储检索代码片段。

app.mcpTool('getSnippet', {
    toolName: GET_SNIPPET_TOOL_NAME,
    description: GET_SNIPPET_TOOL_DESCRIPTION,
    toolProperties: [
        {
            propertyName: SNIPPET_NAME_PROPERTY_NAME,
            propertyValue: PROPERTY_TYPE,
            description: SNIPPET_NAME_PROPERTY_DESCRIPTION,
        }
    ],
    extraInputs: [blobInputBinding],
    handler: getSnippet
});

这是处理 getsnippet 触发器的代码:

export async function getSnippet(_toolArguments: unknown, context: InvocationContext): Promise<string> {
    console.info('Getting snippet');

    // Get snippet name from the tool arguments
    const mcptoolargs = context.triggerMetadata.mcptoolargs as { snippetname?: string };
    const snippetName = mcptoolargs?.snippetname;

    console.info(`Snippet name: ${snippetName}`);

    if (!snippetName) {
        return "No snippet name provided";
    }

    // Get the content from blob binding - properly retrieving from extraInputs
    const snippetContent = context.extraInputs.get(blobInputBinding);

    if (!snippetContent) {
        return `Snippet '${snippetName}' not found`;
    }

    console.info(`Retrieved snippet: ${snippetName}`);
    return snippetContent as string;
}

此代码创建一个终结点,用于公开一个名为将命名 savesnippet 代码片段保存到 Blob 存储的工具。

app.mcpTool('saveSnippet', {
    toolName: SAVE_SNIPPET_TOOL_NAME,
    description: SAVE_SNIPPET_TOOL_DESCRIPTION,
    toolProperties: [
        {
            propertyName: SNIPPET_NAME_PROPERTY_NAME,
            propertyValue: PROPERTY_TYPE,
            description: SNIPPET_NAME_PROPERTY_DESCRIPTION,
        },
        {
            propertyName: SNIPPET_PROPERTY_NAME,
            propertyValue: PROPERTY_TYPE,
            description: SNIPPET_PROPERTY_DESCRIPTION,
        }
    ],
    extraOutputs: [blobOutputBinding],
    handler: saveSnippet
});

这是处理 savesnippet 触发器的代码:

export async function saveSnippet(_toolArguments: unknown, context: InvocationContext): Promise<string> {
    console.info('Saving snippet');

    // Get snippet name and content from the tool arguments
    const mcptoolargs = context.triggerMetadata.mcptoolargs as { 
        snippetname?: string;
        snippet?: string;
    };

    const snippetName = mcptoolargs?.snippetname;
    const snippet = mcptoolargs?.snippet;

    if (!snippetName) {
        return "No snippet name provided";
    }

    if (!snippet) {
        return "No snippet content provided";
    }

    // Save the snippet to blob storage using the output binding
    context.extraOutputs.set(blobOutputBinding, snippet);

    console.info(`Saved snippet: ${snippetName}`);
    return snippet;
}

有关完整的代码示例,请参阅 snippetsMcpTool.ts

此代码使用 generic_trigger 修饰器创建一个终结点,以公开一个名为 get_snippet 的工具,该工具尝试按名称从 Blob 存储检索代码片段。

@app.generic_trigger(
    arg_name="context",
    type="mcpToolTrigger",
    toolName="get_snippet",
    description="Retrieve a snippet by name.",
    toolProperties=tool_properties_get_snippets_json,
)
@app.generic_input_binding(arg_name="file", type="blob", connection="AzureWebJobsStorage", path=_BLOB_PATH)
def get_snippet(file: func.InputStream, context) -> str:
    """
    Retrieves a snippet by name from Azure Blob Storage.

    Args:
        file (func.InputStream): The input binding to read the snippet from Azure Blob Storage.
        context: The trigger context containing the input arguments.

    Returns:
        str: The content of the snippet or an error message.
    """
    snippet_content = file.read().decode("utf-8")
    logging.info(f"Retrieved snippet: {snippet_content}")
    return snippet_content

此代码使用 generic_trigger 修饰器创建一个终结点,以公开一个名为 save_snippet 将命名代码片段保存到 Blob 存储的工具。

@app.generic_trigger(
    arg_name="context",
    type="mcpToolTrigger",
    toolName="save_snippet",
    description="Save a snippet with a name.",
    toolProperties=tool_properties_save_snippets_json,
)
@app.generic_output_binding(arg_name="file", type="blob", connection="AzureWebJobsStorage", path=_BLOB_PATH)
def save_snippet(file: func.Out[str], context) -> str:
    content = json.loads(context)
    snippet_name_from_args = content["arguments"][_SNIPPET_NAME_PROPERTY_NAME]
    snippet_content_from_args = content["arguments"][_SNIPPET_PROPERTY_NAME]

    if not snippet_name_from_args:
        return "No snippet name provided"

    if not snippet_content_from_args:
        return "No snippet content provided"

    file.set(snippet_content_from_args)
    logging.info(f"Saved snippet: {snippet_content_from_args}")
    return f"Snippet '{snippet_content_from_args}' saved successfully"

有关完整的代码示例,请参阅 function_app.py

重要

MCP 扩展目前不支持 PowerShell 应用。

特性

C# 库用于 McpToolTriggerAttribute 定义函数触发器。

该特性的构造函数采用以下参数:

参数 DESCRIPTION
ToolName (必需)由 MCP 触发器终结点公开的工具的名称。
说明 (可选)客户端工具终结点的友好说明。

请参阅 “用法 ”,了解如何将终结点的属性定义为输入参数。

批注

McpTrigger 注创建一个函数,用于在远程 MCP 服务器中公开工具终结点。

注释支持以下配置选项:

参数 DESCRIPTION
toolName (必需)由 MCP 触发器终结点公开的工具的名称。
说明 (可选)客户端工具终结点的友好说明。
toolProperties 向客户端公开工具属性的一个或多个属性对象的 JSON 字符串表示形式。

修饰器

仅适用于 Python v2 编程模型。

注释

目前,必须使用泛型修饰器来定义 MCP 触发器。

支持 generic_trigger以下 MCP 触发器属性:

资产 DESCRIPTION
类型 (必需)必须在修饰器中设置为<
arg_name 函数代码中用于访问执行上下文的变量名称(通常 context)。
toolName (必需)函数终结点公开的 MCP 服务器工具的名称。
说明 函数终结点公开的 MCP 服务器工具的说明。
toolProperties 向客户端公开工具属性的一个或多个属性对象的 JSON 字符串表示形式。

配置

触发器支持以下绑定选项,这些选项在代码中定义:

选项 DESCRIPTION
类型 必须设置为 mcpToolTrigger。 仅用于泛型定义。
toolName (必需)函数终结点公开的 MCP 服务器工具的名称。
说明 函数终结点公开的 MCP 服务器工具的说明。
toolProperties 向客户端公开工具属性的对象数组 toolProperty
extraOutputs 定义后,将函数输出发送到另一个绑定。
处理器 包含实际函数代码的方法。

有关完整示例,请参阅示例部分

用法

MCP 协议使 MCP 服务器能够向客户端了解工具终结点的其他属性。 在 C# 中,可以使用触发器函数代码的属性或使用McpToolProperty应用启动时将工具的属性定义为输入参数FunctionsApplicationBuilder

可以通过将 McpToolProperty 属性应用于函数中的输入绑定样式参数来定义一个或多个工具属性。

McpToolPropertyAttribute 类型支持以下属性:

资产 DESCRIPTION
PropertyName 向客户端公开的工具属性的名称。
PropertyType 工具属性的数据类型,例如 string
说明 (可选)工具属性的作用说明。

可以在SaveSnippet”中查看工具中使用的这些属性。

远程 MCP 服务器公开的工具的属性是使用工具属性定义的。 这些属性由 toolProperties 字段返回,该字段是对象的数组的 ToolProperty 字符串表示形式。

对象 ToolProperty 具有以下结构:

{
    "propertyName": "Name of the property",
    "propertyType": "Type of the property",
    "description": "Optional property description",
}

远程 MCP 服务器公开的工具的属性是使用工具属性定义的。 这些属性由 toolProperties 字段返回,该字段是对象的数组的 ToolProperty 字符串表示形式。

对象 ToolProperty 具有以下结构:

{
    "propertyName": "Name of the property",
    "propertyValue": "Type of the property",
    "description": "Optional property description",
}

有关详细信息,请参阅 示例

host.json 设置

host.json 文件包含控制 MCP 触发器行为的设置。 有关可用设置的详细信息,请参阅 host.json 设置部分。