Skip to content

Commit c88998a

Browse files
committed
feat: Enhance MCP integration with authentication status and tooltips
- Updated the `McpIntegrationsAccordion` component to display authentication status for MCP servers, including new icons and badges for authenticated and unauthenticated states. - Modified the backend to include authentication checks for known MCP servers (Google Workspace and Jira) and return relevant messages. - Added a new `webfetch` server configuration to the `.mcp.json` file for improved web content extraction. - Refactored the session API to provide clearer information on server authentication status in the response. These changes improve user awareness of MCP server states and enhance the overall integration experience.
1 parent d3d4239 commit c88998a

File tree

5 files changed

+126
-33
lines changed

5 files changed

+126
-33
lines changed

components/frontend/src/app/projects/[name]/sessions/[sessionName]/components/accordions/mcp-integrations-accordion.tsx

Lines changed: 57 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
'use client'
22

3-
import { Plug, CheckCircle2, XCircle, AlertCircle } from 'lucide-react'
3+
import { Plug, CheckCircle2, XCircle, AlertCircle, KeyRound, KeyRoundIcon } from 'lucide-react'
44
import {
55
AccordionItem,
66
AccordionTrigger,
77
AccordionContent,
88
} from '@/components/ui/accordion'
99
import { Badge } from '@/components/ui/badge'
10+
import {
11+
Tooltip,
12+
TooltipContent,
13+
TooltipProvider,
14+
TooltipTrigger,
15+
} from '@/components/ui/tooltip'
1016
import { useMcpStatus } from '@/services/queries/use-mcp'
17+
import type { McpServer } from '@/services/api/sessions'
1118

