Emit MCP-related information when deploying code to a MCP function app
- Dominant language
- Go
- Stars
- 569
- Forks
- 364
- Avg merge
- 2d 19h
- Merged PRs (30d)
- 136
Description
## 1. Background
**Goal**: minimize the friction to add a custom MCP tool hosted on Functions to your agent.
**Problem**: developers must know to construct the remote MCP endpoint themselves, get the authentication information, and know where to go to supply this information to their agent.
> [!NOTE]
> This is a point-in-time optimization until we can declaratively add MCP tools hosted on Functions to agents.
## 2. Ideal user journey
1. Developer initializes MCP function app project: e.g., `azd init --template python-mcp-sdk-functions-azd`
2. Developer modifies sample code and tests locally
3. Developer runs `azd up` to deploy MCP server to Azure
**a. Terminal returns information to help the next step.**
4. Developer manually adds the MCP tool to their Foundry agent, inputting information copied from terminal.
5. [LATER] Developer modifies code and runs `azd deploy`
**a. Terminal returns same information to help with next steps.**
**Bold** is the scope of this issue.
## 3. Information to emit
- P0: `Remote MCP server endpoint - https://{function_app_name}.azurewebsites.net/mcp`
- P0: `How do I add my MCP function app as a tool to a Foundry agent? aka.ms/functions-mcp-next-steps`
- _I'm open on the wording_
> [!NOTE]
> Long-term, we should still be emitting the `remote mcp server endpoint`. However, the recommended doc will no longer be necessary once we can automate adding tools to agent.s
## 4. Technical requirements
1. P0: Identify that the function app is a MCP server
2. P0: Construct the endpoint
3. P1: Provide tailored auth recommendations
### 4.1 Identify that the function app is a MCP server
#### 4.1.1. Approach 1 - Interrrogate the function app
Make two api calls since we support two ways of building MCP servers:
- `GET /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Web/sites/{app_name}/functions?api-version=2022-03-01`
- Parse entries for `content.value` for `"properties.config.bindings.type": "mcpToolTrigger"`
- `GET https://management.azure.com/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Web/sites/{app_name}/hostruntime/admin/vfs//host.json?relativePath=1&api-version=2022-03-01`
- Parse response for `"configurationProfile": "mcp-custom-handler"`
#### 4.1.2 Approach 2 - Infer MCP app from `azure.yaml`
Potentially, we could standardize a way to define a MCP function app. Maybe something like:
```yaml
name: python-mcp-sdk-functions-azd
metadata:
template: python-mcp-sdk-functions-azd@1.0.0
services:
mcp:
project: .
language: python
host: function
```
So, MCP Function app == (`services` is `mcp` AND `host` is `function`)
#### 4.1.3. Approach 3 - Rely on hardcoded outputs
In `main.bicep` we could ensure we output the right endpoint path since the author of the template would know what technology the MCP server is built with.
- `output SERVICE_MCP_ENDPOINT string = '${mcp.outputs.SERVICE_MCP_DEFAULT_HOSTNAME}/mcp'` or
- `output SERVICE_MCP_ENDPOINT string = '${mcp.outputs.SERVICE_MCP_DEFAULT_HOSTNAME}/runtime/webhooks/mcp'`
### 4.2. Construct the endpoint
There are two technologies to build MCP Function apps, each has its own endpoint path:
- **MCP Extension**: `{function_app_default_hostname}/runtime/webhooks/mcp`
- **Self-hosted MCP**: `{function_app_default_hostname}/mcp`
An example of the **MCP Extension** is `https://my-mcp-app.azurewebsites.net/runtime/webhooks/mcp`
### 4.3. Provide tailored auth recommendations
> Out of scope for now, but including for creativity's sake
Theoretically, we could also define somewhere in `/infra` what auth type the function app is using. That way, `azd` can output what `az cli` command to run to fetch that information for the developer - or even ask permission to run it.
Not in scope because if we link to docs, the developer can figure it out themselves.
cc. @rajeshkamal5050
Contributor guide
Assessment
This issue has not been assessed yet.