Skip to content

Support for creating self-hosted MCP servers#4789

Merged
nturinski merged 3 commits intomainfrom
nat/selfHostedMcpServerCreate
Nov 13, 2025
Merged

Support for creating self-hosted MCP servers#4789
nturinski merged 3 commits intomainfrom
nat/selfHostedMcpServerCreate

Conversation

@nturinski
Copy link
Copy Markdown
Member

@nturinski nturinski commented Nov 13, 2025

Use this repository to follow along: https://github.com/Azure-Samples/mcp-sdk-functions-hosting-node

The idea of the MCP in Functions is pretty convoluted, but I'll try my best to explain it here concisely and then explain the changes in this pull request.

All other PRs build off of this one. Don't mind the build errors, I didn't import changes I made in a file because those were more deploy related. When all 3 PRs (#4789, #4790. #4791) are merged, everything should be fine.

There are two ways to have MCP tools in Azure Functions:

  • Using the MCP extension (it's not a VS Code extension, but an optional extension that the function host runtime will download when it sees it defined in the host.json)
  • Using self-hosted MCP servers

Like how it sounds, self-hosted MCP servers are function apps that behave like a remote MCP server. In order to configure the host runtime, there a few things that you have to set in the host.json, but there's a shortcut-- set the configurationProfile to equal -mcp-custom-handler. The host will see that and set all the defaults required to run the server.

Whenever we create the project, we set the workspace setting to indicate that this is a SelfHostedMcpServer. That comes into play in the deploy scenario.

You also need to have a feature flag enabled, EnableMcpCustomHandlerPreview. This flag is not required for MCP extension function apps.

Don't mind the mcpGetHostKey. That is for the deployment piece, but it was defined in the package.json so I just left it in.

@nturinski nturinski requested a review from a team as a code owner November 13, 2025 00:33
Copy link
Copy Markdown
Contributor

@MicroFish91 MicroFish91 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly nits and questions, LGTM

Comment thread package.json
"description": "%azureFunctions.allowProgrammingModelSelection%",
"default": false
},
"azureFunctions.showBallerinaProjectCreation": {
Copy link
Copy Markdown
Contributor

@MicroFish91 MicroFish91 Nov 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Were the ballerina changes intentional?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, if you look at this issue: #4749, Lily asked that I remove Ballerina from the project runtimes.

But I didn't have the heart to completely rip out Ballerina since it was a significant open-source contribution. I hid it behind a VS Code setting that users can enable if they need it.

But I did remove the tests for Ballerina since we don't officially support it anymore.

return !context.functionTemplate && context['buildTool'] !== JavaBuildTool.maven;
return !context.functionTemplate &&
context['buildTool'] !== JavaBuildTool.maven &&
context.language !== ProjectLanguage.SelfHostedMCPServer;
Copy link
Copy Markdown
Contributor

@MicroFish91 MicroFish91 Nov 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It feels too generous to call an MCP server a project language instead of maybe a project type, although I see the project flow becomes difficult if you don't do it this way (also could introduce a lot of tangential changes).

I still think it could be worth leaving an issue or todo for us to revisit this though, when we have more time to consider all the implications of lumping these together.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, and I can explain this more tomorrow offline, self-hosted MCP servers are completely handled differently by the runtime. I think the biggest callout is that underneath the hood, the runtime is actually a "custom handler" type which is used to run any server process that you want.

You typically wouldn't want a self-hosted MCP project to be included with a normal functions runtime.

export class MCPDownloadSnippetsExecuteStep extends AzureWizardExecuteStepWithActivityOutput<MCPProjectWizardContext> {
stepName: string = 'MCPDownloadSampleCodeExecuteStep';
protected getTreeItemLabel(context: MCPProjectWizardContext): string {
return localize('downloadSampleCode', 'Downloading {0} sample server code', nonNullProp(context, 'serverLanguage'));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Present case for tree item labels

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will put up a different PR since changing it here will have a bunch of annoying cascading effects.

@nturinski nturinski merged commit 3e0a9f1 into main Nov 13, 2025
1 of 2 checks passed
@nturinski nturinski deleted the nat/selfHostedMcpServerCreate branch November 13, 2025 23:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants