{"id":3676,"date":"2026-04-06T08:01:58","date_gmt":"2026-04-06T15:01:58","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/azure-sdk\/?p=3676"},"modified":"2026-04-06T14:03:34","modified_gmt":"2026-04-06T21:03:34","slug":"mcp-apps-on-azure-functions-quickstart-with-typescript","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/azure-sdk\/mcp-apps-on-azure-functions-quickstart-with-typescript\/","title":{"rendered":"MCP Apps on Azure Functions: Quickstart with TypeScript"},"content":{"rendered":"<p>Azure Functions makes hosting MCP apps simple: build locally, create a secure endpoint, and deploy fast with Azure Developer CLI (azd).<\/p>\n<p>This guide shows you how using a weather app example.<\/p>\n<h2>What are MCP Apps?<\/h2>\n<p><a href=\"https:\/\/modelcontextprotocol.io\/extensions\/apps\/overview\">MCP Apps<\/a> let MCP servers return interactive HTML interfaces such as data visualizations, forms, dashboards that render directly inside MCP-compatible hosts (Visual Studio Code Copilot, Claude, ChatGPT, etc.). Learn more about MCP Apps in the <a href=\"https:\/\/apps.extensions.modelcontextprotocol.io\/api\/\">official documentation<\/a>.<\/p>\n<p>Having an interactive UI removes many restrictions that plain texts have, such as if your scenario has:<\/p>\n<ul>\n<li><strong>Interactive Data<\/strong>: Replacing lists with clickable maps or charts for deep exploration.<\/li>\n<li><strong>Complex Setup<\/strong>: Use one-page forms instead of long, back-and-forth questioning.<\/li>\n<li><strong>Rich Media<\/strong>: Embed native viewers to pan, zoom, or rotate 3D models and documents.<\/li>\n<li><strong>Live Updates<\/strong>: Maintain real-time dashboards that refresh without new prompts.<\/li>\n<li><strong>Workflow Management<\/strong>: Handle multi-step tasks like approvals with navigation buttons and persistent state.<\/li>\n<\/ul>\n<h2>Hosting MCP Apps on Azure Functions<\/h2>\n<p>Azure Functions provides an easy abstraction to help you build MCP servers without having to learn the nitty-gritty of the MCP protocol. When hosting your MCP App on Functions, you get:<\/p>\n<ul>\n<li><strong>MCP tools<\/strong> (server logic): Handle client requests, call backend services, return structured data &#8211; Azure Functions manages the MCP protocol details for you<\/li>\n<li><strong>MCP resources<\/strong> (UI payloads such as app widgets): Serve interactive HTML, JSON documents, or formatted content &#8211; just focus on your UI logic<\/li>\n<li><strong>Secure HTTPS access<\/strong>: Built-in authentication using Azure Functions keys, plus <a href=\"https:\/\/learn.microsoft.com\/azure\/azure-functions\/functions-mcp-tutorial?tabs=mcp-extension&amp;pivots=programming-language-python#enable-built-in-server-authorization-and-authentication\">built-in MCP authentication with OAuth support<\/a> for enterprise-grade security<\/li>\n<li><strong>Easy deployment<\/strong> with Bicep and azd: Infrastructure as Code for reliable deployments<\/li>\n<li><strong>Local development<\/strong>: Test and debug locally before deploying<\/li>\n<li><strong>Auto-scaling<\/strong>: Azure Functions handles scaling, retries, and monitoring automatically<\/li>\n<\/ul>\n<p>The weather app in this repo is an example of this feature, not the only use case.<\/p>\n<h2>Architecture overview<\/h2>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-content\/uploads\/sites\/58\/2026\/04\/04-01-mcp-apps-on-functions-ts-architecture.png\" alt=\"Architecture Diagram\" \/><\/p>\n<h2>Example: The classic weather app<\/h2>\n<p>The sample implementation includes:<\/p>\n<ul>\n<li>A <strong>GetWeather MCP tool<\/strong> that fetches weather by location (calls Open-Meteo geocoding and forecast APIs)<\/li>\n<li>A <strong>Weather Widget MCP resource<\/strong> that serves interactive HTML\/JS code (runs in the client; fetches data via GetWeather tool)<\/li>\n<li>A TypeScript service layer that abstracts API calls and data transformation (runs on the server)<\/li>\n<li>Local and remote testing flow for MCP clients (via MCP Inspector, Visual Studio Code, or custom clients)<\/li>\n<\/ul>\n<h3>How UI rendering works in MCP Apps<\/h3>\n<p><strong>In the Weather App example<\/strong>:<\/p>\n<ul>\n<li>Azure Functions serves <code>getWeatherWidget<\/code> as a resource \u2192 returns <code>weather-app.ts<\/code> compiled to HTML\/JS<\/li>\n<li>Client renders the Weather Widget UI<\/li>\n<li>User interacts with the widget or requests are made internally<\/li>\n<li>The widget calls the <code>getWeather<\/code> tool \u2192 server processes and returns weather data<\/li>\n<li>The widget renders the weather data on the client side<\/li>\n<\/ul>\n<p>This architecture keeps the UI <strong>responsive locally<\/strong> while using <strong>server-side logic and data<\/strong> on demand.<\/p>\n<h2>Quickstart<\/h2>\n<p>Clone the repository:<\/p>\n<pre><code class=\"language-bash\">git clone https:\/\/github.com\/Azure-Samples\/remote-mcp-functions-typescript.git\ncd remote-mcp-functions-typescript<\/code><\/pre>\n<p>Run locally:<\/p>\n<pre><code class=\"language-bash\">npm install\nnpm run build\nfunc start<\/code><\/pre>\n<p>Local endpoint:<\/p>\n<pre><code class=\"language-text\">http:\/\/0.0.0.0:7071\/runtime\/webhooks\/mcp<\/code><\/pre>\n<p>Deploy to Azure:<\/p>\n<pre><code class=\"language-bash\">azd provision\nazd deploy<\/code><\/pre>\n<p>Remote endpoint:<\/p>\n<pre><code class=\"language-text\">https:\/\/&lt;function-app-name&gt;.azurewebsites.net\/runtime\/webhooks\/mcp<\/code><\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-content\/uploads\/sites\/58\/2026\/04\/04-01-mcp-apps-on-functions-ts-architecture.gif\" alt=\"MCP Apps Architecture Demo\" \/><\/p>\n<h2>TypeScript MCP tools snippet (Get Weather service)<\/h2>\n<p>In Azure Functions, you define MCP tools using <code>app.mcpTool()<\/code>. The <code>toolName<\/code> and <code>description<\/code> tell clients what this tool does, <code>toolProperties<\/code> defines the input arguments (like <code>location<\/code> as a string), and <code>handler<\/code> points to your function that processes the request.<\/p>\n<pre><code class=\"language-typescript\">app.mcpTool(\"getWeather\", {\n  toolName: \"GetWeather\",\n  description: \"Returns current weather for a location via Open-Meteo.\",\n  toolProperties: {\n    location: arg.string().describe(\"City name to check weather for\")\n  },\n  handler: getWeather,\n});<\/code><\/pre>\n<h2>TypeScript MCP Resource trigger snippet (Weather App Hook)<\/h2>\n<p>MCP resources are defined using <code>app.mcpResource()<\/code>. The <code>uri<\/code> is how clients reference this resource, <code>resourceName<\/code> and <code>description<\/code> provide metadata, <code>mimeType<\/code> tells clients what type of content to expect, and <code>handler<\/code> is your function that returns the actual content (like HTML for a widget).<\/p>\n<pre><code class=\"language-typescript\">app.mcpResource(\"getWeatherWidget\", {\n  uri: \"ui:\/\/weather\/index.html\",\n  resourceName: \"Weather Widget\",\n  description: \"Interactive weather display for MCP Apps\",\n  mimeType: \"text\/html;profile=mcp-app\",\n  handler: getWeatherWidget,\n});<\/code><\/pre>\n<h2>Sample repos and references<\/h2>\n<ul>\n<li>Complete sample repository with TypeScript implementation: <a href=\"https:\/\/github.com\/Azure-Samples\/remote-mcp-functions-typescript\">Azure-Samples\/remote-mcp-functions-typescript<\/a><\/li>\n<li>Official MCP extension documentation: <a href=\"https:\/\/learn.microsoft.com\/azure\/azure-functions\/functions-bindings-mcp?pivots=programming-language-typescript\">Azure Functions MCP bindings<\/a><\/li>\n<li>Java sample: <a href=\"https:\/\/github.com\/Azure-Samples\/remote-mcp-functions-java\">Azure-Samples\/remote-mcp-functions-java<\/a><\/li>\n<li>.NET sample: <a href=\"https:\/\/github.com\/Azure-Samples\/remote-mcp-functions-dotnet\">Azure-Samples\/remote-mcp-functions-dotnet<\/a><\/li>\n<li>Python sample: <a href=\"https:\/\/github.com\/Azure-Samples\/remote-mcp-functions-python\">Azure-Samples\/remote-mcp-functions-python<\/a><\/li>\n<li>MCP Inspector: <a href=\"https:\/\/github.com\/modelcontextprotocol\/inspector\">modelcontextprotocol\/inspector<\/a><\/li>\n<\/ul>\n<h2>Final takeaway<\/h2>\n<p>MCP Apps are just MCP servers but they represent a paradigm shift by transforming the AI from a text-based chatbot into a functional interface. Instead of forcing users to navigate complex tasks through back-and-forth conversations, these apps embed interactive UIs and tools directly into the chat, significantly improving the user experience and the usefulness of MCP servers.<\/p>\n<p><strong>Azure Functions<\/strong> allows developers to quickly build and host an MCP app by providing an <strong>easy abstraction and deployment experience<\/strong>. The platform also provides built-in features to <strong>secure and scale<\/strong> your MCP apps, plus a serverless pricing model so you can just focus on the business logic.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Learn how to build and deploy MCP (Model Context Protocol) apps on Azure Functions using TypeScript. This guide covers MCP tools, resources, local development, and serverless deployment with a practical weather app example.<\/p>\n","protected":false},"author":209626,"featured_media":3682,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[734,765,864,159,940,962,961,959,162,960,733],"class_list":["post-3676","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure-sdk","tag-azure","tag-azure-functions","tag-azure-developer-cli","tag-javascript","tag-mcp","tag-mcp-resources","tag-mcp-tools","tag-model-context-protocol","tag-python","tag-serverless","tag-typescript"],"acf":[],"blog_post_summary":"<p>Learn how to build and deploy MCP (Model Context Protocol) apps on Azure Functions using TypeScript. This guide covers MCP tools, resources, local development, and serverless deployment with a practical weather app example.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/posts\/3676","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/users\/209626"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/comments?post=3676"}],"version-history":[{"count":2,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/posts\/3676\/revisions"}],"predecessor-version":[{"id":3695,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/posts\/3676\/revisions\/3695"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/media\/3682"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/media?parent=3676"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/categories?post=3676"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/tags?post=3676"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}