使用Azure函数(Node.js/TypeScript)开始使用远程MCP服务器
这是一个快速入门模板,可以使用Azure函数轻松构建自定义远程MCP服务器并将其部署到云端。您可以通过调试在本地计算机上克隆/还原/运行,以及 azd up 几分钟后就可以把它放在云端了。
MCP服务器配置了 内置身份验证 使用Microsoft Entra作为身份提供者。
你也可以使用 API管理 以保护服务器以及使用VNET进行网络隔离。
观看视频概述
](https://codespaces.new/Azure-Samples/remote-mcp-functions-typescript)
以下是使用Azure Functions的远程MCP服务器的架构图:
存储库布局
此存储库现在包括两个可独立部署的功能应用程序:
- mcp工具包含mcp工具触发器、丰富内容示例和代码段存储示例。
- mcp天气应用程序包含mcp应用程序天气样本(资源+天气工具)。
每个应用程序都有自己的azure.yaml、package.json和README.md。从每个应用程序文件夹中运行azd命令以独立配置和部署它。
存储库布局
此存储库现在包括两个可独立部署的功能应用程序:
- mcp工具包含mcp工具触发器、丰富内容示例和代码段存储示例。
- mcp天气应用程序包含mcp应用程序天气样本(资源+天气工具)。
每个应用程序都有自己的azure.yaml、package.json和README.md。从每个应用程序文件夹中运行azd命令以独立配置和部署它。
先决条件
- 版本18或更高
- Azure功能核心工具 >=
4.0.7030 - Azure开发者命令行界面
- 要使用Visual Studio代码在本地运行和调试,请执行以下操作:
- Visual Studio Code - Azure功能扩展
- 码头工人 要运行Azure存储模拟器Azurite(可选)
准备好当地环境
此特定示例需要Azure存储模拟器,因为我们将从blob存储中保存和获取代码段。
- 开始Azurite
docker run -p 10000:10000 -p 10001:10001 -p 10002:10002 \
mcr.microsoft.com/azure-storage/azurite备注 如果你使用来自VS Code扩展的Azurite,你需要运行 Azurite: Start 现在,否则你会看到错误。从终端本地运行MCP服务器
此存储库包含多个可独立运行的功能应用程序。每个应用程序在默认的Functions端口上公开自己的MCP端点(7071).要同时运行多个应用程序,请从单独的终端启动每个应用程序并通过 --port 以避免碰撞。
根代码片段/工具应用程序(此文件夹)
- 安装依赖项
npm install- 构建项目
npm run build- 在本地启动Functions主机:
func startmcp工具应用程序
包含用于丰富内容示例(图像、资源链接、结构化内容)和代码段示例(通过blob绑定保存/获取代码段)的MCP工具触发器。看 mcp工具/README.md 了解详情。
cd mcp-tools
npm install
npm run build
func startmcp天气应用程序
包含MCP应用程序示例:一个服务于交互式天气小部件的MCP资源触发器,以及一个调用Open Meteo的MCP工具触发器。看 mcp天气应用程序/README.md 了解详情。
cd mcp-weather-app
npm install
npm run build:app # bundle the widget UI
npm run build
func startmcp提示应用程序
包含MCP提示触发器(代码审查清单、总结内容、生成文档)。看 mcp提示 了解详情。
cd mcp-prompts
npm install
npm run build
func start备注 默认情况下,这将使用webhooks路由:/runtime/webhooks/mcp稍后,我们将在Azure中使用它来设置客户端/主机调用的密钥:/runtime/webhooks/mcp?code=如果你想同时运行多个应用程序,请为每个应用程序分配自己的端口,例如。func start --port 7072,并在配置客户端时使用该端口。
使用 *本地* 客户端/主机内的MCP服务器
下面的示例URL指向端口上的根应用程序7071。要连接到 mcp工具 应用程序, mcp天气应用程序,或 mcp提示 应用程序,使用相同的/runtime/webhooks/mcp应用程序正在侦听的端口的路径(请参见 mcp工具/README.md, mcp天气应用程序/README.md,以及 mcp提示 每个应用程序公开的工具、天气小部件和提示的文件夹)。
VS代码-副本编辑
- 添加MCP服务器 从命令面板中,将URL添加到正在运行的Function应用程序的mcp端点:
http://0.0.0.0:7071/runtime/webhooks/mcp- 选择 HTTP(服务器发送事件) 用于添加MCP服务器的类型。
- 输入运行函数应用程序mcp端点的URL
- 输入服务器ID。(这可以是您想要的任何名称)
- 选择是要在用户设置(适用于所有应用程序)中运行此操作,还是在工作区设置(仅适用于此应用程序)下运行此操作
- 列出MCP服务器 从命令面板启动服务器。上一步可能已经启动了您的本地服务器。如果是这样,您可以跳过此步骤。
- 在Copilot聊天代理模式下,输入提示以触发工具,例如,选择一些代码并输入此提示
Say Hello Save this snippet as snippet1 Retrieve snippet1 and apply to newFile.ts- 当系统提示运行该工具时,点击同意 继续
- 完成后,在终端窗口中按Ctrl+C停止
func.exe主机进程,以及 列出MCP服务器 从命令面板中选择并停止本地服务器。
MCP检查员
- 在一个 新终端窗口,安装并运行MCP检查器
npx @modelcontextprotocol/inspector node build/index.js- 如果您之前停止了功能应用程序,请在本地启动功能主机:
func start- 按CTRL键单击可从应用程序显示的URL加载MCP Inspector web应用程序(例如。http://0.0.0.0:5173/#resources)
- 将运输类型设置为
http
- 将URL设置为正在运行的Function应用程序的mcp端点,然后 连接:
http://0.0.0.0:7071/runtime/webhooks/mcp- 列出工具。单击工具,然后 运行工具.
- 完成后,在终端窗口中按Ctrl+C停止
func.exe主机进程,在终端窗口中按Ctrl+C停止@modelcontextprotocol/inspector主机进程。
验证Azurite中的本地blob存储
在本地测试代码段保存功能后,您可以验证blob是否正确存储在本地Azurite存储模拟器中。
使用Azure存储资源管理器
- 打开Azure存储资源管理器
- 在左侧面板中,展开 模拟器和附件 → 存储帐户 → (模拟器-默认端口)(按键)
- 导航至 Blob容器 → 片段
- 您应该看到此容器中所有保存的代码段都是blob文件
- 双击任何blob以查看其内容并验证代码段数据是否已正确保存
使用Azure CLI(替代方案)
如果您更喜欢使用命令行,还可以使用Azure CLI和存储模拟器验证blob:
# List blobs in the snippets container
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;"# Download a specific blob to view its contents
az storage blob download --container-name snippets --name --file --connection-string "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;"此验证步骤可确保您的MCP服务器与本地存储模拟器正确交互,并且blob存储功能在部署到Azure之前按预期工作。
部署到Azure以实现远程MCP
azd env new 将VS Code配置为允许的客户端应用程序,以从Microsoft Entra请求访问令牌:
azd env set PRE_AUTHORIZED_CLIENT_IDS aebc6443-996d-45c2-90f0-388ff96faa56您也可以选择加入示例中正在使用的ExpressRoute。(如果您选择此项,请先执行此操作 azd up)
azd env set VNET_ENABLED true运行这些 azd 命令来为功能应用程序配置任何所需的Azure资源,并部署您的代码:
azd provision等待几分钟以使访问权限生效,然后运行
azd deploy备注 API管理 可用于提高MCP服务器的安全性和策略。
独立部署mcp工具或mcp天气应用程序
这 mcp-tools, mcp-weather-app,以及 mcp-prompts 每个文件夹都包含自己的 azure.yaml 并且可以作为单独的功能应用程序进行配置和部署。运行相同 azd 从要部署的应用程序文件夹内部进行流:
cd mcp-tools # or: cd mcp-weather-app | cd mcp-prompts
azd init # first time only
azd env new # first time only
azd provision
azd deploy每个应用程序都重用共享的infrastructure 红外线/ 而是作为其自己的功能应用程序部署。看 mcp工具/README.md 和 mcp天气应用程序/README.md 针对特定应用程序的注释。
备注 API管理 可用于提高MCP服务器的安全性和策略,以及 App Service内置身份验证 可用于设置您最喜欢的OAuth提供程序,包括Entra。
在VS Code中连接到远程MCP服务器-GitHub Copilot
对于VS Code中的GitHub Copilot,您可以使用 https://.azurewebsites.net/runtime/webhooks/mcp 以下示例来自 mcp.json 该文件包含在此存储库中,并使用输入提示您在从VS Code启动服务器时提供函数名。服务器配置了内置的MCP身份验证,因此您也会被要求登录。你的 mcp.json 文件看起来像这样:
连接到您的 *远程* 来自客户端的MCP服务器功能应用程序
您的客户端将需要一个密钥来调用新的托管SSE端点,其格式为 https://.azurewebsites.net/runtime/webhooks/mcp默认情况下,托管功能需要一个系统密钥,可以从 门户 或CLI(az functionapp keys list --resource-group --name ).获取名为的系统密钥 mcp_extension.
在MCP Inspector中连接到远程MCP服务器
对于MCP检查器,您可以在URL中包含密钥:
https://.azurewebsites.net/runtime/webhooks/mcp?code=在VS Code中连接到远程MCP服务器-GitHub Copilot
对于VS Code中的GitHub Copilot,您应该将密钥设置为 x-functions-key 标题在 mcp.json,你会使用 https://.azurewebsites.net/runtime/webhooks/mcp 以下示例来自 mcp.json 该文件包含在此存储库中,并使用输入提示您在从VS Code启动服务器时提供密钥。你的 mcp.json 文件看起来像这样:
{
"inputs": [
{
"type": "promptString",
"id": "functions-mcp-extension-system-key",
"description": "Azure Functions MCP Extension System Key",
"password": true
},
{
"type": "promptString",
"id": "functionapp-name",
"description": "Azure Functions App Name"
}
],
"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"
}
}
}- 在服务器上单击“开始”
remote-mcp-function,里面mcp.json文件:
- 当VS Code提示时,输入您在Azure门户中创建的功能应用程序的名称。
- 输入
Azure Functions MCP Extension System Key进入提示。您可以通过转到“功能”菜单项,然后单击“应用密钥”,并复制mcp_extension从系统密钥中选择密钥。
- 在Copilot聊天代理模式下,输入提示以触发工具,例如,选择一些代码并输入此提示
Say Hello Save this snippet as snippet1 Retrieve snippet1 and apply to newFile.ts重新部署代码
你可以运行 azd deploy 根据需要多次执行命令,将代码更新部署到功能应用程序。
\[!注意\] 部署的代码文件总是被最新的部署包覆盖。
清理资源
使用完功能应用程序和相关资源后,您可以使用此命令从Azure中删除功能应用程序及其相关资源,从而避免产生任何进一步的成本:
azd down源代码
的功能代码 getSnippet 和 saveSnippet 端点在TypeScript文件中定义 src 目录。MCP函数注释将这些函数作为MCP服务器工具公开。
这显示了一些MCP服务器示例的代码(获取字符串、获取对象、保存对象):
// Hello function - responds with hello message
export async function mcpToolHello(context: InvocationContext): Promise {
return "Hello I am MCP Tool!";
}
// Register the hello tool
app.mcpTool('hello', {
toolName: 'hello',
description: 'Simple hello world MCP Tool that responses with a hello message.',
handler: mcpToolHello
});
// GetSnippet function - retrieves a snippet by name
export async function getSnippet(_message: unknown, context: InvocationContext): Promise {
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;
}
// Register the GetSnippet tool
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
});
// SaveSnippet function - saves a snippet with a name
export async function saveSnippet(_message: unknown, context: InvocationContext): Promise {
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;
}
// Register the SaveSnippet tool
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
});结果模式(UseResultSchema)
TypeScript MCP工具触发器现在支持显式定义 resultSchema 上 app.mcpTool(...) 选项。 当存在有效的JSON时,它将与 useResultSchema: true 因此,宿主可以使用您声明的结果形状。
const imageInfoSchema = JSON.stringify({
type: "object",
properties: {
imageId: { type: "string" },
format: { type: "string" },
tags: { type: "array", items: { type: "string" } }
},
required: ["imageId", "format", "tags"],
additionalProperties: false
});
app.mcpTool("GetImageInfo", {
toolName: "GetImageInfo",
description: "Get image information",
toolProperties: {
imageId: arg.string().describe("Optional image identifier").optional()
},
resultSchema: imageInfoSchema,
handler: getImageInfo
});请注意 host.json 文件还包括对扩展包的引用,这是使用此功能的应用程序所必需的:
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[4.*, 5.0.0)"
}天气应用程序示例
一个示例MCP应用程序,通过交互式UI显示天气信息。
什么是MCP应用程序?
MCP应用程序 让工具返回交互式界面而不是纯文本。当工具声明UI资源时,主机会在沙盒iframe中呈现它,用户可以在其中直接交互。
MCP应用程序=工具+UI资源
该架构依赖于两个MCP原语:
- 工具 UI元数据指向资源URI
- 资源 包含通过
ui://方案
Azure Functions使两者都易于构建。
天气应用程序的先决条件
- (用于构建UI)
- Azure功能核心工具v4
- Visual Studio Code
天气应用程序入门
本节中的所有命令都必须从 mcp天气应用程序/ 文件夹。先导航到那里: ``shell cd mcp-weather-app ``1.构建UI
在运行功能应用程序之前,必须捆绑UI:
cd src/app npm install npm run build
这将创建一个捆绑 src/app/dist/index.html 函数所服务的文件。
2.构建并运行功能应用程序
- 安装Function应用程序的依赖项:
cd ../../
npm install- 构建项目:
npm run build- 在本地启动Functions主机:
func start3.从VS代码连接
打开 .vcode/mcp.json.查找被调用的服务器 _本地mcp功能_ 然后单击 开始 名字之上。服务器已经设置了正在运行的Function应用程序的MCP端点:
http://0.0.0.0:7071/runtime/webhooks/mcp
4.提示代理人
问Copilot:“西雅图的天气怎么样?”
它是如何协同工作的
- 用户问:“西雅图的天气怎么样?”
- 代理人致电
getWeather工具 - 工具返回天气数据(JSON) 和 主机看到
ui.resourceUri元数据 - 主机从以下位置获取UI资源
ui://weather/index.html - 主机在沙盒iframe中呈现HTML,并将工具结果作为上下文传递
- 用户看到的是交互式天气小部件,而不是纯文本
用户界面(TypeScript)
前端在 src/app/src/weatherMcpApp.ts 接收工具结果并呈现天气显示。它与Vite捆绑在一起 index.html 资源所服务的。
下一步
- 添加 API管理 到您的MCP服务器(身份验证、网关、策略等!)
- 添加 内置身份验证 到您的MCP服务器
- 使用VNET_ENABLED=true标志启用VNET
- 了解更多关于 Azure功能MCP扩展
- 更多了解 微软的相关MCP工作
