diff --git a/libs/designer-v2/src/lib/ui/panel/connectionsPanel/createConnection/createConnection.tsx b/libs/designer-v2/src/lib/ui/panel/connectionsPanel/createConnection/createConnection.tsx index 31da5ecc740..c4a2a1b4153 100644 --- a/libs/designer-v2/src/lib/ui/panel/connectionsPanel/createConnection/createConnection.tsx +++ b/libs/designer-v2/src/lib/ui/panel/connectionsPanel/createConnection/createConnection.tsx @@ -405,12 +405,23 @@ export const CreateConnection = (props: CreateConnectionProps) => { }, [enabledCapabilities, parametersByCapability]); // Don't show name for simple connections - const showNameInput = useMemo( - () => + const showNameInput = useMemo(() => { + const isMcpClientConnection = connectorId?.toLowerCase().includes('mcpclient'); + + if (isMcpClientConnection) { + const connectionService = ConnectionService(); + const isConsumptionSku = connectionService.constructor.name === 'ConsumptionConnectionService'; + + if (isConsumptionSku) { + return false; + } + } + + return ( !(isUsingOAuth && !isMultiAuth) && - (isMultiAuth || Object.keys(capabilityEnabledParameters ?? {}).length > 0 || legacyManagedIdentitySelected), - [isUsingOAuth, isMultiAuth, capabilityEnabledParameters, legacyManagedIdentitySelected] - ); + (isMultiAuth || Object.keys(capabilityEnabledParameters ?? {}).length > 0 || legacyManagedIdentitySelected) + ); + }, [connectorId, isUsingOAuth, isMultiAuth, capabilityEnabledParameters, legacyManagedIdentitySelected]); const validParams = useMemo(() => { if (showNameInput && !connectionDisplayName) { diff --git a/libs/logic-apps-shared/src/designer-client-services/lib/consumption/__tests__/connection.spec.ts b/libs/logic-apps-shared/src/designer-client-services/lib/consumption/__tests__/connection.spec.ts new file mode 100644 index 00000000000..b0515529c69 --- /dev/null +++ b/libs/logic-apps-shared/src/designer-client-services/lib/consumption/__tests__/connection.spec.ts @@ -0,0 +1,301 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { ConsumptionConnectionService } from '../connection'; +import type { Connector } from '../../../../utils/src'; +import type { ConnectionCreationInfo } from '../../connection'; +import { InitLoggerService } from '../../logger'; + +// Mock the LoggerService +const mockLoggerService = { + log: vi.fn(), + startTrace: vi.fn().mockReturnValue('mock-trace-id'), + endTrace: vi.fn(), + logErrorWithFormatting: vi.fn(), +}; + +describe('ConsumptionConnectionService', () => { + const mockHttpClient = { + get: vi.fn(), + post: vi.fn(), + put: vi.fn(), + delete: vi.fn(), + }; + + const mockOptions = { + apiVersion: '2018-07-01-preview', + baseUrl: 'https://management.azure.com', + subscriptionId: 'test-sub', + resourceGroup: 'test-rg', + location: 'eastus', + httpClient: mockHttpClient, + apiHubServiceDetails: { + apiVersion: '2018-07-01-preview', + baseUrl: 'https://management.azure.com', + subscriptionId: 'test-sub', + resourceGroup: 'test-rg', + location: 'eastus', + httpClient: mockHttpClient, + }, + }; + + let service: ConsumptionConnectionService; + + beforeEach(() => { + // Initialize the logger service before each test + InitLoggerService([mockLoggerService]); + + service = new ConsumptionConnectionService(mockOptions as any); + vi.clearAllMocks(); + + // Re-setup logger mocks after clearAllMocks + mockLoggerService.startTrace.mockReturnValue('mock-trace-id'); + }); + + describe('createBuiltInMcpConnection', () => { + it('should create a built-in MCP connection with correct structure', async () => { + const connector: Partial = { + id: 'connectionProviders/mcpclient', + type: 'connectionProviders/mcpclient', + name: 'mcpclient', + properties: { + displayName: 'MCP Client', + iconUri: 'https://example.com/icon.png', + brandColor: '#000000', + capabilities: ['builtin'], + description: 'MCP Client Connector', + generalInformation: { + displayName: 'MCP Client', + iconUrl: 'https://example.com/icon.png', + }, + }, + }; + + const connectionInfo: ConnectionCreationInfo = { + displayName: 'test-mcp-connection', + connectionParameters: { + serverUrl: { value: 'https://mcp-server.example.com' }, + }, + connectionParametersSet: { + name: 'ApiKey', + values: { + key: { value: 'test-api-key' }, + }, + }, + }; + + const result = await service.createConnection('test-connection-id', connector as Connector, connectionInfo); + + expect(result).toBeDefined(); + expect(result.name).toBe('test-mcp-connection'); + expect(result.id).toContain('connectionProviders/mcpclient/connections/'); + expect((result.properties as any).parameterValues.mcpServerUrl).toBe('https://mcp-server.example.com'); + expect((result.properties as any).parameterValues.authenticationType).toBe('ApiKey'); + }); + + it('should throw error when serverUrl is missing', async () => { + const connector: Partial = { + id: 'connectionProviders/mcpclient', + type: 'connectionProviders/mcpclient', + name: 'mcpclient', + properties: { + displayName: 'MCP Client', + capabilities: ['builtin'], + generalInformation: { + displayName: 'MCP Client', + }, + iconUri: '', + }, + }; + + const connectionInfo: ConnectionCreationInfo = { + displayName: 'test-mcp-connection', + connectionParameters: {}, + }; + + await expect(service.createConnection('test-connection-id', connector as Connector, connectionInfo)).rejects.toThrow( + 'Server URL is required for MCP connection' + ); + }); + + it('should use connectionId as fallback name when displayName is not provided', async () => { + const connector: Partial = { + id: 'connectionProviders/mcpclient', + type: 'connectionProviders/mcpclient', + name: 'mcpclient', + properties: { + displayName: 'MCP Client', + capabilities: ['builtin'], + generalInformation: { + displayName: 'MCP Client', + }, + iconUri: '', + }, + }; + + const connectionInfo: ConnectionCreationInfo = { + connectionParameters: { + serverUrl: { value: 'https://mcp-server.example.com' }, + }, + }; + + const result = await service.createConnection( + '/subscriptions/sub/connections/my-connection-name', + connector as Connector, + connectionInfo + ); + + expect(result.name).toBe('my-connection-name'); + }); + + it('should handle None authentication type', async () => { + const connector: Partial = { + id: 'connectionProviders/mcpclient', + type: 'connectionProviders/mcpclient', + name: 'mcpclient', + properties: { + displayName: 'MCP Client', + capabilities: ['builtin'], + generalInformation: { + displayName: 'MCP Client', + }, + iconUri: '', + }, + }; + + const connectionInfo: ConnectionCreationInfo = { + displayName: 'test-mcp-connection', + connectionParameters: { + serverUrl: { value: 'https://mcp-server.example.com' }, + }, + connectionParametersSet: { + name: 'None', + values: {}, + }, + }; + + const result = await service.createConnection('test-connection-id', connector as Connector, connectionInfo); + + expect((result.properties as any).parameterValues.authenticationType).toBe('None'); + }); + }); + + describe('extractParameterValue', () => { + it('should extract value from wrapped object', () => { + const result = (service as any).extractParameterValue({ value: 'test' }); + expect(result).toBe('test'); + }); + + it('should return direct value if not wrapped', () => { + const result = (service as any).extractParameterValue('direct-value'); + expect(result).toBe('direct-value'); + }); + + it('should handle null value', () => { + const result = (service as any).extractParameterValue(null); + expect(result).toBe(null); + }); + + it('should handle undefined value', () => { + const result = (service as any).extractParameterValue(undefined); + expect(result).toBe(undefined); + }); + + it('should handle object without value property', () => { + const result = (service as any).extractParameterValue({ other: 'prop' }); + expect(result).toEqual({ other: 'prop' }); + }); + }); + + describe('extractAuthParameters', () => { + it('should extract authentication parameters correctly', () => { + const result = (service as any).extractAuthParameters({ + name: 'ApiKey', + values: { + key: { value: 'my-api-key' }, + keyHeaderName: { value: 'X-API-Key' }, + }, + }); + + expect(result.authenticationType).toBe('ApiKey'); + expect(result.authParams.key).toBe('my-api-key'); + expect(result.authParams.keyHeaderName).toBe('X-API-Key'); + }); + + it('should return None for undefined connectionParametersSet', () => { + const result = (service as any).extractAuthParameters(undefined); + + expect(result.authenticationType).toBe('None'); + expect(result.authParams).toEqual({}); + }); + + it('should return None for null connectionParametersSet', () => { + const result = (service as any).extractAuthParameters(null); + + expect(result.authenticationType).toBe('None'); + expect(result.authParams).toEqual({}); + }); + + it('should handle BasicAuth parameters', () => { + const result = (service as any).extractAuthParameters({ + name: 'BasicAuth', + values: { + username: { value: 'testuser' }, + password: { value: 'testpass' }, + }, + }); + + expect(result.authenticationType).toBe('BasicAuth'); + expect(result.authParams.username).toBe('testuser'); + expect(result.authParams.password).toBe('testpass'); + }); + + it('should handle OAuth2 parameters', () => { + const result = (service as any).extractAuthParameters({ + name: 'OAuth2', + values: { + clientId: { value: 'client-123' }, + secret: { value: 'secret-456' }, + tenant: { value: 'tenant-789' }, + authority: { value: 'https://login.microsoftonline.com' }, + audience: { value: 'api://my-app' }, + }, + }); + + expect(result.authenticationType).toBe('OAuth2'); + expect(result.authParams.clientId).toBe('client-123'); + expect(result.authParams.secret).toBe('secret-456'); + expect(result.authParams.tenant).toBe('tenant-789'); + expect(result.authParams.authority).toBe('https://login.microsoftonline.com'); + expect(result.authParams.audience).toBe('api://my-app'); + }); + + it('should only extract known auth keys', () => { + const result = (service as any).extractAuthParameters({ + name: 'Custom', + values: { + key: { value: 'valid-key' }, + unknownParam: { value: 'should-be-ignored' }, + anotherUnknown: { value: 'also-ignored' }, + }, + }); + + expect(result.authParams.key).toBe('valid-key'); + expect(result.authParams.unknownParam).toBeUndefined(); + expect(result.authParams.anotherUnknown).toBeUndefined(); + }); + }); + + describe('getConnector', () => { + it('should return mcpclient connector for mcpclient connectorId', async () => { + const result = await service.getConnector('connectionProviders/mcpclient'); + + expect(result).toBeDefined(); + expect(result.id).toContain('mcpclient'); + }); + + it('should return agent connector for agent connectorId', async () => { + const result = await service.getConnector('connectionProviders/agent'); + + expect(result).toBeDefined(); + }); + }); +}); diff --git a/libs/logic-apps-shared/src/designer-client-services/lib/consumption/connection.ts b/libs/logic-apps-shared/src/designer-client-services/lib/consumption/connection.ts index b89ac826eb8..fa4450563f7 100644 --- a/libs/logic-apps-shared/src/designer-client-services/lib/consumption/connection.ts +++ b/libs/logic-apps-shared/src/designer-client-services/lib/consumption/connection.ts @@ -1,5 +1,5 @@ import type { QueryClient } from '@tanstack/react-query'; -import type { Connector, Connection } from '../../../utils/src'; +import type { Connector, Connection, ConnectionStatus } from '../../../utils/src'; import type { BaseConnectionServiceOptions } from '../base'; import { BaseConnectionService } from '../base'; import type { ConnectionCreationInfo, ConnectionParametersMetadata, CreateConnectionResult } from '../connection'; @@ -8,6 +8,7 @@ import { LogEntryLevel, Status } from '../logging/logEntry'; import type { IOAuthPopup } from '../oAuth'; import { OAuthService } from '../oAuth'; import agentLoopConnector from './manifests/agentLoopConnector'; +import mcpclientconnector from './manifests/mcpclientconnector'; export interface ConsumptionConnectionServiceOptions extends BaseConnectionServiceOptions { getCachedConnector?: (connectorId: string) => Promise; @@ -19,6 +20,38 @@ export class ConsumptionConnectionService extends BaseConnectionService { this._vVersion = 'V1'; } + private extractParameterValue(val: unknown): unknown { + if (typeof val === 'object' && val !== null && 'value' in val) { + return (val as { value: unknown }).value; + } + return val; + } + + private extractAuthParameters(connectionParametersSet: ConnectionCreationInfo['connectionParametersSet']): { + authenticationType: string; + authParams: Record; + } { + let authenticationType = 'None'; + const authParams: Record = {}; + + if (connectionParametersSet?.name && connectionParametersSet.name !== 'None') { + authenticationType = connectionParametersSet.name; + } + + if (connectionParametersSet?.values) { + const values = connectionParametersSet.values; + const authKeys = ['username', 'password', 'key', 'keyHeaderName', 'clientId', 'secret', 'tenant', 'authority', 'audience', 'pfx']; + + for (const key of authKeys) { + if (values[key] !== undefined) { + authParams[key] = this.extractParameterValue(values[key]); + } + } + } + + return { authenticationType, authParams }; + } + async getConnector(connectorId: string, getCached = false): Promise { let connector: Connector | undefined; if (getCached && this._options.getCachedConnector) { @@ -28,6 +61,9 @@ export class ConsumptionConnectionService extends BaseConnectionService { if (connectorIdKeyword === 'agent') { return agentLoopConnector; } + if (connectorIdKeyword === 'mcpclient') { + return mcpclientconnector; + } return connector ?? this._getAzureConnector(connectorId); } @@ -49,6 +85,22 @@ export class ConsumptionConnectionService extends BaseConnectionService { _parametersMetadata?: ConnectionParametersMetadata, shouldTestConnection = true ): Promise { + const isBuiltInMcpConnection = + (connector.id?.toLowerCase().includes('mcpclient') || connector.type?.toLowerCase() === 'mcpclient') && + connector.properties?.capabilities?.includes('builtin'); + + if (isBuiltInMcpConnection) { + return this.createBuiltInMcpConnection(connectionId, connector, connectionInfo); + } + + const isManagedMcpConnection = + (connector.id?.toLowerCase().includes('mcpclient') || connector.type?.toLowerCase() === 'mcpclient') && + !connector.properties?.capabilities?.includes('builtin'); + + if (isManagedMcpConnection) { + return this.createManagedMcpConnection(connectionId, connector, connectionInfo); + } + const connectionName = connectionId.split('/').at(-1) as string; const logId = LoggerService().startTrace({ action: 'createConnection', @@ -83,6 +135,128 @@ export class ConsumptionConnectionService extends BaseConnectionService { } } + private createBuiltInMcpConnection(connectionId: string, connector: Connector, connectionInfo: ConnectionCreationInfo): Connection { + const logId = LoggerService().startTrace({ + action: 'createBuiltInMcpConnection', + name: 'Creating Built-in MCP Connection', + source: 'connection.ts', + }); + + try { + const connectionName = connectionInfo.displayName || connectionId.split('/').at(-1) || `mcp-${Date.now()}`; + + const connectionParameters = connectionInfo.connectionParameters ?? {}; + + let serverUrl = ''; + if (connectionParameters['serverUrl']) { + serverUrl = this.extractParameterValue(connectionParameters['serverUrl']) as string; + } + + if (!serverUrl) { + throw new Error('Server URL is required for MCP connection'); + } + + const { authenticationType, authParams } = this.extractAuthParameters(connectionInfo.connectionParametersSet); + + const connection = { + id: `connectionProviders/mcpclient/connections/${connectionName}`, + name: connectionName, + type: 'connections', + location: '', + properties: { + displayName: connectionName, + overallStatus: 'Connected', + statuses: [{ status: 'Connected' }] as ConnectionStatus[], + api: { + id: connector.id, + name: 'mcpclient', + displayName: connector.properties?.displayName || 'MCP Client', + iconUri: connector.properties?.iconUri ?? '', + brandColor: connector.properties?.brandColor ?? '#000000', + description: connector.properties?.description ?? '', + category: 'MCP', + type: 'mcpclient', + }, + createdTime: new Date().toISOString(), + parameterValues: { + mcpServerUrl: serverUrl, + authenticationType, + ...authParams, + }, + }, + }; + + LoggerService().endTrace(logId, { status: Status.Success }); + return connection as unknown as Connection; + } catch (error) { + const errorMessage = `Failed to create built-in MCP connection: ${this.tryParseErrorMessage(error)}`; + LoggerService().log({ + level: LogEntryLevel.Error, + area: 'createBuiltInMcpConnection', + message: errorMessage, + error: error instanceof Error ? error : undefined, + traceId: logId, + }); + LoggerService().endTrace(logId, { status: Status.Failure }); + throw new Error(errorMessage); + } + } + + private async createManagedMcpConnection( + connectionId: string, + connector: Connector, + connectionInfo: ConnectionCreationInfo + ): Promise { + const connectionName = connectionInfo.displayName || connectionId.split('/').at(-1) || `mcp-${Date.now()}`; + + const parameterValues: Record = {}; + const connectionParameters = connectionInfo.connectionParameters ?? {}; + + if (connectionParameters['serverUrl']) { + parameterValues['serverUrl'] = this.extractParameterValue(connectionParameters['serverUrl']); + } + + const { authenticationType, authParams } = this.extractAuthParameters(connectionInfo.connectionParametersSet); + if (authenticationType !== 'None') { + parameterValues['authentication'] = { + type: authenticationType, + ...authParams, + }; + } + + const mcpConnectionInfo: ConnectionCreationInfo = { + displayName: connectionName, + connectionParameters: parameterValues, + }; + + const logId = LoggerService().startTrace({ + action: 'createManagedMcpConnection', + name: 'Creating Managed MCP Connection', + source: 'connection.ts', + }); + + try { + const connection = await this.createConnectionInApiHub(connectionName, connector.id, mcpConnectionInfo); + + LoggerService().endTrace(logId, { + status: Status.Success, + data: { connectorId: connector.id }, + }); + return connection; + } catch (error) { + const errorMessage = `Failed to create managed MCP connection: ${this.tryParseErrorMessage(error)}`; + LoggerService().log({ + level: LogEntryLevel.Error, + area: 'createManagedMcpConnection', + message: errorMessage, + error: error instanceof Error ? error : undefined, + traceId: logId, + }); + LoggerService().endTrace(logId, { status: Status.Failure }); + return Promise.reject(errorMessage); + } + } + async createAndAuthorizeOAuthConnection( connectionId: string, connectorId: string, diff --git a/libs/logic-apps-shared/src/designer-client-services/lib/consumption/manifests/mcpclientconnector.ts b/libs/logic-apps-shared/src/designer-client-services/lib/consumption/manifests/mcpclientconnector.ts new file mode 100644 index 00000000000..ef7f83f241d --- /dev/null +++ b/libs/logic-apps-shared/src/designer-client-services/lib/consumption/manifests/mcpclientconnector.ts @@ -0,0 +1,345 @@ +import type { Connector } from '../../../../utils/src'; + +export default { + type: 'McpClient', + name: 'mcpclient', + id: 'connectionProviders/mcpclient', + properties: { + displayName: 'MCP Client', + iconUri: + 'data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%3Crect%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23242424%22%2F%3E%0A%3Cg%20clip-path%3D%22url(%23clip0_1258_56822)%22%3E%0A%3Crect%20width%3D%2220%22%20height%3D%2220%22%20transform%3D%22translate(2%202)%22%20fill%3D%22%23242424%22%2F%3E%0A%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M15.0733%203.9524C14.6707%203.56054%2014.131%203.34127%2013.5691%203.34127C13.0073%203.34127%2012.4676%203.56054%2012.065%203.9524L4.04331%2011.8191C3.90907%2011.9495%203.72926%2012.0225%203.54206%2012.0225C3.35486%2012.0225%203.17504%2011.9495%203.04081%2011.8191C2.97509%2011.7552%202.92285%2011.6787%202.88718%2011.5943C2.85151%2011.5098%202.83313%2011.4191%202.83313%2011.3274C2.83313%2011.2357%202.85151%2011.145%202.88718%2011.0605C2.92285%2010.9761%202.97509%2010.8996%203.04081%2010.8357L11.0625%202.96907C11.7335%202.31606%2012.6328%201.95068%2013.5691%201.95068C14.5055%201.95068%2015.4048%202.31606%2016.0758%202.96907C16.4641%203.34665%2016.7574%203.81081%2016.9318%204.32356C17.1062%204.8363%2017.1567%205.38306%2017.0791%205.91907C17.6223%205.84182%2018.1759%205.89031%2018.6973%206.06079C19.2187%206.23128%2019.6941%206.51921%2020.0866%206.9024L20.1283%206.94407C20.4569%207.26363%2020.7181%207.64584%2020.8965%208.06808C21.0748%208.49032%2021.1667%208.94404%2021.1667%209.4024C21.1667%209.86077%2021.0748%2010.3145%2020.8965%2010.7367C20.7181%2011.159%2020.4569%2011.5412%2020.1283%2011.8607L12.8733%2018.9749C12.8514%2018.9962%2012.834%2019.0216%2012.8221%2019.0498C12.8102%2019.0779%2012.8041%2019.1081%2012.8041%2019.1387C12.8041%2019.1692%2012.8102%2019.1994%2012.8221%2019.2275C12.834%2019.2557%2012.8514%2019.2811%2012.8733%2019.3024L14.3633%2020.7641C14.429%2020.828%2014.4813%2020.9044%2014.5169%2020.9889C14.5526%2021.0733%2014.571%2021.1641%2014.571%2021.2557C14.571%2021.3474%2014.5526%2021.4381%2014.5169%2021.5226C14.4813%2021.607%2014.429%2021.6835%2014.3633%2021.7474C14.2291%2021.8779%2014.0493%2021.9509%2013.8621%2021.9509C13.6749%2021.9509%2013.495%2021.8779%2013.3608%2021.7474L11.8708%2020.2866C11.7173%2020.1374%2011.5953%2019.9591%2011.512%2019.762C11.4287%2019.5649%2011.3858%2019.353%2011.3858%2019.1391C11.3858%2018.9251%2011.4287%2018.7133%2011.512%2018.5162C11.5953%2018.3191%2011.7173%2018.1407%2011.8708%2017.9916L19.1258%2010.8766C19.3229%2010.6848%2019.4795%2010.4554%2019.5864%2010.2021C19.6934%209.94875%2019.7485%209.67655%2019.7485%209.40157C19.7485%209.12658%2019.6934%208.85438%2019.5864%208.60104C19.4795%208.34771%2019.3229%208.11837%2019.1258%207.92657L19.0841%207.88573C18.6819%207.49428%2018.143%207.27504%2017.5817%207.27457C17.0205%207.27411%2016.4812%207.49245%2016.0783%207.88323L10.1016%2013.7449L10.1%2013.7466L10.0183%2013.8274C9.88404%2013.9581%209.70404%2014.0313%209.51664%2014.0313C9.32925%2014.0313%209.14925%2013.9581%209.01498%2013.8274C8.94926%2013.7635%208.89702%2013.687%208.86135%2013.6026C8.82568%2013.5182%208.8073%2013.4274%208.8073%2013.3357C8.8073%2013.2441%208.82568%2013.1533%208.86135%2013.0689C8.89702%2012.9844%208.94926%2012.908%209.01498%2012.8441L15.0758%206.8999C15.2723%206.70797%2015.4284%206.47866%2015.5349%206.22546C15.6414%205.97226%2015.6962%205.70031%2015.696%205.42562C15.6957%205.15094%2015.6405%204.87908%2015.5336%204.62606C15.4266%204.37305%2015.2701%204.14399%2015.0733%203.9524Z%22%20fill%3D%22white%22%2F%3E%0A%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M14.0708%205.91914C14.1365%205.85522%2014.1887%205.77878%2014.2244%205.69433C14.2601%205.60989%2014.2785%205.51914%2014.2785%205.42747C14.2785%205.3358%2014.2601%205.24505%2014.2244%205.1606C14.1887%205.07616%2014.1365%204.99972%2014.0708%204.9358C13.9365%204.80508%2013.7565%204.73193%2013.5691%204.73193C13.3817%204.73193%2013.2017%204.80508%2013.0675%204.9358L7.13495%2010.7541C6.80636%2011.0737%206.54516%2011.4559%206.36681%2011.8781C6.18845%2012.3004%206.09656%2012.7541%206.09656%2013.2125C6.09656%2013.6708%206.18845%2014.1245%206.36681%2014.5468C6.54516%2014.969%206.80636%2015.3512%207.13495%2015.6708C7.80607%2016.3236%208.70538%2016.6889%209.64162%2016.6889C10.5779%2016.6889%2011.4772%2016.3236%2012.1483%2015.6708L18.0816%209.85247C18.1473%209.78856%2018.1996%209.71212%2018.2352%209.62767C18.2709%209.54322%2018.2893%209.45248%2018.2893%209.3608C18.2893%209.26913%2018.2709%209.17839%2018.2352%209.09394C18.1996%209.00949%2018.1473%208.93305%2018.0816%208.86914C17.9473%208.73841%2017.7674%208.66527%2017.58%208.66527C17.3926%208.66527%2017.2126%208.73841%2017.0783%208.86914L11.1458%2014.6875C10.7431%2015.0793%2010.2035%2015.2986%209.64162%2015.2986C9.07977%2015.2986%208.5401%2015.0793%208.13745%2014.6875C7.9404%2014.4957%207.78377%2014.2663%207.67683%2014.013C7.56988%2013.7597%207.51478%2013.4875%207.51478%2013.2125C7.51478%2012.9375%207.56988%2012.6653%207.67683%2012.4119C7.78377%2012.1586%207.9404%2011.9293%208.13745%2011.7375L14.0708%205.91914Z%22%20fill%3D%22white%22%2F%3E%0A%3C%2Fg%3E%0A%3Cdefs%3E%0A%3CclipPath%20id%3D%22clip0_1258_56822%22%3E%0A%3Crect%20width%3D%2220%22%20height%3D%2220%22%20fill%3D%22white%22%20transform%3D%22translate(2%202)%22%2F%3E%0A%3C%2FclipPath%3E%0A%3C%2Fdefs%3E%0A%3C%2Fsvg%3E%0A', + brandColor: '#000000', + description: 'Easily integrate cutting-edge artificial intelligence capabilities into your workflows', + capabilities: ['actions', 'builtin'], + connectionMode: 'mcp', + connectionParameterSets: { + uiDefinition: { + displayName: 'Authentication type', + description: 'The authentication type to use.', + }, + values: [ + { + name: 'None', + parameters: { + serverUrl: { + type: 'string', + uiDefinition: { + displayName: 'Server URL', + constraints: { + required: 'true', + }, + description: 'Server URL', + }, + }, + }, + uiDefinition: { + displayName: 'None', + description: 'None', + }, + }, + { + name: 'Basic', + parameters: { + serverUrl: { + type: 'string', + uiDefinition: { + displayName: 'Server URL', + constraints: { + required: 'true', + }, + description: 'Server URL', + }, + }, + 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', + }, + }, + { + name: 'ClientCertificate', + parameters: { + serverUrl: { + type: 'string', + uiDefinition: { + displayName: 'Server URL', + constraints: { + required: 'true', + }, + description: 'Server URL', + }, + }, + pfx: { + type: 'securestring', + uiDefinition: { + displayName: 'Pfx', + constraints: { + required: 'true', + propertyPath: ['authentication'], + }, + description: 'Client Certificate pfx', + }, + }, + password: { + type: 'securestring', + uiDefinition: { + displayName: 'Password', + constraints: { + propertyPath: ['authentication'], + }, + description: 'Client Certificate password', + }, + }, + }, + uiDefinition: { + displayName: 'Client certificate', + }, + }, + { + name: 'ActiveDirectoryOAuth', + parameters: { + serverUrl: { + type: 'string', + uiDefinition: { + displayName: 'Server URL', + constraints: { + required: 'true', + }, + description: 'Server URL', + }, + }, + authority: { + type: 'string', + uiDefinition: { + displayName: 'Authority', + constraints: { + propertyPath: ['authentication'], + }, + description: 'Active Directory authority', + }, + }, + tenant: { + type: 'string', + uiDefinition: { + displayName: 'Tenant', + constraints: { + required: 'true', + propertyPath: ['authentication'], + }, + description: 'Active Directory tenant', + }, + }, + audience: { + type: 'string', + parameterSource: 'AppConfiguration', + uiDefinition: { + displayName: 'Audience', + constraints: { + required: 'true', + propertyPath: ['authentication'], + }, + description: 'Active Directory audience', + }, + }, + credentialType: { + type: 'string', + uiDefinition: { + displayName: 'Credential type', + constraints: { + propertyPath: ['authentication'], + allowedValues: [ + { + text: 'Certificate', + value: 'Certificate', + }, + { + text: 'Secret', + value: 'Secret', + }, + ], + }, + description: 'Active Directory credential type', + }, + }, + clientId: { + type: 'string', + uiDefinition: { + displayName: 'Client ID', + constraints: { + required: 'true', + propertyPath: ['authentication'], + }, + description: 'Active Directory client ID', + }, + }, + secret: { + type: 'securestring', + uiDefinition: { + displayName: 'Client secret', + constraints: { + required: 'true', + propertyPath: ['authentication'], + dependentParameter: { + parameter: 'CredentialType', + value: 'Secret', + }, + }, + description: 'Active Directory client secret', + }, + }, + pfx: { + type: 'securestring', + uiDefinition: { + displayName: 'Pfx', + constraints: { + required: 'true', + propertyPath: ['authentication'], + dependentParameter: { + parameter: 'CredentialType', + value: 'Certificate', + }, + }, + description: 'Active Directory pfx', + }, + }, + password: { + type: 'securestring', + uiDefinition: { + displayName: 'Password', + constraints: { + required: 'true', + propertyPath: ['authentication'], + dependentParameter: { + parameter: 'CredentialType', + value: 'Certificate', + }, + }, + description: 'Active Directory password', + }, + }, + }, + uiDefinition: { + displayName: 'Active Directory OAuth', + }, + }, + { + name: 'Raw', + parameters: { + serverUrl: { + type: 'string', + uiDefinition: { + displayName: 'Server URL', + constraints: { + required: 'true', + }, + description: 'Server URL', + }, + }, + value: { + type: 'string', + uiDefinition: { + displayName: 'Value', + constraints: { + propertyPath: ['authentication'], + required: 'true', + }, + }, + }, + }, + uiDefinition: { + displayName: 'Raw', + }, + }, + { + name: 'Key', + parameters: { + serverUrl: { + type: 'string', + uiDefinition: { + displayName: 'Server URL', + constraints: { + required: 'true', + }, + description: 'Server URL', + }, + }, + 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', + }, + }, + { + name: 'ManagedServiceIdentity', + parameters: { + serverUrl: { + type: 'string', + uiDefinition: { + displayName: 'Server URL', + constraints: { + required: 'true', + }, + description: 'Server URL', + }, + }, + audience: { + type: 'string', + uiDefinition: { + displayName: 'Audience', + constraints: { + required: 'true', + propertyPath: ['authentication'], + }, + description: 'The audience', + }, + }, + }, + uiDefinition: { + displayName: 'Managed identity', + }, + }, + ], + }, + }, +} as Connector; diff --git a/servers b/servers new file mode 160000 index 00000000000..e6b0b0f5d35 --- /dev/null +++ b/servers @@ -0,0 +1 @@ +Subproject commit e6b0b0f5d355530ebdd09bc547240e556fbc6c19