| title | Build an MCP Apps server using Azure Functions | |
|---|---|---|
| description | Learn how to create and deploy an MCP App that returns interactive UI using Azure Functions. This quickstart uses the Azure Developer CLI to deploy an MCP App project that enables AI clients to access tools with rich interactive interfaces hosted on Azure's Flex Consumption plan. | |
| ms.date | 02/25/2026 | |
| ms.update-cycle | 180-days | |
| ms.topic | quickstart | |
| ai-usage | ai-assisted | |
| ms.collection |
|
|
| zone_pivot_groups | programming-languages-set-functions |
In this quickstart, you create a Model Context Protocol (MCP) App from a template project built using the Azure Functions MCP extension. MCP Apps are MCP servers with tools that return results in rich, interactive user interfaces instead of text. You deploy the app using the Azure Developer CLI (azd). You can also use the Azure Functions MCP extension to create MCP servers that have text-based tools.
After running the project locally and verifying your code by using GitHub Copilot, you deploy it to a new serverless function app in Azure Functions that follows current best practices for secure and scalable deployments.
:::image type="content" source="media/scenario-mcp-apps/mcp-weather-app-seattle.png" alt-text="Screenshot of a weather app UI for Seattle showing drizzle, temperature, humidity, wind, and report timestamp." lightbox="media/scenario-mcp-apps/mcp-weather-app-seattle-full.png":::
Because the new app runs on the Flex Consumption plan, which follows a pay-for-what-you-use billing model, completing this quickstart incurs a small cost of a few USD cents or less in your Azure account.
::: zone pivot="programming-language-javascript"
Important
While creating MCP Apps is supported for JavaScript, this quickstart currently only has examples for C#, Java, Python, and TypeScript. To complete this quickstart, select one of these supported languages at the top of the article. ::: zone-end
[!INCLUDE functions-mcp-extension-powershell-note]
::: zone pivot="programming-language-typescript" This article supports version 4 of the Node.js programming model for Azure Functions. ::: zone-end ::: zone pivot="programming-language-python" This article supports version 2 of the Python programming model for Azure Functions. ::: zone-end ::: zone pivot="programming-language-csharp,programming-language-java,programming-language-python,programming-language-typescript"
::: zone-end
::: zone pivot="programming-language-csharp"
- .NET 10 SDK
::: zone-end
::: zone pivot="programming-language-java" - Java 17 Developer Kit
- If you use another supported version of Java, update the project's
pom.xmlfile. - Set the
JAVA_HOMEenvironment variable to the install location of the correct version of the Java Development Kit (JDK).
- If you use another supported version of Java, update the project's
- Apache Maven 3.8.x
::: zone-end
::: zone pivot="programming-language-typescript"
-
Node.js 20
::: zone-end
::: zone pivot="programming-language-python" -
Python 3.11 ::: zone-end
::: zone pivot="programming-language-csharp" -
Node.js (required to build the MCP Apps UI)
-
Visual Studio Code with this extension:
- Azure Functions extension. This extension requires Azure Functions Core Tools and attempts to install it when not available.
-
Azure Developer CLI version 1.23.x or a later version ::: zone-end
::: zone pivot="programming-language-java,programming-language-python,programming-language-typescript" -
Node.js (required to build the MCP Apps UI)
-
Visual Studio Code with these extensions:
-
Azure Functions extension. This extension requires Azure Functions Core Tools and attempts to install it when not available.
-
Azure Developer CLI extension. ::: zone-end
::: zone pivot="programming-language-csharp,programming-language-java,programming-language-python,programming-language-typescript"
-
-
Azure CLI. You can also run Azure CLI commands in Azure Cloud Shell.
-
An Azure account with an active subscription. Create an account for free.
Use the Azure Developer CLI to create an Azure Functions code project from a template.
-
In Visual Studio Code, open a folder or workspace where you want to create your project. ::: zone-end
::: zone pivot="programming-language-csharp" -
Run the following command in the Terminal:
azd init --template remote-mcp-functions-dotnet -e mcpweather-dotnetThis command pulls the project files from the template repository and initializes the project in the current folder. The -e flag sets a name for the current environment. In
azd, the environment maintains a unique deployment context for your app, and you can define more than one. It's also used in names of the resources you create in Azure.
::: zone-end
::: zone pivot="programming-language-java,programming-language-python,programming-language-typescript" -
Press F1 to open the command palette. Search for and run
Azure Developer CLI (azd): init. -
When prompted, select Select a template.
::: zone-end
::: zone pivot="programming-language-typescript" -
Search for and select Remote MCP Functions with TypeScript.
-
When prompted, enter
mcpweather-tsas the environment name.The command pulls the project files from the template repository and initializes the project in the current folder. In
azd, the environment maintains a unique deployment context for your app, and you can define more than one. It's also used in the names of the resources you create in Azure.
::: zone-end ::: zone pivot="programming-language-python" -
Search for and select Remote MCP Functions with Python.
-
When prompted, enter
mcpweather-pythonas the environment name.The command pulls the project files from the template repository and initializes the project in the current folder. In
azd, the environment maintains a unique deployment context for your app, and you can define more than one. It's also used in the names of the resources you create in Azure. ::: zone-end ::: zone pivot="programming-language-java" -
Search for and select Remote MCP Functions with Java.
-
When prompted, enter
mcpweather-javaas the environment name.The command pulls the project files from the template repository and initializes the project in the current folder. In
azd, the environment maintains a unique deployment context for your app, and you can define more than one. It's also used in names of the resources you create in Azure. ::: zone-end ::: zone pivot="programming-language-csharp,programming-language-java,programming-language-python,programming-language-typescript"
[!INCLUDE start-storage-emulator]
The MCP Apps weather tool includes a frontend application that you must build before running the project. ::: zone-end ::: zone pivot="programming-language-csharp"
-
In the terminal, go to the UI app folder and build the application:
cd src/McpWeatherApp/app npm install npm run build cd ../
::: zone-end ::: zone pivot="programming-language-java"
-
In the terminal, go to the UI app folder and build the application:
cd samples/McpWeatherApp/app npm install npm run build cd ..
::: zone-end ::: zone pivot="programming-language-python"
-
In the terminal, go to the UI app folder and build the application:
cd src/app npm install npm run build cd ..
-
In the
srcdirectory, create a virtual environment for running the app:python -m venv .venv
python -m venv .venv
::: zone-end ::: zone pivot="programming-language-typescript"
-
In the terminal, go to the UI app folder and build the application:
cd src/app npm install npm run build cd ../..
::: zone-end
::: zone pivot="programming-language-csharp,programming-language-java,programming-language-python,programming-language-typescript"
::: zone-end
::: zone pivot="programming-language-csharp"
When prompted, select src/McpWeatherApp. You see this prompt because there are two projects in the solution, and the other project isn't used by this article.
::: zone-end
::: zone pivot="programming-language-java"
In a terminal window, make sure you're in the samples/McpWeatherApp project folder.
::: zone-end
::: zone pivot="programming-language-csharp,programming-language-java,programming-language-python,programming-language-typescript"
[!INCLUDE run-locally]
The project template includes a .vscode/mcp.json file that defines a local-mcp-function server pointing to your local MCP endpoint. Use this configuration to verify your code by using GitHub Copilot in Visual Studio Code:
-
Open the
.vscode/mcp.jsonfile and select the Start button above thelocal-mcp-functionconfiguration. -
In the Copilot Chat window, make sure that the Agent mode is selected, select the Configure tools icon, and verify that
MCP Server:local-mcp-functionis enabled in the chat. -
Run this prompt:
What's the weather in Seattle?When prompted to run the tool, select Allow in this Workspace so you don't have to keep granting permission. The prompt runs the
GetWeathertool, which returns weather data. Because this tool declares UI metadata, the MCP host also fetches the UI resource and renders an interactive weather widget in a sandboxed iframe within the chat. -
When you're done testing, press Ctrl+C to stop the Functions host.
You can review the code that defines the MCP Apps tools. An MCP Apps tool requires two components:
- A tool with UI metadata that declares a
ui.resourceUripointing to a UI resource. - A resource that serves the bundled HTML/JavaScript at the matching
ui://URI. ::: zone-end
::: zone pivot="programming-language-csharp" The function code for the MCP Apps weather tool is defined in thesrc/McpWeatherAppfolder. In this function, the[McpMetadata]attribute adds UI metadata to theGetWeathertool.
:::code language="csharp" source="~/functions-scenarios-custom-mcp-dotnet/src/McpWeatherApp/WeatherFunction.cs" range="48-76" :::
The [McpResourceTrigger] attribute is applied to the GetWeatherWidget function, which serves the HTML widget.
:::code language="csharp" source="~/functions-scenarios-custom-mcp-dotnet/src/McpWeatherApp/WeatherFunction.cs" range="34-46" :::
The ToolMetadata constant declares a ui.resourceUri that tells the MCP host to fetch the interactive UI from ui://weather/index.html after the tool runs.
:::code language="csharp" source="~/functions-scenarios-custom-mcp-dotnet/src/McpWeatherApp/WeatherFunction.cs" range="12-18" :::
The GetWeatherWidget function serves the bundled HTML file at that URI using [McpResourceTrigger].
You can view the complete project template in the Azure Functions .NET MCP Server GitHub repository.
::: zone-end
::: zone pivot="programming-language-python"
The function code for the MCP Apps weather tool is defined in the src/function_app.py file. In this function, the metadata parameter on @app.mcp_tool() adds UI metadata to the get_weather tool.
:::code language="python" source="~/functions-scenarios-custom-mcp-python/src/function_app.py" range="109-130" :::
The @app.mcp_resource_trigger() decorator is applied to the get_weather_widget function, which serves the HTML widget.
:::code language="python" source="~/functions-scenarios-custom-mcp-python/src/function_app.py" range="64-105" :::
The TOOL_METADATA constant declares a ui.resourceUri that tells the MCP host to fetch the interactive UI from ui://weather/index.html after the tool runs.
:::code language="python" source="~/functions-scenarios-custom-mcp-python/src/function_app.py" range="20-21" :::
The get_weather_widget function serves the bundled HTML file at that URI using @app.mcp_resource_trigger().
You can view the complete project template in the Azure Functions Python MCP Server GitHub repository.
::: zone-end
::: zone pivot="programming-language-typescript"
The function code for the MCP Apps weather tool is defined in the src/functions/weatherMcpApp.ts file. In this function, the metadata property on app.mcpTool() adds UI metadata to the getWeather tool when it's registered.
:::code language="typescript" source="~/functions-scenarios-custom-mcp-typescript/src/functions/weatherMcpApp.ts" range="102-110" :::
The getWeather handler fetches weather data for a location and returns it as JSON.
:::code language="typescript" source="~/functions-scenarios-custom-mcp-typescript/src/functions/weatherMcpApp.ts" range="54-87" :::
The app.mcpResource() function registers the getWeatherWidget handler, which serves the HTML widget.
:::code language="typescript" source="~/functions-scenarios-custom-mcp-typescript/src/functions/weatherMcpApp.ts" range="89-97" :::
The getWeatherWidget handler reads and returns the bundled HTML file.
:::code language="typescript" source="~/functions-scenarios-custom-mcp-typescript/src/functions/weatherMcpApp.ts" range="29-52" :::
The TOOL_METADATA constant declares a ui.resourceUri that tells the MCP host to fetch the interactive UI from ui://weather/index.html after the tool runs.
:::code language="typescript" source="~/functions-scenarios-custom-mcp-typescript/src/functions/weatherMcpApp.ts" range="13-17" :::
You can view the complete project template in the Azure Functions TypeScript MCP Server GitHub repository.
::: zone-end
::: zone pivot="programming-language-java"
The function code for the MCP Apps weather tool is defined in the samples/McpWeatherApp folder. In this function, the @McpMetadata annotation adds UI metadata to the GetWeather tool.
:::code language="java" source="~/functions-scenarios-custom-mcp-java/samples/McpWeatherApp/src/main/java/com/function/weather/WeatherFunction.java" range="98-132" :::
The @McpResourceTrigger annotation is applied to the GetWeatherWidget function, which serves the HTML widget.
:::code language="java" source="~/functions-scenarios-custom-mcp-java/samples/McpWeatherApp/src/main/java/com/function/weather/WeatherFunction.java" range="53-66" :::
The TOOL_METADATA constant declares a ui.resourceUri that tells the MCP host to fetch the interactive UI from ui://weather/index.html after the tool runs.
:::code language="java" source="~/functions-scenarios-custom-mcp-java/samples/McpWeatherApp/src/main/java/com/function/weather/WeatherFunction.java" range="29-35" :::
The GetWeatherWidget function serves the bundled HTML file at that URI using @McpResourceTrigger.
You can view the complete project template in the Azure Functions Java MCP Server GitHub repository.
::: zone-end
::: zone pivot="programming-language-csharp,programming-language-java,programming-language-python,programming-language-typescript"
After verifying the MCP Apps tools locally, you can publish the project to Azure.
::: zone-end
::: zone pivot="programming-language-java,programming-language-python,programming-language-typescript"
[!INCLUDE deploy-azure]
::: zone-end
::: zone pivot="programming-language-csharp"
This project is configured to use azd to deploy this project to a new function app in a Flex Consumption plan in Azure. The project includes a set of Bicep files that azd uses to create a secure deployment to a Flex Consumption plan that follows best practices.
-
In the Terminal, run this
azd env setcommand:azd env set DEPLOY_SERVICE weatherThis command sets the
DEPLOY_SERVICEvariable to provisionweatherapp related resources -
Run the
azd provisioncommand and supply the required parameters to provision resources:azd provisionParameter Description Azure subscription Subscription in which your resources are created. Azure location Azure region in which to create the resource group that contains the new Azure resources. Only regions that currently support the Flex Consumption plan are shown. vnetEnabled Falseto skip creating virtual network resources, which simplifies the deployment.When prompted, pick your subscription, an Azure region for the resources, and choose
falseto skip creating virtual network resources to simplify the deployment. -
Run the
azd deploycommand to deploy theweatherapp to Azure:azd deploy --service weather
::: zone-end ::: zone pivot="programming-language-csharp,programming-language-java,programming-language-python,programming-language-typescript"
[!INCLUDE connect-remote]
You can now have GitHub Copilot use your remote MCP tools just as you did locally, but now the code runs securely in Azure. Replay the same commands you used earlier to ensure everything works correctly.
[!INCLUDE cleanup] ::: zone-end
[!div class="nextstepaction"] Configure built-in MCP server authorization