@apteva/apteva-darwin-arm64 0.4.41 → 0.4.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/apteva +0 -0
  2. package/dist/ActivityPage.9v5ha2p7.js +3 -0
  3. package/dist/{ActivityPage.7907h64p.js.map → ActivityPage.9v5ha2p7.js.map} +3 -3
  4. package/dist/ApiDocsPage.qsehxvkb.js +4 -0
  5. package/dist/ApiDocsPage.qsehxvkb.js.map +10 -0
  6. package/dist/App.168av39e.js +221 -0
  7. package/dist/{App.qcknavjz.js.map → App.168av39e.js.map} +15 -15
  8. package/dist/App.2j20h2gt.js +8 -0
  9. package/dist/App.2j20h2gt.js.map +12 -0
  10. package/dist/App.7gj4jht5.js +53 -0
  11. package/dist/{App.apjrmctz.js.map → App.7gj4jht5.js.map} +50 -52
  12. package/dist/App.aexwv4rk.js +4 -0
  13. package/dist/App.aexwv4rk.js.map +10 -0
  14. package/dist/App.anvw0hjc.js +61 -0
  15. package/dist/App.anvw0hjc.js.map +13 -0
  16. package/dist/App.cjcyr5aj.js +4 -0
  17. package/dist/App.cjcyr5aj.js.map +10 -0
  18. package/dist/App.dmvykj97.js +4 -0
  19. package/dist/App.dmvykj97.js.map +10 -0
  20. package/dist/App.e2kkda2a.js +4 -0
  21. package/dist/App.e2kkda2a.js.map +10 -0
  22. package/dist/App.j4ec9k18.js +13 -0
  23. package/dist/App.j4ec9k18.js.map +10 -0
  24. package/dist/{App.7fb3e7mp.js → App.jdkx6eqd.js} +1 -1
  25. package/dist/App.kz3qyyre.js +4 -0
  26. package/dist/{App.myxqcj9x.js.map → App.kz3qyyre.js.map} +3 -3
  27. package/dist/App.sd685nt9.js +4 -0
  28. package/dist/App.sd685nt9.js.map +10 -0
  29. package/dist/App.shfd8tp9.js +20 -0
  30. package/dist/{App.3qw8nben.js.map → App.shfd8tp9.js.map} +6 -4
  31. package/dist/App.wghtdzsk.js +1 -0
  32. package/dist/App.x6x8s16g.js +4 -0
  33. package/dist/App.x6x8s16g.js.map +14 -0
  34. package/dist/App.y2vn8m06.js +4 -0
  35. package/dist/App.y2vn8m06.js.map +10 -0
  36. package/dist/ConnectionsPage.1dyyfqbk.js +3 -0
  37. package/dist/McpPage.xvr8hk05.js +3 -0
  38. package/dist/SettingsPage.5jmnefwe.js +3 -0
  39. package/dist/SkillsPage.jw7carjq.js +3 -0
  40. package/dist/TasksPage.r8txe0e9.js +3 -0
  41. package/dist/TasksPage.r8txe0e9.js.map +9 -0
  42. package/dist/TelemetryPage.pcafk41x.js +3 -0
  43. package/dist/TelemetryPage.pcafk41x.js.map +9 -0
  44. package/dist/TestsPage.pkymr7yt.js +3 -0
  45. package/dist/ThreadsPage.49tgq4fq.js +3 -0
  46. package/dist/apteva-kit.css +1 -1
  47. package/dist/index.html +1 -1
  48. package/dist/styles.css +1 -1
  49. package/package.json +1 -1
  50. package/dist/ActivityPage.7907h64p.js +0 -3
  51. package/dist/ApiDocsPage.k3jjenpq.js +0 -4
  52. package/dist/ApiDocsPage.k3jjenpq.js.map +0 -10
  53. package/dist/App.01nq20st.js +0 -4
  54. package/dist/App.01nq20st.js.map +0 -10
  55. package/dist/App.1maqvamf.js +0 -4
  56. package/dist/App.1maqvamf.js.map +0 -14
  57. package/dist/App.2yjrh32f.js +0 -4
  58. package/dist/App.2yjrh32f.js.map +0 -10
  59. package/dist/App.3qw8nben.js +0 -20
  60. package/dist/App.7sy3wq8c.js +0 -4
  61. package/dist/App.7sy3wq8c.js.map +0 -10
  62. package/dist/App.apjrmctz.js +0 -57
  63. package/dist/App.av6t2yhe.js +0 -4
  64. package/dist/App.av6t2yhe.js.map +0 -10
  65. package/dist/App.jqj5a094.js +0 -46
  66. package/dist/App.jqj5a094.js.map +0 -13
  67. package/dist/App.mc7xf85h.js +0 -4
  68. package/dist/App.mc7xf85h.js.map +0 -10
  69. package/dist/App.myxqcj9x.js +0 -4
  70. package/dist/App.nm91r1mp.js +0 -13
  71. package/dist/App.nm91r1mp.js.map +0 -10
  72. package/dist/App.p02f4ret.js +0 -1
  73. package/dist/App.qcknavjz.js +0 -221
  74. package/dist/App.vc7vfhg4.js +0 -4
  75. package/dist/App.vc7vfhg4.js.map +0 -10
  76. package/dist/App.z4s9zkw5.js +0 -4
  77. package/dist/App.z4s9zkw5.js.map +0 -10
  78. package/dist/ConnectionsPage.z1pw5xe2.js +0 -3
  79. package/dist/McpPage.8vc97z0b.js +0 -3
  80. package/dist/SettingsPage.p61bz8kd.js +0 -3
  81. package/dist/SkillsPage.r9x43g3g.js +0 -3
  82. package/dist/TasksPage.1e0zkye4.js +0 -3
  83. package/dist/TasksPage.1e0zkye4.js.map +0 -9
  84. package/dist/TelemetryPage.p9vbe4gf.js +0 -3
  85. package/dist/TelemetryPage.p9vbe4gf.js.map +0 -9
  86. package/dist/TestsPage.d4xy504e.js +0 -3
  87. package/dist/ThreadsPage.m016am3x.js +0 -3
  88. /package/dist/{App.7fb3e7mp.js.map → App.jdkx6eqd.js.map} +0 -0
  89. /package/dist/{ConnectionsPage.z1pw5xe2.js.map → ConnectionsPage.1dyyfqbk.js.map} +0 -0
  90. /package/dist/{McpPage.8vc97z0b.js.map → McpPage.xvr8hk05.js.map} +0 -0
  91. /package/dist/{SettingsPage.p61bz8kd.js.map → SettingsPage.5jmnefwe.js.map} +0 -0
  92. /package/dist/{SkillsPage.r9x43g3g.js.map → SkillsPage.jw7carjq.js.map} +0 -0
  93. /package/dist/{TestsPage.d4xy504e.js.map → TestsPage.pkymr7yt.js.map} +0 -0
  94. /package/dist/{ThreadsPage.m016am3x.js.map → ThreadsPage.49tgq4fq.js.map} +0 -0
