Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ export interface CreateConnectionProps {
operationManifest?: OperationManifest;
workflowKind?: string;
workflowMetadata?: ConsumptionWorkflowMetadata;
enableManagedIdentityPicker?: boolean;
}

export const CreateConnection = (props: CreateConnectionProps) => {
Expand Down Expand Up @@ -406,6 +407,15 @@ export const CreateConnection = (props: CreateConnectionProps) => {
return output ?? {};
}, [enabledCapabilities, parametersByCapability]);

// Show MI picker only when explicitly enabled by the caller (e.g. MCP wizard) AND
// there are no visible parameters (form would be empty without it).
const isMultiAuthManagedIdentitySet = useMemo(() => {
if (!props.enableManagedIdentityPicker || !isMultiAuth) {
return false;
}
return Object.keys(capabilityEnabledParameters ?? {}).length === 0;
}, [props.enableManagedIdentityPicker, isMultiAuth, capabilityEnabledParameters]);

// Don't show name for simple connections
const showNameInput = useMemo(() => {
const isMcpClientConnection = connectorId?.toLowerCase().includes('mcpclient');
Expand Down Expand Up @@ -439,6 +449,9 @@ export const CreateConnection = (props: CreateConnectionProps) => {
if (legacyManagedIdentitySelected && !selectedManagedIdentity) {
return false;
}
if (isMultiAuthManagedIdentitySet && !selectedManagedIdentity) {
return false;
}
Comment thread
Bhavd13 marked this conversation as resolved.
if (Object.keys(capabilityEnabledParameters ?? {}).length === 0) {
return true;
}
Expand All @@ -451,6 +464,7 @@ export const CreateConnection = (props: CreateConnectionProps) => {
resourceSelectorProps,
legacyManagedIdentitySelected,
selectedManagedIdentity,
isMultiAuthManagedIdentitySet,
capabilityEnabledParameters,
parameterValues,
]);
Expand Down Expand Up @@ -497,7 +511,7 @@ export const CreateConnection = (props: CreateConnectionProps) => {
}

const alternativeParameterValues = legacyManagedIdentitySelected ? {} : undefined;
const identitySelected = legacyManagedIdentitySelected ? selectedManagedIdentity : undefined;
const identitySelected = legacyManagedIdentitySelected || isMultiAuthManagedIdentitySet ? selectedManagedIdentity : undefined;

Comment thread
Bhavd13 marked this conversation as resolved.
return createConnectionCallback?.(
showNameInput ? connectionDisplayName : undefined,
Expand Down Expand Up @@ -530,6 +544,7 @@ export const CreateConnection = (props: CreateConnectionProps) => {
operationParameterValues,
isUsingDynamicConnection,
isDynamicConnectionOptionValidForConnector,
isMultiAuthManagedIdentitySet,
]);

// INTL STRINGS
Expand Down Expand Up @@ -919,6 +934,25 @@ export const CreateConnection = (props: CreateConnectionProps) => {
/>
)}

{/* Multi-auth Managed Identity Selection (for MCP custom connectors with MI parameter set) */}
{isMultiAuthManagedIdentitySet && (
<div className="param-row">
Comment thread
Bhavd13 marked this conversation as resolved.
<Label
className="label"
isRequiredField={true}
text={legacyManagedIdentityLabelText}
htmlFor={'multi-auth-managed-identity-select'}
disabled={isLoading}
/>
<LegacyManagedIdentityDropdown
id={'multi-auth-managed-identity-select'}
identity={identity}
onChange={onLegacyManagedIdentityChange}
disabled={isLoading}
/>
</div>
)}

{/* OAuth tenant ID selection */}
{showTenantIdSelection && (
<TenantPicker
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { CreateConnection, type CreateButtonTexts } from './createConnection';
import { Spinner, SpinnerSize } from '@fluentui/react/lib/Spinner';
import type {
ConnectionParameterSetValues,
ConnectionParameterSets,
ConnectionMetadata,
ConnectionCreationInfo,
ConnectionParametersMetadata,
Expand Down Expand Up @@ -46,6 +47,8 @@ export const CreateConnectionInternal = (props: {
operationManifest?: OperationManifest;
workflowKind?: string;
workflowMetadata?: { agentType?: string };
connectionParameterSetsOverride?: ConnectionParameterSets;
enableManagedIdentityPicker?: boolean;
}) => {
const {
classes,
Expand All @@ -68,6 +71,8 @@ export const CreateConnectionInternal = (props: {
operationManifest,
workflowKind,
workflowMetadata,
connectionParameterSetsOverride,
enableManagedIdentityPicker,
} = props;
const dispatch = useDispatch<AppDispatch>();

Expand Down Expand Up @@ -320,7 +325,7 @@ export const CreateConnectionInternal = (props: {
classes={classes}
connector={connector}
connectionParameterSets={getSupportedParameterSets(
connector.properties.connectionParameterSets,
connector.properties.connectionParameterSets ?? connectionParameterSetsOverride,
operationType,
connector.properties.capabilities
)}
Expand All @@ -345,6 +350,7 @@ export const CreateConnectionInternal = (props: {
operationManifest={operationManifest}
workflowKind={workflowKind}
workflowMetadata={workflowMetadata}
enableManagedIdentityPicker={enableManagedIdentityPicker}
/>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import { useEffect, useMemo, useRef } from 'react';
import { useIntl } from 'react-intl';

interface LegacyManagedIdentityDropdownProps {
id?: string;
identity?: ManagedIdentity;
onChange: (event: any, item?: IDropdownOption<any>) => void;
disabled?: boolean;
}

const LegacyManagedIdentityDropdown = (props: LegacyManagedIdentityDropdownProps) => {
const { identity, onChange, disabled } = props;
const { id, identity, onChange, disabled } = props;
const intl = useIntl();
const dropdownOptions = useMemo(() => getIdentityDropdownOptions(identity, intl), [identity, intl]);

Expand All @@ -29,6 +30,7 @@ const LegacyManagedIdentityDropdown = (props: LegacyManagedIdentityDropdownProps

return (
<Dropdown
id={id}
className={'connection-parameter-input'}
onChange={onChange}
placeholder={noIdentitiesAvailable ? noIdentityText : undefined}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,95 @@ import { isConnectionValid, getAssistedConnectionProps } from '../../../../core/
import { addOperation } from '../../../../core/actions/bjsworkflow/add';
import { useMcpToolWizardStyles } from './styles/McpToolWizard.styles';
import { useConnector } from '../../../../core/state/connection/connectionSelector';
import type { Connection, DiscoveryOperation, DiscoveryResultTypes } from '@microsoft/logic-apps-shared';
import type { Connection, ConnectionParameterSets, DiscoveryOperation, DiscoveryResultTypes } from '@microsoft/logic-apps-shared';
import { useQuery } from '@tanstack/react-query';
import { MCP_CLIENT_CONNECTOR_ID } from '../helpers';

/**
* Connection parameter sets for MCP servers. Used as a fallback when a custom connector
* doesn't have its own connectionParameterSets, so users can select auth type
* (None, Basic, Key, or Managed Identity) during connection creation.
*/
const mcpConnectionParameterSets: ConnectionParameterSets = {
uiDefinition: {
displayName: 'Authentication type',
description: 'The authentication type to use.',
},
values: [
{
name: 'None',
parameters: {},
uiDefinition: { displayName: 'None', description: 'None' },
},
{
name: 'Basic',
parameters: {
username: {
type: 'string',
uiDefinition: {
displayName: 'Username',
constraints: { propertyPath: ['authentication'], required: 'true' },
description: 'Username',
},
},
password: {
type: 'securestring',
uiDefinition: {
displayName: 'Password',
constraints: { propertyPath: ['authentication'], required: 'true' },
description: 'Password',
},
},
},
uiDefinition: { displayName: 'Basic', description: 'Basic authentication' },
},
{
name: 'Key',
parameters: {
key: {
type: 'securestring',
uiDefinition: {
displayName: 'Key',
constraints: { required: 'true', propertyPath: ['authentication'] },
description: 'Key',
},
},
keyHeaderName: {
type: 'string',
uiDefinition: {
displayName: 'Key Header Name',
constraints: { propertyPath: ['authentication'] },
description: 'Key header name',
},
},
},
uiDefinition: { displayName: 'Key', description: 'Key authentication' },
},
{
name: 'ManagedServiceIdentity',
parameters: {
identity: {
type: 'string',
uiDefinition: {
displayName: 'Managed identity',
constraints: { required: 'false', editor: 'identitypicker', propertyPath: ['authentication'] },
description: 'The managed identity to use for authentication',
},
},
audience: {
type: 'string',
uiDefinition: {
displayName: 'Audience',
constraints: { required: 'true', propertyPath: ['authentication'] },
description: 'The audience',
},
},
},
uiDefinition: { displayName: 'Managed identity', description: 'Managed identity authentication' },
},
],
};

export const McpToolWizard = () => {
const intl = useIntl();
const dispatch = useDispatch<AppDispatch>();
Expand Down Expand Up @@ -603,6 +688,12 @@ export const McpToolWizard = () => {
// Managed MCP servers use the default Azure connection flow
const connectionMetadata = isManagedMcpServer ? undefined : { type: ConnectionType.Mcp, required: true };

// For managed MCP servers (custom connectors), the connector from Azure API
// may not include connectionParameterSets (auth options). Provide MCP auth
// parameter sets as a fallback so users can select auth type (None, Basic,
// Managed Identity, etc.) when creating a connection.
const parameterSetsOverride = isManagedMcpServer ? mcpConnectionParameterSets : undefined;

return (
<div className={classes.createConnectionContainer}>
<CreateConnectionInternal
Expand All @@ -617,6 +708,8 @@ export const McpToolWizard = () => {
onConnectionCreated={handleConnectionCreated}
onConnectionCancelled={handleConnectionCancelled}
description=" "
connectionParameterSetsOverride={parameterSetsOverride}
enableManagedIdentityPicker={isManagedMcpServer}
/>
</div>
);
Expand Down
Loading