feat(ai): add mcp integration (#13004)
This commit is contained in:
@ -435,14 +435,6 @@ export type ConnectionParametersOutput = {
|
||||
username: Scalars['String'];
|
||||
};
|
||||
|
||||
export type CreateAgentInput = {
|
||||
description?: InputMaybe<Scalars['String']>;
|
||||
modelId: Scalars['String'];
|
||||
name: Scalars['String'];
|
||||
prompt: Scalars['String'];
|
||||
responseFormat?: InputMaybe<Scalars['JSON']>;
|
||||
};
|
||||
|
||||
export type CreateAppTokenInput = {
|
||||
expiresAt: Scalars['DateTime'];
|
||||
};
|
||||
@ -688,6 +680,7 @@ export enum FeatureFlagKey {
|
||||
IS_IMAP_ENABLED = 'IS_IMAP_ENABLED',
|
||||
IS_JSON_FILTER_ENABLED = 'IS_JSON_FILTER_ENABLED',
|
||||
IS_POSTGRESQL_INTEGRATION_ENABLED = 'IS_POSTGRESQL_INTEGRATION_ENABLED',
|
||||
IS_RELATION_CONNECT_ENABLED = 'IS_RELATION_CONNECT_ENABLED',
|
||||
IS_STRIPE_INTEGRATION_ENABLED = 'IS_STRIPE_INTEGRATION_ENABLED',
|
||||
IS_UNIQUE_INDEXES_ENABLED = 'IS_UNIQUE_INDEXES_ENABLED',
|
||||
IS_WORKFLOW_FILTERING_ENABLED = 'IS_WORKFLOW_FILTERING_ENABLED'
|
||||
@ -1007,7 +1000,6 @@ export type Mutation = {
|
||||
createDraftFromWorkflowVersion: WorkflowVersion;
|
||||
createOIDCIdentityProvider: SetupSsoOutput;
|
||||
createObjectEvent: Analytics;
|
||||
createOneAgent: Agent;
|
||||
createOneAppToken: AppToken;
|
||||
createOneField: Field;
|
||||
createOneObject: Object;
|
||||
@ -1020,7 +1012,6 @@ export type Mutation = {
|
||||
deleteApprovedAccessDomain: Scalars['Boolean'];
|
||||
deleteCurrentWorkspace: Workspace;
|
||||
deleteDatabaseConfigVariable: Scalars['Boolean'];
|
||||
deleteOneAgent: Agent;
|
||||
deleteOneField: Field;
|
||||
deleteOneObject: Object;
|
||||
deleteOneRemoteServer: RemoteServer;
|
||||
@ -1154,11 +1145,6 @@ export type MutationCreateObjectEventArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationCreateOneAgentArgs = {
|
||||
input: CreateAgentInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationCreateOneAppTokenArgs = {
|
||||
input: CreateOneAppTokenInput;
|
||||
};
|
||||
@ -1214,11 +1200,6 @@ export type MutationDeleteDatabaseConfigVariableArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationDeleteOneAgentArgs = {
|
||||
input: AgentIdInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationDeleteOneFieldArgs = {
|
||||
input: DeleteOneFieldInput;
|
||||
};
|
||||
@ -1745,7 +1726,6 @@ export type Query = {
|
||||
field: Field;
|
||||
fields: FieldConnection;
|
||||
findDistantTablesWithStatus: Array<RemoteTable>;
|
||||
findManyAgents: Array<Agent>;
|
||||
findManyRemoteServersByType: Array<RemoteServer>;
|
||||
findManyServerlessFunctions: Array<ServerlessFunction>;
|
||||
findOneAgent: Agent;
|
||||
|
||||
@ -435,14 +435,6 @@ export type ConnectionParametersOutput = {
|
||||
username: Scalars['String'];
|
||||
};
|
||||
|
||||
export type CreateAgentInput = {
|
||||
description?: InputMaybe<Scalars['String']>;
|
||||
modelId: Scalars['String'];
|
||||
name: Scalars['String'];
|
||||
prompt: Scalars['String'];
|
||||
responseFormat?: InputMaybe<Scalars['JSON']>;
|
||||
};
|
||||
|
||||
export type CreateApprovedAccessDomainInput = {
|
||||
domain: Scalars['String'];
|
||||
email: Scalars['String'];
|
||||
@ -652,6 +644,7 @@ export enum FeatureFlagKey {
|
||||
IS_IMAP_ENABLED = 'IS_IMAP_ENABLED',
|
||||
IS_JSON_FILTER_ENABLED = 'IS_JSON_FILTER_ENABLED',
|
||||
IS_POSTGRESQL_INTEGRATION_ENABLED = 'IS_POSTGRESQL_INTEGRATION_ENABLED',
|
||||
IS_RELATION_CONNECT_ENABLED = 'IS_RELATION_CONNECT_ENABLED',
|
||||
IS_STRIPE_INTEGRATION_ENABLED = 'IS_STRIPE_INTEGRATION_ENABLED',
|
||||
IS_UNIQUE_INDEXES_ENABLED = 'IS_UNIQUE_INDEXES_ENABLED',
|
||||
IS_WORKFLOW_FILTERING_ENABLED = 'IS_WORKFLOW_FILTERING_ENABLED'
|
||||
@ -964,7 +957,6 @@ export type Mutation = {
|
||||
createDraftFromWorkflowVersion: WorkflowVersion;
|
||||
createOIDCIdentityProvider: SetupSsoOutput;
|
||||
createObjectEvent: Analytics;
|
||||
createOneAgent: Agent;
|
||||
createOneAppToken: AppToken;
|
||||
createOneField: Field;
|
||||
createOneObject: Object;
|
||||
@ -976,7 +968,6 @@ export type Mutation = {
|
||||
deleteApprovedAccessDomain: Scalars['Boolean'];
|
||||
deleteCurrentWorkspace: Workspace;
|
||||
deleteDatabaseConfigVariable: Scalars['Boolean'];
|
||||
deleteOneAgent: Agent;
|
||||
deleteOneField: Field;
|
||||
deleteOneObject: Object;
|
||||
deleteOneRole: Scalars['String'];
|
||||
@ -1105,11 +1096,6 @@ export type MutationCreateObjectEventArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationCreateOneAgentArgs = {
|
||||
input: CreateAgentInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationCreateOneFieldArgs = {
|
||||
input: CreateOneFieldMetadataInput;
|
||||
};
|
||||
@ -1150,11 +1136,6 @@ export type MutationDeleteDatabaseConfigVariableArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationDeleteOneAgentArgs = {
|
||||
input: AgentIdInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationDeleteOneFieldArgs = {
|
||||
input: DeleteOneFieldInput;
|
||||
};
|
||||
@ -1655,7 +1636,6 @@ export type Query = {
|
||||
currentWorkspace: Workspace;
|
||||
field: Field;
|
||||
fields: FieldConnection;
|
||||
findManyAgents: Array<Agent>;
|
||||
findManyServerlessFunctions: Array<ServerlessFunction>;
|
||||
findOneAgent: Agent;
|
||||
findOneServerlessFunction: ServerlessFunction;
|
||||
|
||||
@ -8,10 +8,12 @@ import { Button } from 'twenty-ui/input';
|
||||
import {
|
||||
IconArrowUpRight,
|
||||
IconBolt,
|
||||
IconCopy,
|
||||
IconPlus,
|
||||
Status,
|
||||
} from 'twenty-ui/display';
|
||||
import { Pill } from 'twenty-ui/components';
|
||||
import { useCopyToClipboard } from '~/hooks/useCopyToClipboard';
|
||||
|
||||
interface SettingsIntegrationComponentProps {
|
||||
integration: SettingsIntegration;
|
||||
@ -64,6 +66,7 @@ const StyledLogo = styled.img`
|
||||
export const SettingsIntegrationComponent = ({
|
||||
integration,
|
||||
}: SettingsIntegrationComponentProps) => {
|
||||
const { copyToClipboard } = useCopyToClipboard();
|
||||
return (
|
||||
<StyledContainer
|
||||
to={integration.type === 'Active' ? integration.link : undefined}
|
||||
@ -100,6 +103,17 @@ export const SettingsIntegrationComponent = ({
|
||||
title="Use"
|
||||
size="small"
|
||||
/>
|
||||
) : integration.type === 'Copy' ? (
|
||||
<Button
|
||||
onClick={() => {
|
||||
if (isDefined(integration.content)) {
|
||||
copyToClipboard(integration.content);
|
||||
}
|
||||
}}
|
||||
Icon={IconCopy}
|
||||
title={integration.linkText}
|
||||
size="small"
|
||||
/>
|
||||
) : (
|
||||
<Button
|
||||
to={integration.link}
|
||||
|
||||
@ -0,0 +1,36 @@
|
||||
import { SettingsIntegrationCategory } from '@/settings/integrations/types/SettingsIntegrationCategory';
|
||||
import { REACT_APP_SERVER_BASE_URL } from '~/config';
|
||||
|
||||
export const SETTINGS_INTEGRATION_AI_CATEGORY: SettingsIntegrationCategory = {
|
||||
key: 'ai',
|
||||
title: 'With AI',
|
||||
hyperlink: null,
|
||||
integrations: [
|
||||
{
|
||||
from: {
|
||||
key: 'mcp',
|
||||
image: '/images/integrations/mcp.svg',
|
||||
},
|
||||
to: null,
|
||||
type: 'Copy',
|
||||
content: JSON.stringify(
|
||||
{
|
||||
mcpServers: {
|
||||
twenty: {
|
||||
type: 'remote',
|
||||
url: `${REACT_APP_SERVER_BASE_URL}/mcp`,
|
||||
headers: {
|
||||
Authorization: 'Bearer [API_KEY]',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
text: 'Connect MCP Client',
|
||||
link: '#',
|
||||
linkText: 'Copy',
|
||||
},
|
||||
],
|
||||
};
|
||||
@ -1,21 +0,0 @@
|
||||
import { SettingsIntegrationCategory } from '@/settings/integrations/types/SettingsIntegrationCategory';
|
||||
|
||||
export const SETTINGS_INTEGRATION_WINDMILL_CATEGORY: SettingsIntegrationCategory =
|
||||
{
|
||||
key: 'windmill',
|
||||
title: 'With Windmill',
|
||||
hyperlink: null,
|
||||
integrations: [
|
||||
{
|
||||
from: {
|
||||
key: 'windmill',
|
||||
image: '/images/integrations/windmill-logo.png',
|
||||
},
|
||||
to: null,
|
||||
type: 'Goto',
|
||||
text: 'Create a workflow with Windmill',
|
||||
link: 'https://www.windmill.dev',
|
||||
linkText: 'Go to Windmill',
|
||||
},
|
||||
],
|
||||
};
|
||||
@ -1,6 +1,6 @@
|
||||
import { MOCK_REMOTE_DATABASES } from '@/settings/integrations/constants/MockRemoteDatabases';
|
||||
import { SETTINGS_INTEGRATION_AI_CATEGORY } from '@/settings/integrations/constants/SettingsIntegrationMcp';
|
||||
import { SETTINGS_INTEGRATION_REQUEST_CATEGORY } from '@/settings/integrations/constants/SettingsIntegrationRequest';
|
||||
import { SETTINGS_INTEGRATION_WINDMILL_CATEGORY } from '@/settings/integrations/constants/SettingsIntegrationWindmill';
|
||||
import { SETTINGS_INTEGRATION_ZAPIER_CATEGORY } from '@/settings/integrations/constants/SettingsIntegrationZapier';
|
||||
import { SettingsIntegrationCategory } from '@/settings/integrations/types/SettingsIntegrationCategory';
|
||||
import { getSettingsIntegrationAll } from '@/settings/integrations/utils/getSettingsIntegrationAll';
|
||||
@ -30,6 +30,10 @@ export const useSettingsIntegrationCategories =
|
||||
({ name }) => name === 'stripe',
|
||||
)?.isActive;
|
||||
|
||||
const isAiIntegrationEnabled = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IS_AI_ENABLED,
|
||||
);
|
||||
|
||||
const allIntegrations = getSettingsIntegrationAll({
|
||||
isAirtableIntegrationEnabled,
|
||||
isAirtableIntegrationActive,
|
||||
@ -42,7 +46,7 @@ export const useSettingsIntegrationCategories =
|
||||
return [
|
||||
...(allIntegrations.integrations.length > 0 ? [allIntegrations] : []),
|
||||
SETTINGS_INTEGRATION_ZAPIER_CATEGORY,
|
||||
SETTINGS_INTEGRATION_WINDMILL_CATEGORY,
|
||||
...(isAiIntegrationEnabled ? [SETTINGS_INTEGRATION_AI_CATEGORY] : []),
|
||||
SETTINGS_INTEGRATION_REQUEST_CATEGORY,
|
||||
];
|
||||
};
|
||||
|
||||
@ -3,13 +3,15 @@ export type SettingsIntegrationType =
|
||||
| 'Add'
|
||||
| 'Goto'
|
||||
| 'Soon'
|
||||
| 'Use';
|
||||
| 'Use'
|
||||
| 'Copy';
|
||||
|
||||
export type SettingsIntegration = {
|
||||
from: { key: string; image: string };
|
||||
to?: { key: string; image: string } | null;
|
||||
type: SettingsIntegrationType;
|
||||
linkText?: string;
|
||||
content?: string;
|
||||
link: string;
|
||||
text: string;
|
||||
};
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import { useMutation } from '@apollo/client';
|
||||
import { useState } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { useDebouncedCallback } from 'use-debounce';
|
||||
import { useFindOneAgentQuery } from '~/generated-metadata/graphql';
|
||||
import { UPDATE_ONE_AGENT } from '../graphql/mutations/updateOneAgent';
|
||||
import {
|
||||
useFindOneAgentQuery,
|
||||
useUpdateOneAgentMutation,
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
type AgentFormValues = {
|
||||
name: string;
|
||||
@ -39,9 +40,9 @@ export const useAgentUpdateFormState = ({
|
||||
},
|
||||
});
|
||||
|
||||
const [updateAgent] = useMutation(UPDATE_ONE_AGENT);
|
||||
const [updateAgent] = useUpdateOneAgentMutation();
|
||||
|
||||
const updateAgentMutation = async (updates: Partial<AgentFormValues>) => {
|
||||
const updateAgentMutation = async (updates: AgentFormValues) => {
|
||||
if (!agentId) {
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user