你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

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(SaveSnippet))]
[BlobOutput(BlobPath)]
public string SaveSnippet(
    [McpToolTrigger(SaveSnippetToolName, SaveSnippetToolDescription)]
        ToolInvocationContext context,
    [McpToolProperty(SnippetNamePropertyName, PropertyType, SnippetNamePropertyDescription)]
        string name,
    [McpToolProperty(SnippetPropertyName, PropertyType, SnippetPropertyDescription)]
        string snippet
)
{
    return snippet;
}

有关完整的代码示例,请参阅 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 存储检索代码片段。

  }

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

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

// Register the GetSnippet tool
app.mcpTool("getSnippet", {
  toolName: GET_SNIPPET_TOOL_NAME,
  description: GET_SNIPPET_TOOL_DESCRIPTION,

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


// GetSnippet function - retrieves a snippet by name
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);

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

      propertyName: SNIPPET_NAME_PROPERTY_NAME,
      propertyType: PROPERTY_TYPE,
      description: SNIPPET_NAME_PROPERTY_DESCRIPTION,
    },
  ],
  extraInputs: [blobInputBinding],
  handler: getSnippet,
});

// Register the SaveSnippet tool
app.mcpTool("saveSnippet", {
  toolName: SAVE_SNIPPET_TOOL_NAME,
  description: SAVE_SNIPPET_TOOL_DESCRIPTION,
  toolProperties: [
    {
      propertyName: SNIPPET_NAME_PROPERTY_NAME,
      propertyType: PROPERTY_TYPE,
      description: SNIPPET_NAME_PROPERTY_DESCRIPTION,

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

  }

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

// SaveSnippet function - saves a snippet with a name
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";
  }

有关完整的代码示例,请参阅 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 设置部分。

适用于 Azure Functions 的 Azure OpenAI 扩展