feat: Add Antigravity to the MCP client connection dialog (#40879)

Co-authored-by: n8n-cat-bot[bot] <n8n-cat-bot[bot]@users.noreply.github.com>
Co-authored-by: Svetoslav Dekov <svetoslav.dekov@n8n.io>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
n8n-cat-bot[bot] 2026-10-12 13:53:19 +00:00 committed by GitHub
parent 27b43de85f
commit f0a38cfe58
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 52 additions and 4 deletions

View File

@ -3649,6 +3649,7 @@
"settings.mcp.connectDialog.install.description": "Run this command to add n8n to {client} (it must already be installed)",
"settings.mcp.connectDialog.configure.title": "Configure",
"settings.mcp.connectDialog.configure.description": "Add this to your config file to connect to n8n",
"settings.mcp.connectDialog.configure.antigravity.description": "Add this mcpServers entry to ~/.gemini/config/mcp_config.json. The Antigravity IDE, desktop app, and CLI (agy) share this file.",
"settings.mcp.connectDialog.configure.titleAlt": "Or configure manually",
"settings.mcp.connectDialog.configure.descriptionAlt": "Prefer not to run the command? Add this to your config file instead",
"settings.mcp.connectDialog.authenticate.title": "Authenticate",

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@ -69,6 +69,30 @@ describe('McpConnectClientDialog', () => {
expect(body().queryByText('Authenticate')).not.toBeInTheDocument();
});
it('should show the shared Antigravity config file and entry', async () => {
renderComponent({ pinia });
await waitFor(() => {
expect(body().getByTestId('mcp-connect-client-picker-trigger')).toBeInTheDocument();
});
await userEvent.click(body().getByTestId('mcp-connect-client-picker-trigger'));
const menuLabel = await body().findByText('Antigravity');
expect(
menuLabel.closest('[role="menuitem"]')?.querySelector('svg.brand-icon'),
).toBeInTheDocument();
await userEvent.click(menuLabel);
expect(
body().getByTestId('mcp-connect-client-picker-trigger').querySelector('svg.brand-icon'),
).toBeInTheDocument();
expect(body().getByText(/~\/\.gemini\/config\/mcp_config\.json/)).toHaveTextContent(
'IDE, desktop app, and CLI (agy) share this file',
);
expect(body().getByTestId('mcp-config-snippet')).toHaveTextContent('mcpServers');
expect(body().getByTestId('mcp-config-snippet')).toHaveTextContent('serverUrl');
expect(body().queryByTestId('mcp-connect-one-click')).not.toBeInTheDocument();
});
it('should show only the server URL (no one-click) for web clients without a connector URL', async () => {
renderComponent({ pinia });

View File

@ -354,7 +354,11 @@ const serverUrlDescription = computed(() =>
layout="vertical"
:show-divider="false"
:title="i18n.baseText('settings.mcp.connectDialog.configure.title')"
:description="i18n.baseText('settings.mcp.connectDialog.configure.description')"
:description="
activeClient.id === 'antigravity'
? i18n.baseText('settings.mcp.connectDialog.configure.antigravity.description')
: i18n.baseText('settings.mcp.connectDialog.configure.description')
"
>
<template #action>
<McpConfigSnippet

View File

@ -11,10 +11,20 @@ describe('getMcpClientCatalog', () => {
expect(catalog.map((group) => group.clients.map((client) => client.id))).toEqual([
['claude-code', 'codex', 'gemini-cli'],
['claude-ai', 'chatgpt', 'mistral-vibe'],
['cursor', 'vscode', 'windsurf'],
['antigravity', 'cursor', 'vscode', 'windsurf'],
]);
});
it('should give Antigravity an HTTP server entry and keep Gemini CLI available', () => {
const antigravity = clients.find((client) => client.id === 'antigravity');
expect(JSON.parse(antigravity!.configSnippet!)).toEqual({
mcpServers: { n8n: { serverUrl: SERVER_URL } },
});
expect(clients.find((client) => client.id === 'gemini-cli')?.installCommand).toContain(
'gemini mcp add',
);
});
it('should embed the server URL in every install command and config snippet', () => {
for (const client of clients) {
if (client.installCommand) expect(client.installCommand).toContain(SERVER_URL);

View File

@ -1,5 +1,6 @@
import type { Component } from 'vue';
import AntigravityIcon from './assets/client-icons/antigravity.svg?component';
import ClaudeIcon from './assets/client-icons/claude.svg?component';
import CodexIcon from './assets/client-icons/codex.svg?component';
import CursorIcon from './assets/client-icons/cursor.svg?component';
@ -80,7 +81,7 @@ url = "${serverUrl}"`;
}
}
}`;
const windsurfSnippet = `{\n "mcpServers": {\n "n8n": {\n "serverUrl": "${serverUrl}"\n }\n }\n}`;
const serverUrlSnippet = `{\n "mcpServers": {\n "n8n": {\n "serverUrl": "${serverUrl}"\n }\n }\n}`;
// One-click deep links, exactly as each editor expects: Cursor takes base64 of
// `{"url": …}` in a `config` query param, VS Code a URL-encoded JSON object.
@ -154,6 +155,13 @@ url = "${serverUrl}"`;
{
id: 'ide',
clients: [
{
id: 'antigravity',
name: 'Antigravity',
category: 'ide',
icon: AntigravityIcon,
configSnippet: serverUrlSnippet,
},
{
id: 'cursor',
name: 'Cursor',
@ -175,7 +183,7 @@ url = "${serverUrl}"`;
name: 'Windsurf',
category: 'ide',
icon: null,
configSnippet: windsurfSnippet,
configSnippet: serverUrlSnippet,
},
],
},