This quick-start shows how to build and deploy a remote MCP server with Azure Functions (Java).
You can run it locally for debugging, then ship it to the cloud with azd up in minutes.
The server is secured by design (system keys + HTTPS), supports OAuth via EasyAuth or API Management, and can be isolated inside a VNet.
| Purpose | Tool | Notes |
|---|---|---|
| Java build + run | JDK 17 (or newer) | Java 8 runtime still works but JDK 17 is recommended. |
| Local Functions runtime | Azure Functions Core Tools v4 ≥ 4.0.7030 |
Used by func start / mvn azure-functions:run. |
| Provision & deploy | Azure Developer CLI (azd) | Simplifies end-to-end deployment. |
| IDE (optional) | Visual Studio Code + Azure Functions extension | One-click debug & log streaming. |
| Blob Storage emulator | Docker to run Azurite | Needed only when running locally with UseDevelopmentStorage=true. |
Why Azurite?
TheSaveSnippet/GetSnippettools persist snippets in Azure Blob Storage.
Azurite emulates that storage account on your dev machine.
docker run -p 10000:10000 -p 10001:10001 -p 10002:10002 \
mcr.microsoft.com/azure-storage/azuriteIf you prefer the Azurite VS Code extension, run “Azurite: Start” from the command palette instead.
# 1 – Build the project
mvn clean package
# 2 – Start the Functions host (via Maven wrapper)
mvn azure-functions:run
# └─ or use `func start` if you preferThe SSE endpoint will be available at:
http://127.0.0.1:7071/runtime/webhooks/mcp/sse
-
Add MCP Server → choose HTTP (Server-Sent Events).
-
URL:
http://127.0.0.1:7071/runtime/webhooks/mcp/sse -
Give it any server-ID you like and save to User or Workspace settings.
-
List MCP Servers → Start your new server.
-
In Copilot Chat (agent-mode) try prompts such as:
Say Hello Save this snippet as snippet1 Retrieve snippet1 and apply to MyFile.java -
When finished, Stop the server (command palette) and
Ctrl+Cthe terminal running the function host.
# In a second terminal
npx @modelcontextprotocol/inspector node build/index.js
# If the Functions host isn’t running, start it:
# func start- Open the Inspector UI (URL printed in the terminal).
- Transport: SSE.
- URL:
http://127.0.0.1:7071/runtime/webhooks/mcp/sse→ Connect. - List Tools → pick one → Run Tool.
Stop both terminals with Ctrl+C when done.
Want the function app inside a VNet before provisioning? Just set:
azd env set VNET_ENABLED trueThen provision + deploy in one step:
azd upThe hosted SSE endpoint will be:
https://<FUNC_APP_NAME>.azurewebsites.net/runtime/webhooks/mcp/sse
Key required Grab the system key named
mcp_extensionfrom the Azure Portal or via CLI:az functionapp keys list --resource-group <rg> --name <func-app>
https://<FUNC_APP_NAME>.azurewebsites.net/runtime/webhooks/mcp/sse?code=<mcp_extension_key>
Add a header in mcp.json:
Start remote-mcp-function and chat as usual in Copilot.
azd up # Safe to run repeatedly—always overwrites the app with the latest buildazd down| Tool | Path | Description |
|---|---|---|
| HelloWorld | src/main/java/com/function/HelloWorld.java |
Logs an argument then prints “Hello World”. |
| SaveSnippets / GetSnippets | src/main/java/com/function/Snippets.java |
Saves / retrieves snippets to Blob Storage. |
Click to expand
@McpToolTrigger(
toolName = "saveSnippets",
description = "Saves a text snippet to your snippets collection.",
toolProperties = SAVE_SNIPPET_ARGUMENTS // JSON schema string
)toolPropertiesdefines the JSON payload expected from the client.- At runtime the JSON is passed to your function in
toolArguments.
@BlobOutput(
name = "snippetOut",
path = "snippets/{mcptoolargs.snippetName}.json",
dataType = "binary")SaveSnippetswrites to a blob;GetSnippetsreads the same path.- The default storage account is referenced with
@StorageAccount("AzureWebJobsStorage").
<azure.functions.java.library.version>3.1.1-alpha</azure.functions.java.library.version>// host.json
{
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle.Experimental",
"version": "[4.*, 5.0.0)"
}
}- Front your MCP server with API Management for fine-grained policies.
- Add EasyAuth to use your favourite OAuth provider (including Entra ID).
- Toggle VNet integration via
VNET_ENABLED=truefor network isolation. - Explore the Model Context Protocol ecosystem for more tools.
{ "servers": { "remote-mcp-function": { "type": "sse", "url": "https://<FUNC_APP_NAME>.azurewebsites.net/runtime/webhooks/mcp/sse", "headers": { "x-functions-key": "<mcp_extension_key>" } }, "local-mcp-function": { "type": "sse", "url": "http://127.0.0.1:7071/runtime/webhooks/mcp/sse" } } }