-
Notifications
You must be signed in to change notification settings - Fork 325
Add functionapp create command #1327
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Add functionapp create command #1327
Conversation
…ners package references
… App configuration
…ate FunctionAppJsonContext for serialization
…and related services
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds the azmcp functionapp create command to enable creating Azure Function Apps with comprehensive automatic dependency provisioning and flexible hosting options.
Key Changes
- Introduces the
FunctionAppCreateCommandwith support for multiple hosting plans (Consumption, Flex Consumption, Premium, App Service, Container Apps) - Implements automatic provisioning of Storage accounts and App Service plans when not specified
- Adds intelligent runtime and OS selection logic with sensible defaults for .NET, Node.js, Python, Java, and PowerShell
- Extends
FunctionAppInfomodel with operating system field for better resource tracking
Reviewed changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
FunctionAppService.cs |
Core service implementation with create logic, validation, OS resolution, and dual strategies for App Service vs Container Apps hosting |
FunctionAppCreateCommand.cs |
Command implementation with comprehensive option definitions, validation, and error handling |
FunctionAppCreateCommandTests.cs |
Extensive unit tests covering validation, parameter combinations, configuration building, and edge cases |
FunctionAppCommandTests.cs |
Live integration tests for various hosting plans and runtime combinations |
FunctionAppInfo.cs |
Model update adding operating system property |
IFunctionAppService.cs |
Interface extension for the create operation |
FunctionAppCreateOptions.cs |
New options class for create command parameters |
FunctionAppOptionDefinitions.cs |
Option definitions for location, plan, runtime, and storage parameters |
FunctionAppSetup.cs |
Registration of the new create command |
FunctionAppJsonContext.cs |
JSON serialization context update |
Azure.Mcp.Tools.FunctionApp.csproj |
Package references for Storage and AppContainers SDKs |
ResourceGroupService.cs / IResourceGroupService.cs |
New method for resource group creation (though not used by FunctionApp service) |
azmcp-commands.md |
Command documentation addition |
e2eTestPrompts.md |
Test prompts for the new command |
consolidated-tools.json |
Tool metadata for create_azure_app_resource |
cspell.json |
Dictionary additions for new terms |
| * python -> 3.12 | ||
| * node -> 22 | ||
| * dotnet -> 8.0 | ||
| * java -> 21.0 |
Copilot
AI
Dec 8, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Documentation inconsistency: The command description states the default Java version is "21.0" (line 72), but the code implementation in GetDefaultRuntimeVersion returns "17" for Java runtime (line 55 in FunctionAppService.cs). These should match.
| * java -> 21.0 | |
| * java -> 17.0 |
| { | ||
| baseName = "func"; | ||
| } | ||
| var trimmed = baseName.Length > 18 ? baseName.Substring(0, 18) : baseName; |
Copilot
AI
Dec 8, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider using baseName[..18] instead of baseName.Substring(0, 18) for consistency with modern C# range syntax used elsewhere in the file (e.g., line 526 uses version[..^2]).
| var trimmed = baseName.Length > 18 ? baseName.Substring(0, 18) : baseName; | |
| var trimmed = baseName.Length > 18 ? baseName[..18] : baseName; |
| [Theory] | ||
| [InlineData("invalid")] | ||
| [InlineData("mac")] | ||
| [InlineData("WINDOWS")] |
Copilot
AI
Dec 8, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test case issue: The test expects "WINDOWS" (uppercase) to throw an ArgumentException, but the code normalizes the OS input to lowercase in ValidateAndNormalizeInputs (line 109 in FunctionAppService.cs: os.Trim().ToLowerInvariant()). After normalization, "WINDOWS" becomes "windows" which is a valid value, so this test will fail. Either update the test to use a truly invalid value like "mac" or "invalid", or verify that uppercase values are actually rejected before normalization.
| [InlineData("WINDOWS")] |
| * flex / flexconsumption -> FC1 (FlexConsumption, Linux only) | ||
| * premium / functionspremium -> EP1 (Elastic Premium) | ||
| * appservice -> B1 (Basic) unless overridden by --plan-sku | ||
| * containerapp -> Creates a Container App instead of an App Service plan/site (no plan created). Container App will reuse the function-app name. |
Copilot
AI
Dec 8, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Documentation formatting: Line 56 starts with an asterisk (*) instead of proper indentation/formatting like the lines above it. This should be indented consistently with the other bullets (lines 52-55) to maintain proper documentation structure.
| * containerapp -> Creates a Container App instead of an App Service plan/site (no plan created). Container App will reuse the function-app name. | |
| * containerapp -> Creates a Container App instead of an App Service plan/site (no plan created). Container App will reuse the function-app name. |
| foreach (var p in parts) | ||
| { | ||
| if (p.StartsWith("AccountName=", StringComparison.OrdinalIgnoreCase)) | ||
| return p[12..]; | ||
| } |
Copilot
AI
Dec 8, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This foreach loop implicitly filters its target sequence - consider filtering the sequence explicitly using '.Where(...)'.
| }, | ||
| "readOnly": { | ||
| "value": false, | ||
| "description": "This tool only performs read operations without modifying any state or data." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This description should describe what the tool/tools will do to support this metadata value. Given that readOnly is false, it shouldn't say this tool only performs read operations. You can look at other tools with readOnly=false.
Same comment for other metadata descriptions.
| - os: windows|linux. Default: windows unless runtime/plan requires linux (python, flex consumption, containerapp). Overridden to linux automatically when required. Python & flex consumption do not support Windows. | ||
| Automatic resources & defaults: | ||
| - Storage account: Always created (Standard_LRS, HTTPS only, blob public access disabled). Name pattern: <sanitized-functionapp>[random6]. Connection string injected as AzureWebJobsStorage. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Azure Function supports using managed identity to connect to storage account. If it is not too hard we should recommend users to use that instead of the connection string since connection strings use storage account keys.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. I was following what Azure Portal does by default. That's been my pattern. I don't disagree that using managed identities are best practices.
| public const string RuntimeVersionName = "runtime-version"; | ||
| public const string OperatingSystemName = "os"; | ||
| public const string StorageAccountName = "storage-account"; | ||
| public const string ContainerAppsEnvironmentName = "container-apps-environment"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I understand correctly, this option will be ignored when not using the containerapp plan, if not rejected by the argument validation logic.
I don't feel good that some arguments will be completely ignored depending on the value of some other arguments. This looks like a signal that there should be two commands. One is for creating a traditional Azure Function App using an App Service Plan. The other is for creating a container app that runs an Azure Function App.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can see how that would be clearer. I'll work on breaking these out into two separate commands.
What does this PR do?
Adds azmcp functionapp create command to create Azure Function Apps with automatic dependency provisioning.
Features
GitHub issue number?
#77
Pre-merge Checklist
servers/Azure.Mcp.Server/CHANGELOG.mdand/orservers/Fabric.Mcp.Server/CHANGELOG.mdfor product changes (features, bug fixes, UI/UX, updated dependencies)servers/Azure.Mcp.Server/README.mdand/orservers/Fabric.Mcp.Server/README.mddocumentationeng/scripts/Process-PackageReadMe.ps1. See Package README/servers/Azure.Mcp.Server/docs/azmcp-commands.mdand/or/docs/fabric-commands.md.\eng\scripts\Update-AzCommandsMetadata.ps1to update tool metadata in azmcp-commands.md (required for CI)ToolDescriptionEvaluatorand obtained a score of0.4or more and a top 3 ranking for all related test promptsconsolidated-tools.json/servers/Azure.Mcp.Server/docs/e2eTestPrompts.mdcrypto mining, spam, data exfiltration, etc.)/azp run mcp - pullrequest - liveto run Live Test Pipeline