33 * Licensed under the MIT License. See License.txt in the project root for license information.
44 *--------------------------------------------------------------------------------------------*/
55
6- import { AzExtFsExtra , AzureWizardExecuteStepWithActivityOutput , callWithTelemetryAndErrorHandling , nonNullValue , type IActionContext } from '@microsoft/vscode-azext-utils' ;
6+ import { AzExtFsExtra , AzureWizardExecuteStepWithActivityOutput , callWithTelemetryAndErrorHandling , nonNullProp , nonNullValue , type IActionContext } from '@microsoft/vscode-azext-utils' ;
77import * as path from 'path' ;
88import { Uri , window , workspace , type Progress } from 'vscode' ;
9- import { hostFileName } from '../../constants' ;
9+ import { hostFileName , McpProjectType , mcpProjectTypeSetting } from '../../constants' ;
1010import { ext } from '../../extensionVariables' ;
1111import { type IHostJsonV2 } from '../../funcConfig/host' ;
1212import { localize } from '../../localize' ;
1313import { type FunctionTemplateBase } from '../../templates/IFunctionTemplate' ;
14+ import { addLocalMcpServer , checkIfMcpServerExists , getLocalServerName , getOrCreateMcpJson , saveMcpJson } from '../../utils/mcpUtils' ;
1415import { verifyTemplateIsV1 } from '../../utils/templateVersionUtils' ;
1516import { verifyExtensionBundle } from '../../utils/verifyExtensionBundle' ;
1617import { getContainingWorkspace } from '../../utils/workspace' ;
18+ import { updateWorkspaceSetting } from '../../vsCodeConfig/settings' ;
1719import { type IFunctionWizardContext } from './IFunctionWizardContext' ;
1820
1921interface ICachedFunction {
2022 projectPath : string ;
2123 newFilePath : string ;
2224 isHttpTrigger : boolean ;
25+ isMcpTrigger : boolean ;
2326}
2427
2528const cacheKey : string = 'azFuncPostFunctionCreate' ;
@@ -68,9 +71,23 @@ export abstract class FunctionCreateStepBase<T extends IFunctionWizardContext> e
6871 progress . report ( { message : localize ( 'creatingFunction' , 'Creating new {0}...' , template . name ) } ) ;
6972
7073 const newFilePath : string = await this . executeCore ( context ) ;
74+ if ( context . functionTemplate ?. isMcpTrigger ) {
75+ // indicate that this is a MCP Extension Server project
76+ await updateWorkspaceSetting ( mcpProjectTypeSetting , McpProjectType . McpExtensionServer , context . workspacePath ) ;
77+ // add the local server to the mcp.json if it doesn't already exist
78+ const workspace = nonNullProp ( context , 'workspaceFolder' ) ;
79+ const mcpJson = await getOrCreateMcpJson ( workspace ) ;
80+ const serverName = getLocalServerName ( workspace ) ;
81+ // only add if it doesn't already exist
82+ if ( ! checkIfMcpServerExists ( mcpJson , serverName ) ) {
83+ const newMcpJson = await addLocalMcpServer ( mcpJson , serverName , McpProjectType . McpExtensionServer ) ;
84+ await saveMcpJson ( workspace , newMcpJson ) ;
85+ }
86+ }
87+
7188 await verifyExtensionBundle ( context , template ) ;
7289
73- const cachedFunc : ICachedFunction = { projectPath : context . projectPath , newFilePath, isHttpTrigger : template . isHttpTrigger } ;
90+ const cachedFunc : ICachedFunction = { projectPath : context . projectPath , newFilePath, isHttpTrigger : template . isHttpTrigger , isMcpTrigger : template . isMcpTrigger } ;
7491 const hostFilePath : string = path . join ( context . projectPath , hostFileName ) ;
7592 if ( await AzExtFsExtra . pathExists ( hostFilePath ) ) {
7693 if ( verifyTemplateIsV1 ( context . functionTemplate ) && context . functionTemplate ?. isDynamicConcurrent ) {
@@ -80,6 +97,24 @@ export abstract class FunctionCreateStepBase<T extends IFunctionWizardContext> e
8097 snapshotPersistenceEnabled : true
8198 }
8299 await AzExtFsExtra . writeJSON ( hostFilePath , hostJson ) ;
100+ } else if ( context . functionTemplate ?. isMcpTrigger ) {
101+ const hostJson = await AzExtFsExtra . readJSON < IHostJsonV2 > ( hostFilePath ) ;
102+ hostJson . extensions = hostJson . extensions ?? { } ;
103+ if ( ! hostJson . extensions . mcp ) {
104+ hostJson . extensions . mcp = {
105+ instructions : "Some test instructions on how to use the server" ,
106+ serverName : "TestServer" ,
107+ serverVersion : "2.0.0" ,
108+ encryptClientState : true ,
109+ messageOptions : {
110+ useAbsoluteUriForEndpoint : false
111+ } ,
112+ system : {
113+ webhookAuthorizationLevel : "System"
114+ }
115+ }
116+ }
117+ await AzExtFsExtra . writeJSON ( hostFilePath , hostJson ) ;
83118 }
84119 }
85120
@@ -105,7 +140,15 @@ function runPostFunctionCreateSteps(func: ICachedFunction): void {
105140
106141 // If function creation created a new file, open it in an editor...
107142 if ( func . newFilePath && getContainingWorkspace ( func . projectPath ) ) {
108- if ( await AzExtFsExtra . pathExists ( func . newFilePath ) ) {
143+ const mcpJsonFilePath : string = path . join ( func . projectPath , '.vscode' , 'mcp.json' ) ;
144+ if ( await AzExtFsExtra . pathExists ( func . newFilePath ) && await AzExtFsExtra . pathExists ( mcpJsonFilePath ) && func . isMcpTrigger ) {
145+ // show the func new file path and the mcp json file in a split editor
146+ const templateFile = await workspace . openTextDocument ( Uri . file ( func . newFilePath ) ) ;
147+ const mcpJsonFile = await workspace . openTextDocument ( Uri . file ( mcpJsonFilePath ) ) ;
148+ await window . showTextDocument ( templateFile , { viewColumn : 1 , preserveFocus : false } ) ;
149+ await window . showTextDocument ( mcpJsonFile , { viewColumn : 2 , preserveFocus : true } ) ;
150+ }
151+ else if ( await AzExtFsExtra . pathExists ( func . newFilePath ) ) {
109152 await window . showTextDocument ( await workspace . openTextDocument ( Uri . file ( func . newFilePath ) ) ) ;
110153 }
111154 }
0 commit comments