feat: add Exa and Chrome DevTools as one-click MCP server options (Vibe Kanban) (#1801)

* I've added the Exa Code MCP server as a one-click install option. Here's what was configured:

**Changes made to `crates/executors/default_mcp.json`:**

1. **Server configuration** (lines 23-33):
   - Command: `npx -y exa-mcp-server`
   - Tools enabled: `web_search_exa` and `get_code_context_exa` (as requested)
   - Environment variable: `EXA_API_KEY` (required for authentication)

2. **Metadata** (lines 53-58):
   - Name: "Exa"
   - Description: "Web search and code context retrieval powered by Exa AI"
   - URL: https://docs.exa.ai/reference/exa-mcp
   - Icon: `mcp/exa_logo.svg` (already exists)

The Exa MCP server icon was already present in the frontend public assets at `frontend/public/mcp/exa_logo.svg`.

* Done. I've added Chrome DevTools MCP as a one-click install option:

**Server configuration** (lines 34-39):
- Command: `npx chrome-devtools-mcp@latest`
- No environment variables required

**Metadata** (lines 65-70):
- Name: "Chrome DevTools"
- Description: "Browser automation, debugging and performance analysis with Chrome DevTools"
- URL: https://github.com/ChromeDevTools/chrome-devtools-mcp
- Icon: `mcp/chrome_devtools_logo.svg`

* The issue was that `justify-center` and `gap-3` were interfering with Embla Carousel's scroll calculations. Embla uses a specific margin/padding system (`-ml-4` on the content container and `pl-4` on items) to handle spacing and scroll positions. Adding `justify-center` shifts items in a way that breaks the scroll math, making it impossible to scroll to the leftmost items.

The fix removes these conflicting classes from `CarouselContent`.
This commit is contained in:
Gabriel Gordon-Hall
2026-01-07 16:30:39 +00:00
committed by GitHub
parent 25c6d0a7c0
commit 76feaefdfe
4 changed files with 32 additions and 1 deletions

View File

@@ -20,6 +20,23 @@
"@playwright/mcp@latest"
]
},
"exa": {
"command": "npx",
"args": [
"-y",
"exa-mcp-server",
"tools=web_search_exa,get_code_context_exa"
],
"env": {
"EXA_API_KEY": "YOUR_API_KEY"
}
},
"chrome_devtools": {
"command": "npx",
"args": [
"chrome-devtools-mcp@latest"
]
},
"meta": {
"vibe_kanban": {
"name": "Vibe Kanban",
@@ -38,6 +55,18 @@
"description": "Browser automation with Playwright",
"url": "https://github.com/microsoft/playwright-mcp",
"icon": "mcp/playwright_logo_icon.svg"
},
"exa": {
"name": "Exa",
"description": "Web search and code context retrieval powered by Exa AI",
"url": "https://docs.exa.ai/reference/exa-mcp",
"icon": "mcp/exa_logo.svg"
},
"chrome_devtools": {
"name": "Chrome DevTools",
"description": "Browser automation, debugging and performance analysis with Chrome DevTools",
"url": "https://github.com/ChromeDevTools/chrome-devtools-mcp",
"icon": "mcp/chrome_devtools_logo.svg"
}
}
}

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 48 48" height="48" width="48"><defs><linearGradient id="a" x1="3.2173" y1="15" x2="44.7812" y2="15" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#d93025"/><stop offset="1" stop-color="#ea4335"/></linearGradient><linearGradient id="b" x1="20.7219" y1="47.6791" x2="41.5039" y2="11.6837" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fcc934"/><stop offset="1" stop-color="#fbbc04"/></linearGradient><linearGradient id="c" x1="26.5981" y1="46.5015" x2="5.8161" y2="10.506" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#1e8e3e"/><stop offset="1" stop-color="#34a853"/></linearGradient></defs><circle cx="24" cy="23.9947" r="12" style="fill:#fff"/><path d="M3.2154,36A24,24,0,1,0,12,3.2154,24,24,0,0,0,3.2154,36ZM34.3923,18A12,12,0,1,1,18,13.6077,12,12,0,0,1,34.3923,18Z" style="fill:none"/><path d="M24,12H44.7812a23.9939,23.9939,0,0,0-41.5639.0029L13.6079,30l.0093-.0024A11.9852,11.9852,0,0,1,24,12Z" style="fill:url(#a)"/><circle cx="24" cy="24" r="9.5" style="fill:#1a73e8"/><path d="M34.3913,30.0029,24.0007,48A23.994,23.994,0,0,0,44.78,12.0031H23.9989l-.0025.0093A11.985,11.985,0,0,1,34.3913,30.0029Z" style="fill:url(#b)"/><path d="M13.6086,30.0031,3.218,12.006A23.994,23.994,0,0,0,24.0025,48L34.3931,30.0029l-.0067-.0068a11.9852,11.9852,0,0,1-20.7778.007Z" style="fill:url(#c)"/></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1 @@
<svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Exa</title><path clip-rule="evenodd" d="M3 0h19v1.791L13.892 12 22 22.209V24H3V0zm9.62 10.348l6.589-8.557H6.03l6.59 8.557zM5.138 3.935v7.17h5.52l-5.52-7.17zm5.52 8.96h-5.52v7.17l5.52-7.17zM6.03 22.21l6.59-8.557 6.589 8.557H6.03z" fill="#1F40ED" fill-rule="evenodd"></path></svg>

After

Width:  |  Height:  |  Size: 402 B

View File

@@ -368,7 +368,7 @@ export function McpSettings() {
<div className="relative overflow-hidden rounded-xl border bg-background">
<Carousel className="w-full px-4 py-3">
<CarouselContent className="gap-3 justify-center">
<CarouselContent>
{Object.entries(servers).map(([key]) => {
const metaObj = getMetaFor(key) as {
name?: string;