@@ -8,7 +8,6 @@ import { JiraConnectionCard } from '@/components/jira-connection-card'
88import { MCPCredentialCard } from '@/components/mcp-credential-card'
99import { PageHeader } from '@/components/page-header'
1010import { useIntegrationsStatus } from '@/services/queries/use-integrations'
11- import { Card } from '@/components/ui/card'
1211import { Loader2 } from 'lucide-react'
1312
1413type FieldDefinition = {
@@ -19,53 +18,21 @@ type FieldDefinition = {
1918 helpText ?: string
2019}
2120
22- type MCPServerEntry = {
21+ type MCPCredentialServer = {
2322 displayName : string
2423 description : string
25- iconBg : string
26- icon : ReactNode
27- } & (
28- | { kind : 'enabled' }
29- | { kind : 'credentials' ; fields : FieldDefinition [ ] }
30- )
31-
32- /* eslint-disable @next/next/no-img-element */
24+ iconBg ?: string
25+ icon ?: ReactNode
26+ fields : FieldDefinition [ ]
27+ }
3328
3429/**
35- * All MCP servers configured in the platform (.mcp.json) .
36- * - "enabled" servers require no credentials and are always active.
37- * - "credentials" servers need user-provided fields to function .
30+ * MCP servers that require user-provided credentials .
31+ * Platform-wide no-auth servers (context7, deepwiki, webfetch) are not shown
32+ * here — they belong at the project scope, not user-scoped integrations .
3833 */
39- const MCP_SERVERS : Record < string , MCPServerEntry > = {
40- context7 : {
41- kind : 'enabled' ,
42- displayName : 'Context7' ,
43- description : 'Up-to-date documentation and code examples for libraries and frameworks' ,
44- iconBg : '' ,
45- icon : < img src = "/logos/context7.svg" alt = "Context7" className = "w-16 h-16 rounded-lg" /> ,
46- } ,
47- deepwiki : {
48- kind : 'enabled' ,
49- displayName : 'DeepWiki' ,
50- description : 'AI-powered knowledge base for open-source repositories' ,
51- iconBg : 'bg-white' ,
52- icon : < img src = "/logos/deepwiki.png" alt = "DeepWiki" className = "w-10 h-10" /> ,
53- } ,
54- webfetch : {
55- kind : 'enabled' ,
56- displayName : 'Web Fetch' ,
57- description : 'Fetch and extract content from web pages' ,
58- iconBg : 'bg-emerald-600' ,
59- icon : (
60- < svg className = "w-8 h-8 text-white" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" strokeWidth = "1.5" strokeLinecap = "round" strokeLinejoin = "round" aria-hidden = "true" >
61- < circle cx = "12" cy = "12" r = "10" />
62- < path d = "M2 12h20" />
63- < path d = "M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" />
64- </ svg >
65- ) ,
66- } ,
34+ const MCP_CREDENTIAL_SERVERS : Record < string , MCPCredentialServer > = {
6735 'mcp-atlassian' : {
68- kind : 'credentials' ,
6936 displayName : 'Jira (MCP)' ,
7037 description :
7138 'Provide Jira credentials for the MCP Atlassian server used in agentic sessions' ,
@@ -99,56 +66,13 @@ const MCP_SERVERS: Record<string, MCPServerEntry> = {
9966 } ,
10067}
10168
102- function MCPEnabledCard ( {
103- displayName,
104- description,
105- iconBg,
106- icon,
107- } : {
108- displayName : string
109- description : string
110- iconBg : string
111- icon : ReactNode
112- } ) {
113- return (
114- < Card className = "bg-card border border-border/60 shadow-sm shadow-black/[0.03] dark:shadow-black/[0.15] flex flex-col h-full" >
115- < div className = "p-6 flex flex-col flex-1" >
116- < div className = "flex items-start gap-4 mb-6" >
117- { iconBg ? (
118- < div className = { `flex-shrink-0 w-16 h-16 ${ iconBg } rounded-lg flex items-center justify-center` } >
119- { icon }
120- </ div >
121- ) : (
122- < div className = "flex-shrink-0 w-16 h-16" >
123- { icon }
124- </ div >
125- ) }
126- < div className = "flex-1" >
127- < h3 className = "text-xl font-semibold text-foreground mb-1" > { displayName } </ h3 >
128- < p className = "text-muted-foreground" > { description } </ p >
129- </ div >
130- </ div >
131- < div className = "flex items-center gap-2 mt-auto" >
132- < span className = "w-2 h-2 rounded-full bg-green-500" />
133- < span className = "text-sm font-medium text-foreground/80" >
134- Enabled
135- </ span >
136- < span className = "text-xs text-muted-foreground ml-1" >
137- No configuration required
138- </ span >
139- </ div >
140- </ div >
141- </ Card >
142- )
143- }
144-
14569type Props = { appSlug ?: string }
14670
14771export default function IntegrationsClient ( { appSlug } : Props ) {
14872 const { data : integrations , isLoading, refetch } = useIntegrationsStatus ( )
14973
150- // Merge known servers with any additional servers that have stored credentials
151- const mcpServerNames = new Set < string > ( Object . keys ( MCP_SERVERS ) )
74+ // Merge known credential servers with any additional servers that have stored credentials
75+ const mcpServerNames = new Set < string > ( Object . keys ( MCP_CREDENTIAL_SERVERS ) )
15276 if ( integrations ?. mcpServers ) {
15377 for ( const name of Object . keys ( integrations . mcpServers ) ) {
15478 mcpServerNames . add ( name )
@@ -198,61 +122,46 @@ export default function IntegrationsClient({ appSlug }: Props) {
198122 />
199123 </ div >
200124
201- { /* MCP Servers section */ }
202- < div className = "mt-8" >
203- < h2 className = "text-lg font-semibold text-foreground mb-4" > MCP Servers</ h2 >
204- < div className = "grid grid-cols-1 md:grid-cols-2 gap-6" >
205- { [ ...mcpServerNames ] . map ( ( name ) => {
206- const entry = MCP_SERVERS [ name ]
207- const serverStatus = integrations ?. mcpServers ?. [ name ]
208-
209- if ( entry ?. kind === 'enabled' ) {
125+ { /* MCP Servers section — only credential-based servers (user-scoped) */ }
126+ { mcpServerNames . size > 0 && (
127+ < div className = "mt-8" >
128+ < h2 className = "text-lg font-semibold text-foreground mb-4" > MCP Servers</ h2 >
129+ < div className = "grid grid-cols-1 md:grid-cols-2 gap-6" >
130+ { [ ...mcpServerNames ] . map ( ( name ) => {
131+ const entry = MCP_CREDENTIAL_SERVERS [ name ]
132+ const serverStatus = integrations ?. mcpServers ?. [ name ]
210133 return (
211- < MCPEnabledCard
134+ < MCPCredentialCard
212135 key = { name }
213- displayName = { entry . displayName }
214- description = { entry . description }
215- iconBg = { entry . iconBg }
216- icon = { entry . icon }
136+ serverName = { name }
137+ displayName = { entry ?. displayName ?? name }
138+ icon = { entry ?. icon }
139+ iconBg = { entry ?. iconBg }
140+ description = {
141+ entry ?. description ?? `Credentials for the ${ name } MCP server`
142+ }
143+ fields = {
144+ entry ?. fields ?? [
145+ {
146+ name : 'api_key' ,
147+ label : 'API Key' ,
148+ type : 'password' as const ,
149+ placeholder : 'Enter API key' ,
150+ } ,
151+ ]
152+ }
153+ status = {
154+ serverStatus
155+ ? { connected : serverStatus . connected , serverName : name }
156+ : { connected : false , serverName : name }
157+ }
158+ onRefresh = { refetch }
217159 />
218160 )
219- }
220-
221- return (
222- < MCPCredentialCard
223- key = { name }
224- serverName = { name }
225- displayName = { entry ?. displayName ?? name }
226- icon = { entry ?. icon }
227- iconBg = { entry ?. iconBg }
228- description = {
229- entry ?. kind === 'credentials'
230- ? entry . description
231- : `Credentials for the ${ name } MCP server`
232- }
233- fields = {
234- entry ?. kind === 'credentials'
235- ? entry . fields
236- : [
237- {
238- name : 'api_key' ,
239- label : 'API Key' ,
240- type : 'password' as const ,
241- placeholder : 'Enter API key' ,
242- } ,
243- ]
244- }
245- status = {
246- serverStatus
247- ? { connected : serverStatus . connected , serverName : name }
248- : { connected : false , serverName : name }
249- }
250- onRefresh = { refetch }
251- />
252- )
253- } ) }
161+ } ) }
162+ </ div >
254163 </ div >
255- </ div >
164+ ) }
256165 </ >
257166 ) }
258167 </ div >
0 commit comments