This repo contains instructions and samples for running MCP server built with the Node MCP SDK on Azure Functions. The repo uses the weather sample server to demonstrate how this can be done. You can clone to run and test the server locally, follow by easy deploy with azd up
to have it in the cloud in a few minutes. If you already have a server, you can follow the instructions provided to manually add the required Functions artifacts for hosting, or have Visual Studio Code's Copilot make those additions for you by using the experimental prompt provided.
Find the repo for other languages:
Language (Stack) | Repo Location |
---|---|
C# (.NET) | dotnet-mcp-sdk-functions-hosting |
Python | python-mcp-sdk-functions-hosting |
Recently Azure Functions released the Functions MCP extension, allowing developers to build MCP servers using Functions programming model, which is essentially Function's event-driven framework, and host them remotely on the serverless platform.
For those who have already built servers with Anthropic's MCP SDKs, it's also possible host the servers on Azure Functions by running them as custom handlers, which are lightweight web servers that receive events from the Functions host. They allow you to host your already-built MCP servers with minimal code change and benefit from Function's bursty scale, serverless pricing model, and security features.
You'll need an Azure subscription. If you don't already have an account, create a free one before you begin.
Ensure you have the following installed:
- Azure Developer CLI
- Azure Functions Core Tools
- Visual Studio Code
- Azure Functions extension on Visual Studio Code
Tip
If you want to get started quickly or you don't have a server yet, follow the instructions in this section. If you already have a server, skip to Prepare Node MCP server for deployment.
The sample server in this repo contains the required Functions artifacts to be run as a custom handler and can be deployed as is.
- Clone the repo
git clone https://github.com/Azure-Samples/node-mcp-sdk-functions-hosting.git
- Open up the sample in VSCode, run
func start
in the root directory to start the MCP server locally. The server is treated as an http trigger, so there's an endpoint returned that looks likehttp://localhost:7071/{*route}
. - Open the command palette (
cntrl/cmd+shift+p
) and search for MCP: Add server - Choose HTTP
- Connect to the MCP server by entering the endpoint, replacing
{*route}
withmcp
.
In the root directory, and run azd up
. This command will create and deploy the app, plus other required resources.
- After deployment completes, go to the Function App resource on Azure portal
- Find the app's endpoint and key by clicking on function-route -> Get function URL -> copy the second endpoint with Function key. While the app is publically accessable, the server endpoint is protected and requires a function key to access it. The endpoint with key should look like:
https://<function app name>.azurewebsites.net/{*route}?code=<key>
- Open the command palette (
cntrl/cmd+shift+p
) and search for MCP: Add server - Choose HTTP
- Enter the function endpoint from above, replace
{*route}
withmcp
If you have already have server, this section provides guidance on how to prepare the MCP server for deployment as a custom handler.
Note
Before moving on to the next steps, check that your server is stateless and uses the streamable HTTP transport.
You can manually take the steps below to prepare for custom handler deployment, or try out the Azure Functions MCP server deployment helper to have VSCode's Copilot go through the steps by following an experimental prompt.
-
In the root directory of your MCP server project, create a
host.json
with the following:{ "version": "2.0", "extensions": { "http": { "routePrefix": "" } }, "customHandler": { "description": { "defaultExecutablePath": "node", "workingDirectory": "", "arguments": ["<path to compiled JavaScript file (e.g., server.js)>"] }, "enableForwardingHttpRequest": true, "enableHttpProxyingRequest": true } }
-
Create a folder named
function-route
in the root directory. Inside the folder, create a file namedfunction.json
with the following:{ "bindings": [ { "authLevel": "function", "type": "httpTrigger", "direction": "in", "name": "req", "methods": ["get", "post", "put", "delete", "patch", "head", "options"], "route": "{*route}" }, { "type": "http", "direction": "out", "name": "res" } ] }
This file marks the MCP server as an HTTP trigger to the Functions host, allowing access to the server through an HTTP endpoint. Functions allows you to use access keys to make it harder to access function endpoints. In this case, the line
"authLevel": "function"
specifies that a key must be included in the request when accessing the MCP server. -
Again in the root directory, create a
local.settings.json
file with the following:{ "IsEncrypted": false, "Values": { "FUNCTIONS_WORKER_RUNTIME": "custom" } }
This file is where all the environment variables are kept.
-
Modify the MCP server code to listen for HTTP requests on the port specified by the
FUNCTIONS_CUSTOMHANDLER_PORT
environment variable. This is the only line of code that needs modification:const PORT = process.env.FUNCTIONS_CUSTOMHANDLER_PORT || process.env.PORT || 3000; app.listen(PORT, (error?: Error) => { // code });
That's it! You're ready to run your MCP server locally and deploy to Azure Functions as a custom handler.
Following instructions in Run the server locally for testing.
- Create a Function app hosted on the Flex Consumption plan and related resources.
- Choose Node 22 as the runtime stack and version.
- On Networking tab, choose "Enable public access" to allow all IPs to access the app. This helps with the deployment step and allows for accessing the app (i.e. server) during testing. For production scenarios, it's recommended that you configure IP allowlist or set up VNET instead.
- Open the command palette and search for Azure Functions: Deploy to Function app.
- Choose your Azure subscription and the function app created in Step 1. Select Deploy when prompted.
- After deployment completes, follow steps in Test in Visual Studio Code.
In addition to protecting server access through function keys, you can also leverage APIM to add server authorization with Entra ID.
[TODO]