@@ -17,7 +17,7 @@ import { addResultSchema } from '../../state/staticresultschema/staticresultsSli
1717import type { NodeTokens , VariableDeclaration } from '../../state/tokens/tokensSlice' ;
1818import { initializeTokensAndVariables } from '../../state/tokens/tokensSlice' ;
1919import { WorkflowKind , type NodesMetadata , type WorkflowState } from '../../state/workflow/workflowInterfaces' ;
20- import { addAgentTool , addNode , setFocusNode , setWorkflowKind } from '../../state/workflow/workflowSlice' ;
20+ import { addAgentTool , addNode , addMcpServer , setFocusNode , setWorkflowKind } from '../../state/workflow/workflowSlice' ;
2121import type { AppDispatch , RootState } from '../../store' ;
2222import { getBrandColorFromManifest , getIconUriFromManifest } from '../../utils/card' ;
2323import { getTriggerNodeId , isTriggerNode } from '../../utils/graph' ;
@@ -49,6 +49,7 @@ import {
4949 UserPreferenceService ,
5050 LoggerService ,
5151 LogEntryLevel ,
52+ removeConnectionPrefix ,
5253} from '@microsoft/logic-apps-shared' ;
5354import type {
5455 Connection ,
@@ -63,7 +64,7 @@ import type { Dispatch } from '@reduxjs/toolkit';
6364import { createAsyncThunk } from '@reduxjs/toolkit' ;
6465import { batch } from 'react-redux' ;
6566import { operationSupportsSplitOn } from '../../utils/outputs' ;
66- import { isA2AWorkflow } from '../../state/workflow/helper' ;
67+ import { isA2AWorkflow , isManagedMcpOperation } from '../../state/workflow/helper' ;
6768import { openKindChangeDialog } from '../../state/modal/modalSlice' ;
6869import constants from '../../../common/constants' ;
6970import { addOperationRunAfter , removeOperationRunAfter } from './runafter' ;
@@ -79,15 +80,16 @@ type AddOperationPayload = {
7980 actionMetadata ?: Record < string , any > ;
8081 isAddingHandoff ?: boolean ;
8182 isAddingMcpServer ?: boolean ;
83+ connectionId ?: string ;
8284} ;
8385
8486export const addOperation = createAsyncThunk ( 'addOperation' , async ( payload : AddOperationPayload , { dispatch, getState } ) => {
85- batch ( ( ) => {
86- const { operation, nodeId : actionId , presetParameterValues, actionMetadata, isAddingHandoff = false , isTrigger } = payload ;
87- if ( ! operation ) {
88- throw new Error ( 'Operation does not exist' ) ; // Just an optional catch, should never happen
89- }
87+ const { operation, nodeId : actionId , presetParameterValues, actionMetadata, isAddingHandoff = false , isTrigger, connectionId } = payload ;
88+ if ( ! operation ) {
89+ throw new Error ( 'Operation does not exist' ) ; // Just an optional catch, should never happen
90+ }
9091
92+ batch ( ( ) => {
9193 const workflowState = ( getState ( ) as RootState ) . workflow ;
9294
9395 // Catch workflow kind conflicts before adding node
@@ -134,17 +136,20 @@ export const addOperation = createAsyncThunk('addOperation', async (payload: Add
134136 const agentToolMetadata = ( getState ( ) as RootState ) . panel . discoveryContent . agentToolMetadata ;
135137 const newToolId = ( getState ( ) as RootState ) . panel . discoveryContent . relationshipIds . subgraphId ;
136138
137- if ( isAddingAgentTool ) {
138- if ( newToolId && newToolGraphId ) {
139- if ( agentToolMetadata ?. newAdditiveSubgraphId && agentToolMetadata ?. subGraphManifest ) {
140- initializeSubgraphFromManifest ( agentToolMetadata . newAdditiveSubgraphId , agentToolMetadata ?. subGraphManifest , dispatch ) ;
139+ if ( payload . isAddingMcpServer ) {
140+ dispatch ( addMcpServer ( newPayload as any ) ) ;
141+ } else {
142+ if ( isAddingAgentTool ) {
143+ if ( newToolId && newToolGraphId ) {
144+ if ( agentToolMetadata ?. newAdditiveSubgraphId && agentToolMetadata ?. subGraphManifest ) {
145+ initializeSubgraphFromManifest ( agentToolMetadata . newAdditiveSubgraphId , agentToolMetadata ?. subGraphManifest , dispatch ) ;
146+ }
147+ dispatch ( addAgentTool ( { toolId : newToolId , graphId : newToolGraphId } ) ) ;
141148 }
142- dispatch ( addAgentTool ( { toolId : newToolId , graphId : newToolGraphId } ) ) ;
143149 }
150+ dispatch ( addNode ( newPayload as any ) ) ;
144151 }
145152
146- dispatch ( addNode ( newPayload as any ) ) ;
147-
148153 const nodeOperationInfo = {
149154 connectorId : operation . properties . api . id , // 'api' could be different based on type, could be 'function' or 'config' see old designer 'connectionOperation.ts' this is still pending for danielle
150155 operationId : operation . name ,
@@ -160,7 +165,8 @@ export const addOperation = createAsyncThunk('addOperation', async (payload: Add
160165 dispatch ,
161166 presetParameterValues ,
162167 actionMetadata ,
163- ! isAddingHandoff
168+ ! isAddingHandoff ,
169+ connectionId
164170 ) ;
165171
166172 // Adjust workflow for kind change if needed
@@ -208,7 +214,7 @@ export const addOperation = createAsyncThunk('addOperation', async (payload: Add
208214 }
209215
210216 dispatch ( setFocusNode ( nodeId ) ) ;
211- if ( isAddingAgentTool && newToolId ) {
217+ if ( isAddingAgentTool && newToolId && ! payload . isAddingMcpServer ) {
212218 dispatch (
213219 setAlternateSelectedNode ( {
214220 nodeId : newToolId ,
@@ -246,7 +252,8 @@ export const initializeOperationDetails = async (
246252 dispatch : Dispatch ,
247253 presetParameterValues ?: Record < string , any > ,
248254 actionMetadata ?: Record < string , any > ,
249- openPanel = true
255+ openPanel = true ,
256+ connectionId ?: string
250257) : Promise < void > => {
251258 const state = getState ( ) ;
252259 const isTrigger = isTriggerNode ( nodeId , state . workflow . nodesMetadata ) ;
@@ -265,7 +272,68 @@ export const initializeOperationDetails = async (
265272 let manifest : OperationManifest | undefined = undefined ;
266273 let swagger : SwaggerParser | undefined = undefined ;
267274 let parsedManifest : ManifestParser | undefined = undefined ;
268- if ( operationManifestService . isSupported ( type , kind ) ) {
275+ const isManagedMcpClient = isManagedMcpOperation ( { type, kind } ) ;
276+
277+ if ( isManagedMcpClient ) {
278+ // managed mcp client ignores the swagger and uses a fixed set of parameters similar to manifest based native mcp client
279+ const { connector : swaggerConnector , parsedSwagger } = await getConnectorWithSwagger ( connectorId ) ;
280+ connector = swaggerConnector ;
281+ const iconUri = getIconUriFromConnector ( connector ) ;
282+ const brandColor = getBrandColorFromConnector ( connector ) ;
283+
284+ const swaggerOperation = parsedSwagger . getOperationByOperationId ( operationId ) ;
285+ const operationPath = swaggerOperation ? removeConnectionPrefix ( swaggerOperation . path ) : undefined ;
286+ if ( operationPath ) {
287+ dispatch ( initializeOperationInfo ( { id : nodeId , ...operationInfo , operationPath } ) ) ;
288+ }
289+
290+ const nativeMcpOperationInfo = { connectorId : 'connectionProviders/mcpclient' , operationId : 'nativemcpclient' } ;
291+ const nativeMcpManifest = await getOperationManifest ( nativeMcpOperationInfo ) ;
292+ isConnectionRequired = isConnectionRequiredForOperation ( nativeMcpManifest ) ;
293+ const { inputs : nodeInputs , dependencies : inputDependencies } = getInputParametersFromManifest (
294+ nodeId ,
295+ operationInfo ,
296+ nativeMcpManifest ,
297+ presetParameterValues
298+ ) ;
299+
300+ const { outputs : nodeOutputs , dependencies : outputDependencies } = getOutputParametersFromManifest (
301+ nodeId ,
302+ nativeMcpManifest ,
303+ isTrigger ,
304+ nodeInputs ,
305+ operationInfo ,
306+ dispatch ,
307+ operationSupportsSplitOn ( isTrigger ) ? getSplitOnValue ( nativeMcpManifest , undefined , undefined , undefined ) : undefined
308+ ) ;
309+ parsedManifest = new ManifestParser ( nativeMcpManifest , operationManifestService . isAliasingSupported ( type , kind ) ) ;
310+
311+ const nodeDependencies = {
312+ inputs : inputDependencies ,
313+ outputs : outputDependencies ,
314+ } ;
315+ let settings = getOperationSettings (
316+ isTrigger ,
317+ operationInfo ,
318+ nativeMcpManifest ,
319+ /* swagger */ undefined ,
320+ /* operation */ undefined ,
321+ state . workflow . workflowKind
322+ ) ;
323+ settings = addDefaultSecureSettings ( settings , connector ?. properties . isSecureByDefault ?? false ) ;
324+ const updatedOutputs = nodeOutputs ;
325+ initData = {
326+ id : nodeId ,
327+ nodeInputs,
328+ nodeOutputs : updatedOutputs ,
329+ nodeDependencies,
330+ settings,
331+ operationMetadata : { iconUri, brandColor } ,
332+ actionMetadata,
333+ } ;
334+ dispatch ( initializeNodes ( { nodes : [ initData ] } ) ) ;
335+ addTokensAndVariables ( nodeId , type , { ...initData , manifest : nativeMcpManifest } , state , dispatch ) ;
336+ } else if ( operationManifestService . isSupported ( type , kind ) ) {
269337 manifest = await getOperationManifest ( operationInfo ) ;
270338 isConnectionRequired = isConnectionRequiredForOperation ( manifest ) ;
271339 connector = manifest . properties ?. connector ;
@@ -394,8 +462,13 @@ export const initializeOperationDetails = async (
394462
395463 if ( isConnectionRequired ) {
396464 try {
397- await trySetDefaultConnectionForNode ( nodeId , connector as Connector , dispatch , isConnectionRequired , ( c : Connection ) =>
398- AgentUtils . filterDynamicConnectionFeatures ( c , nodeId , state )
465+ await trySetDefaultConnectionForNode (
466+ nodeId ,
467+ connector as Connector ,
468+ dispatch as AppDispatch ,
469+ isConnectionRequired ,
470+ ( c : Connection ) => AgentUtils . filterDynamicConnectionFeatures ( c , nodeId , state ) ,
471+ connectionId
399472 ) ;
400473 } catch ( e : any ) {
401474 dispatch (
@@ -487,14 +560,17 @@ export const trySetDefaultConnectionForNode = async (
487560 connector : Connector ,
488561 dispatch : AppDispatch ,
489562 isConnectionRequired : boolean ,
490- connectionFilterFunc ?: ( connection : Connection ) => boolean
563+ connectionFilterFunc ?: ( connection : Connection ) => boolean ,
564+ preferredConnectionId ?: string
491565) => {
492566 const connectorId = connector . id ;
493567 const connections = ( await getConnectionsForConnector ( connectorId ) ) . filter (
494568 ( c ) => c . properties . overallStatus !== 'Error' && ( ! connectionFilterFunc || connectionFilterFunc ( c ) )
495569 ) ;
496570 if ( connections . length > 0 ) {
497- const connection = ( await tryGetMostRecentlyUsedConnectionId ( connectorId , connections ) ) ?? connections [ 0 ] ;
571+ // Use preferred connection if provided and found, otherwise fall back to most recently used or first available
572+ const preferredConnection = preferredConnectionId ? connections . find ( ( c ) => c . id === preferredConnectionId ) : undefined ;
573+ const connection = preferredConnection ?? ( await tryGetMostRecentlyUsedConnectionId ( connectorId , connections ) ) ?? connections [ 0 ] ;
498574 await ConnectionService ( ) . setupConnectionIfNeeded ( connection ) ;
499575 dispatch ( updateNodeConnection ( { nodeId, connection, connector } ) ) ;
500576 } else if ( isConnectionRequired ) {
0 commit comments