返回市场
远程-mcp功能-dotnet

远程-mcp功能-dotnet

作者:Azure-Samples114 星标更新:2025-11-06

项目介绍

使用 Azure Functions (.NET/C#) 快速入门远程 MCP 服务器

这是一个快速入门模板,可以轻松构建并部署一个自定义的远程 MCP 服务器到云端,使用 Azure 函数。您可以在本地机器上进行克隆/恢复/运行,并通过调试,使用 azd up 在几分钟内将其部署到云端。MCP 服务器通过设计使用密钥和 HTTPS 进行安全保护,并允许通过 EasyAuth 和/或 API 管理以及 VNET 进行网络隔离来提供更多 OAuth 选项。

观看视频概述

<a href="https://www.youtube.com/watch?v=XwnEtZxaokg"> <img src="./images/video-overview.png" alt="观看视频" width="500" /> </a>

如果您正在寻找更多语言的示例,请查看 Node.js/TypeScriptPython 示例。

在 GitHub Codespaces 中打开

先决条件

所有开发方法都需要:

对于 Visual Studio 开发:

对于 Visual Studio Code 开发:

选择一种:您可以使用 Visual Studio 或 Visual Studio Code。两者都提供完整的调试支持,但设置步骤略有不同。

以下是使用 Azure Functions 的远程 MCP 服务器架构图:

架构图

准备本地环境

此特定示例需要 Azure 存储模拟器,因为我们将从 Blob 存储中保存和获取片段。

  1. 启动 Azurite

    docker run -p 10000:10000 -p 10001:10001 -p 10002:10002 \
        mcr.microsoft.com/azure-storage/azurite
    

注意 如果您使用来自 VS Code 扩展的 Azurite,现在需要运行 Azurite: Start,否则您会看到错误。

在本地运行您的 MCP 服务器

选择您偏好的开发环境:

选项 A:使用 Visual Studio Code

从终端运行

  1. src 文件夹,运行以下命令以启动本地的函数主机:

    cd src
    func start
    

请注意,默认情况下这将使用 webhook 路由:/runtime/webhooks/mcp。稍后我们将在 Azure 中设置客户端/主机调用的密钥:/runtime/webhooks/mcp?code=<system_key>

从 MCP 客户端工具连接到您的 本地 MCP 服务器

一旦您的 Azure Functions MCP 服务器在本地运行(通过 Visual Studio Code 或 Visual Studio),您可以从各种 MCP 客户端工具连接到它:

使用 VS Code 和 GitHub Copilot

  1. 添加 MCP 服务器 从命令面板添加 URL 到正在运行的函数应用的 MCP 终点:

    http://localhost:7071/runtime/webhooks/mcp
    

    注意:如果您是从 Visual Studio(而不是 VS Code)运行,请使用 http://localhost:7071/runtime/webhooks/mcp/sse

  2. 列出 MCP 服务器 从命令面板开始服务器

  3. 在 Copilot 聊天代理模式下输入提示以触发工具,例如,选择一些代码并输入以下提示

    说你好
    
    将此片段保存为 snippet1
    
    检索 snippet1 并应用于 NewFile.cs
    
  4. 当提示运行工具时,点击 继续 同意

  5. 当您完成时,在终端窗口中按 Ctrl+C 停止 func.exe 主机进程(或在您的 IDE 中停止调试)。

使用 MCP Inspector

  1. 新的终端窗口 中,安装并运行 MCP Inspector

    npx @modelcontextprotocol/inspector node build/index.js
    
  2. CTRL 点击以从应用程序显示的 URL 加载 MCP Inspector Web 应用(例如 http://0.0.0.0:5173/#resources)

  3. 设置传输类型为 Streamable HTTP

  4. 设置 URL 为正在运行的函数应用的 MCP 终点并 连接

    http://0.0.0.0:7071/runtime/webhooks/mcp
    

    注意:如果您是从 Visual Studio(而不是 VS Code)运行,请使用 http://localhost:7071/runtime/webhooks/mcp/sse

  5. 列出工具。点击一个工具并 运行工具

本地开发故障排除

问题:尝试连接到 MCP 服务器时连接被拒绝

  • 解决方案:确保 Azurite 正在运行 (docker run -p 10000:10000 -p 10001:10001 -p 10002:10002 mcr.microsoft.com/azure-storage/azurite)

问题:错误的 URL(0.0.0.0 与 localhost)

  • 解决方案:对于 VS Code 使用 http://0.0.0.0:7071/runtime/webhooks/mcp/sse,对于 Visual Studio 使用 http://localhost:7071/runtime/webhooks/mcp/sse

问题:Visual Studio F5 不起作用

  • 解决方案:确保已安装 Azure 开发工作负载,并且 FunctionsMcpTool 已设置为启动项目

验证本地 Azurite 中的 Blob 存储

在本地测试片段保存功能之后,您可以验证片段是否正确存储在本地 Azurite 存储模拟器中。

使用 Azure 存储资源管理器

  1. 打开 Azure 存储资源管理器
  2. 在左侧面板中,展开 模拟器 & 附加存储帐户(模拟器 - 默认端口) (密钥)
  3. 导航到 Blob 容器snippets
  4. 您应该在此容器中看到任何已保存的片段作为 Blob 文件
  5. 双击任何 Blob 查看其内容并验证片段数据是否正确保存

使用 Azure CLI(替代方案)

如果您更喜欢使用命令行,也可以使用 Azure CLI 与存储模拟器验证 Blob:

# 列出 snippets 容器中的 Blob
az storage blob list --container-name snippets --connection-string "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;"
# 下载特定 Blob 以查看其内容
az storage blob download --container-name snippets --name <blob-name> --file <local-file-path> --connection-string "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;"

此验证步骤确保您的 MCP 服务器正确地与本地存储模拟器交互,并且在部署到 Azure 之前 Blob 存储功能按预期工作。

部署到 Azure 以实现远程 MCP

运行此 azd 命令以配置函数应用,包括任何所需的 Azure 资源,并部署您的代码:

azd up

您可以选择在示例中使用 VNet。要在 azd up 之前这样做,请执行以下操作:

azd env set VNET_ENABLED true

此外,API 管理 可用于提高 MCP 服务器的安全性和策略,而 App Service 内置身份验证 可用于设置您最喜欢的 OAuth 提供商,包括 Entra。

从客户端连接到您的 远程 MCP 服务器函数应用

您的客户端需要一个密钥才能调用新的托管 MCP 终点,该密钥的形式为 https://<funcappname>.azurewebsites.net/runtime/webhooks/mcp。托管函数默认需要一个系统密钥,可以从 门户 或 CLI (az functionapp keys list --resource-group <resource_group> --name <function_app_name>) 获取。获取名为 mcp_extension 的系统密钥。

在 MCP Inspector 中连接到远程 MCP 服务器

对于 MCP Inspector,您可以在 URL 中包含密钥:

https://<funcappname>.azurewebsites.net/runtime/webhooks/mcp?code=<your-mcp-extension-system-key>

在 VS Code - GitHub Copilot 中连接到远程 MCP 服务器

对于 GitHub Copilot 在 VS Code 中,您应将密钥设置为 mcp.json 中的 x-functions-key 头,并且您只需使用 https://<funcappname>.azurewebsites.net/runtime/webhooks/mcp 作为 URL。以下示例使用输入,并在您从 VS Code 启动服务器时提示您提供密钥。注意 mcp.json 已包含在此仓库中并将被 VS Code 捕获。点击服务器上的“开始”以提示输入值,包括 functionapp-name(在您的 /.azure/*/.env 文件中)和 functions-mcp-extension-system-key,这些可以从上面的 CLI 命令或函数应用的门户中的 API 密钥获取。

{
    "inputs": [
        {
            "type": "promptString",
            "id": "functions-mcp-extension-system-key",
            "description": "Azure Functions MCP 扩展系统密钥",
            "password": true
        },
        {
            "type": "promptString",
            "id": "functionapp-name",
            "description": "Azure Functions 应用名称"
        }
    ],
    "servers": {
        "remote-mcp-function": {
            "type": "http",
            "url": "https://${input:functionapp-name}.azurewebsites.net/runtime/webhooks/mcp",
            "headers": {
                "x-functions-key": "${input:functions-mcp-extension-system-key}"
            }
        },
        "local-mcp-function": {
            "type": "http",
            "url": "http://0.0.0.0:7071/runtime/webhooks/mcp"
        }
    }
}

点击服务器上的“开始”以提示输入值,包括 functionapp-name(在您的 /.azure/*/.env 文件中)和 functions-mcp-extension-system-key,这些可以从上面的 CLI 命令或函数应用的门户中的 API 密钥获取。

重新部署您的代码

您可以根据需要多次运行 azd up 命令以配置 Azure 资源并部署代码更新到您的函数应用。

[!NOTE] 已部署的代码文件始终会被最新的部署包覆盖。

清理资源

当您完成与函数应用及相关资源的工作时,可以使用此命令从 Azure 删除函数应用及其相关资源,避免产生进一步的成本:

azd down

源代码

GetSnippetSaveSnippet 终点的函数代码定义在 SnippetsTool.cs 中。应用于异步 Run 方法的 McpToolsTrigger 属性将代码函数暴露为 MCP 服务器。

这展示了几个 MCP 服务器示例的代码(获取字符串、获取对象、保存对象):

[Function(nameof(SayHello))]
public string SayHello(
    [McpToolTrigger(HelloToolName, HelloToolDescription)] ToolInvocationContext context
)
{
    logger.LogInformation("说你好");
    return "你好,我是 MCP 工具!";
}

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

[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;
}

下一步