1219
type McpIntegrationsAccordionProps = {
1320
projectName: string
@@ -21,8 +28,19 @@ export function McpIntegrationsAccordion({
2128
// Fetch real MCP status from runner
2229
const { data: mcpStatus } = useMcpStatus(projectName, sessionName)
2330
const mcpServers = mcpStatus?.servers || []
24-
const getStatusIcon = (status: 'configured' | 'connected' | 'disconnected' | 'error') => {
25-
switch (status) {
31+
32+
const getStatusIcon = (server: McpServer) => {
33+
// If we have auth info, use that for the icon
34+
if (server.authenticated !== undefined) {
35+
if (server.authenticated) {
36+
return <CheckCircle2 className="h-4 w-4 text-green-600" />
37+
} else {
38+
return <KeyRound className="h-4 w-4 text-amber-500" />
39+
}
40+
}
41+
42+
// Fall back to status-based icons
43+
switch (server.status) {
2644
case 'configured':
2745
case 'connected':
2846
return <CheckCircle2 className="h-4 w-4 text-blue-600" />
@@ -34,8 +52,28 @@ export function McpIntegrationsAccordion({
3452
}
3553
}
3654

37-
const getStatusBadge = (status: 'configured' | 'connected' | 'disconnected' | 'error') => {
38-
switch (status) {
55+
const getAuthBadge = (server: McpServer) => {
56+
// If auth info is available, show auth status
57+
if (server.authenticated !== undefined) {
58+
if (server.authenticated) {
59+
return (
60+
<Badge variant="outline" className="text-xs bg-green-50 text-green-700 border-green-200">
61+
<KeyRoundIcon className="h-3 w-3 mr-1" />
62+
Authenticated
63+
</Badge>
64+
)
65+
} else {
66+
return (
67+
<Badge variant="outline" className="text-xs bg-amber-50 text-amber-700 border-amber-200">
68+
<KeyRound className="h-3 w-3 mr-1" />
69+
Not Authenticated
70+
</Badge>
71+
)
72+
}
73+
}
74+
75+
// Fall back to status-based badges
76+
switch (server.status) {
3977
case 'configured':
4078
return (
4179
<Badge variant="outline" className="text-xs bg-blue-50 text-blue-700 border-blue-200">
@@ -82,17 +120,28 @@ export function McpIntegrationsAccordion({
82120
>
83121
<div className="flex items-center gap-3">
84122
<div className="flex-shrink-0">
85-
{getStatusIcon(server.status)}
123+
{getStatusIcon(server)}
86124
</div>
87125
<div className="flex-1">
88126
<h4 className="font-medium text-sm">{server.displayName}</h4>
89127
<p className="text-xs text-muted-foreground mt-0.5">
90-
{server.name}
128+
{server.authMessage || server.name}
91129
</p>
92130
</div>
93131
</div>
94132
<div className="flex-shrink-0">
95-
{getStatusBadge(server.status)}
133+
<TooltipProvider>
134+
<Tooltip>
135+
<TooltipTrigger asChild>
136+
{getAuthBadge(server)}
137+
</TooltipTrigger>
138+
{server.authMessage && (
139+
<TooltipContent>
140+
<p>{server.authMessage}</p>
141+
</TooltipContent>
142+
)}
143+
</Tooltip>
144+
</TooltipProvider>
96145
</div>
97146
</div>
98147
))

components/frontend/src/services/api/sessions.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ export type McpServer = {
2121
name: string;
2222
displayName: string;
2323
status: 'configured' | 'connected' | 'disconnected' | 'error';
24+
authenticated?: boolean;
25+
authMessage?: string;
2426
source?: string;
2527
command?: string;
2628
};

components/runners/claude-code-runner/.mcp.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
{
22
"mcpServers": {
3+
"webfetch": {
4+
"command": "uvx",
5+
"args": ["mcp-server-fetch"]
6+
},
37
"mcp-atlassian": {
48
"command": "mcp-atlassian",
59
"args": [],

components/runners/claude-code-runner/adapter.py

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -398,22 +398,10 @@ async def _run_claude_agent_sdk(
398398
logger.info(f"Claude SDK CWD: {cwd_path}")
399399
logger.info(f"Claude SDK additional directories: {add_dirs}")
400400

401-
# Load MCP server configuration
402-
mcp_servers = self._load_mcp_config(cwd_path)
401+
# Load MCP server configuration (webfetch is included in static .mcp.json)
402+
mcp_servers = self._load_mcp_config(cwd_path) or {}
403403

404-
# Add WebFetch.MCP as default if no MCP config exists
405-
if not mcp_servers:
406-
mcp_servers = {}
407-
408-
# Always include WebFetch.MCP for better web content extraction
409-
if "webfetch" not in mcp_servers:
410-
mcp_servers["webfetch"] = {
411-
"command": "npx",
412-
"args": ["-y", "@manooll/webfetch-mcp"]
413-
}
414-
logger.info("Added WebFetch.MCP as default web fetch provider")
415-
416-
# Disable built-in WebFetch in favor of WebFetch.MCP
404+
# Disable built-in WebFetch in favor of WebFetch.MCP from config
417405
allowed_tools = ["Read", "Write", "Bash", "Glob", "Grep", "Edit", "MultiEdit", "WebSearch"]
418406
if mcp_servers:
419407
for server_name in mcp_servers.keys():

components/runners/claude-code-runner/main.py

Lines changed: 60 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -284,14 +284,54 @@ async def interrupt_run():
284284
raise HTTPException(status_code=500, detail=str(e))
285285

286286

287+
def _check_mcp_authentication(server_name: str) -> tuple[bool | None, str | None]:
288+
"""
289+
Check if credentials are available for known MCP servers.
290+
291+
Returns:
292+
Tuple of (is_authenticated, auth_message)
293+
Returns (None, None) for servers we don't know how to check
294+
"""
295+
from pathlib import Path
296+
297+
# Google Workspace MCP - we know how to check this
298+
if server_name == "google-workspace":
299+
# Check mounted secret location first, then workspace copy
300+
secret_path = Path("/app/.google_workspace_mcp/credentials/credentials.json")
301+
workspace_path = Path("/workspace/.google_workspace_mcp/credentials/credentials.json")
302+
303+
for cred_path in [workspace_path, secret_path]:
304+
if cred_path.exists():
305+
try:
306+
if cred_path.stat().st_size > 0:
307+
return True, "Google OAuth credentials available"
308+
except OSError:
309+
pass
310+
return False, "Google OAuth not configured - authenticate via Integrations page"
311+
312+
# Jira/Atlassian MCP - we know how to check this
313+
if server_name in ("mcp-atlassian", "jira"):
314+
jira_url = os.getenv("JIRA_URL", "").strip()
315+
jira_token = os.getenv("JIRA_API_TOKEN", "").strip()
316+
317+
if jira_url and jira_token:
318+
return True, "Jira credentials configured"
319+
elif jira_url:
320+
return False, "Jira URL set but API token missing"
321+
else:
322+
return False, "Jira not configured - set credentials in Workspace Settings"
323+
324+
# For all other servers (webfetch, unknown) - don't claim to know auth status
325+
return None, None
326+
327+
287328
@app.get("/mcp/status")
288329
async def get_mcp_status():
289330
"""
290-
Returns MCP servers configured for this session.
331+
Returns MCP servers configured for this session with authentication status.
291332
Goes straight to the source - uses adapter's _load_mcp_config() method.
292333
293-
Note: Status is "configured" not "connected" - we can't verify runtime state
294-
without introspecting the Claude SDK's internal MCP server processes.
334+
For known integrations (Google, Jira), also checks if credentials are present.
295335
"""
296336
try:
297337
global adapter
@@ -323,21 +363,31 @@ async def get_mcp_status():
323363

324364
if mcp_config:
325365
for server_name, server_config in mcp_config.items():
326-
# Check if this is WebFetch (auto-added by adapter)
327-
is_webfetch = server_name == "webfetch"
366+
# Check authentication status for known servers (Google, Jira)
367+
is_authenticated, auth_message = _check_mcp_authentication(server_name)
368+
369+
# Platform servers are built-in (webfetch), workflow servers come from config
370+
is_platform = server_name == "webfetch"
328371

329-
mcp_servers_list.append({
372+
server_info = {
330373
"name": server_name,
331374
"displayName": server_name.replace('-', ' ').replace('_', ' ').title(),
332-
"status": "configured", # Honest: we know it's configured, not if it's actually running
375+
"status": "configured",
333376
"command": server_config.get("command", ""),
334-
"source": "platform" if is_webfetch else "workflow"
335-
})
377+
"source": "platform" if is_platform else "workflow"
378+
}
379+
380+
# Only include auth fields for servers we know how to check
381+
if is_authenticated is not None:
382+
server_info["authenticated"] = is_authenticated
383+
server_info["authMessage"] = auth_message
384+
385+
mcp_servers_list.append(server_info)
336386

337387
return {
338388
"servers": mcp_servers_list,
339389
"totalCount": len(mcp_servers_list),
340-
"note": "Status shows 'configured' - actual runtime state requires SDK introspection"
390+
"note": "Status shows 'configured' - check 'authenticated' field for credential status"
341391
}
342392

343393
except Exception as e:

0 commit comments

Comments
 (0)