@@ -0,0 +1,4 @@
1
+ import{j as r}from"./App.kz3qyyre.js";import{t as Oz}from"./App.jdkx6eqd.js";import{O as Jz,P as o}from"./App.e2kkda2a.js";import{U as t}from"./App.sd685nt9.js";import{$ as Qz,X as a,aa as zz,ja as c,ma as Gz}from"./App.shfd8tp9.js";var J=a(Qz(),1);var z=a(zz(),1);function Mz(){let{authFetch:G}=c(),{projects:$,currentProjectId:H}=Gz(),[K,w]=J.useState([]),[X,B]=J.useState(!0),[q,F]=J.useState(!1),[U,T]=J.useState(null),[M,L]=J.useState(null),[Q,k]=J.useState("servers"),{confirm:y,ConfirmDialog:f}=Jz(),Y=$.length>0,A=async()=>{try{let b=await(await G("/api/mcp/servers")).json();w(b.servers||[])}catch(W){console.error("Failed to fetch MCP servers:",W)}B(!1)};J.useEffect(()=>{A()},[G]);let Z=K.filter((W)=>{if(!H)return!0;if(H==="unassigned")return W.project_id===null;return W.project_id===null||W.project_id===H}),S=async(W)=>{try{await G(`/api/mcp/servers/${W}/start`,{method:"POST"}),A()}catch(b){console.error("Failed to start server:",b)}},I=async(W)=>{try{await G(`/api/mcp/servers/${W}/stop`,{method:"POST"}),A()}catch(b){console.error("Failed to stop server:",b)}},p=async(W)=>{if(!await y("Delete this MCP server?",{confirmText:"Delete",title:"Delete Server"}))return;try{if(await G(`/api/mcp/servers/${W}`,{method:"DELETE"}),M?.id===W)L(null);A()}catch(C){console.error("Failed to delete server:",C)}},u=async(W,b)=>{try{await G(`/api/mcp/servers/${W}`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:b})}),A()}catch(C){console.error("Failed to rename server:",C)}},i=async(W,b)=>{try{await G(`/api/mcp/servers/${W}`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(b)}),A()}catch(C){throw console.error("Failed to update server:",C),C}};return z.jsxDEV(z.Fragment,{children:[f,z.jsxDEV("div",{className:"flex-1 overflow-auto p-6",children:[z.jsxDEV("div",{className:"max-w-6xl",children:[z.jsxDEV("div",{className:"flex items-center justify-between mb-6",children:[z.jsxDEV("div",{children:[z.jsxDEV("h1",{className:"text-2xl font-semibold mb-1",children:"MCP Servers"},void 0,!1,void 0,this),z.jsxDEV("p",{className:"text-[var(--color-text-muted)]",children:"Manage Model Context Protocol servers for tool integrations."},void 0,!1,void 0,this)]},void 0,!0,void 0,this),Q==="servers"&&z.jsxDEV("button",{onClick:()=>F(!0),className:"bg-[var(--color-accent)] hover:bg-[var(--color-accent-hover)] text-black px-4 py-2 rounded font-medium transition",children:"+ Add Server"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),z.jsxDEV("div",{className:"flex gap-1 mb-6 bg-[var(--color-surface)] card p-1 w-fit",children:[z.jsxDEV("button",{onClick:()=>k("servers"),className:`px-4 py-2 rounded text-sm font-medium transition ${Q==="servers"?"bg-[var(--color-surface-raised)] text-white":"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]"}`,children:"My Servers"},void 0,!1,void 0,this),z.jsxDEV("button",{onClick:()=>k("hosted"),className:`px-4 py-2 rounded text-sm font-medium transition ${Q==="hosted"?"bg-[var(--color-surface-raised)] text-white":"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]"}`,children:"Hosted Services"},void 0,!1,void 0,this),z.jsxDEV("button",{onClick:()=>k("registry"),className:`px-4 py-2 rounded text-sm font-medium transition ${Q==="registry"?"bg-[var(--color-surface-raised)] text-white":"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]"}`,children:"Browse Registry"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),Q==="servers"&&z.jsxDEV(z.Fragment,{children:[X&&z.jsxDEV("div",{className:"text-center py-8 text-[var(--color-text-muted)]",children:"Loading..."},void 0,!1,void 0,this),!X&&Z.length===0&&K.length===0&&z.jsxDEV("div",{className:"bg-[var(--color-surface)] card p-8 text-center",children:[z.jsxDEV(Oz,{className:"w-12 h-12 text-[var(--color-border-light)] mx-auto mb-4"},void 0,!1,void 0,this),z.jsxDEV("h3",{className:"text-lg font-medium mb-2",children:"No MCP servers configured"},void 0,!1,void 0,this),z.jsxDEV("p",{className:"text-[var(--color-text-muted)] mb-6 max-w-md mx-auto",children:"MCP servers extend your agents with tools like file access, web browsing, database connections, and more."},void 0,!1,void 0,this),z.jsxDEV("div",{className:"flex gap-3 justify-center",children:[z.jsxDEV("button",{onClick:()=>F(!0),className:"bg-[var(--color-accent)] hover:bg-[var(--color-accent-hover)] text-black px-4 py-2 rounded font-medium transition",children:"Add Manually"},void 0,!1,void 0,this),z.jsxDEV("button",{onClick:()=>k("registry"),className:"border border-[var(--color-border-light)] hover:border-[var(--color-text-muted)] px-4 py-2 rounded font-medium transition",children:"Browse Registry"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),!X&&Z.length===0&&K.length>0&&z.jsxDEV("div",{className:"bg-[var(--color-surface)] card p-6 text-center",children:z.jsxDEV("p",{className:"text-[var(--color-text-muted)]",children:"No servers match this filter."},void 0,!1,void 0,this)},void 0,!1,void 0,this),!X&&Z.length>0&&z.jsxDEV("div",{className:"flex gap-6",children:[z.jsxDEV("div",{className:`space-y-3 ${M?"w-1/2":"w-full"}`,children:Z.map((W)=>{let C=W.type==="http"&&W.url||W.status==="running",h=Y&&W.project_id?$.find((v)=>v.id===W.project_id):null;return z.jsxDEV(Wz,{server:W,project:h,selected:M?.id===W.id,onSelect:()=>L(C?W:null),onStart:()=>S(W.id),onStop:()=>I(W.id),onDelete:()=>p(W.id),onEdit:async()=>{try{let D=await(await G(`/api/mcp/servers/${W.id}`)).json();T(D.server||W)}catch{T(W)}}},W.id,!1,void 0,this)})},void 0,!1,void 0,this),M&&z.jsxDEV("div",{className:"w-1/2",children:z.jsxDEV(Xz,{server:M,onClose:()=>L(null)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),Q==="hosted"&&z.jsxDEV(_z,{onServerAdded:A,projectId:H},void 0,!1,void 0,this),Q==="registry"&&z.jsxDEV(Zz,{onInstall:(W)=>{A(),k("servers")}},void 0,!1,void 0,this),Q==="servers"&&z.jsxDEV("div",{className:"mt-8 p-4 bg-[var(--color-surface)] card",children:[z.jsxDEV("h3",{className:"font-medium mb-2",children:"Quick Start"},void 0,!1,void 0,this),z.jsxDEV("p",{className:"text-sm text-[var(--color-text-muted)] mb-3",children:"Add an MCP server by providing its npm package name. For example:"},void 0,!1,void 0,this),z.jsxDEV("div",{className:"flex flex-wrap gap-2",children:[{name:"filesystem",pkg:"@modelcontextprotocol/server-filesystem"},{name:"fetch",pkg:"@modelcontextprotocol/server-fetch"},{name:"memory",pkg:"@modelcontextprotocol/server-memory"}].map((W)=>z.jsxDEV("code",{className:"text-xs bg-[var(--color-bg)] px-2 py-1 rounded",children:W.pkg},W.name,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),q&&z.jsxDEV(Bz,{onClose:()=>F(!1),onAdded:()=>{F(!1),A()},projects:Y?$:void 0,defaultProjectId:H&&H!=="unassigned"?H:null},void 0,!1,void 0,this),U&&z.jsxDEV(Uz,{server:U,projects:Y?$:void 0,onClose:()=>T(null),onSaved:()=>{T(null),A()}},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function Wz({server:G,project:$,selected:H,onSelect:K,onStart:w,onStop:X,onDelete:B,onEdit:q}){let F=G.type==="http"&&G.url,U=F||G.status==="running",T=()=>{if(F)return`${G.source||"remote"} • http`;return`${G.type} • ${G.package||G.command||"custom"}${G.status==="running"&&G.port?` • :${G.port}`:""}`},M=()=>{if($)return z.jsxDEV("span",{className:"text-xs px-1.5 py-0.5 rounded",style:{backgroundColor:`${$.color}20`,color:$.color},children:$.name},void 0,!1,void 0,this);if(G.project_id===null)return z.jsxDEV("span",{className:"text-xs text-[var(--color-text-muted)] bg-[var(--color-surface-raised)] px-1.5 py-0.5 rounded",children:"Global"},void 0,!1,void 0,this);return null};return z.jsxDEV("div",{className:`bg-[var(--color-surface)] border rounded-lg p-4 cursor-pointer transition ${H?"border-[var(--color-accent)]":"border-[var(--color-border)] hover:border-[var(--color-border-light)]"}`,onClick:U?K:void 0,children:z.jsxDEV("div",{className:"flex items-center justify-between",children:[z.jsxDEV("div",{className:"flex items-center gap-3",children:[z.jsxDEV("div",{className:`w-2 h-2 rounded-full ${U?"bg-green-400":"bg-[var(--color-scrollbar)]"}`},void 0,!1,void 0,this),z.jsxDEV("div",{children:[z.jsxDEV("div",{className:"flex items-center gap-2",children:[z.jsxDEV("h3",{className:"font-medium",children:G.name},void 0,!1,void 0,this),M()]},void 0,!0,void 0,this),z.jsxDEV("p",{className:"text-sm text-[var(--color-text-muted)]",children:T()},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),z.jsxDEV("div",{className:"flex items-center gap-2",children:[z.jsxDEV("button",{onClick:(L)=>{L.stopPropagation(),q()},className:"text-sm text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)] px-3 py-1 transition",title:"Edit server settings",children:"Edit"},void 0,!1,void 0,this),F?z.jsxDEV("button",{onClick:(L)=>{L.stopPropagation(),B()},className:"text-sm text-[var(--color-text-muted)] hover:text-red-400 px-3 py-1 transition",children:"Remove"},void 0,!1,void 0,this):G.status==="running"?z.jsxDEV(z.Fragment,{children:[z.jsxDEV("button",{onClick:(L)=>{L.stopPropagation(),K()},className:"text-sm text-[var(--color-accent)] hover:text-[var(--color-accent-hover)] px-3 py-1 transition",children:"Tools"},void 0,!1,void 0,this),z.jsxDEV("button",{onClick:(L)=>{L.stopPropagation(),X()},className:"text-sm text-[var(--color-text-muted)] hover:text-red-400 px-3 py-1 transition",children:"Stop"},void 0,!1,void 0,this),z.jsxDEV("button",{onClick:(L)=>{L.stopPropagation(),B()},className:"text-sm text-[var(--color-text-muted)] hover:text-red-400 px-3 py-1 transition",children:"Delete"},void 0,!1,void 0,this)]},void 0,!0,void 0,this):z.jsxDEV(z.Fragment,{children:[z.jsxDEV("button",{onClick:(L)=>{L.stopPropagation(),w()},className:"text-sm text-[var(--color-text-muted)] hover:text-green-400 px-3 py-1 transition",children:"Start"},void 0,!1,void 0,this),z.jsxDEV("button",{onClick:(L)=>{L.stopPropagation(),B()},className:"text-sm text-[var(--color-text-muted)] hover:text-red-400 px-3 py-1 transition",children:"Delete"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}function Xz({server:G,onClose:$}){let{authFetch:H}=c(),[K,w]=J.useState([]),[X,B]=J.useState(null),[q,F]=J.useState(!0),[U,T]=J.useState(null),[M,L]=J.useState(null);return J.useEffect(()=>{(async()=>{F(!0),T(null);try{let k=await H(`/api/mcp/servers/${G.id}/tools`),y=await k.json();if(!k.ok){T(y.error||"Failed to fetch tools");return}w(y.tools||[]),B(y.serverInfo||null)}catch(k){T(`Failed to fetch tools: ${k}`)}finally{F(!1)}})()},[G.id,H]),z.jsxDEV("div",{className:"bg-[var(--color-surface)] card overflow-hidden",children:[z.jsxDEV("div",{className:"p-4 border-b border-[var(--color-border)] flex items-center justify-between",children:[z.jsxDEV("div",{children:[z.jsxDEV("h3",{className:"font-medium",children:[G.name," Tools"]},void 0,!0,void 0,this),X&&z.jsxDEV("p",{className:"text-xs text-[var(--color-text-muted)]",children:[X.name," v",X.version]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),z.jsxDEV("button",{onClick:$,className:"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)] text-xl leading-none",children:"×"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),z.jsxDEV("div",{className:"p-4 max-h-[500px] overflow-auto",children:[q&&z.jsxDEV("p",{className:"text-[var(--color-text-muted)]",children:"Loading tools..."},void 0,!1,void 0,this),U&&z.jsxDEV("div",{className:"text-red-400 text-sm p-3 bg-red-500/10 rounded",children:U},void 0,!1,void 0,this),!q&&!U&&K.length===0&&z.jsxDEV("p",{className:"text-[var(--color-text-muted)]",children:"No tools available from this server."},void 0,!1,void 0,this),!q&&!U&&K.length>0&&!M&&z.jsxDEV("div",{className:"space-y-2",children:K.map((Q)=>z.jsxDEV("button",{onClick:()=>L(Q),className:"w-full text-left p-3 bg-[var(--color-bg)] hover:bg-[var(--color-surface-raised)] border border-[var(--color-border-light)] hover:border-[var(--color-border-light)] rounded transition",children:[z.jsxDEV("div",{className:"font-medium text-sm",children:Q.name},void 0,!1,void 0,this),Q.description&&z.jsxDEV("div",{className:"text-xs text-[var(--color-text-muted)] mt-1",children:Q.description},void 0,!1,void 0,this)]},Q.name,!0,void 0,this))},void 0,!1,void 0,this),M&&z.jsxDEV(Yz,{serverId:G.id,tool:M,onBack:()=>L(null)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function Yz({serverId:G,tool:$,onBack:H}){let{authFetch:K}=c(),[w,X]=J.useState("{}"),[B,q]=J.useState(null),[F,U]=J.useState(null),[T,M]=J.useState(!1);J.useEffect(()=>{let Q=$.inputSchema;if(Q&&typeof Q==="object"&&"properties"in Q){let k=Q.properties,y={};for(let[f,Y]of Object.entries(k))if(Y.default!==void 0)y[f]=Y.default;else if(Y.type==="string")y[f]="";else if(Y.type==="number"||Y.type==="integer")y[f]=0;else if(Y.type==="boolean")y[f]=!1;else if(Y.type==="array")y[f]=[];else if(Y.type==="object")y[f]={};X(JSON.stringify(y,null,2))}},[$]);let L=async()=>{M(!0),U(null),q(null);try{let Q=JSON.parse(w),k=await K(`/api/mcp/servers/${G}/tools/${encodeURIComponent($.name)}/call`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({arguments:Q})}),y=await k.json();if(!k.ok){U(y.error||"Failed to call tool");return}q(y.result)}catch(Q){U(`Error: ${Q}`)}finally{M(!1)}};return z.jsxDEV("div",{className:"space-y-4",children:[z.jsxDEV("div",{className:"flex items-center gap-2",children:[z.jsxDEV("button",{onClick:H,className:"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)] text-sm",children:"← Back"},void 0,!1,void 0,this),z.jsxDEV("span",{className:"text-[var(--color-text-faint)]",children:"/"},void 0,!1,void 0,this),z.jsxDEV("span",{className:"font-medium",children:$.name},void 0,!1,void 0,this)]},void 0,!0,void 0,this),$.description&&z.jsxDEV("p",{className:"text-sm text-[var(--color-text-muted)]",children:$.description},void 0,!1,void 0,this),$.inputSchema&&z.jsxDEV("div",{className:"text-xs",children:z.jsxDEV("details",{className:"cursor-pointer",children:[z.jsxDEV("summary",{className:"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]",children:"Input Schema"},void 0,!1,void 0,this),z.jsxDEV("pre",{className:"mt-2 p-2 bg-[var(--color-bg)] rounded text-[var(--color-text-secondary)] overflow-auto max-h-32",children:JSON.stringify($.inputSchema,null,2)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),z.jsxDEV("div",{children:[z.jsxDEV("label",{className:"block text-sm text-[var(--color-text-muted)] mb-1",children:"Arguments (JSON)"},void 0,!1,void 0,this),z.jsxDEV("textarea",{value:w,onChange:(Q)=>X(Q.target.value),className:"w-full bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-3 py-2 h-32 font-mono text-sm focus:outline-none focus:border-[var(--color-accent)] resize-none",placeholder:"{}"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),z.jsxDEV("button",{onClick:L,disabled:T,className:"w-full bg-[var(--color-accent)] hover:bg-[var(--color-accent-hover)] disabled:opacity-50 text-black px-4 py-2 rounded font-medium transition",children:T?"Calling...":"Call Tool"},void 0,!1,void 0,this),F&&z.jsxDEV("div",{className:"text-red-400 text-sm p-3 bg-red-500/10 rounded",children:F},void 0,!1,void 0,this),B&&z.jsxDEV("div",{className:"space-y-2",children:[z.jsxDEV("div",{className:"text-sm text-[var(--color-text-muted)]",children:["Result ",B.isError&&z.jsxDEV("span",{className:"text-red-400",children:"(error)"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),z.jsxDEV("div",{className:`p-3 rounded text-sm ${B.isError?"bg-red-500/10":"bg-green-500/10"}`,children:B.content.map((Q,k)=>z.jsxDEV("div",{className:"mb-2 last:mb-0",children:[Q.type==="text"&&z.jsxDEV("pre",{className:"whitespace-pre-wrap font-mono text-xs",children:Q.text},void 0,!1,void 0,this),Q.type==="image"&&Q.data&&z.jsxDEV("img",{src:`data:${Q.mimeType||"image/png"};base64,${Q.data}`,alt:"Tool result",className:"max-w-full rounded"},void 0,!1,void 0,this)]},k,!0,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function Zz({onInstall:G}){let{authFetch:$}=c(),[H,K]=J.useState(""),[w,X]=J.useState([]),[B,q]=J.useState(!1),[F,U]=J.useState(!1),[T,M]=J.useState(null),[L,Q]=J.useState(null),k=async(Y)=>{q(!0),Q(null);try{let A=await $(`/api/mcp/registry?search=${encodeURIComponent(Y)}&limit=20`),Z=await A.json();if(!A.ok)Q(Z.error||"Failed to search registry"),X([]);else X(Z.servers||[])}catch(A){Q(`Failed to search: ${A}`),X([])}finally{q(!1),U(!0)}},y=(Y)=>{if(Y.preventDefault(),H.trim())k(H.trim())};J.useEffect(()=>{k("")},[]);let f=async(Y)=>{if(!Y.npmPackage){Q("This server does not have an npm package");return}M(Y.id),Q(null);try{let A=await $("/api/mcp/servers",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:Y.name,type:"npm",package:Y.npmPackage})});if(!A.ok){let Z=await A.json();Q(Z.error||"Failed to add server");return}G(Y)}catch(A){Q(`Failed to add server: ${A}`)}finally{M(null)}};return z.jsxDEV("div",{className:"space-y-6",children:[z.jsxDEV("form",{onSubmit:y,className:"flex gap-2",children:[z.jsxDEV("input",{type:"text",value:H,onChange:(Y)=>K(Y.target.value),placeholder:"Search MCP servers (e.g., filesystem, github, slack...)",className:"flex-1 bg-[var(--color-surface)] border border-[var(--color-border-light)] rounded-lg px-4 py-3 focus:outline-none focus:border-[var(--color-accent)]"},void 0,!1,void 0,this),z.jsxDEV("button",{type:"submit",disabled:B,className:"bg-[var(--color-accent)] hover:bg-[var(--color-accent-hover)] disabled:opacity-50 text-black px-6 py-3 rounded-lg font-medium transition",children:B?"...":"Search"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),L&&z.jsxDEV("div",{className:"text-red-400 text-sm p-3 bg-red-500/10 border border-red-500/20 rounded-lg",children:L},void 0,!1,void 0,this),!B&&F&&w.length===0&&z.jsxDEV("div",{className:"text-center py-8 text-[var(--color-text-muted)]",children:"No servers found. Try a different search term."},void 0,!1,void 0,this),w.length>0&&z.jsxDEV("div",{className:"grid gap-4 md:grid-cols-2",children:w.map((Y)=>z.jsxDEV("div",{className:"bg-[var(--color-surface)] card p-4 hover:border-[var(--color-border-light)] transition",children:z.jsxDEV("div",{className:"flex items-start justify-between gap-3",children:[z.jsxDEV("div",{className:"flex-1 min-w-0",children:[z.jsxDEV("h3",{className:"font-medium truncate",children:Y.name},void 0,!1,void 0,this),z.jsxDEV("p",{className:"text-sm text-[var(--color-text-muted)] mt-1 line-clamp-2",children:Y.description||"No description"},void 0,!1,void 0,this),z.jsxDEV("div",{className:"flex items-center gap-2 mt-2 text-xs text-[var(--color-text-faint)]",children:[Y.version&&z.jsxDEV("span",{children:["v",Y.version]},void 0,!0,void 0,this),z.jsxDEV("span",{className:`px-1.5 py-0.5 rounded ${Y.npmPackage?"bg-green-500/10 text-green-400":"bg-blue-500/10 text-blue-400"}`,children:Y.npmPackage?"npm":"remote"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),z.jsxDEV("code",{className:"text-xs text-[var(--color-text-faint)] bg-[var(--color-bg)] px-2 py-0.5 rounded mt-2 inline-block truncate max-w-full",children:Y.npmPackage||Y.fullName},void 0,!1,void 0,this)]},void 0,!0,void 0,this),z.jsxDEV("div",{className:"flex-shrink-0",children:Y.npmPackage?z.jsxDEV("button",{onClick:()=>f(Y),disabled:T===Y.id,className:"text-sm bg-[var(--color-surface-raised)] hover:bg-[var(--color-surface-raised)] border border-[var(--color-border-light)] hover:border-[var(--color-accent)] px-3 py-1.5 rounded transition disabled:opacity-50",children:T===Y.id?"Adding...":"Add"},void 0,!1,void 0,this):Y.repository?z.jsxDEV("a",{href:Y.repository,target:"_blank",rel:"noopener noreferrer",className:"text-sm text-[var(--color-text-muted)] hover:text-[var(--color-accent)] transition",children:"View →"},void 0,!1,void 0,this):null},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},Y.id,!1,void 0,this))},void 0,!1,void 0,this),B&&z.jsxDEV("div",{className:"text-center py-8 text-[var(--color-text-muted)]",children:"Searching registry..."},void 0,!1,void 0,this),z.jsxDEV("div",{className:"p-4 bg-[var(--color-surface)] card text-sm text-[var(--color-text-muted)]",children:z.jsxDEV("p",{children:["Servers are sourced from the"," ",z.jsxDEV("a",{href:"https://github.com/modelcontextprotocol/servers",target:"_blank",rel:"noopener noreferrer",className:"text-[var(--color-accent)] hover:underline",children:"official MCP registry"},void 0,!1,void 0,this),". Not all servers have npm packages - some require manual setup."]},void 0,!0,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function _z({onServerAdded:G,projectId:$}){let{authFetch:H}=c(),[K,w]=J.useState("composio"),[X,B]=J.useState("configs"),[q,F]=J.useState(!1),[U,T]=J.useState(!1),[M,L]=J.useState(!1),[Q,k]=J.useState([]),[y,f]=J.useState(new Set),[Y,A]=J.useState(!0),[Z,S]=J.useState(!1),[I,p]=J.useState(null),{alert:u,AlertDialog:i}=o(),W=async()=>{try{let P=$&&$!=="unassigned"?`/api/mcp/servers?project=${encodeURIComponent($)}`:"/api/mcp/servers",[x,_]=await Promise.all([H("/api/providers"),H(P)]),R=await x.json(),g=await _.json(),V=R.providers||[],O=g.servers||[],N=new Set(O.filter((E)=>E.source==="composio"&&E.url).map((E)=>{let e=E.url.match(/\/v3\/mcp\/([^/]+)/);return e?e[1]:null}).filter(Boolean));f(N);let m=V.find((E)=>E.id==="composio"),l=V.find((E)=>E.id==="smithery"),n=V.find((E)=>E.id==="agentdojo"),d=m?.hasKey||!1,j=l?.hasKey||!1,s=n?.hasKey||!1;if(F(d),T(j),L(s),d)w("composio"),b();else if(j)w("smithery");else if(s)w("agentdojo")}catch(P){console.error("Failed to fetch providers:",P)}A(!1)},b=async()=>{S(!0);try{let P=$&&$!=="unassigned"?`?project_id=${$}`:"",_=await(await H(`/api/integrations/composio/configs${P}`)).json();k(_.configs||[])}catch(P){console.error("Failed to fetch Composio configs:",P)}S(!1)},C=async(P)=>{p(P);try{let x=$&&$!=="unassigned"?`?project_id=${$}`:"",_=await H(`/api/integrations/composio/configs/${P}/add${x}`,{method:"POST"});if(_.ok)f((R)=>new Set([...R,P])),G?.();else{let R=await _.json();await u(R.error||"Failed to add config",{title:"Error",variant:"error"})}}catch(x){console.error("Failed to add config:",x)}p(null)},h=(P)=>{return y.has(P)};if(J.useEffect(()=>{W()},[H,$]),Y)return z.jsxDEV("div",{className:"text-center py-8 text-[var(--color-text-muted)]",children:"Loading..."},void 0,!1,void 0,this);let v=q||U||M,D=[q,U,M].filter(Boolean).length;if(!v)return z.jsxDEV("div",{className:"bg-[var(--color-surface)] card p-8 text-center",children:[z.jsxDEV("p",{className:"text-[var(--color-text-secondary)] mb-2",children:"No hosted MCP services connected"},void 0,!1,void 0,this),z.jsxDEV("p",{className:"text-sm text-[var(--color-text-muted)] mb-4",children:"Connect Composio, Smithery, or AgentDojo in Settings to access cloud-based MCP servers."},void 0,!1,void 0,this),z.jsxDEV("a",{href:"/settings",className:"inline-block bg-[var(--color-surface-raised)] hover:bg-[var(--color-surface-raised)] border border-[var(--color-border-light)] hover:border-[var(--color-accent)] px-4 py-2 rounded text-sm font-medium transition",children:"Go to Settings →"},void 0,!1,void 0,this)]},void 0,!0,void 0,this);return z.jsxDEV(z.Fragment,{children:[i,z.jsxDEV("div",{className:"space-y-6",children:[D>1&&z.jsxDEV("div",{className:"flex gap-1 bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded-lg p-1 w-fit",children:[q&&z.jsxDEV("button",{onClick:()=>{w("composio"),B("configs")},className:`px-4 py-2 rounded text-sm font-medium transition flex items-center gap-2 ${K==="composio"?"bg-[var(--color-surface-raised)] text-white":"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]"}`,children:[z.jsxDEV("span",{className:"w-2 h-2 rounded-full bg-purple-500"},void 0,!1,void 0,this),"Composio"]},void 0,!0,void 0,this),U&&z.jsxDEV("button",{onClick:()=>w("smithery"),className:`px-4 py-2 rounded text-sm font-medium transition flex items-center gap-2 ${K==="smithery"?"bg-[var(--color-surface-raised)] text-white":"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]"}`,children:[z.jsxDEV("span",{className:"w-2 h-2 rounded-full bg-blue-500"},void 0,!1,void 0,this),"Smithery"]},void 0,!0,void 0,this),M&&z.jsxDEV("button",{onClick:()=>w("agentdojo"),className:`px-4 py-2 rounded text-sm font-medium transition flex items-center gap-2 ${K==="agentdojo"?"bg-[var(--color-surface-raised)] text-white":"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]"}`,children:[z.jsxDEV("span",{className:"w-2 h-2 rounded-full bg-green-500"},void 0,!1,void 0,this),"AgentDojo"]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),q&&(D===1||K==="composio")&&z.jsxDEV(z.Fragment,{children:[z.jsxDEV("div",{className:"flex items-center justify-between",children:[z.jsxDEV("div",{className:"flex gap-1 bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded-lg p-1",children:[z.jsxDEV("button",{onClick:()=>B("configs"),className:`px-4 py-2 rounded text-sm font-medium transition ${X==="configs"?"bg-[var(--color-surface-raised)] text-white":"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]"}`,children:"MCP Configs"},void 0,!1,void 0,this),z.jsxDEV("button",{onClick:()=>B("connect"),className:`px-4 py-2 rounded text-sm font-medium transition ${X==="connect"?"bg-[var(--color-surface-raised)] text-white":"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]"}`,children:"Connect Apps"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),D===1&&z.jsxDEV("div",{className:"flex items-center gap-2 text-xs text-[var(--color-text-muted)]",children:[z.jsxDEV("span",{className:"w-2 h-2 rounded-full bg-purple-500"},void 0,!1,void 0,this),"Composio",z.jsxDEV("span",{className:"text-green-400",children:"Connected"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),X==="connect"&&z.jsxDEV("div",{children:[z.jsxDEV("p",{className:"text-sm text-[var(--color-text-muted)] mb-4",children:"Connect your accounts to enable tools in MCP configs"},void 0,!1,void 0,this),z.jsxDEV(r,{providerId:"composio",projectId:$,onConnectionComplete:()=>{b()}},void 0,!1,void 0,this)]},void 0,!0,void 0,this),X==="configs"&&z.jsxDEV("div",{children:[z.jsxDEV("div",{className:"flex items-center justify-between mb-3",children:[z.jsxDEV("p",{className:"text-sm text-[var(--color-text-muted)]",children:"Your MCP configs from Composio"},void 0,!1,void 0,this),z.jsxDEV("div",{className:"flex items-center gap-3",children:[z.jsxDEV("button",{onClick:b,disabled:Z,className:"text-xs text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)] transition",children:Z?"Loading...":"Refresh"},void 0,!1,void 0,this),z.jsxDEV("a",{href:"https://app.composio.dev/mcp_configs",target:"_blank",rel:"noopener noreferrer",className:"text-xs text-[var(--color-text-muted)] hover:text-[var(--color-accent)] transition",children:"Create Config →"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),Z?z.jsxDEV("div",{className:"text-center py-6 text-[var(--color-text-muted)]",children:"Loading configs..."},void 0,!1,void 0,this):Q.length===0?z.jsxDEV("div",{className:"bg-[var(--color-surface)] card p-4 text-center",children:[z.jsxDEV("p",{className:"text-sm text-[var(--color-text-muted)]",children:"No MCP configs found"},void 0,!1,void 0,this),z.jsxDEV("p",{className:"text-xs text-[var(--color-text-faint)] mt-2",children:["First ",z.jsxDEV("button",{onClick:()=>B("connect"),className:"text-[var(--color-accent)] hover:text-[var(--color-accent-hover)]",children:"connect some apps"},void 0,!1,void 0,this),", then create a config."]},void 0,!0,void 0,this),z.jsxDEV("a",{href:"https://app.composio.dev/mcp_configs",target:"_blank",rel:"noopener noreferrer",className:"text-xs text-[var(--color-accent)] hover:text-[var(--color-accent-hover)] mt-2 inline-block",children:"Create in Composio →"},void 0,!1,void 0,this)]},void 0,!0,void 0,this):z.jsxDEV("div",{className:"space-y-2",children:Q.map((P)=>{let x=h(P.id),_=I===P.id;return z.jsxDEV("div",{className:`bg-[var(--color-surface)] border rounded-lg p-3 transition flex items-center justify-between ${x?"border-green-500/30":"border-[var(--color-border)] hover:border-[var(--color-border-light)]"}`,children:[z.jsxDEV("div",{className:"flex-1 min-w-0",children:[z.jsxDEV("div",{className:"flex items-center gap-2",children:[z.jsxDEV("span",{className:"font-medium text-sm",children:P.name},void 0,!1,void 0,this),z.jsxDEV("span",{className:"text-xs text-[var(--color-text-faint)]",children:[P.toolsCount," tools"]},void 0,!0,void 0,this),x&&z.jsxDEV("span",{className:"text-xs text-green-400",children:"Added"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),P.toolkits.length>0&&z.jsxDEV("div",{className:"flex flex-wrap gap-1 mt-1",children:[P.toolkits.slice(0,4).map((R)=>z.jsxDEV("span",{className:"text-xs bg-[var(--color-surface-raised)] text-[var(--color-text-muted)] px-1.5 py-0.5 rounded",children:R},R,!1,void 0,this)),P.toolkits.length>4&&z.jsxDEV("span",{className:"text-xs text-[var(--color-text-faint)]",children:["+",P.toolkits.length-4]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),z.jsxDEV("div",{className:"flex items-center gap-2 ml-3",children:[x?z.jsxDEV("span",{className:"text-xs text-[var(--color-text-faint)] px-2 py-1",children:"In Servers"},void 0,!1,void 0,this):z.jsxDEV("button",{onClick:()=>C(P.id),disabled:_,className:"text-xs bg-[var(--color-accent)] hover:bg-[var(--color-accent-hover)] text-black px-3 py-1 rounded font-medium transition disabled:opacity-50",children:_?"Adding...":"Add"},void 0,!1,void 0,this),z.jsxDEV("a",{href:`https://app.composio.dev/mcp_configs/${P.id}`,target:"_blank",rel:"noopener noreferrer",className:"text-xs text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)] transition",children:"Edit"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},P.id,!0,void 0,this)})},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),U&&(D===1||K==="smithery")&&z.jsxDEV("div",{children:[D===1&&z.jsxDEV("div",{className:"flex items-center gap-2 text-xs text-[var(--color-text-muted)] mb-4",children:[z.jsxDEV("span",{className:"w-2 h-2 rounded-full bg-blue-500"},void 0,!1,void 0,this),"Smithery",z.jsxDEV("span",{className:"text-green-400",children:"Connected"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),z.jsxDEV("div",{className:"flex items-center justify-between mb-3",children:[z.jsxDEV("p",{className:"text-sm text-[var(--color-text-muted)]",children:"Add MCP servers from the Smithery registry"},void 0,!1,void 0,this),z.jsxDEV("a",{href:"https://smithery.ai/servers",target:"_blank",rel:"noopener noreferrer",className:"text-xs text-[var(--color-text-muted)] hover:text-[var(--color-accent)] transition",children:"Browse Smithery →"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),z.jsxDEV("div",{className:"bg-[var(--color-surface)] card p-4 text-center",children:[z.jsxDEV("p",{className:"text-sm text-[var(--color-text-muted)]",children:["Smithery servers can be added from the ",z.jsxDEV("strong",{children:"Browse Registry"},void 0,!1,void 0,this)," tab."]},void 0,!0,void 0,this),z.jsxDEV("p",{className:"text-xs text-[var(--color-text-faint)] mt-2",children:"Your API key will be used automatically when adding Smithery servers."},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),M&&(D===1||K==="agentdojo")&&z.jsxDEV($z,{projectId:$,onServerAdded:G,showProviderBadge:D===1},void 0,!1,void 0,this),z.jsxDEV("div",{className:"p-3 bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded text-xs text-[var(--color-text-muted)]",children:[z.jsxDEV("strong",{className:"text-[var(--color-text-secondary)]",children:"Tip:"},void 0,!1,void 0,this)," Connect apps first, then add MCP configs to make tools available to your agents."," · ",z.jsxDEV("a",{href:"/settings",className:"text-[var(--color-accent)] hover:text-[var(--color-accent-hover)]",children:"Add more providers in Settings"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function $z({projectId:G,onServerAdded:$,showProviderBadge:H}){let{authFetch:K}=c(),[w,X]=J.useState("configs"),[B,q]=J.useState([]),[F,U]=J.useState(new Set),[T,M]=J.useState(!1),[L,Q]=J.useState(null),{alert:k,AlertDialog:y}=o(),f=async()=>{M(!0);try{let Z=G&&G!=="unassigned"?`?project_id=${G}`:"",S=G&&G!=="unassigned"?`/api/mcp/servers?project=${encodeURIComponent(G)}`:"/api/mcp/servers";console.log(`[AgentDojo:fetchConfigs] projectId=${G} serversUrl=${S}`);let[I,p]=await Promise.all([K(`/api/integrations/agentdojo/configs${Z}`),K(S)]),u=await I.json(),i=await p.json();console.log(`[AgentDojo:fetchConfigs] configs=${(u.configs||[]).length} servers=${(i.servers||[]).length}`),q(u.configs||[]);let W=(i.servers||[]).filter((C)=>C.source==="agentdojo");console.log(`[AgentDojo:fetchConfigs] agentdojo servers found: ${W.length}`);for(let C of W){let h=C.url?.match(/\/mcp\/([^/?]+)/);console.log(`[AgentDojo:fetchConfigs] server: id=${C.id} name=${C.name} project_id=${C.project_id} url=${C.url?.substring(0,80)} extracted=${h?h[1]:C.name}`)}let b=new Set(W.map((C)=>{let h=C.url?.match(/\/mcp\/([^/?]+)/);return h?h[1]:C.name}));console.log("[AgentDojo:fetchConfigs] addedServers set:",[...b]),U(b)}catch(Z){console.error("Failed to fetch AgentDojo configs:",Z)}M(!1)},Y=async(Z)=>{Q(Z);try{let S=G&&G!=="unassigned"?`?project_id=${G}`:"";console.log(`[AgentDojo:addConfig] configId=${Z} projectParam=${S}`);let I=await K(`/api/integrations/agentdojo/configs/${Z}/add${S}`,{method:"POST"}),p=await I.json();if(console.log(`[AgentDojo:addConfig] response status=${I.status} ok=${I.ok} message=${p.message} server.id=${p.server?.id} server.project_id=${p.server?.project_id}`),I.ok){let u=B.find((W)=>W.id===Z),i=u?.slug||Z;console.log(`[AgentDojo:addConfig] marking as added: key=${i} config.slug=${u?.slug} config.id=${u?.id} config.name=${u?.name}`),U((W)=>new Set([...W,i])),$?.()}else await k(p.error||"Failed to add config",{title:"Error",variant:"error"})}catch(S){console.error("Failed to add config:",S)}Q(null)},A=(Z)=>{return F.has(Z.slug)||F.has(Z.id)||F.has(Z.name)};return J.useEffect(()=>{f()},[K,G]),z.jsxDEV(z.Fragment,{children:[y,z.jsxDEV("div",{children:[H&&z.jsxDEV("div",{className:"flex items-center gap-2 text-xs text-[var(--color-text-muted)] mb-4",children:[z.jsxDEV("span",{className:"w-2 h-2 rounded-full bg-green-500"},void 0,!1,void 0,this),"AgentDojo",z.jsxDEV("span",{className:"text-green-400",children:"Connected"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),z.jsxDEV("div",{className:"flex items-center justify-between mb-4",children:z.jsxDEV("div",{className:"flex gap-1 bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded-lg p-1",children:[z.jsxDEV("button",{onClick:()=>X("configs"),className:`px-4 py-2 rounded text-sm font-medium transition ${w==="configs"?"bg-[var(--color-surface-raised)] text-white":"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]"}`,children:"MCP Servers"},void 0,!1,void 0,this),z.jsxDEV("button",{onClick:()=>X("toolkits"),className:`px-4 py-2 rounded text-sm font-medium transition ${w==="toolkits"?"bg-[var(--color-surface-raised)] text-white":"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]"}`,children:"Browse Toolkits"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),w==="configs"&&z.jsxDEV("div",{children:[z.jsxDEV("div",{className:"flex items-center justify-between mb-3",children:[z.jsxDEV("p",{className:"text-sm text-[var(--color-text-muted)]",children:"Your MCP servers from AgentDojo"},void 0,!1,void 0,this),z.jsxDEV("button",{onClick:f,disabled:T,className:"text-xs text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)] transition",children:T?"Loading...":"Refresh"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),T?z.jsxDEV("div",{className:"text-center py-6 text-[var(--color-text-muted)]",children:"Loading servers..."},void 0,!1,void 0,this):B.length===0?z.jsxDEV("div",{className:"bg-[var(--color-surface)] card p-4 text-center",children:[z.jsxDEV("p",{className:"text-sm text-[var(--color-text-muted)]",children:"No MCP servers found"},void 0,!1,void 0,this),z.jsxDEV("p",{className:"text-xs text-[var(--color-text-faint)] mt-2",children:[z.jsxDEV("button",{onClick:()=>X("toolkits"),className:"text-[var(--color-accent)] hover:text-[var(--color-accent-hover)]",children:"Browse toolkits"},void 0,!1,void 0,this)," ","to create a new MCP server."]},void 0,!0,void 0,this)]},void 0,!0,void 0,this):z.jsxDEV("div",{className:"space-y-2",children:B.map((Z)=>{let S=A(Z),I=L===Z.id;return z.jsxDEV("div",{className:`bg-[var(--color-surface)] border rounded-lg p-3 transition flex items-center justify-between ${S?"border-green-500/30":"border-[var(--color-border)] hover:border-[var(--color-border-light)]"}`,children:[z.jsxDEV("div",{className:"flex-1 min-w-0",children:[z.jsxDEV("div",{className:"flex items-center gap-2",children:[z.jsxDEV("span",{className:"font-medium text-sm",children:Z.name},void 0,!1,void 0,this),z.jsxDEV("span",{className:"text-xs text-[var(--color-text-faint)]",children:[Z.toolsCount," tools"]},void 0,!0,void 0,this),S&&z.jsxDEV("span",{className:"text-xs text-green-400",children:"Added"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),Z.mcpUrl&&z.jsxDEV("code",{className:"text-xs text-[var(--color-text-faint)] mt-1 block truncate",children:Z.mcpUrl},void 0,!1,void 0,this),!Z.mcpUrl&&Z.slug&&z.jsxDEV("code",{className:"text-xs text-[var(--color-text-faint)] mt-1 block truncate",children:Z.slug},void 0,!1,void 0,this)]},void 0,!0,void 0,this),z.jsxDEV("div",{className:"flex items-center gap-2 ml-3",children:S?z.jsxDEV("span",{className:"text-xs text-[var(--color-text-faint)] px-2 py-1",children:"In Servers"},void 0,!1,void 0,this):z.jsxDEV("button",{onClick:()=>Y(Z.id),disabled:I,className:"text-xs bg-[var(--color-accent)] hover:bg-[var(--color-accent-hover)] text-black px-3 py-1 rounded font-medium transition disabled:opacity-50",children:I?"Adding...":"Add"},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},Z.id,!0,void 0,this)})},void 0,!1,void 0,this)]},void 0,!0,void 0,this),w==="toolkits"&&z.jsxDEV("div",{children:[z.jsxDEV("p",{className:"text-sm text-[var(--color-text-muted)] mb-4",children:"Browse available toolkits and create MCP servers"},void 0,!1,void 0,this),z.jsxDEV(r,{providerId:"agentdojo",projectId:G,onConnectionComplete:()=>{f()}},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function qz(G){let $=[],H=G,K=null,w=G.match(/(?:npx\s+-y\s+)?(@?[\w-]+\/)?(@?[\w-]+)(?:@[\w.-]+)?/);if(w){let q=w[2]||w[1];if(q)K=q.replace(/^@/,"").replace(/-mcp$/,"").replace(/-server$/,"").replace(/^server-/,"").replace(/^mcp-/,"")}let X=/--(\w+[-\w]*)\s+(YOUR_\w+|<[\w_]+>|\{[\w_]+\}|\$[\w_]+|[\w_]*(?:TOKEN|KEY|SECRET|PASSWORD|USER|ID|APIKEY)[\w_]*)/gi,B;while((B=X.exec(G))!==null){let q=B[1],F=B[2],U=q.toUpperCase().replace(/-/g,"_"),T=K?`${K.toUpperCase().replace(/-/g,"_")}_${U}`:U;$.push({key:T,flag:q}),H=H.replace(new RegExp(`(--${q}\\s+)${F.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}`,"i"),`--${q} $${T}`)}return{cleanCommand:H,credentials:$,serverName:K}}function Bz({onClose:G,onAdded:$,projects:H,defaultProjectId:K}){let{authFetch:w}=c(),[X,B]=J.useState("npm"),[q,F]=J.useState(""),[U,T]=J.useState(""),[M,L]=J.useState(""),[Q,k]=J.useState(""),[y,f]=J.useState(""),[Y,A]=J.useState(""),[Z,S]=J.useState(""),[I,p]=J.useState([]),[u,i]=J.useState(K||null),[W,b]=J.useState(!1),[C,h]=J.useState(null),v=H&&H.length>0,D=()=>{p([...I,{key:"",value:""}])},P=(O,N,m)=>{let l=[...I];l[O][N]=m,p(l)},x=(O)=>{p(I.filter((N,m)=>m!==O))},_=(O)=>{if(k(O),O.includes("YOUR_")||O.includes("<")||O.includes("{")||/TOKEN|KEY|SECRET|PASSWORD/i.test(O)){let{cleanCommand:N,credentials:m,serverName:l}=qz(O);if(!q&&l)F(l);if(m.length>0){let n=new Set(I.map((j)=>j.key)),d=m.filter((j)=>!n.has(j.key)).map((j)=>({key:j.key,value:""}));if(d.length>0)p([...I,...d]),k(N)}}},R=(O)=>{if(O.startsWith("npx ")||O.includes(" --")||O.includes("YOUR_")||O.includes("<")||/\s+(TOKEN|KEY|SECRET|PASSWORD)/i.test(O))B("command"),_(O);else if(T(O),!q&&O){let m=O.replace(/^@[\w-]+\//,"").replace(/@[\w.-]+$/,"").replace(/^server-/,"").replace(/-server$/,"").replace(/^mcp-/,"").replace(/-mcp$/,"");if(m&&m!==O)F(m)}},g=async()=>{if(!q){h("Name is required");return}if(X==="npm"&&!U){h("npm package is required");return}if(X==="pip"&&!U){h("pip package is required");return}if(X==="command"&&!Q){h("Command is required");return}if(X==="http"&&!y){h("URL is required");return}b(!0),h(null);let O={};for(let{key:N,value:m}of I)if(N.trim())O[N.trim()]=m;try{let N={name:q};if(X==="npm")N.type="npm",N.package=U;else if(X==="pip"){if(N.type="pip",N.package=U,M)N.pip_module=M}else if(X==="http"){N.type="http",N.url=y;let l={"Content-Type":"application/json"};if(Y&&Z){let n=btoa(`${Y}:${Z}`);l.Authorization=`Basic ${n}`}N.headers=l}else{let l=Q.trim().split(/\s+/);N.type="custom",N.command=l[0],N.args=l.slice(1).join(" ")}if(Object.keys(O).length>0)N.env=O;if(u)N.project_id=u;let m=await w("/api/mcp/servers",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(N)});if(!m.ok){let l=await m.json();h(l.error||"Failed to add server"),b(!1);return}$()}catch(N){h("Failed to add server"),b(!1)}},V=(O,N)=>{B("npm"),F(O),T(N)};return z.jsxDEV("div",{className:"fixed inset-0 bg-black/50 backdrop-blur-[2px] z-50 flex items-center justify-center p-4",children:z.jsxDEV("div",{className:"bg-[var(--color-surface)] card w-full max-w-lg max-h-[90vh] overflow-y-auto",children:[z.jsxDEV("div",{className:"p-4 border-b border-[var(--color-border)] flex items-center justify-between sticky top-0 bg-[var(--color-surface)]",children:[z.jsxDEV("h2",{className:"text-lg font-semibold",children:"Add MCP Server"},void 0,!1,void 0,this),z.jsxDEV("button",{onClick:G,className:"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]",children:"✕"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),z.jsxDEV("div",{className:"p-4 space-y-4",children:[z.jsxDEV("div",{children:[z.jsxDEV("p",{className:"text-sm text-[var(--color-text-muted)] mb-2",children:"Quick add:"},void 0,!1,void 0,this),z.jsxDEV("div",{className:"flex flex-wrap gap-2",children:[{name:"filesystem",pkg:"@modelcontextprotocol/server-filesystem",type:"npm"},{name:"fetch",pkg:"@modelcontextprotocol/server-fetch",type:"npm"},{name:"memory",pkg:"@modelcontextprotocol/server-memory",type:"npm"},{name:"github",pkg:"@modelcontextprotocol/server-github",type:"npm"},{name:"time",pkg:"mcp-server-time",module:"mcp_server_time",type:"pip"}].map((O)=>z.jsxDEV("button",{onClick:()=>{if(B(O.type),F(O.name),T(O.pkg),O.type==="pip"&&"module"in O)L(O.module||"");else L("")},className:"text-sm bg-[var(--color-surface-raised)] hover:bg-[var(--color-surface-raised)] px-3 py-1 rounded transition",children:O.name},O.name,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),z.jsxDEV("div",{className:"flex gap-1 bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded p-1",children:[z.jsxDEV("button",{onClick:()=>B("npm"),className:`flex-1 px-2 py-1.5 rounded text-sm transition ${X==="npm"?"bg-[var(--color-surface-raised)] text-white":"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]"}`,children:"npm"},void 0,!1,void 0,this),z.jsxDEV("button",{onClick:()=>B("pip"),className:`flex-1 px-2 py-1.5 rounded text-sm transition ${X==="pip"?"bg-[var(--color-surface-raised)] text-white":"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]"}`,children:"pip"},void 0,!1,void 0,this),z.jsxDEV("button",{onClick:()=>B("command"),className:`flex-1 px-2 py-1.5 rounded text-sm transition ${X==="command"?"bg-[var(--color-surface-raised)] text-white":"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]"}`,children:"Command"},void 0,!1,void 0,this),z.jsxDEV("button",{onClick:()=>B("http"),className:`flex-1 px-2 py-1.5 rounded text-sm transition ${X==="http"?"bg-[var(--color-surface-raised)] text-white":"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]"}`,children:"HTTP"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),z.jsxDEV("div",{children:[z.jsxDEV("label",{className:"block text-sm text-[var(--color-text-muted)] mb-1",children:"Name"},void 0,!1,void 0,this),z.jsxDEV("input",{type:"text",value:q,onChange:(O)=>F(O.target.value),placeholder:"e.g., pushover",className:"w-full bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-3 py-2 focus:outline-none focus:border-[var(--color-accent)]"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),v&&z.jsxDEV("div",{children:[z.jsxDEV("label",{className:"block text-sm text-[var(--color-text-muted)] mb-1",children:"Scope"},void 0,!1,void 0,this),z.jsxDEV(t,{value:u||"",onChange:(O)=>i(O||null),options:[{value:"",label:"Global (all projects)"},...H.map((O)=>({value:O.id,label:O.name}))],placeholder:"Select scope..."},void 0,!1,void 0,this),z.jsxDEV("p",{className:"text-xs text-[var(--color-text-faint)] mt-1",children:"Global servers are available to all agents. Project-scoped servers are only available to agents in that project."},void 0,!1,void 0,this)]},void 0,!0,void 0,this),X==="npm"&&z.jsxDEV("div",{children:[z.jsxDEV("label",{className:"block text-sm text-[var(--color-text-muted)] mb-1",children:"npm Package"},void 0,!1,void 0,this),z.jsxDEV("input",{type:"text",value:U,onChange:(O)=>R(O.target.value),placeholder:"e.g., @modelcontextprotocol/server-filesystem or paste full command",className:"w-full bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-3 py-2 focus:outline-none focus:border-[var(--color-accent)]"},void 0,!1,void 0,this),z.jsxDEV("p",{className:"text-xs text-[var(--color-text-faint)] mt-1",children:"Package name or paste a full npx command with credentials"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),X==="pip"&&z.jsxDEV("div",{className:"space-y-4",children:[z.jsxDEV("div",{children:[z.jsxDEV("label",{className:"block text-sm text-[var(--color-text-muted)] mb-1",children:"pip Package"},void 0,!1,void 0,this),z.jsxDEV("input",{type:"text",value:U,onChange:(O)=>{if(T(O.target.value),!M&&O.target.value){let N=O.target.value.split("[")[0].replace(/-/g,".");L(N)}},placeholder:"e.g., late-sdk[mcp]",className:"w-full bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-3 py-2 focus:outline-none focus:border-[var(--color-accent)]"},void 0,!1,void 0,this),z.jsxDEV("p",{className:"text-xs text-[var(--color-text-faint)] mt-1",children:"Python package with extras, e.g., late-sdk[mcp] or mcp-server-time"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),z.jsxDEV("div",{children:[z.jsxDEV("label",{className:"block text-sm text-[var(--color-text-muted)] mb-1",children:"Module (optional)"},void 0,!1,void 0,this),z.jsxDEV("input",{type:"text",value:M,onChange:(O)=>L(O.target.value),placeholder:"e.g., late.mcp",className:"w-full bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-3 py-2 font-mono text-sm focus:outline-none focus:border-[var(--color-accent)]"},void 0,!1,void 0,this),z.jsxDEV("p",{className:"text-xs text-[var(--color-text-faint)] mt-1",children:"Python module to run with -m. Auto-detected from package name if not specified."},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),X==="command"&&z.jsxDEV("div",{children:[z.jsxDEV("label",{className:"block text-sm text-[var(--color-text-muted)] mb-1",children:"Command"},void 0,!1,void 0,this),z.jsxDEV("input",{type:"text",value:Q,onChange:(O)=>_(O.target.value),placeholder:"e.g., npx -y pushover-mcp@latest start --token YOUR_TOKEN",className:"w-full bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-3 py-2 font-mono text-sm focus:outline-none focus:border-[var(--color-accent)]"},void 0,!1,void 0,this),z.jsxDEV("p",{className:"text-xs text-[var(--color-text-faint)] mt-1",children:"Paste the full command - credentials like YOUR_TOKEN will be auto-extracted"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),X==="http"&&z.jsxDEV("div",{className:"space-y-4",children:[z.jsxDEV("div",{children:[z.jsxDEV("label",{className:"block text-sm text-[var(--color-text-muted)] mb-1",children:"URL"},void 0,!1,void 0,this),z.jsxDEV("input",{type:"text",value:y,onChange:(O)=>f(O.target.value),placeholder:"e.g., https://example.com/wp-json/mcp/v1/messages",className:"w-full bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-3 py-2 font-mono text-sm focus:outline-none focus:border-[var(--color-accent)]"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),z.jsxDEV("div",{className:"p-3 bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded",children:[z.jsxDEV("p",{className:"text-xs text-[var(--color-text-muted)] mb-3",children:"Optional: Basic Auth credentials (will be encoded and stored securely)"},void 0,!1,void 0,this),z.jsxDEV("div",{className:"grid grid-cols-2 gap-3",children:[z.jsxDEV("div",{children:[z.jsxDEV("label",{className:"block text-xs text-[var(--color-text-faint)] mb-1",children:"Username"},void 0,!1,void 0,this),z.jsxDEV("input",{type:"text",value:Y,onChange:(O)=>A(O.target.value),placeholder:"username",className:"w-full bg-[var(--color-surface)] border border-[var(--color-border-light)] rounded px-3 py-2 text-sm focus:outline-none focus:border-[var(--color-accent)]"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),z.jsxDEV("div",{children:[z.jsxDEV("label",{className:"block text-xs text-[var(--color-text-faint)] mb-1",children:"Password"},void 0,!1,void 0,this),z.jsxDEV("input",{type:"password",value:Z,onChange:(O)=>S(O.target.value),placeholder:"password or app key",className:"w-full bg-[var(--color-surface)] border border-[var(--color-border-light)] rounded px-3 py-2 text-sm focus:outline-none focus:border-[var(--color-accent)]"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),z.jsxDEV("div",{children:[z.jsxDEV("div",{className:"flex items-center justify-between mb-2",children:[z.jsxDEV("label",{className:"text-sm text-[var(--color-text-muted)]",children:"Environment Variables / Credentials"},void 0,!1,void 0,this),z.jsxDEV("button",{onClick:D,className:"text-xs text-[var(--color-accent)] hover:text-[var(--color-accent-hover)] transition",children:"+ Add Variable"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),I.length===0&&z.jsxDEV("p",{className:"text-xs text-[var(--color-text-faint)] bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded p-3",children:"Add environment variables for API tokens and credentials. These are stored encrypted and passed to the server at startup."},void 0,!1,void 0,this),I.length>0&&z.jsxDEV("div",{className:"space-y-2",children:I.map((O,N)=>z.jsxDEV("div",{className:"flex gap-2",children:[z.jsxDEV("input",{type:"text",value:O.key,onChange:(m)=>P(N,"key",m.target.value),placeholder:"KEY",className:"w-1/3 bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-2 py-1.5 text-sm font-mono focus:outline-none focus:border-[var(--color-accent)]"},void 0,!1,void 0,this),z.jsxDEV("input",{type:"password",value:O.value,onChange:(m)=>P(N,"value",m.target.value),placeholder:"value",className:"flex-1 bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-2 py-1.5 text-sm font-mono focus:outline-none focus:border-[var(--color-accent)]"},void 0,!1,void 0,this),z.jsxDEV("button",{onClick:()=>x(N),className:"text-[var(--color-text-muted)] hover:text-red-400 px-2 transition",children:"✕"},void 0,!1,void 0,this)]},N,!0,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),C&&z.jsxDEV("p",{className:"text-red-400 text-sm",children:C},void 0,!1,void 0,this)]},void 0,!0,void 0,this),z.jsxDEV("div",{className:"p-4 border-t border-[var(--color-border)] flex justify-end gap-2 sticky bottom-0 bg-[var(--color-surface)]",children:[z.jsxDEV("button",{onClick:G,className:"px-4 py-2 border border-[var(--color-border-light)] hover:border-[var(--color-text-muted)] rounded transition",children:"Cancel"},void 0,!1,void 0,this),z.jsxDEV("button",{onClick:g,disabled:W||!q||(X==="npm"?!U:X==="pip"?!U:X==="http"?!y:!Q),className:"px-4 py-2 bg-[var(--color-accent)] hover:bg-[var(--color-accent-hover)] text-black rounded font-medium transition disabled:opacity-50",children:W?"Adding...":"Add Server"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}function Uz({server:G,projects:$,onClose:H,onSaved:K}){let{authFetch:w}=c(),[X,B]=J.useState(G.name),[q,F]=J.useState(G.package||""),[U,T]=J.useState(G.command||""),[M,L]=J.useState(G.args||""),[Q,k]=J.useState(G.url||""),[y,f]=J.useState(()=>{let _=G.headers?.Authorization||"";if(_.startsWith("Basic "))try{return atob(_.slice(6)).split(":")[0]||""}catch{return""}return""}),[Y,A]=J.useState(()=>{let _=G.headers?.Authorization||"";if(_.startsWith("Basic "))try{return atob(_.slice(6)).split(":").slice(1).join(":")||""}catch{return""}return""}),[Z,S]=J.useState(()=>{return Object.entries(G.env||{}).map(([_,R])=>({key:_,value:R}))}),[I,p]=J.useState(G.project_id),[u,i]=J.useState(!1),[W,b]=J.useState(null),C=$&&$.length>0,h=G.type==="http",v=()=>{S([...Z,{key:"",value:""}])},D=(_,R,g)=>{let V=[...Z];V[_][R]=g,S(V)},P=(_)=>{S(Z.filter((R,g)=>g!==_))},x=async()=>{if(!X.trim()){b("Name is required");return}i(!0),b(null);let _={};for(let{key:R,value:g}of Z)if(R.trim())_[R.trim()]=g;try{let R={name:X.trim(),env:_};if(h){if(Q.trim())R.url=Q.trim();let V={"Content-Type":"application/json"};if(y&&Y){let O=btoa(`${y}:${Y}`);V.Authorization=`Basic ${O}`}R.headers=V}else{if(G.type==="npm"&&q.trim())R.package=q.trim();if(G.type==="pip"&&q.trim())R.package=q.trim();if(G.type==="custom"){if(U.trim())R.command=U.trim();if(M.trim())R.args=M.trim()}}R.project_id=I;let g=await w(`/api/mcp/servers/${G.id}`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(R)});if(!g.ok){let V=await g.json();b(V.error||"Failed to save changes"),i(!1);return}if(G.status==="running"&&!h)try{await w(`/api/mcp/servers/${G.id}/stop`,{method:"POST"}),await w(`/api/mcp/servers/${G.id}/start`,{method:"POST"})}catch(V){console.error("Failed to restart server:",V)}K()}catch(R){b("Failed to save changes"),i(!1)}};return z.jsxDEV("div",{className:"fixed inset-0 bg-black/50 backdrop-blur-[2px] z-50 flex items-center justify-center p-4",children:z.jsxDEV("div",{className:"bg-[var(--color-surface)] card w-full max-w-lg max-h-[90vh] overflow-y-auto",children:[z.jsxDEV("div",{className:"p-4 border-b border-[var(--color-border)] flex items-center justify-between sticky top-0 bg-[var(--color-surface)]",children:[z.jsxDEV("h2",{className:"text-lg font-semibold",children:"Edit MCP Server"},void 0,!1,void 0,this),z.jsxDEV("button",{onClick:H,className:"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]",children:"✕"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),z.jsxDEV("div",{className:"p-4 space-y-4",children:[z.jsxDEV("div",{className:"text-sm text-[var(--color-text-muted)] bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded p-3",children:["Type: ",z.jsxDEV("span",{className:"text-[var(--color-text-secondary)]",children:G.type},void 0,!1,void 0,this),G.package&&z.jsxDEV(z.Fragment,{children:[" • Package: ",z.jsxDEV("span",{className:"text-[var(--color-text-secondary)] font-mono",children:G.package},void 0,!1,void 0,this)]},void 0,!0,void 0,this),G.command&&z.jsxDEV(z.Fragment,{children:[" • Command: ",z.jsxDEV("span",{className:"text-[var(--color-text-secondary)] font-mono",children:G.command},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),z.jsxDEV("div",{children:[z.jsxDEV("label",{className:"block text-sm text-[var(--color-text-muted)] mb-1",children:"Name"},void 0,!1,void 0,this),z.jsxDEV("input",{type:"text",value:X,onChange:(_)=>B(_.target.value),className:"w-full bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-3 py-2 focus:outline-none focus:border-[var(--color-accent)]"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),C&&z.jsxDEV("div",{children:[z.jsxDEV("label",{className:"block text-sm text-[var(--color-text-muted)] mb-1",children:"Scope"},void 0,!1,void 0,this),z.jsxDEV(t,{value:I||"",onChange:(_)=>p(_||null),options:[{value:"",label:"Global (all projects)"},...$.map((_)=>({value:_.id,label:_.name}))],placeholder:"Select scope..."},void 0,!1,void 0,this)]},void 0,!0,void 0,this),G.type==="npm"&&z.jsxDEV("div",{children:[z.jsxDEV("label",{className:"block text-sm text-[var(--color-text-muted)] mb-1",children:"npm Package"},void 0,!1,void 0,this),z.jsxDEV("input",{type:"text",value:q,onChange:(_)=>F(_.target.value),className:"w-full bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-3 py-2 font-mono text-sm focus:outline-none focus:border-[var(--color-accent)]"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),G.type==="pip"&&z.jsxDEV("div",{children:[z.jsxDEV("label",{className:"block text-sm text-[var(--color-text-muted)] mb-1",children:"pip Package"},void 0,!1,void 0,this),z.jsxDEV("input",{type:"text",value:q,onChange:(_)=>F(_.target.value),className:"w-full bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-3 py-2 font-mono text-sm focus:outline-none focus:border-[var(--color-accent)]"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),h&&z.jsxDEV(z.Fragment,{children:[z.jsxDEV("div",{children:[z.jsxDEV("label",{className:"block text-sm text-[var(--color-text-muted)] mb-1",children:"Server URL"},void 0,!1,void 0,this),z.jsxDEV("input",{type:"text",value:Q,onChange:(_)=>k(_.target.value),placeholder:"https://example.com/mcp",className:"w-full bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-3 py-2 font-mono text-sm focus:outline-none focus:border-[var(--color-accent)]"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),z.jsxDEV("div",{children:[z.jsxDEV("label",{className:"block text-sm text-[var(--color-text-muted)] mb-1",children:"Authentication (Basic Auth)"},void 0,!1,void 0,this),z.jsxDEV("div",{className:"flex gap-2",children:[z.jsxDEV("input",{type:"text",value:y,onChange:(_)=>f(_.target.value),placeholder:"Username",className:"flex-1 bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-3 py-2 text-sm focus:outline-none focus:border-[var(--color-accent)]"},void 0,!1,void 0,this),z.jsxDEV("input",{type:"password",value:Y,onChange:(_)=>A(_.target.value),placeholder:"Password / App Password",className:"flex-1 bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-3 py-2 text-sm focus:outline-none focus:border-[var(--color-accent)]"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),z.jsxDEV("p",{className:"text-xs text-[var(--color-text-faint)] mt-1",children:"Leave empty if no authentication required"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),G.type==="custom"&&z.jsxDEV(z.Fragment,{children:[z.jsxDEV("div",{children:[z.jsxDEV("label",{className:"block text-sm text-[var(--color-text-muted)] mb-1",children:"Command"},void 0,!1,void 0,this),z.jsxDEV("input",{type:"text",value:U,onChange:(_)=>T(_.target.value),className:"w-full bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-3 py-2 font-mono text-sm focus:outline-none focus:border-[var(--color-accent)]"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),z.jsxDEV("div",{children:[z.jsxDEV("label",{className:"block text-sm text-[var(--color-text-muted)] mb-1",children:"Arguments"},void 0,!1,void 0,this),z.jsxDEV("input",{type:"text",value:M,onChange:(_)=>L(_.target.value),placeholder:"e.g., --token $TOKEN --verbose",className:"w-full bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-3 py-2 font-mono text-sm focus:outline-none focus:border-[var(--color-accent)]"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),!h&&z.jsxDEV("div",{children:[z.jsxDEV("div",{className:"flex items-center justify-between mb-2",children:[z.jsxDEV("label",{className:"text-sm text-[var(--color-text-muted)]",children:"Environment Variables / Credentials"},void 0,!1,void 0,this),z.jsxDEV("button",{onClick:v,className:"text-xs text-[var(--color-accent)] hover:text-[var(--color-accent-hover)] transition",children:"+ Add Variable"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),Z.length===0&&z.jsxDEV("p",{className:"text-xs text-[var(--color-text-faint)] bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded p-3",children:"No environment variables configured."},void 0,!1,void 0,this),Z.length>0&&z.jsxDEV("div",{className:"space-y-2",children:Z.map((_,R)=>z.jsxDEV("div",{className:"flex gap-2",children:[z.jsxDEV("input",{type:"text",value:_.key,onChange:(g)=>D(R,"key",g.target.value),placeholder:"KEY",className:"w-1/3 bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-2 py-1.5 text-sm font-mono focus:outline-none focus:border-[var(--color-accent)]"},void 0,!1,void 0,this),z.jsxDEV("input",{type:"password",value:_.value,onChange:(g)=>D(R,"value",g.target.value),placeholder:"value",className:"flex-1 bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-2 py-1.5 text-sm font-mono focus:outline-none focus:border-[var(--color-accent)]"},void 0,!1,void 0,this),z.jsxDEV("button",{onClick:()=>P(R),className:"text-[var(--color-text-muted)] hover:text-red-400 px-2 transition",children:"✕"},void 0,!1,void 0,this)]},R,!0,void 0,this))},void 0,!1,void 0,this),z.jsxDEV("p",{className:"text-xs text-[var(--color-text-faint)] mt-2",children:G.status==="running"?"Server will be automatically restarted to apply changes.":"Changes will take effect when the server is started."},void 0,!1,void 0,this)]},void 0,!0,void 0,this),W&&z.jsxDEV("p",{className:"text-red-400 text-sm",children:W},void 0,!1,void 0,this)]},void 0,!0,void 0,this),z.jsxDEV("div",{className:"p-4 border-t border-[var(--color-border)] flex justify-end gap-2 sticky bottom-0 bg-[var(--color-surface)]",children:[z.jsxDEV("button",{onClick:H,className:"px-4 py-2 border border-[var(--color-border-light)] hover:border-[var(--color-text-muted)] rounded transition",children:"Cancel"},void 0,!1,void 0,this),z.jsxDEV("button",{onClick:x,disabled:u||!X.trim(),className:"px-4 py-2 bg-[var(--color-accent)] hover:bg-[var(--color-accent-hover)] text-black rounded font-medium transition disabled:opacity-50",children:u?"Saving...":"Save Changes"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}
2
+ export{Mz as i};
3
+
4
+ //# debugId=C82C00D733F3FB7164756E2164756E21
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/web/components/mcp/McpPage.tsx"],
4
+ "sourcesContent": [
5
+ "import React, { useState, useEffect } from \"react\";\nimport { McpIcon } from \"../common/Icons\";\nimport { useAuth, useProjects } from \"../../context\";\nimport { useConfirm, useAlert } from \"../common/Modal\";\nimport { Select } from \"../common/Select\";\nimport type { McpTool, McpToolCallResult } from \"../../types\";\nimport { IntegrationsPanel } from \"./IntegrationsPanel\";\n\ninterface McpServer {\n id: string;\n name: string;\n type: \"npm\" | \"pip\" | \"github\" | \"http\" | \"custom\";\n package: string | null;\n pip_module: string | null; // For pip type: module to run (e.g., \"late.mcp\")\n command: string | null;\n args: string | null;\n env: Record<string, string>;\n url: string | null;\n headers: Record<string, string>;\n port: number | null;\n status: \"stopped\" | \"running\";\n source: string | null; // \"composio\", \"smithery\", or null for local\n project_id: string | null; // null = global\n created_at: string;\n}\n\ninterface RegistryServer {\n id: string;\n name: string;\n fullName: string;\n description: string;\n version?: string;\n repository?: string;\n npmPackage: string | null;\n remoteUrl: string | null;\n transport: string;\n}\n\nexport function McpPage() {\n const { authFetch } = useAuth();\n const { projects, currentProjectId } = useProjects();\n const [servers, setServers] = useState<McpServer[]>([]);\n const [loading, setLoading] = useState(true);\n const [showAdd, setShowAdd] = useState(false);\n const [editingServer, setEditingServer] = useState<McpServer | null>(null);\n const [selectedServer, setSelectedServer] = useState<McpServer | null>(null);\n const [activeTab, setActiveTab] = useState<\"servers\" | \"hosted\" | \"registry\">(\"servers\");\n const { confirm, ConfirmDialog } = useConfirm();\n\n const hasProjects = projects.length > 0;\n\n const fetchServers = async () => {\n try {\n const res = await authFetch(\"/api/mcp/servers\");\n const data = await res.json();\n setServers(data.servers || []);\n } catch (e) {\n console.error(\"Failed to fetch MCP servers:\", e);\n }\n setLoading(false);\n };\n\n useEffect(() => {\n fetchServers();\n }, [authFetch]);\n\n // Filter servers based on global project selector\n // When a project is selected, show global + that project's servers\n const filteredServers = servers.filter(server => {\n if (!currentProjectId) return true; // \"All Projects\" - show everything\n if (currentProjectId === \"unassigned\") return server.project_id === null; // Only global\n // Project selected: show global + project-specific\n return server.project_id === null || server.project_id === currentProjectId;\n });\n\n const startServer = async (id: string) => {\n try {\n await authFetch(`/api/mcp/servers/${id}/start`, { method: \"POST\" });\n fetchServers();\n } catch (e) {\n console.error(\"Failed to start server:\", e);\n }\n };\n\n const stopServer = async (id: string) => {\n try {\n await authFetch(`/api/mcp/servers/${id}/stop`, { method: \"POST\" });\n fetchServers();\n } catch (e) {\n console.error(\"Failed to stop server:\", e);\n }\n };\n\n const deleteServer = async (id: string) => {\n const confirmed = await confirm(\"Delete this MCP server?\", { confirmText: \"Delete\", title: \"Delete Server\" });\n if (!confirmed) return;\n try {\n await authFetch(`/api/mcp/servers/${id}`, { method: \"DELETE\" });\n if (selectedServer?.id === id) {\n setSelectedServer(null);\n }\n fetchServers();\n } catch (e) {\n console.error(\"Failed to delete server:\", e);\n }\n };\n\n const renameServer = async (id: string, newName: string) => {\n try {\n await authFetch(`/api/mcp/servers/${id}`, {\n method: \"PUT\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ name: newName }),\n });\n fetchServers();\n } catch (e) {\n console.error(\"Failed to rename server:\", e);\n }\n };\n\n const updateServer = async (id: string, updates: Partial<McpServer>) => {\n try {\n await authFetch(`/api/mcp/servers/${id}`, {\n method: \"PUT\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(updates),\n });\n fetchServers();\n } catch (e) {\n console.error(\"Failed to update server:\", e);\n throw e;\n }\n };\n\n return (\n <>\n {ConfirmDialog}\n <div className=\"flex-1 overflow-auto p-6\">\n <div className=\"max-w-6xl\">\n {/* Header */}\n <div className=\"flex items-center justify-between mb-6\">\n <div>\n <h1 className=\"text-2xl font-semibold mb-1\">MCP Servers</h1>\n <p className=\"text-[var(--color-text-muted)]\">\n Manage Model Context Protocol servers for tool integrations.\n </p>\n </div>\n {activeTab === \"servers\" && (\n <button\n onClick={() => setShowAdd(true)}\n className=\"bg-[var(--color-accent)] hover:bg-[var(--color-accent-hover)] text-black px-4 py-2 rounded font-medium transition\"\n >\n + Add Server\n </button>\n )}\n </div>\n\n {/* Tabs */}\n <div className=\"flex gap-1 mb-6 bg-[var(--color-surface)] card p-1 w-fit\">\n <button\n onClick={() => setActiveTab(\"servers\")}\n className={`px-4 py-2 rounded text-sm font-medium transition ${\n activeTab === \"servers\"\n ? \"bg-[var(--color-surface-raised)] text-white\"\n : \"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]\"\n }`}\n >\n My Servers\n </button>\n <button\n onClick={() => setActiveTab(\"hosted\")}\n className={`px-4 py-2 rounded text-sm font-medium transition ${\n activeTab === \"hosted\"\n ? \"bg-[var(--color-surface-raised)] text-white\"\n : \"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]\"\n }`}\n >\n Hosted Services\n </button>\n <button\n onClick={() => setActiveTab(\"registry\")}\n className={`px-4 py-2 rounded text-sm font-medium transition ${\n activeTab === \"registry\"\n ? \"bg-[var(--color-surface-raised)] text-white\"\n : \"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]\"\n }`}\n >\n Browse Registry\n </button>\n </div>\n\n {/* My Servers Tab */}\n {activeTab === \"servers\" && (\n <>\n {/* Loading */}\n {loading && (\n <div className=\"text-center py-8 text-[var(--color-text-muted)]\">Loading...</div>\n )}\n\n {/* Empty State */}\n {!loading && filteredServers.length === 0 && servers.length === 0 && (\n <div className=\"bg-[var(--color-surface)] card p-8 text-center\">\n <McpIcon className=\"w-12 h-12 text-[var(--color-border-light)] mx-auto mb-4\" />\n <h3 className=\"text-lg font-medium mb-2\">No MCP servers configured</h3>\n <p className=\"text-[var(--color-text-muted)] mb-6 max-w-md mx-auto\">\n MCP servers extend your agents with tools like file access, web browsing,\n database connections, and more.\n </p>\n <div className=\"flex gap-3 justify-center\">\n <button\n onClick={() => setShowAdd(true)}\n className=\"bg-[var(--color-accent)] hover:bg-[var(--color-accent-hover)] text-black px-4 py-2 rounded font-medium transition\"\n >\n Add Manually\n </button>\n <button\n onClick={() => setActiveTab(\"registry\")}\n className=\"border border-[var(--color-border-light)] hover:border-[var(--color-text-muted)] px-4 py-2 rounded font-medium transition\"\n >\n Browse Registry\n </button>\n </div>\n </div>\n )}\n\n {/* Empty filter state */}\n {!loading && filteredServers.length === 0 && servers.length > 0 && (\n <div className=\"bg-[var(--color-surface)] card p-6 text-center\">\n <p className=\"text-[var(--color-text-muted)]\">No servers match this filter.</p>\n </div>\n )}\n\n {/* Main content with server list and tools panel */}\n {!loading && filteredServers.length > 0 && (\n <div className=\"flex gap-6\">\n {/* Server List */}\n <div className={`space-y-3 ${selectedServer ? \"w-1/2\" : \"w-full\"}`}>\n {filteredServers.map(server => {\n const isRemote = server.type === \"http\" && server.url;\n const isAvailable = isRemote || server.status === \"running\";\n const project = hasProjects && server.project_id\n ? projects.find(p => p.id === server.project_id)\n : null;\n return (\n <McpServerCard\n key={server.id}\n server={server}\n project={project}\n selected={selectedServer?.id === server.id}\n onSelect={() => setSelectedServer(isAvailable ? server : null)}\n onStart={() => startServer(server.id)}\n onStop={() => stopServer(server.id)}\n onDelete={() => deleteServer(server.id)}\n onEdit={async () => {\n // Fetch full server details (with decrypted env/headers) for editing\n try {\n const res = await authFetch(`/api/mcp/servers/${server.id}`);\n const data = await res.json();\n setEditingServer(data.server || server);\n } catch {\n setEditingServer(server);\n }\n }}\n />\n );\n })}\n </div>\n\n {/* Tools Panel */}\n {selectedServer && (\n <div className=\"w-1/2\">\n <ToolsPanel\n server={selectedServer}\n onClose={() => setSelectedServer(null)}\n />\n </div>\n )}\n </div>\n )}\n </>\n )}\n\n {/* Hosted Services Tab */}\n {activeTab === \"hosted\" && (\n <HostedServices onServerAdded={fetchServers} projectId={currentProjectId} />\n )}\n\n {/* Browse Registry Tab */}\n {activeTab === \"registry\" && (\n <RegistryBrowser\n onInstall={(server) => {\n // After installing, switch to servers tab and refresh\n fetchServers();\n setActiveTab(\"servers\");\n }}\n />\n )}\n\n {/* Info - only show on servers tab */}\n {activeTab === \"servers\" && (\n <div className=\"mt-8 p-4 bg-[var(--color-surface)] card\">\n <h3 className=\"font-medium mb-2\">Quick Start</h3>\n <p className=\"text-sm text-[var(--color-text-muted)] mb-3\">\n Add an MCP server by providing its npm package name. For example:\n </p>\n <div className=\"flex flex-wrap gap-2\">\n {[\n { name: \"filesystem\", pkg: \"@modelcontextprotocol/server-filesystem\" },\n { name: \"fetch\", pkg: \"@modelcontextprotocol/server-fetch\" },\n { name: \"memory\", pkg: \"@modelcontextprotocol/server-memory\" },\n ].map(s => (\n <code key={s.name} className=\"text-xs bg-[var(--color-bg)] px-2 py-1 rounded\">\n {s.pkg}\n </code>\n ))}\n </div>\n </div>\n )}\n </div>\n\n {/* Add Server Modal */}\n {showAdd && (\n <AddServerModal\n onClose={() => setShowAdd(false)}\n onAdded={() => {\n setShowAdd(false);\n fetchServers();\n }}\n projects={hasProjects ? projects : undefined}\n defaultProjectId={currentProjectId && currentProjectId !== \"unassigned\" ? currentProjectId : null}\n />\n )}\n\n {editingServer && (\n <EditServerModal\n server={editingServer}\n projects={hasProjects ? projects : undefined}\n onClose={() => setEditingServer(null)}\n onSaved={() => {\n setEditingServer(null);\n fetchServers();\n }}\n />\n )}\n </div>\n </>\n );\n}\n\nfunction McpServerCard({\n server,\n project,\n selected,\n onSelect,\n onStart,\n onStop,\n onDelete,\n onEdit,\n}: {\n server: McpServer;\n project?: { id: string; name: string; color: string } | null;\n selected: boolean;\n onSelect: () => void;\n onStart: () => void;\n onStop: () => void;\n onDelete: () => void;\n onEdit: () => void;\n}) {\n // Remote/hosted servers (http type with url) are always available\n const isRemote = server.type === \"http\" && server.url;\n const isAvailable = isRemote || server.status === \"running\";\n\n // Determine what to show as the server info\n const getServerInfo = () => {\n if (isRemote) {\n // Show source (composio, smithery) or just \"remote\"\n const source = server.source || \"remote\";\n return `${source} • http`;\n }\n return `${server.type} • ${server.package || server.command || \"custom\"}${\n server.status === \"running\" && server.port ? ` • :${server.port}` : \"\"\n }`;\n };\n\n // Scope badge: Global or Project name\n const getScopeBadge = () => {\n if (project) {\n return (\n <span\n className=\"text-xs px-1.5 py-0.5 rounded\"\n style={{ backgroundColor: `${project.color}20`, color: project.color }}\n >\n {project.name}\n </span>\n );\n }\n if (server.project_id === null) {\n return (\n <span className=\"text-xs text-[var(--color-text-muted)] bg-[var(--color-surface-raised)] px-1.5 py-0.5 rounded\">\n Global\n </span>\n );\n }\n return null;\n };\n\n return (\n <div\n className={`bg-[var(--color-surface)] border rounded-lg p-4 cursor-pointer transition ${\n selected ? \"border-[var(--color-accent)]\" : \"border-[var(--color-border)] hover:border-[var(--color-border-light)]\"\n }`}\n onClick={isAvailable ? onSelect : undefined}\n >\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <div className={`w-2 h-2 rounded-full ${\n isAvailable ? \"bg-green-400\" : \"bg-[var(--color-scrollbar)]\"\n }`} />\n <div>\n <div className=\"flex items-center gap-2\">\n <h3 className=\"font-medium\">{server.name}</h3>\n {getScopeBadge()}\n </div>\n <p className=\"text-sm text-[var(--color-text-muted)]\">{getServerInfo()}</p>\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n <button\n onClick={(e) => { e.stopPropagation(); onEdit(); }}\n className=\"text-sm text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)] px-3 py-1 transition\"\n title=\"Edit server settings\"\n >\n Edit\n </button>\n {isRemote ? (\n // Remote servers: no start/stop, just delete\n <button\n onClick={(e) => { e.stopPropagation(); onDelete(); }}\n className=\"text-sm text-[var(--color-text-muted)] hover:text-red-400 px-3 py-1 transition\"\n >\n Remove\n </button>\n ) : server.status === \"running\" ? (\n // Local running server: tools + stop + delete\n <>\n <button\n onClick={(e) => { e.stopPropagation(); onSelect(); }}\n className=\"text-sm text-[var(--color-accent)] hover:text-[var(--color-accent-hover)] px-3 py-1 transition\"\n >\n Tools\n </button>\n <button\n onClick={(e) => { e.stopPropagation(); onStop(); }}\n className=\"text-sm text-[var(--color-text-muted)] hover:text-red-400 px-3 py-1 transition\"\n >\n Stop\n </button>\n <button\n onClick={(e) => { e.stopPropagation(); onDelete(); }}\n className=\"text-sm text-[var(--color-text-muted)] hover:text-red-400 px-3 py-1 transition\"\n >\n Delete\n </button>\n </>\n ) : (\n // Local stopped server: start + delete\n <>\n <button\n onClick={(e) => { e.stopPropagation(); onStart(); }}\n className=\"text-sm text-[var(--color-text-muted)] hover:text-green-400 px-3 py-1 transition\"\n >\n Start\n </button>\n <button\n onClick={(e) => { e.stopPropagation(); onDelete(); }}\n className=\"text-sm text-[var(--color-text-muted)] hover:text-red-400 px-3 py-1 transition\"\n >\n Delete\n </button>\n </>\n )}\n </div>\n </div>\n </div>\n );\n}\n\nfunction ToolsPanel({\n server,\n onClose,\n}: {\n server: McpServer;\n onClose: () => void;\n}) {\n const { authFetch } = useAuth();\n const [tools, setTools] = useState<McpTool[]>([]);\n const [serverInfo, setServerInfo] = useState<{ name: string; version: string } | null>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [selectedTool, setSelectedTool] = useState<McpTool | null>(null);\n\n useEffect(() => {\n const fetchTools = async () => {\n setLoading(true);\n setError(null);\n try {\n const res = await authFetch(`/api/mcp/servers/${server.id}/tools`);\n const data = await res.json();\n if (!res.ok) {\n setError(data.error || \"Failed to fetch tools\");\n return;\n }\n setTools(data.tools || []);\n setServerInfo(data.serverInfo || null);\n } catch (e) {\n setError(`Failed to fetch tools: ${e}`);\n } finally {\n setLoading(false);\n }\n };\n\n fetchTools();\n }, [server.id, authFetch]);\n\n return (\n <div className=\"bg-[var(--color-surface)] card overflow-hidden\">\n {/* Header */}\n <div className=\"p-4 border-b border-[var(--color-border)] flex items-center justify-between\">\n <div>\n <h3 className=\"font-medium\">{server.name} Tools</h3>\n {serverInfo && (\n <p className=\"text-xs text-[var(--color-text-muted)]\">\n {serverInfo.name} v{serverInfo.version}\n </p>\n )}\n </div>\n <button\n onClick={onClose}\n className=\"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)] text-xl leading-none\"\n >\n ×\n </button>\n </div>\n\n {/* Content */}\n <div className=\"p-4 max-h-[500px] overflow-auto\">\n {loading && <p className=\"text-[var(--color-text-muted)]\">Loading tools...</p>}\n\n {error && (\n <div className=\"text-red-400 text-sm p-3 bg-red-500/10 rounded\">\n {error}\n </div>\n )}\n\n {!loading && !error && tools.length === 0 && (\n <p className=\"text-[var(--color-text-muted)]\">No tools available from this server.</p>\n )}\n\n {!loading && !error && tools.length > 0 && !selectedTool && (\n <div className=\"space-y-2\">\n {tools.map(tool => (\n <button\n key={tool.name}\n onClick={() => setSelectedTool(tool)}\n className=\"w-full text-left p-3 bg-[var(--color-bg)] hover:bg-[var(--color-surface-raised)] border border-[var(--color-border-light)] hover:border-[var(--color-border-light)] rounded transition\"\n >\n <div className=\"font-medium text-sm\">{tool.name}</div>\n {tool.description && (\n <div className=\"text-xs text-[var(--color-text-muted)] mt-1\">{tool.description}</div>\n )}\n </button>\n ))}\n </div>\n )}\n\n {selectedTool && (\n <ToolTester\n serverId={server.id}\n tool={selectedTool}\n onBack={() => setSelectedTool(null)}\n />\n )}\n </div>\n </div>\n );\n}\n\nfunction ToolTester({\n serverId,\n tool,\n onBack,\n}: {\n serverId: string;\n tool: McpTool;\n onBack: () => void;\n}) {\n const { authFetch } = useAuth();\n const [args, setArgs] = useState<string>(\"{}\");\n const [result, setResult] = useState<McpToolCallResult | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n\n // Generate default args from schema\n useEffect(() => {\n const schema = tool.inputSchema;\n if (schema && typeof schema === \"object\" && \"properties\" in schema) {\n const properties = schema.properties as Record<string, { type?: string; default?: unknown }>;\n const defaultArgs: Record<string, unknown> = {};\n for (const [key, prop] of Object.entries(properties)) {\n if (prop.default !== undefined) {\n defaultArgs[key] = prop.default;\n } else if (prop.type === \"string\") {\n defaultArgs[key] = \"\";\n } else if (prop.type === \"number\" || prop.type === \"integer\") {\n defaultArgs[key] = 0;\n } else if (prop.type === \"boolean\") {\n defaultArgs[key] = false;\n } else if (prop.type === \"array\") {\n defaultArgs[key] = [];\n } else if (prop.type === \"object\") {\n defaultArgs[key] = {};\n }\n }\n setArgs(JSON.stringify(defaultArgs, null, 2));\n }\n }, [tool]);\n\n const callTool = async () => {\n setLoading(true);\n setError(null);\n setResult(null);\n\n try {\n const parsedArgs = JSON.parse(args);\n const res = await authFetch(`/api/mcp/servers/${serverId}/tools/${encodeURIComponent(tool.name)}/call`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ arguments: parsedArgs }),\n });\n const data = await res.json();\n\n if (!res.ok) {\n setError(data.error || \"Failed to call tool\");\n return;\n }\n\n setResult(data.result);\n } catch (e) {\n setError(`Error: ${e}`);\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <div className=\"space-y-4\">\n {/* Header */}\n <div className=\"flex items-center gap-2\">\n <button\n onClick={onBack}\n className=\"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)] text-sm\"\n >\n ← Back\n </button>\n <span className=\"text-[var(--color-text-faint)]\">/</span>\n <span className=\"font-medium\">{tool.name}</span>\n </div>\n\n {/* Description */}\n {tool.description && (\n <p className=\"text-sm text-[var(--color-text-muted)]\">{tool.description}</p>\n )}\n\n {/* Schema info */}\n {tool.inputSchema && (\n <div className=\"text-xs\">\n <details className=\"cursor-pointer\">\n <summary className=\"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]\">Input Schema</summary>\n <pre className=\"mt-2 p-2 bg-[var(--color-bg)] rounded text-[var(--color-text-secondary)] overflow-auto max-h-32\">\n {JSON.stringify(tool.inputSchema, null, 2)}\n </pre>\n </details>\n </div>\n )}\n\n {/* Arguments input */}\n <div>\n <label className=\"block text-sm text-[var(--color-text-muted)] mb-1\">Arguments (JSON)</label>\n <textarea\n value={args}\n onChange={(e) => setArgs(e.target.value)}\n className=\"w-full bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-3 py-2 h-32 font-mono text-sm focus:outline-none focus:border-[var(--color-accent)] resize-none\"\n placeholder=\"{}\"\n />\n </div>\n\n {/* Call button */}\n <button\n onClick={callTool}\n disabled={loading}\n className=\"w-full bg-[var(--color-accent)] hover:bg-[var(--color-accent-hover)] disabled:opacity-50 text-black px-4 py-2 rounded font-medium transition\"\n >\n {loading ? \"Calling...\" : \"Call Tool\"}\n </button>\n\n {/* Error */}\n {error && (\n <div className=\"text-red-400 text-sm p-3 bg-red-500/10 rounded\">\n {error}\n </div>\n )}\n\n {/* Result */}\n {result && (\n <div className=\"space-y-2\">\n <div className=\"text-sm text-[var(--color-text-muted)]\">\n Result {result.isError && <span className=\"text-red-400\">(error)</span>}\n </div>\n <div className={`p-3 rounded text-sm ${result.isError ? \"bg-red-500/10\" : \"bg-green-500/10\"}`}>\n {result.content.map((block, i) => (\n <div key={i} className=\"mb-2 last:mb-0\">\n {block.type === \"text\" && (\n <pre className=\"whitespace-pre-wrap font-mono text-xs\">\n {block.text}\n </pre>\n )}\n {block.type === \"image\" && block.data && (\n <img\n src={`data:${block.mimeType || \"image/png\"};base64,${block.data}`}\n alt=\"Tool result\"\n className=\"max-w-full rounded\"\n />\n )}\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n );\n}\n\nfunction RegistryBrowser({\n onInstall,\n}: {\n onInstall: (server: RegistryServer) => void;\n}) {\n const { authFetch } = useAuth();\n const [search, setSearch] = useState(\"\");\n const [servers, setServers] = useState<RegistryServer[]>([]);\n const [loading, setLoading] = useState(false);\n const [searched, setSearched] = useState(false);\n const [installing, setInstalling] = useState<string | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n const searchRegistry = async (query: string) => {\n setLoading(true);\n setError(null);\n try {\n const res = await authFetch(`/api/mcp/registry?search=${encodeURIComponent(query)}&limit=20`);\n const data = await res.json();\n if (!res.ok) {\n setError(data.error || \"Failed to search registry\");\n setServers([]);\n } else {\n setServers(data.servers || []);\n }\n } catch (e) {\n setError(`Failed to search: ${e}`);\n setServers([]);\n } finally {\n setLoading(false);\n setSearched(true);\n }\n };\n\n const handleSearch = (e: React.FormEvent) => {\n e.preventDefault();\n if (search.trim()) {\n searchRegistry(search.trim());\n }\n };\n\n // Load popular servers on mount\n useEffect(() => {\n searchRegistry(\"\");\n }, []);\n\n const installServer = async (server: RegistryServer) => {\n if (!server.npmPackage) {\n setError(\"This server does not have an npm package\");\n return;\n }\n\n setInstalling(server.id);\n setError(null);\n\n try {\n const res = await authFetch(\"/api/mcp/servers\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n name: server.name,\n type: \"npm\",\n package: server.npmPackage,\n }),\n });\n\n if (!res.ok) {\n const data = await res.json();\n setError(data.error || \"Failed to add server\");\n return;\n }\n\n onInstall(server);\n } catch (e) {\n setError(`Failed to add server: ${e}`);\n } finally {\n setInstalling(null);\n }\n };\n\n return (\n <div className=\"space-y-6\">\n {/* Search */}\n <form onSubmit={handleSearch} className=\"flex gap-2\">\n <input\n type=\"text\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n placeholder=\"Search MCP servers (e.g., filesystem, github, slack...)\"\n className=\"flex-1 bg-[var(--color-surface)] border border-[var(--color-border-light)] rounded-lg px-4 py-3 focus:outline-none focus:border-[var(--color-accent)]\"\n />\n <button\n type=\"submit\"\n disabled={loading}\n className=\"bg-[var(--color-accent)] hover:bg-[var(--color-accent-hover)] disabled:opacity-50 text-black px-6 py-3 rounded-lg font-medium transition\"\n >\n {loading ? \"...\" : \"Search\"}\n </button>\n </form>\n\n {/* Error */}\n {error && (\n <div className=\"text-red-400 text-sm p-3 bg-red-500/10 border border-red-500/20 rounded-lg\">\n {error}\n </div>\n )}\n\n {/* Results */}\n {!loading && searched && servers.length === 0 && (\n <div className=\"text-center py-8 text-[var(--color-text-muted)]\">\n No servers found. Try a different search term.\n </div>\n )}\n\n {servers.length > 0 && (\n <div className=\"grid gap-4 md:grid-cols-2\">\n {servers.map((server) => (\n <div\n key={server.id}\n className=\"bg-[var(--color-surface)] card p-4 hover:border-[var(--color-border-light)] transition\"\n >\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"flex-1 min-w-0\">\n <h3 className=\"font-medium truncate\">{server.name}</h3>\n <p className=\"text-sm text-[var(--color-text-muted)] mt-1 line-clamp-2\">\n {server.description || \"No description\"}\n </p>\n <div className=\"flex items-center gap-2 mt-2 text-xs text-[var(--color-text-faint)]\">\n {server.version && <span>v{server.version}</span>}\n <span className={`px-1.5 py-0.5 rounded ${\n server.npmPackage ? \"bg-green-500/10 text-green-400\" : \"bg-blue-500/10 text-blue-400\"\n }`}>\n {server.npmPackage ? \"npm\" : \"remote\"}\n </span>\n </div>\n <code className=\"text-xs text-[var(--color-text-faint)] bg-[var(--color-bg)] px-2 py-0.5 rounded mt-2 inline-block truncate max-w-full\">\n {server.npmPackage || server.fullName}\n </code>\n </div>\n <div className=\"flex-shrink-0\">\n {server.npmPackage ? (\n <button\n onClick={() => installServer(server)}\n disabled={installing === server.id}\n className=\"text-sm bg-[var(--color-surface-raised)] hover:bg-[var(--color-surface-raised)] border border-[var(--color-border-light)] hover:border-[var(--color-accent)] px-3 py-1.5 rounded transition disabled:opacity-50\"\n >\n {installing === server.id ? \"Adding...\" : \"Add\"}\n </button>\n ) : server.repository ? (\n <a\n href={server.repository}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-sm text-[var(--color-text-muted)] hover:text-[var(--color-accent)] transition\"\n >\n View →\n </a>\n ) : null}\n </div>\n </div>\n </div>\n ))}\n </div>\n )}\n\n {/* Loading */}\n {loading && (\n <div className=\"text-center py-8 text-[var(--color-text-muted)]\">\n Searching registry...\n </div>\n )}\n\n {/* Registry info */}\n <div className=\"p-4 bg-[var(--color-surface)] card text-sm text-[var(--color-text-muted)]\">\n <p>\n Servers are sourced from the{\" \"}\n <a\n href=\"https://github.com/modelcontextprotocol/servers\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-[var(--color-accent)] hover:underline\"\n >\n official MCP registry\n </a>\n . Not all servers have npm packages - some require manual setup.\n </p>\n </div>\n </div>\n );\n}\n\n// Hosted MCP Services (Composio, Smithery, etc.)\ninterface ComposioConfig {\n id: string;\n name: string;\n toolkits: string[];\n toolsCount: number;\n mcpUrl: string;\n createdAt?: string;\n}\n\nfunction HostedServices({ onServerAdded, projectId }: { onServerAdded?: () => void; projectId?: string | null }) {\n const { authFetch } = useAuth();\n const [activeProvider, setActiveProvider] = useState<\"composio\" | \"smithery\" | \"agentdojo\">(\"composio\");\n const [subTab, setSubTab] = useState<\"configs\" | \"connect\">(\"configs\");\n const [composioConnected, setComposioConnected] = useState(false);\n const [smitheryConnected, setSmitheryConnected] = useState(false);\n const [agentDojoConnected, setAgentDojoConnected] = useState(false);\n const [composioConfigs, setComposioConfigs] = useState<ComposioConfig[]>([]);\n const [addedServers, setAddedServers] = useState<Set<string>>(new Set());\n const [loading, setLoading] = useState(true);\n const [loadingConfigs, setLoadingConfigs] = useState(false);\n const [addingConfig, setAddingConfig] = useState<string | null>(null);\n const { alert, AlertDialog } = useAlert();\n\n const fetchStatus = async () => {\n try {\n const serversUrl = projectId && projectId !== \"unassigned\"\n ? `/api/mcp/servers?project=${encodeURIComponent(projectId)}`\n : \"/api/mcp/servers\";\n const [providersRes, serversRes] = await Promise.all([\n authFetch(\"/api/providers\"),\n authFetch(serversUrl),\n ]);\n const providersData = await providersRes.json();\n const serversData = await serversRes.json();\n\n const providers = providersData.providers || [];\n const servers = serversData.servers || [];\n\n // Track which Composio config IDs are already added as servers\n // Extract config ID from URLs like https://backend.composio.dev/v3/mcp/{configId}/mcp?user_id=...\n const composioConfigIds = new Set(\n servers\n .filter((s: any) => s.source === \"composio\" && s.url)\n .map((s: any) => {\n const match = s.url.match(/\\/v3\\/mcp\\/([^/]+)/);\n return match ? match[1] : null;\n })\n .filter(Boolean)\n );\n setAddedServers(composioConfigIds);\n\n const composio = providers.find((p: any) => p.id === \"composio\");\n const smithery = providers.find((p: any) => p.id === \"smithery\");\n const agentdojo = providers.find((p: any) => p.id === \"agentdojo\");\n const composioHasKey = composio?.hasKey || false;\n const smitheryHasKey = smithery?.hasKey || false;\n const agentdojoHasKey = agentdojo?.hasKey || false;\n\n setComposioConnected(composioHasKey);\n setSmitheryConnected(smitheryHasKey);\n setAgentDojoConnected(agentdojoHasKey);\n\n // Set initial active provider to first connected one\n if (composioHasKey) {\n setActiveProvider(\"composio\");\n fetchComposioConfigs();\n } else if (smitheryHasKey) {\n setActiveProvider(\"smithery\");\n } else if (agentdojoHasKey) {\n setActiveProvider(\"agentdojo\");\n }\n } catch (e) {\n console.error(\"Failed to fetch providers:\", e);\n }\n setLoading(false);\n };\n\n const fetchComposioConfigs = async () => {\n setLoadingConfigs(true);\n try {\n const projectParam = projectId && projectId !== \"unassigned\" ? `?project_id=${projectId}` : \"\";\n const res = await authFetch(`/api/integrations/composio/configs${projectParam}`);\n const data = await res.json();\n setComposioConfigs(data.configs || []);\n } catch (e) {\n console.error(\"Failed to fetch Composio configs:\", e);\n }\n setLoadingConfigs(false);\n };\n\n const addComposioConfig = async (configId: string) => {\n setAddingConfig(configId);\n try {\n const projectParam = projectId && projectId !== \"unassigned\" ? `?project_id=${projectId}` : \"\";\n const res = await authFetch(`/api/integrations/composio/configs/${configId}/add${projectParam}`, {\n method: \"POST\",\n });\n if (res.ok) {\n // Mark as added by config ID\n setAddedServers(prev => new Set([...prev, configId]));\n onServerAdded?.();\n } else {\n const data = await res.json();\n await alert(data.error || \"Failed to add config\", { title: \"Error\", variant: \"error\" });\n }\n } catch (e) {\n console.error(\"Failed to add config:\", e);\n }\n setAddingConfig(null);\n };\n\n const isConfigAdded = (configId: string) => {\n return addedServers.has(configId);\n };\n\n useEffect(() => {\n fetchStatus();\n }, [authFetch, projectId]);\n\n if (loading) {\n return <div className=\"text-center py-8 text-[var(--color-text-muted)]\">Loading...</div>;\n }\n\n const hasAnyConnection = composioConnected || smitheryConnected || agentDojoConnected;\n const connectedCount = [composioConnected, smitheryConnected, agentDojoConnected].filter(Boolean).length;\n\n if (!hasAnyConnection) {\n return (\n <div className=\"bg-[var(--color-surface)] card p-8 text-center\">\n <p className=\"text-[var(--color-text-secondary)] mb-2\">No hosted MCP services connected</p>\n <p className=\"text-sm text-[var(--color-text-muted)] mb-4\">\n Connect Composio, Smithery, or AgentDojo in Settings to access cloud-based MCP servers.\n </p>\n <a\n href=\"/settings\"\n className=\"inline-block bg-[var(--color-surface-raised)] hover:bg-[var(--color-surface-raised)] border border-[var(--color-border-light)] hover:border-[var(--color-accent)] px-4 py-2 rounded text-sm font-medium transition\"\n >\n Go to Settings →\n </a>\n </div>\n );\n }\n\n return (\n <>\n {AlertDialog}\n <div className=\"space-y-6\">\n {/* Provider Tabs - show when multiple providers are connected */}\n {connectedCount > 1 && (\n <div className=\"flex gap-1 bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded-lg p-1 w-fit\">\n {composioConnected && (\n <button\n onClick={() => { setActiveProvider(\"composio\"); setSubTab(\"configs\"); }}\n className={`px-4 py-2 rounded text-sm font-medium transition flex items-center gap-2 ${\n activeProvider === \"composio\"\n ? \"bg-[var(--color-surface-raised)] text-white\"\n : \"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]\"\n }`}\n >\n <span className=\"w-2 h-2 rounded-full bg-purple-500\" />\n Composio\n </button>\n )}\n {smitheryConnected && (\n <button\n onClick={() => setActiveProvider(\"smithery\")}\n className={`px-4 py-2 rounded text-sm font-medium transition flex items-center gap-2 ${\n activeProvider === \"smithery\"\n ? \"bg-[var(--color-surface-raised)] text-white\"\n : \"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]\"\n }`}\n >\n <span className=\"w-2 h-2 rounded-full bg-blue-500\" />\n Smithery\n </button>\n )}\n {agentDojoConnected && (\n <button\n onClick={() => setActiveProvider(\"agentdojo\")}\n className={`px-4 py-2 rounded text-sm font-medium transition flex items-center gap-2 ${\n activeProvider === \"agentdojo\"\n ? \"bg-[var(--color-surface-raised)] text-white\"\n : \"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]\"\n }`}\n >\n <span className=\"w-2 h-2 rounded-full bg-green-500\" />\n AgentDojo\n </button>\n )}\n </div>\n )}\n\n {/* Composio Content */}\n {composioConnected && (connectedCount === 1 || activeProvider === \"composio\") && (\n <>\n {/* Sub-tabs for Composio */}\n <div className=\"flex items-center justify-between\">\n <div className=\"flex gap-1 bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded-lg p-1\">\n <button\n onClick={() => setSubTab(\"configs\")}\n className={`px-4 py-2 rounded text-sm font-medium transition ${\n subTab === \"configs\"\n ? \"bg-[var(--color-surface-raised)] text-white\"\n : \"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]\"\n }`}\n >\n MCP Configs\n </button>\n <button\n onClick={() => setSubTab(\"connect\")}\n className={`px-4 py-2 rounded text-sm font-medium transition ${\n subTab === \"connect\"\n ? \"bg-[var(--color-surface-raised)] text-white\"\n : \"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]\"\n }`}\n >\n Connect Apps\n </button>\n </div>\n {connectedCount === 1 && (\n <div className=\"flex items-center gap-2 text-xs text-[var(--color-text-muted)]\">\n <span className=\"w-2 h-2 rounded-full bg-purple-500\" />\n Composio\n <span className=\"text-green-400\">Connected</span>\n </div>\n )}\n </div>\n\n {/* Connect Apps Tab */}\n {subTab === \"connect\" && (\n <div>\n <p className=\"text-sm text-[var(--color-text-muted)] mb-4\">\n Connect your accounts to enable tools in MCP configs\n </p>\n <IntegrationsPanel\n providerId=\"composio\"\n projectId={projectId}\n onConnectionComplete={() => {\n // Refresh configs after connecting an app\n fetchComposioConfigs();\n }}\n />\n </div>\n )}\n\n {/* MCP Configs Tab */}\n {subTab === \"configs\" && (\n <div>\n <div className=\"flex items-center justify-between mb-3\">\n <p className=\"text-sm text-[var(--color-text-muted)]\">\n Your MCP configs from Composio\n </p>\n <div className=\"flex items-center gap-3\">\n <button\n onClick={fetchComposioConfigs}\n disabled={loadingConfigs}\n className=\"text-xs text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)] transition\"\n >\n {loadingConfigs ? \"Loading...\" : \"Refresh\"}\n </button>\n <a\n href=\"https://app.composio.dev/mcp_configs\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-xs text-[var(--color-text-muted)] hover:text-[var(--color-accent)] transition\"\n >\n Create Config →\n </a>\n </div>\n </div>\n\n {loadingConfigs ? (\n <div className=\"text-center py-6 text-[var(--color-text-muted)]\">Loading configs...</div>\n ) : composioConfigs.length === 0 ? (\n <div className=\"bg-[var(--color-surface)] card p-4 text-center\">\n <p className=\"text-sm text-[var(--color-text-muted)]\">No MCP configs found</p>\n <p className=\"text-xs text-[var(--color-text-faint)] mt-2\">\n First <button onClick={() => setSubTab(\"connect\")} className=\"text-[var(--color-accent)] hover:text-[var(--color-accent-hover)]\">connect some apps</button>, then create a config.\n </p>\n <a\n href=\"https://app.composio.dev/mcp_configs\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-xs text-[var(--color-accent)] hover:text-[var(--color-accent-hover)] mt-2 inline-block\"\n >\n Create in Composio →\n </a>\n </div>\n ) : (\n <div className=\"space-y-2\">\n {composioConfigs.map((config) => {\n const added = isConfigAdded(config.id);\n const isAdding = addingConfig === config.id;\n return (\n <div\n key={config.id}\n className={`bg-[var(--color-surface)] border rounded-lg p-3 transition flex items-center justify-between ${\n added ? \"border-green-500/30\" : \"border-[var(--color-border)] hover:border-[var(--color-border-light)]\"\n }`}\n >\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <span className=\"font-medium text-sm\">{config.name}</span>\n <span className=\"text-xs text-[var(--color-text-faint)]\">{config.toolsCount} tools</span>\n {added && (\n <span className=\"text-xs text-green-400\">Added</span>\n )}\n </div>\n {config.toolkits.length > 0 && (\n <div className=\"flex flex-wrap gap-1 mt-1\">\n {config.toolkits.slice(0, 4).map((toolkit) => (\n <span\n key={toolkit}\n className=\"text-xs bg-[var(--color-surface-raised)] text-[var(--color-text-muted)] px-1.5 py-0.5 rounded\"\n >\n {toolkit}\n </span>\n ))}\n {config.toolkits.length > 4 && (\n <span className=\"text-xs text-[var(--color-text-faint)]\">+{config.toolkits.length - 4}</span>\n )}\n </div>\n )}\n </div>\n <div className=\"flex items-center gap-2 ml-3\">\n {added ? (\n <span className=\"text-xs text-[var(--color-text-faint)] px-2 py-1\">In Servers</span>\n ) : (\n <button\n onClick={() => addComposioConfig(config.id)}\n disabled={isAdding}\n className=\"text-xs bg-[var(--color-accent)] hover:bg-[var(--color-accent-hover)] text-black px-3 py-1 rounded font-medium transition disabled:opacity-50\"\n >\n {isAdding ? \"Adding...\" : \"Add\"}\n </button>\n )}\n <a\n href={`https://app.composio.dev/mcp_configs/${config.id}`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-xs text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)] transition\"\n >\n Edit\n </a>\n </div>\n </div>\n );\n })}\n </div>\n )}\n </div>\n )}\n </>\n )}\n\n {/* Smithery Content */}\n {smitheryConnected && (connectedCount === 1 || activeProvider === \"smithery\") && (\n <div>\n {connectedCount === 1 && (\n <div className=\"flex items-center gap-2 text-xs text-[var(--color-text-muted)] mb-4\">\n <span className=\"w-2 h-2 rounded-full bg-blue-500\" />\n Smithery\n <span className=\"text-green-400\">Connected</span>\n </div>\n )}\n <div className=\"flex items-center justify-between mb-3\">\n <p className=\"text-sm text-[var(--color-text-muted)]\">\n Add MCP servers from the Smithery registry\n </p>\n <a\n href=\"https://smithery.ai/servers\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-xs text-[var(--color-text-muted)] hover:text-[var(--color-accent)] transition\"\n >\n Browse Smithery →\n </a>\n </div>\n <div className=\"bg-[var(--color-surface)] card p-4 text-center\">\n <p className=\"text-sm text-[var(--color-text-muted)]\">\n Smithery servers can be added from the <strong>Browse Registry</strong> tab.\n </p>\n <p className=\"text-xs text-[var(--color-text-faint)] mt-2\">\n Your API key will be used automatically when adding Smithery servers.\n </p>\n </div>\n </div>\n )}\n\n {/* AgentDojo Content */}\n {agentDojoConnected && (connectedCount === 1 || activeProvider === \"agentdojo\") && (\n <AgentDojoContent\n projectId={projectId}\n onServerAdded={onServerAdded}\n showProviderBadge={connectedCount === 1}\n />\n )}\n\n <div className=\"p-3 bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded text-xs text-[var(--color-text-muted)]\">\n <strong className=\"text-[var(--color-text-secondary)]\">Tip:</strong> Connect apps first, then add MCP configs to make tools available to your agents.\n {\" · \"}\n <a href=\"/settings\" className=\"text-[var(--color-accent)] hover:text-[var(--color-accent-hover)]\">Add more providers in Settings</a>\n </div>\n </div>\n </>\n );\n}\n\n// AgentDojo Content Component\ninterface AgentDojoConfig {\n id: string;\n name: string;\n slug: string;\n toolkits: string[];\n toolsCount: number;\n mcpUrl: string;\n createdAt?: string;\n}\n\nfunction AgentDojoContent({\n projectId,\n onServerAdded,\n showProviderBadge,\n}: {\n projectId?: string | null;\n onServerAdded?: () => void;\n showProviderBadge?: boolean;\n}) {\n const { authFetch } = useAuth();\n const [subTab, setSubTab] = useState<\"configs\" | \"toolkits\">(\"configs\");\n const [configs, setConfigs] = useState<AgentDojoConfig[]>([]);\n const [addedServers, setAddedServers] = useState<Set<string>>(new Set());\n const [loadingConfigs, setLoadingConfigs] = useState(false);\n const [addingConfig, setAddingConfig] = useState<string | null>(null);\n const { alert, AlertDialog } = useAlert();\n\n const fetchConfigs = async () => {\n setLoadingConfigs(true);\n try {\n const projectParam = projectId && projectId !== \"unassigned\" ? `?project_id=${projectId}` : \"\";\n const serversUrl = projectId && projectId !== \"unassigned\"\n ? `/api/mcp/servers?project=${encodeURIComponent(projectId)}`\n : \"/api/mcp/servers\";\n console.log(`[AgentDojo:fetchConfigs] projectId=${projectId} serversUrl=${serversUrl}`);\n const [configsRes, serversRes] = await Promise.all([\n authFetch(`/api/integrations/agentdojo/configs${projectParam}`),\n authFetch(serversUrl),\n ]);\n const configsData = await configsRes.json();\n const serversData = await serversRes.json();\n\n console.log(`[AgentDojo:fetchConfigs] configs=${(configsData.configs || []).length} servers=${(serversData.servers || []).length}`);\n setConfigs(configsData.configs || []);\n\n // Track which configs are already added as local servers\n const agentdojoServers = (serversData.servers || []).filter((s: any) => s.source === \"agentdojo\");\n console.log(`[AgentDojo:fetchConfigs] agentdojo servers found: ${agentdojoServers.length}`);\n for (const s of agentdojoServers) {\n const match = s.url?.match(/\\/mcp\\/([^/?]+)/);\n console.log(`[AgentDojo:fetchConfigs] server: id=${s.id} name=${s.name} project_id=${s.project_id} url=${s.url?.substring(0, 80)} extracted=${match ? match[1] : s.name}`);\n }\n const agentdojoServerIds = new Set(\n agentdojoServers.map((s: any) => {\n // Extract config ID from URL or match by name\n const match = s.url?.match(/\\/mcp\\/([^/?]+)/);\n return match ? match[1] : s.name;\n })\n );\n console.log(`[AgentDojo:fetchConfigs] addedServers set:`, [...agentdojoServerIds]);\n setAddedServers(agentdojoServerIds);\n } catch (e) {\n console.error(\"Failed to fetch AgentDojo configs:\", e);\n }\n setLoadingConfigs(false);\n };\n\n const addConfig = async (configId: string) => {\n setAddingConfig(configId);\n try {\n const projectParam = projectId && projectId !== \"unassigned\" ? `?project_id=${projectId}` : \"\";\n console.log(`[AgentDojo:addConfig] configId=${configId} projectParam=${projectParam}`);\n const res = await authFetch(`/api/integrations/agentdojo/configs/${configId}/add${projectParam}`, {\n method: \"POST\",\n });\n const data = await res.json();\n console.log(`[AgentDojo:addConfig] response status=${res.status} ok=${res.ok} message=${data.message} server.id=${data.server?.id} server.project_id=${data.server?.project_id}`);\n if (res.ok) {\n const config = configs.find(c => c.id === configId);\n const addKey = config?.slug || configId;\n console.log(`[AgentDojo:addConfig] marking as added: key=${addKey} config.slug=${config?.slug} config.id=${config?.id} config.name=${config?.name}`);\n setAddedServers(prev => new Set([...prev, addKey]));\n onServerAdded?.();\n } else {\n await alert(data.error || \"Failed to add config\", { title: \"Error\", variant: \"error\" });\n }\n } catch (e) {\n console.error(\"Failed to add config:\", e);\n }\n setAddingConfig(null);\n };\n\n const isConfigAdded = (config: AgentDojoConfig) => {\n return addedServers.has(config.slug) || addedServers.has(config.id) || addedServers.has(config.name);\n };\n\n useEffect(() => {\n fetchConfigs();\n }, [authFetch, projectId]);\n\n return (\n <>\n {AlertDialog}\n <div>\n {showProviderBadge && (\n <div className=\"flex items-center gap-2 text-xs text-[var(--color-text-muted)] mb-4\">\n <span className=\"w-2 h-2 rounded-full bg-green-500\" />\n AgentDojo\n <span className=\"text-green-400\">Connected</span>\n </div>\n )}\n\n {/* Sub-tabs */}\n <div className=\"flex items-center justify-between mb-4\">\n <div className=\"flex gap-1 bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded-lg p-1\">\n <button\n onClick={() => setSubTab(\"configs\")}\n className={`px-4 py-2 rounded text-sm font-medium transition ${\n subTab === \"configs\"\n ? \"bg-[var(--color-surface-raised)] text-white\"\n : \"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]\"\n }`}\n >\n MCP Servers\n </button>\n <button\n onClick={() => setSubTab(\"toolkits\")}\n className={`px-4 py-2 rounded text-sm font-medium transition ${\n subTab === \"toolkits\"\n ? \"bg-[var(--color-surface-raised)] text-white\"\n : \"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]\"\n }`}\n >\n Browse Toolkits\n </button>\n </div>\n </div>\n\n {/* MCP Servers Tab */}\n {subTab === \"configs\" && (\n <div>\n <div className=\"flex items-center justify-between mb-3\">\n <p className=\"text-sm text-[var(--color-text-muted)]\">\n Your MCP servers from AgentDojo\n </p>\n <button\n onClick={fetchConfigs}\n disabled={loadingConfigs}\n className=\"text-xs text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)] transition\"\n >\n {loadingConfigs ? \"Loading...\" : \"Refresh\"}\n </button>\n </div>\n\n {loadingConfigs ? (\n <div className=\"text-center py-6 text-[var(--color-text-muted)]\">Loading servers...</div>\n ) : configs.length === 0 ? (\n <div className=\"bg-[var(--color-surface)] card p-4 text-center\">\n <p className=\"text-sm text-[var(--color-text-muted)]\">No MCP servers found</p>\n <p className=\"text-xs text-[var(--color-text-faint)] mt-2\">\n <button onClick={() => setSubTab(\"toolkits\")} className=\"text-[var(--color-accent)] hover:text-[var(--color-accent-hover)]\">\n Browse toolkits\n </button>\n {\" \"}to create a new MCP server.\n </p>\n </div>\n ) : (\n <div className=\"space-y-2\">\n {configs.map((config) => {\n const added = isConfigAdded(config);\n const isAdding = addingConfig === config.id;\n return (\n <div\n key={config.id}\n className={`bg-[var(--color-surface)] border rounded-lg p-3 transition flex items-center justify-between ${\n added ? \"border-green-500/30\" : \"border-[var(--color-border)] hover:border-[var(--color-border-light)]\"\n }`}\n >\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <span className=\"font-medium text-sm\">{config.name}</span>\n <span className=\"text-xs text-[var(--color-text-faint)]\">{config.toolsCount} tools</span>\n {added && (\n <span className=\"text-xs text-green-400\">Added</span>\n )}\n </div>\n {config.mcpUrl && (\n <code className=\"text-xs text-[var(--color-text-faint)] mt-1 block truncate\">\n {config.mcpUrl}\n </code>\n )}\n {!config.mcpUrl && config.slug && (\n <code className=\"text-xs text-[var(--color-text-faint)] mt-1 block truncate\">\n {config.slug}\n </code>\n )}\n </div>\n <div className=\"flex items-center gap-2 ml-3\">\n {added ? (\n <span className=\"text-xs text-[var(--color-text-faint)] px-2 py-1\">In Servers</span>\n ) : (\n <button\n onClick={() => addConfig(config.id)}\n disabled={isAdding}\n className=\"text-xs bg-[var(--color-accent)] hover:bg-[var(--color-accent-hover)] text-black px-3 py-1 rounded font-medium transition disabled:opacity-50\"\n >\n {isAdding ? \"Adding...\" : \"Add\"}\n </button>\n )}\n </div>\n </div>\n );\n })}\n </div>\n )}\n </div>\n )}\n\n {/* Browse Toolkits Tab */}\n {subTab === \"toolkits\" && (\n <div>\n <p className=\"text-sm text-[var(--color-text-muted)] mb-4\">\n Browse available toolkits and create MCP servers\n </p>\n <IntegrationsPanel\n providerId=\"agentdojo\"\n projectId={projectId}\n onConnectionComplete={() => {\n fetchConfigs();\n }}\n />\n </div>\n )}\n </div>\n </>\n );\n}\n\n// Parse command and extract credential placeholders\nfunction parseCommandForCredentials(cmd: string): {\n cleanCommand: string;\n credentials: Array<{ key: string; flag: string }>;\n serverName: string | null;\n} {\n const credentials: Array<{ key: string; flag: string }> = [];\n let cleanCommand = cmd;\n let serverName: string | null = null;\n\n // Try to extract server name from package (e.g., pushover-mcp@latest -> pushover)\n const pkgMatch = cmd.match(/(?:npx\\s+-y\\s+)?(@?[\\w-]+\\/)?(@?[\\w-]+)(?:@[\\w.-]+)?/);\n if (pkgMatch) {\n const pkg = pkgMatch[2] || pkgMatch[1];\n if (pkg) {\n // Extract name: \"pushover-mcp\" -> \"pushover\", \"@org/server-github\" -> \"github\"\n serverName = pkg\n .replace(/^@/, '')\n .replace(/-mcp$/, '')\n .replace(/-server$/, '')\n .replace(/^server-/, '')\n .replace(/^mcp-/, '');\n }\n }\n\n // Pattern: --flag YOUR_VALUE, --flag <value>, --flag {value}, --flag $VALUE\n // Matches: --token YOUR_TOKEN, --user YOUR_USER, --api-key <API_KEY>, etc.\n const argPattern = /--(\\w+[-\\w]*)\\s+(YOUR_\\w+|<[\\w_]+>|\\{[\\w_]+\\}|\\$[\\w_]+|[\\w_]*(?:TOKEN|KEY|SECRET|PASSWORD|USER|ID|APIKEY)[\\w_]*)/gi;\n\n let match;\n while ((match = argPattern.exec(cmd)) !== null) {\n const flag = match[1];\n const placeholder = match[2];\n\n // Convert flag to env var name: api-key -> API_KEY, token -> TOKEN\n const envKey = flag.toUpperCase().replace(/-/g, '_');\n\n // Add prefix based on server name if available\n const fullKey = serverName\n ? `${serverName.toUpperCase().replace(/-/g, '_')}_${envKey}`\n : envKey;\n\n credentials.push({ key: fullKey, flag });\n\n // Replace placeholder with $ENV_VAR reference in command\n cleanCommand = cleanCommand.replace(\n new RegExp(`(--${flag}\\\\s+)${placeholder.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}`, 'i'),\n `--${flag} $${fullKey}`\n );\n }\n\n return { cleanCommand, credentials, serverName };\n}\n\nfunction AddServerModal({\n onClose,\n onAdded,\n projects,\n defaultProjectId,\n}: {\n onClose: () => void;\n onAdded: () => void;\n projects?: Array<{ id: string; name: string; color: string }>;\n defaultProjectId?: string | null;\n}) {\n const { authFetch } = useAuth();\n const [mode, setMode] = useState<\"npm\" | \"pip\" | \"command\" | \"http\">(\"npm\");\n const [name, setName] = useState(\"\");\n const [pkg, setPkg] = useState(\"\");\n const [pipModule, setPipModule] = useState(\"\");\n const [command, setCommand] = useState(\"\");\n const [url, setUrl] = useState(\"\");\n const [username, setUsername] = useState(\"\");\n const [password, setPassword] = useState(\"\");\n const [envVars, setEnvVars] = useState<Array<{ key: string; value: string }>>([]);\n const [projectId, setProjectId] = useState<string | null>(defaultProjectId || null);\n const [saving, setSaving] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const hasProjects = projects && projects.length > 0;\n\n const addEnvVar = () => {\n setEnvVars([...envVars, { key: \"\", value: \"\" }]);\n };\n\n const updateEnvVar = (index: number, field: \"key\" | \"value\", value: string) => {\n const updated = [...envVars];\n updated[index][field] = value;\n setEnvVars(updated);\n };\n\n const removeEnvVar = (index: number) => {\n setEnvVars(envVars.filter((_, i) => i !== index));\n };\n\n // Handle command input - parse and extract credentials\n const handleCommandChange = (value: string) => {\n setCommand(value);\n\n // Only parse if it looks like a full command with placeholders\n if (value.includes('YOUR_') || value.includes('<') || value.includes('{') ||\n /TOKEN|KEY|SECRET|PASSWORD/i.test(value)) {\n const { cleanCommand, credentials, serverName } = parseCommandForCredentials(value);\n\n // Auto-set name if empty\n if (!name && serverName) {\n setName(serverName);\n }\n\n // Add any new credentials that don't already exist\n if (credentials.length > 0) {\n const existingKeys = new Set(envVars.map(e => e.key));\n const newVars = credentials\n .filter(c => !existingKeys.has(c.key))\n .map(c => ({ key: c.key, value: \"\" }));\n\n if (newVars.length > 0) {\n setEnvVars([...envVars, ...newVars]);\n // Update command to use clean version with env var references\n setCommand(cleanCommand);\n }\n }\n }\n };\n\n // Handle package input - detect if user pasted a full command\n const handlePackageChange = (value: string) => {\n // Check if this looks like a full command (has npx, spaces with args, or credential placeholders)\n const looksLikeCommand =\n value.startsWith('npx ') ||\n value.includes(' --') ||\n value.includes('YOUR_') ||\n value.includes('<') ||\n /\\s+(TOKEN|KEY|SECRET|PASSWORD)/i.test(value);\n\n if (looksLikeCommand) {\n // Switch to command mode and parse\n setMode(\"command\");\n handleCommandChange(value);\n } else {\n // Just a package name\n setPkg(value);\n\n // Try to auto-set name from package\n if (!name && value) {\n const serverName = value\n .replace(/^@[\\w-]+\\//, '') // Remove org prefix\n .replace(/@[\\w.-]+$/, '') // Remove version\n .replace(/^server-/, '')\n .replace(/-server$/, '')\n .replace(/^mcp-/, '')\n .replace(/-mcp$/, '');\n if (serverName && serverName !== value) {\n setName(serverName);\n }\n }\n }\n };\n\n const handleAdd = async () => {\n if (!name) {\n setError(\"Name is required\");\n return;\n }\n\n if (mode === \"npm\" && !pkg) {\n setError(\"npm package is required\");\n return;\n }\n\n if (mode === \"pip\" && !pkg) {\n setError(\"pip package is required\");\n return;\n }\n\n if (mode === \"command\" && !command) {\n setError(\"Command is required\");\n return;\n }\n\n if (mode === \"http\" && !url) {\n setError(\"URL is required\");\n return;\n }\n\n setSaving(true);\n setError(null);\n\n // Build env object from envVars array\n const env: Record<string, string> = {};\n for (const { key, value } of envVars) {\n if (key.trim()) {\n env[key.trim()] = value;\n }\n }\n\n try {\n const body: Record<string, unknown> = { name };\n\n if (mode === \"npm\") {\n body.type = \"npm\";\n body.package = pkg;\n } else if (mode === \"pip\") {\n body.type = \"pip\";\n body.package = pkg;\n if (pipModule) {\n body.pip_module = pipModule;\n }\n } else if (mode === \"http\") {\n body.type = \"http\";\n body.url = url;\n // Build headers with Basic Auth if credentials provided\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n if (username && password) {\n // Base64 encode username:password for Basic Auth\n const credentials = btoa(`${username}:${password}`);\n headers[\"Authorization\"] = `Basic ${credentials}`;\n }\n body.headers = headers;\n } else {\n // Parse command into parts\n const parts = command.trim().split(/\\s+/);\n body.type = \"custom\";\n body.command = parts[0];\n body.args = parts.slice(1).join(\" \");\n }\n\n if (Object.keys(env).length > 0) {\n body.env = env;\n }\n\n // Add project_id if selected\n if (projectId) {\n body.project_id = projectId;\n }\n\n const res = await authFetch(\"/api/mcp/servers\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n\n if (!res.ok) {\n const data = await res.json();\n setError(data.error || \"Failed to add server\");\n setSaving(false);\n return;\n }\n\n onAdded();\n } catch (e) {\n setError(\"Failed to add server\");\n setSaving(false);\n }\n };\n\n const quickAdd = (serverName: string, serverPkg: string) => {\n setMode(\"npm\");\n setName(serverName);\n setPkg(serverPkg);\n };\n\n return (\n <div className=\"fixed inset-0 bg-black/50 backdrop-blur-[2px] z-50 flex items-center justify-center p-4\">\n <div className=\"bg-[var(--color-surface)] card w-full max-w-lg max-h-[90vh] overflow-y-auto\">\n <div className=\"p-4 border-b border-[var(--color-border)] flex items-center justify-between sticky top-0 bg-[var(--color-surface)]\">\n <h2 className=\"text-lg font-semibold\">Add MCP Server</h2>\n <button onClick={onClose} className=\"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]\">\n ✕\n </button>\n </div>\n\n <div className=\"p-4 space-y-4\">\n {/* Quick picks */}\n <div>\n <p className=\"text-sm text-[var(--color-text-muted)] mb-2\">Quick add:</p>\n <div className=\"flex flex-wrap gap-2\">\n {[\n { name: \"filesystem\", pkg: \"@modelcontextprotocol/server-filesystem\", type: \"npm\" as const },\n { name: \"fetch\", pkg: \"@modelcontextprotocol/server-fetch\", type: \"npm\" as const },\n { name: \"memory\", pkg: \"@modelcontextprotocol/server-memory\", type: \"npm\" as const },\n { name: \"github\", pkg: \"@modelcontextprotocol/server-github\", type: \"npm\" as const },\n { name: \"time\", pkg: \"mcp-server-time\", module: \"mcp_server_time\", type: \"pip\" as const },\n ].map(s => (\n <button\n key={s.name}\n onClick={() => {\n setMode(s.type);\n setName(s.name);\n setPkg(s.pkg);\n if (s.type === \"pip\" && \"module\" in s) {\n setPipModule(s.module || \"\");\n } else {\n setPipModule(\"\");\n }\n }}\n className=\"text-sm bg-[var(--color-surface-raised)] hover:bg-[var(--color-surface-raised)] px-3 py-1 rounded transition\"\n >\n {s.name}\n </button>\n ))}\n </div>\n </div>\n\n {/* Mode toggle */}\n <div className=\"flex gap-1 bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded p-1\">\n <button\n onClick={() => setMode(\"npm\")}\n className={`flex-1 px-2 py-1.5 rounded text-sm transition ${\n mode === \"npm\"\n ? \"bg-[var(--color-surface-raised)] text-white\"\n : \"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]\"\n }`}\n >\n npm\n </button>\n <button\n onClick={() => setMode(\"pip\")}\n className={`flex-1 px-2 py-1.5 rounded text-sm transition ${\n mode === \"pip\"\n ? \"bg-[var(--color-surface-raised)] text-white\"\n : \"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]\"\n }`}\n >\n pip\n </button>\n <button\n onClick={() => setMode(\"command\")}\n className={`flex-1 px-2 py-1.5 rounded text-sm transition ${\n mode === \"command\"\n ? \"bg-[var(--color-surface-raised)] text-white\"\n : \"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]\"\n }`}\n >\n Command\n </button>\n <button\n onClick={() => setMode(\"http\")}\n className={`flex-1 px-2 py-1.5 rounded text-sm transition ${\n mode === \"http\"\n ? \"bg-[var(--color-surface-raised)] text-white\"\n : \"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]\"\n }`}\n >\n HTTP\n </button>\n </div>\n\n {/* Name */}\n <div>\n <label className=\"block text-sm text-[var(--color-text-muted)] mb-1\">Name</label>\n <input\n type=\"text\"\n value={name}\n onChange={e => setName(e.target.value)}\n placeholder=\"e.g., pushover\"\n className=\"w-full bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-3 py-2 focus:outline-none focus:border-[var(--color-accent)]\"\n />\n </div>\n\n {/* Project Scope - only show when projects exist */}\n {hasProjects && (\n <div>\n <label className=\"block text-sm text-[var(--color-text-muted)] mb-1\">Scope</label>\n <Select\n value={projectId || \"\"}\n onChange={(value) => setProjectId(value || null)}\n options={[\n { value: \"\", label: \"Global (all projects)\" },\n ...projects!.map(p => ({ value: p.id, label: p.name }))\n ]}\n placeholder=\"Select scope...\"\n />\n <p className=\"text-xs text-[var(--color-text-faint)] mt-1\">\n Global servers are available to all agents. Project-scoped servers are only available to agents in that project.\n </p>\n </div>\n )}\n\n {/* npm Package */}\n {mode === \"npm\" && (\n <div>\n <label className=\"block text-sm text-[var(--color-text-muted)] mb-1\">npm Package</label>\n <input\n type=\"text\"\n value={pkg}\n onChange={e => handlePackageChange(e.target.value)}\n placeholder=\"e.g., @modelcontextprotocol/server-filesystem or paste full command\"\n className=\"w-full bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-3 py-2 focus:outline-none focus:border-[var(--color-accent)]\"\n />\n <p className=\"text-xs text-[var(--color-text-faint)] mt-1\">\n Package name or paste a full npx command with credentials\n </p>\n </div>\n )}\n\n {/* pip Package (Python) */}\n {mode === \"pip\" && (\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-sm text-[var(--color-text-muted)] mb-1\">pip Package</label>\n <input\n type=\"text\"\n value={pkg}\n onChange={e => {\n setPkg(e.target.value);\n // Auto-set module from package name\n if (!pipModule && e.target.value) {\n const basePkg = e.target.value.split(\"[\")[0].replace(/-/g, \".\");\n setPipModule(basePkg);\n }\n }}\n placeholder=\"e.g., late-sdk[mcp]\"\n className=\"w-full bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-3 py-2 focus:outline-none focus:border-[var(--color-accent)]\"\n />\n <p className=\"text-xs text-[var(--color-text-faint)] mt-1\">\n Python package with extras, e.g., late-sdk[mcp] or mcp-server-time\n </p>\n </div>\n <div>\n <label className=\"block text-sm text-[var(--color-text-muted)] mb-1\">Module (optional)</label>\n <input\n type=\"text\"\n value={pipModule}\n onChange={e => setPipModule(e.target.value)}\n placeholder=\"e.g., late.mcp\"\n className=\"w-full bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-3 py-2 font-mono text-sm focus:outline-none focus:border-[var(--color-accent)]\"\n />\n <p className=\"text-xs text-[var(--color-text-faint)] mt-1\">\n Python module to run with -m. Auto-detected from package name if not specified.\n </p>\n </div>\n </div>\n )}\n\n {/* Custom Command */}\n {mode === \"command\" && (\n <div>\n <label className=\"block text-sm text-[var(--color-text-muted)] mb-1\">Command</label>\n <input\n type=\"text\"\n value={command}\n onChange={e => handleCommandChange(e.target.value)}\n placeholder=\"e.g., npx -y pushover-mcp@latest start --token YOUR_TOKEN\"\n className=\"w-full bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-3 py-2 font-mono text-sm focus:outline-none focus:border-[var(--color-accent)]\"\n />\n <p className=\"text-xs text-[var(--color-text-faint)] mt-1\">\n Paste the full command - credentials like YOUR_TOKEN will be auto-extracted\n </p>\n </div>\n )}\n\n {/* HTTP Endpoint */}\n {mode === \"http\" && (\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-sm text-[var(--color-text-muted)] mb-1\">URL</label>\n <input\n type=\"text\"\n value={url}\n onChange={e => setUrl(e.target.value)}\n placeholder=\"e.g., https://example.com/wp-json/mcp/v1/messages\"\n className=\"w-full bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-3 py-2 font-mono text-sm focus:outline-none focus:border-[var(--color-accent)]\"\n />\n </div>\n <div className=\"p-3 bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded\">\n <p className=\"text-xs text-[var(--color-text-muted)] mb-3\">\n Optional: Basic Auth credentials (will be encoded and stored securely)\n </p>\n <div className=\"grid grid-cols-2 gap-3\">\n <div>\n <label className=\"block text-xs text-[var(--color-text-faint)] mb-1\">Username</label>\n <input\n type=\"text\"\n value={username}\n onChange={e => setUsername(e.target.value)}\n placeholder=\"username\"\n className=\"w-full bg-[var(--color-surface)] border border-[var(--color-border-light)] rounded px-3 py-2 text-sm focus:outline-none focus:border-[var(--color-accent)]\"\n />\n </div>\n <div>\n <label className=\"block text-xs text-[var(--color-text-faint)] mb-1\">Password</label>\n <input\n type=\"password\"\n value={password}\n onChange={e => setPassword(e.target.value)}\n placeholder=\"password or app key\"\n className=\"w-full bg-[var(--color-surface)] border border-[var(--color-border-light)] rounded px-3 py-2 text-sm focus:outline-none focus:border-[var(--color-accent)]\"\n />\n </div>\n </div>\n </div>\n </div>\n )}\n\n {/* Environment Variables / Credentials */}\n <div>\n <div className=\"flex items-center justify-between mb-2\">\n <label className=\"text-sm text-[var(--color-text-muted)]\">\n Environment Variables / Credentials\n </label>\n <button\n onClick={addEnvVar}\n className=\"text-xs text-[var(--color-accent)] hover:text-[var(--color-accent-hover)] transition\"\n >\n + Add Variable\n </button>\n </div>\n\n {envVars.length === 0 && (\n <p className=\"text-xs text-[var(--color-text-faint)] bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded p-3\">\n Add environment variables for API tokens and credentials.\n These are stored encrypted and passed to the server at startup.\n </p>\n )}\n\n {envVars.length > 0 && (\n <div className=\"space-y-2\">\n {envVars.map((env, index) => (\n <div key={index} className=\"flex gap-2\">\n <input\n type=\"text\"\n value={env.key}\n onChange={e => updateEnvVar(index, \"key\", e.target.value)}\n placeholder=\"KEY\"\n className=\"w-1/3 bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-2 py-1.5 text-sm font-mono focus:outline-none focus:border-[var(--color-accent)]\"\n />\n <input\n type=\"password\"\n value={env.value}\n onChange={e => updateEnvVar(index, \"value\", e.target.value)}\n placeholder=\"value\"\n className=\"flex-1 bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-2 py-1.5 text-sm font-mono focus:outline-none focus:border-[var(--color-accent)]\"\n />\n <button\n onClick={() => removeEnvVar(index)}\n className=\"text-[var(--color-text-muted)] hover:text-red-400 px-2 transition\"\n >\n ✕\n </button>\n </div>\n ))}\n </div>\n )}\n </div>\n\n {error && <p className=\"text-red-400 text-sm\">{error}</p>}\n </div>\n\n <div className=\"p-4 border-t border-[var(--color-border)] flex justify-end gap-2 sticky bottom-0 bg-[var(--color-surface)]\">\n <button\n onClick={onClose}\n className=\"px-4 py-2 border border-[var(--color-border-light)] hover:border-[var(--color-text-muted)] rounded transition\"\n >\n Cancel\n </button>\n <button\n onClick={handleAdd}\n disabled={saving || !name || (mode === \"npm\" ? !pkg : mode === \"pip\" ? !pkg : mode === \"http\" ? !url : !command)}\n className=\"px-4 py-2 bg-[var(--color-accent)] hover:bg-[var(--color-accent-hover)] text-black rounded font-medium transition disabled:opacity-50\"\n >\n {saving ? \"Adding...\" : \"Add Server\"}\n </button>\n </div>\n </div>\n </div>\n );\n}\n\nfunction EditServerModal({\n server,\n projects,\n onClose,\n onSaved,\n}: {\n server: McpServer;\n projects?: Array<{ id: string; name: string; color: string }>;\n onClose: () => void;\n onSaved: () => void;\n}) {\n const { authFetch } = useAuth();\n const [name, setName] = useState(server.name);\n const [pkg, setPkg] = useState(server.package || \"\");\n const [command, setCommand] = useState(server.command || \"\");\n const [args, setArgs] = useState(server.args || \"\");\n const [url, setUrl] = useState(server.url || \"\");\n // Extract username/password from existing Basic Auth header\n const [username, setUsername] = useState(() => {\n const authHeader = server.headers?.[\"Authorization\"] || \"\";\n if (authHeader.startsWith(\"Basic \")) {\n try {\n const decoded = atob(authHeader.slice(6));\n return decoded.split(\":\")[0] || \"\";\n } catch { return \"\"; }\n }\n return \"\";\n });\n const [password, setPassword] = useState(() => {\n const authHeader = server.headers?.[\"Authorization\"] || \"\";\n if (authHeader.startsWith(\"Basic \")) {\n try {\n const decoded = atob(authHeader.slice(6));\n const parts = decoded.split(\":\");\n return parts.slice(1).join(\":\") || \"\";\n } catch { return \"\"; }\n }\n return \"\";\n });\n const [envVars, setEnvVars] = useState<Array<{ key: string; value: string }>>(() => {\n // Convert env object to array format\n return Object.entries(server.env || {}).map(([key, value]) => ({ key, value }));\n });\n const [projectId, setProjectId] = useState<string | null>(server.project_id);\n const [saving, setSaving] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const hasProjects = projects && projects.length > 0;\n const isRemote = server.type === \"http\";\n\n const addEnvVar = () => {\n setEnvVars([...envVars, { key: \"\", value: \"\" }]);\n };\n\n const updateEnvVar = (index: number, field: \"key\" | \"value\", value: string) => {\n const updated = [...envVars];\n updated[index][field] = value;\n setEnvVars(updated);\n };\n\n const removeEnvVar = (index: number) => {\n setEnvVars(envVars.filter((_, i) => i !== index));\n };\n\n const handleSave = async () => {\n if (!name.trim()) {\n setError(\"Name is required\");\n return;\n }\n\n setSaving(true);\n setError(null);\n\n // Build env object from envVars array\n const env: Record<string, string> = {};\n for (const { key, value } of envVars) {\n if (key.trim()) {\n env[key.trim()] = value;\n }\n }\n\n try {\n const updates: Record<string, unknown> = {\n name: name.trim(),\n env,\n };\n\n // Only include fields that are relevant to the server type\n if (isRemote) {\n // HTTP server - update URL and headers\n if (url.trim()) {\n updates.url = url.trim();\n }\n // Build headers with Basic Auth if credentials provided\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n if (username && password) {\n const credentials = btoa(`${username}:${password}`);\n headers[\"Authorization\"] = `Basic ${credentials}`;\n }\n updates.headers = headers;\n } else {\n if (server.type === \"npm\" && pkg.trim()) {\n updates.package = pkg.trim();\n }\n if (server.type === \"pip\" && pkg.trim()) {\n updates.package = pkg.trim();\n }\n if (server.type === \"custom\") {\n if (command.trim()) updates.command = command.trim();\n if (args.trim()) updates.args = args.trim();\n }\n }\n\n // Include project_id update\n updates.project_id = projectId;\n\n const res = await authFetch(`/api/mcp/servers/${server.id}`, {\n method: \"PUT\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(updates),\n });\n\n if (!res.ok) {\n const data = await res.json();\n setError(data.error || \"Failed to save changes\");\n setSaving(false);\n return;\n }\n\n // If server was running, restart it to apply new env vars\n if (server.status === \"running\" && !isRemote) {\n try {\n // Stop the server\n await authFetch(`/api/mcp/servers/${server.id}/stop`, { method: \"POST\" });\n // Start it again\n await authFetch(`/api/mcp/servers/${server.id}/start`, { method: \"POST\" });\n } catch (e) {\n console.error(\"Failed to restart server:\", e);\n // Don't fail the save, just log the error\n }\n }\n\n onSaved();\n } catch (e) {\n setError(\"Failed to save changes\");\n setSaving(false);\n }\n };\n\n return (\n <div className=\"fixed inset-0 bg-black/50 backdrop-blur-[2px] z-50 flex items-center justify-center p-4\">\n <div className=\"bg-[var(--color-surface)] card w-full max-w-lg max-h-[90vh] overflow-y-auto\">\n <div className=\"p-4 border-b border-[var(--color-border)] flex items-center justify-between sticky top-0 bg-[var(--color-surface)]\">\n <h2 className=\"text-lg font-semibold\">Edit MCP Server</h2>\n <button onClick={onClose} className=\"text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]\">\n ✕\n </button>\n </div>\n\n <div className=\"p-4 space-y-4\">\n {/* Server Type Info */}\n <div className=\"text-sm text-[var(--color-text-muted)] bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded p-3\">\n Type: <span className=\"text-[var(--color-text-secondary)]\">{server.type}</span>\n {server.package && <> • Package: <span className=\"text-[var(--color-text-secondary)] font-mono\">{server.package}</span></>}\n {server.command && <> • Command: <span className=\"text-[var(--color-text-secondary)] font-mono\">{server.command}</span></>}\n </div>\n\n {/* Name */}\n <div>\n <label className=\"block text-sm text-[var(--color-text-muted)] mb-1\">Name</label>\n <input\n type=\"text\"\n value={name}\n onChange={e => setName(e.target.value)}\n className=\"w-full bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-3 py-2 focus:outline-none focus:border-[var(--color-accent)]\"\n />\n </div>\n\n {/* Project Scope */}\n {hasProjects && (\n <div>\n <label className=\"block text-sm text-[var(--color-text-muted)] mb-1\">Scope</label>\n <Select\n value={projectId || \"\"}\n onChange={(value) => setProjectId(value || null)}\n options={[\n { value: \"\", label: \"Global (all projects)\" },\n ...projects!.map(p => ({ value: p.id, label: p.name }))\n ]}\n placeholder=\"Select scope...\"\n />\n </div>\n )}\n\n {/* Package (for npm type) */}\n {server.type === \"npm\" && (\n <div>\n <label className=\"block text-sm text-[var(--color-text-muted)] mb-1\">npm Package</label>\n <input\n type=\"text\"\n value={pkg}\n onChange={e => setPkg(e.target.value)}\n className=\"w-full bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-3 py-2 font-mono text-sm focus:outline-none focus:border-[var(--color-accent)]\"\n />\n </div>\n )}\n\n {/* Package (for pip type) */}\n {server.type === \"pip\" && (\n <div>\n <label className=\"block text-sm text-[var(--color-text-muted)] mb-1\">pip Package</label>\n <input\n type=\"text\"\n value={pkg}\n onChange={e => setPkg(e.target.value)}\n className=\"w-full bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-3 py-2 font-mono text-sm focus:outline-none focus:border-[var(--color-accent)]\"\n />\n </div>\n )}\n\n {/* URL & Credentials (for http type) */}\n {isRemote && (\n <>\n <div>\n <label className=\"block text-sm text-[var(--color-text-muted)] mb-1\">Server URL</label>\n <input\n type=\"text\"\n value={url}\n onChange={e => setUrl(e.target.value)}\n placeholder=\"https://example.com/mcp\"\n className=\"w-full bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-3 py-2 font-mono text-sm focus:outline-none focus:border-[var(--color-accent)]\"\n />\n </div>\n <div>\n <label className=\"block text-sm text-[var(--color-text-muted)] mb-1\">Authentication (Basic Auth)</label>\n <div className=\"flex gap-2\">\n <input\n type=\"text\"\n value={username}\n onChange={e => setUsername(e.target.value)}\n placeholder=\"Username\"\n className=\"flex-1 bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-3 py-2 text-sm focus:outline-none focus:border-[var(--color-accent)]\"\n />\n <input\n type=\"password\"\n value={password}\n onChange={e => setPassword(e.target.value)}\n placeholder=\"Password / App Password\"\n className=\"flex-1 bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-3 py-2 text-sm focus:outline-none focus:border-[var(--color-accent)]\"\n />\n </div>\n <p className=\"text-xs text-[var(--color-text-faint)] mt-1\">\n Leave empty if no authentication required\n </p>\n </div>\n </>\n )}\n\n {/* Command & Args (for custom type) */}\n {server.type === \"custom\" && (\n <>\n <div>\n <label className=\"block text-sm text-[var(--color-text-muted)] mb-1\">Command</label>\n <input\n type=\"text\"\n value={command}\n onChange={e => setCommand(e.target.value)}\n className=\"w-full bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-3 py-2 font-mono text-sm focus:outline-none focus:border-[var(--color-accent)]\"\n />\n </div>\n <div>\n <label className=\"block text-sm text-[var(--color-text-muted)] mb-1\">Arguments</label>\n <input\n type=\"text\"\n value={args}\n onChange={e => setArgs(e.target.value)}\n placeholder=\"e.g., --token $TOKEN --verbose\"\n className=\"w-full bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-3 py-2 font-mono text-sm focus:outline-none focus:border-[var(--color-accent)]\"\n />\n </div>\n </>\n )}\n\n {/* Environment Variables */}\n {!isRemote && (\n <div>\n <div className=\"flex items-center justify-between mb-2\">\n <label className=\"text-sm text-[var(--color-text-muted)]\">\n Environment Variables / Credentials\n </label>\n <button\n onClick={addEnvVar}\n className=\"text-xs text-[var(--color-accent)] hover:text-[var(--color-accent-hover)] transition\"\n >\n + Add Variable\n </button>\n </div>\n\n {envVars.length === 0 && (\n <p className=\"text-xs text-[var(--color-text-faint)] bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded p-3\">\n No environment variables configured.\n </p>\n )}\n\n {envVars.length > 0 && (\n <div className=\"space-y-2\">\n {envVars.map((env, index) => (\n <div key={index} className=\"flex gap-2\">\n <input\n type=\"text\"\n value={env.key}\n onChange={e => updateEnvVar(index, \"key\", e.target.value)}\n placeholder=\"KEY\"\n className=\"w-1/3 bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-2 py-1.5 text-sm font-mono focus:outline-none focus:border-[var(--color-accent)]\"\n />\n <input\n type=\"password\"\n value={env.value}\n onChange={e => updateEnvVar(index, \"value\", e.target.value)}\n placeholder=\"value\"\n className=\"flex-1 bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-2 py-1.5 text-sm font-mono focus:outline-none focus:border-[var(--color-accent)]\"\n />\n <button\n onClick={() => removeEnvVar(index)}\n className=\"text-[var(--color-text-muted)] hover:text-red-400 px-2 transition\"\n >\n ✕\n </button>\n </div>\n ))}\n </div>\n )}\n\n <p className=\"text-xs text-[var(--color-text-faint)] mt-2\">\n {server.status === \"running\" ? \"Server will be automatically restarted to apply changes.\" : \"Changes will take effect when the server is started.\"}\n </p>\n </div>\n )}\n\n {error && <p className=\"text-red-400 text-sm\">{error}</p>}\n </div>\n\n <div className=\"p-4 border-t border-[var(--color-border)] flex justify-end gap-2 sticky bottom-0 bg-[var(--color-surface)]\">\n <button\n onClick={onClose}\n className=\"px-4 py-2 border border-[var(--color-border-light)] hover:border-[var(--color-text-muted)] rounded transition\"\n >\n Cancel\n </button>\n <button\n onClick={handleSave}\n disabled={saving || !name.trim()}\n className=\"px-4 py-2 bg-[var(--color-accent)] hover:bg-[var(--color-accent-hover)] text-black rounded font-medium transition disabled:opacity-50\"\n >\n {saving ? \"Saving...\" : \"Save Changes\"}\n </button>\n </div>\n </div>\n </div>\n );\n}\n"
6
+ ],
7
+ "mappings": "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",
8
+ "debugId": "C82C00D733F3FB7164756E2164756E21",
9
+ "names": []
10
+ }