From d96e26064fd73e81d666b4fc752ed861230cf96b Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Fri, 22 May 2026 21:25:28 +0530 Subject: [PATCH 1/3] Fix conflicts and UI (#28477) --- .../_next/static/chunks/e1a670efcb966aaa.js | 26 +------------------ 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/litellm/proxy/_experimental/out/_next/static/chunks/e1a670efcb966aaa.js b/litellm/proxy/_experimental/out/_next/static/chunks/e1a670efcb966aaa.js index 87d6af3231a..aafe9858009 100644 --- a/litellm/proxy/_experimental/out/_next/static/chunks/e1a670efcb966aaa.js +++ b/litellm/proxy/_experimental/out/_next/static/chunks/e1a670efcb966aaa.js @@ -1,19 +1,11 @@ -<<<<<<<< HEAD:litellm/proxy/_experimental/out/_next/static/chunks/0279e5299e9f6e98.js -(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,111790,758472,280881,e=>{"use strict";e.s([],111790);var t=e.i(843476),s=e.i(708347),r=e.i(750113),l=e.i(994388),a=e.i(197647),n=e.i(653824),i=e.i(881073),o=e.i(404206),c=e.i(723731),d=e.i(599724),m=e.i(629569),u=e.i(844444),x=e.i(869216),h=e.i(212931),p=e.i(199133),g=e.i(592968),f=e.i(898586),b=e.i(271645),j=e.i(500727),y=e.i(266027),v=e.i(912598),N=e.i(243652),_=e.i(764205),w=e.i(135214);let S=(0,N.createQueryKeys)("mcpServerHealth");var C=e.i(727749),T=e.i(988846),k=e.i(678784),A=e.i(995926),I=e.i(328196),P=e.i(302202),O=e.i(409797),M=e.i(54131),F=e.i(440987);let E=[{label:"Documentation",fields:[{key:"description",label:"Description",description:"Must have a non-empty description",check:e=>!!e.description?.trim()},{key:"alias",label:"Alias",description:"Must have a display alias",check:e=>!!e.alias?.trim()}]},{label:"Source",fields:[{key:"source_url",label:"GitHub / Source URL",description:"Must link to a source repository",check:e=>!!e.source_url?.trim()}]},{label:"Connection",fields:[{key:"url",label:"Server URL",description:"Must have a URL configured",check:e=>!!e.url?.trim()}]},{label:"Security",fields:[{key:"auth_type",label:"Auth configured",description:"Must use authentication (not 'none')",check:e=>!!e.auth_type&&"none"!==e.auth_type}]}],L=E.flatMap(e=>e.fields),R="mcp_required_fields",U={active:{label:"Active",bg:"bg-green-50",text:"text-green-700",dot:"bg-green-500"},pending_review:{label:"Pending Review",bg:"bg-yellow-50",text:"text-yellow-700",dot:"bg-yellow-500"},rejected:{label:"Rejected",bg:"bg-red-50",text:"text-red-700",dot:"bg-red-500"}};function z({label:e,value:s,color:r}){return(0,t.jsxs)("div",{className:"bg-white border border-gray-200 rounded-lg px-4 py-3",children:[(0,t.jsx)("div",{className:`text-2xl font-bold ${r}`,children:s}),(0,t.jsx)("div",{className:"text-xs text-gray-500 mt-0.5",children:e})]})}function B({action:e,serverName:s,isCurrentlyActive:r,onConfirm:l,onCancel:a}){let[n,i]=(0,b.useState)(""),o="approve"===e;return(0,t.jsx)("div",{className:"fixed inset-0 bg-black/30 flex items-center justify-center z-50",children:(0,t.jsxs)("div",{className:"bg-white rounded-xl shadow-xl p-6 max-w-sm w-full mx-4",children:[(0,t.jsx)("div",{className:`w-10 h-10 rounded-full flex items-center justify-center mb-4 ${o?"bg-green-100":"bg-red-100"}`,children:o?(0,t.jsx)(k.CheckIcon,{className:"h-5 w-5 text-green-600"}):(0,t.jsx)(I.AlertCircleIcon,{className:"h-5 w-5 text-red-600"})}),(0,t.jsx)("h3",{className:"text-base font-semibold text-gray-900 mb-1",children:o?"Approve MCP Server":"Reject MCP Server"}),(0,t.jsxs)("p",{className:"text-sm text-gray-500 mb-4",children:["Are you sure you want to ",e," ",(0,t.jsxs)("span",{className:"font-medium text-gray-700",children:['"',s,'"']}),"?"," ",o?"This will make it active and available for use.":r?"This server is currently live. Rejecting it will immediately remove it from the proxy runtime.":"This will mark the submission as rejected."]}),!o&&(0,t.jsx)("textarea",{placeholder:"Reason for rejection (optional)",value:n,onChange:e=>i(e.target.value),className:"w-full border border-gray-200 rounded-md px-3 py-2 text-sm text-gray-700 placeholder-gray-400 focus:outline-none focus:ring-1 focus:ring-blue-500 mb-4 resize-none",rows:3}),(0,t.jsxs)("div",{className:"flex gap-3",children:[(0,t.jsx)("button",{type:"button",onClick:a,className:"flex-1 border border-gray-300 text-gray-700 hover:bg-gray-50 text-sm font-medium py-2 rounded-md transition-colors",children:"Cancel"}),(0,t.jsx)("button",{type:"button",onClick:()=>l(o?void 0:n||void 0),className:`flex-1 text-white text-sm font-medium py-2 rounded-md transition-colors ${o?"bg-green-500 hover:bg-green-600":"bg-red-500 hover:bg-red-600"}`,children:o?"Approve":"Reject"})]})]})})}function q({requiredFields:e,onChange:s,onSave:r,isSaving:l}){let[a,n]=(0,b.useState)(!1),i=L.filter(t=>e.includes(t.key));return(0,t.jsxs)("div",{className:"mb-5 border border-gray-200 rounded-lg bg-white overflow-hidden",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between px-4 py-3 cursor-pointer select-none",onClick:()=>n(e=>!e),children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(F.SettingsIcon,{className:"h-4 w-4 text-gray-400"}),(0,t.jsx)("span",{className:"text-sm font-semibold text-gray-800",children:"Submission Rules"}),i.length>0?(0,t.jsxs)("span",{className:"text-xs text-gray-500",children:["(",i.length," required field",1!==i.length?"s":"",")"]}):(0,t.jsx)("span",{className:"text-xs text-gray-400 italic",children:"no rules set"})]}),(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[!a&&i.length>0&&(0,t.jsx)("div",{className:"flex flex-wrap gap-1.5 max-w-md",children:i.map(e=>(0,t.jsxs)("span",{className:"inline-flex items-center gap-1 text-xs bg-blue-50 text-blue-700 border border-blue-200 px-2 py-0.5 rounded-full",children:[(0,t.jsx)(k.CheckIcon,{className:"h-3 w-3"}),e.label]},e.key))}),a?(0,t.jsx)(M.ChevronUpIcon,{className:"h-4 w-4 text-gray-400"}):(0,t.jsx)(O.ChevronDownIcon,{className:"h-4 w-4 text-gray-400"})]})]}),a&&(0,t.jsxs)("div",{className:"border-t border-gray-100 px-4 pt-4 pb-4",children:[(0,t.jsx)("p",{className:"text-xs text-gray-500 mb-4",children:"Select which fields must be filled in before a submission is considered compliant. LiteLLM will show ✓ / ✗ for each rule on every submission card below."}),(0,t.jsx)("div",{className:"grid grid-cols-2 gap-x-8 gap-y-5",children:E.map(r=>(0,t.jsxs)("div",{children:[(0,t.jsx)("div",{className:"text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2",children:r.label}),(0,t.jsx)("div",{className:"space-y-2",children:r.fields.map(r=>{let l=e.includes(r.key);return(0,t.jsxs)("label",{className:"flex items-start gap-2.5 cursor-pointer group",children:[(0,t.jsx)("input",{type:"checkbox",checked:l,onChange:()=>{var t;return t=r.key,void s(e.includes(t)?e.filter(e=>e!==t):[...e,t])},className:"mt-0.5 h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500 cursor-pointer"}),(0,t.jsxs)("div",{children:[(0,t.jsx)("div",{className:"text-sm font-medium text-gray-800 group-hover:text-blue-700 transition-colors",children:r.label}),(0,t.jsx)("div",{className:"text-xs text-gray-400",children:r.description})]})]},r.key)})})]},r.label))}),(0,t.jsxs)("div",{className:"mt-5 flex items-center gap-3",children:[(0,t.jsx)("button",{type:"button",disabled:l,onClick:async()=>{await r(),n(!1)},className:"px-4 py-1.5 text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 disabled:opacity-50 rounded-md transition-colors",children:l?"Saving…":"Save Rules"}),(0,t.jsx)("button",{type:"button",onClick:()=>n(!1),className:"px-4 py-1.5 text-sm font-medium text-gray-600 hover:text-gray-900 border border-gray-200 rounded-md hover:bg-gray-50 transition-colors",children:"Cancel"})]})]})]})}function V({server:e,onApprove:s,onReject:r,requiredFields:l}){let a=e.approval_status??"active",n=U[a]??U.active,i=L.filter(e=>l.includes(e.key)).map(t=>({key:t.key,label:t.label,description:t.description,passed:t.check(e)})),o=i.filter(e=>e.passed).length,c=i.length-o,d=i.length>0&&0===c;return(0,t.jsxs)("div",{className:"bg-white border border-gray-200 rounded-lg overflow-hidden",children:[(0,t.jsx)("div",{className:"px-4 pt-4 pb-3",children:(0,t.jsxs)("div",{className:"flex items-start justify-between gap-4",children:[(0,t.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,t.jsx)("div",{className:"flex items-center gap-2 mb-1.5",children:(0,t.jsxs)("span",{className:`inline-flex items-center gap-1.5 text-xs font-medium px-2 py-0.5 rounded-full ${n.bg} ${n.text}`,children:[(0,t.jsx)("span",{className:`w-1.5 h-1.5 rounded-full ${n.dot}`}),n.label]})}),(0,t.jsx)("h3",{className:"text-sm font-semibold text-gray-900",children:e.alias??e.server_name??e.server_id}),e.description&&(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 line-clamp-1",children:e.description}),e.url&&(0,t.jsxs)("div",{className:"flex items-center gap-1.5 mt-1.5",children:[(0,t.jsx)(P.ServerIcon,{className:"h-3.5 w-3.5 text-gray-400 flex-shrink-0"}),(0,t.jsx)("code",{className:"text-xs text-gray-500 font-mono truncate",children:e.url})]}),(0,t.jsxs)("div",{className:"flex items-center gap-3 mt-1.5 text-xs text-gray-400",children:[(0,t.jsxs)("span",{children:["Transport: ",(0,t.jsx)("span",{className:"text-gray-600",children:e.transport??"sse"})]}),(0,t.jsx)("span",{children:"·"}),(0,t.jsxs)("span",{children:["Submitted by: ",(0,t.jsx)("span",{className:"text-gray-600",children:e.submitted_by??"—"})]}),(0,t.jsx)("span",{children:"·"}),(0,t.jsx)("span",{children:function(e){if(!e)return"—";try{let t=new Date(e);return isNaN(t.getTime())?e:t.toISOString().slice(0,10)}catch{return e}}(e.submitted_at)})]}),"rejected"===a&&e.review_notes&&(0,t.jsxs)("p",{className:"text-xs text-red-600 mt-1.5",children:["Rejection reason: ",e.review_notes]})]}),0===i.length&&"rejected"!==a&&(0,t.jsxs)("div",{className:"flex items-center gap-2 flex-shrink-0",children:["active"!==a&&(0,t.jsx)("button",{type:"button",onClick:s,className:"text-xs bg-green-500 hover:bg-green-600 text-white px-3 py-1.5 rounded-md transition-colors font-medium",children:"Approve"}),(0,t.jsx)("button",{type:"button",onClick:r,className:"text-xs border border-red-300 text-red-600 hover:bg-red-50 px-3 py-1.5 rounded-md transition-colors font-medium",children:"Reject"})]}),0===i.length&&"rejected"===a&&(0,t.jsx)("div",{className:"flex items-center gap-2 flex-shrink-0",children:(0,t.jsx)("button",{type:"button",onClick:s,className:"text-xs bg-green-500 hover:bg-green-600 text-white px-3 py-1.5 rounded-md transition-colors font-medium",children:"Re-approve"})})]})}),i.length>0&&(0,t.jsxs)("div",{className:"border-t border-gray-200",children:[(0,t.jsxs)("div",{className:`flex items-center gap-3 px-4 py-3 ${d?"bg-green-50 border-b border-green-100":"bg-red-50 border-b border-red-100"}`,children:[(0,t.jsx)("div",{className:`w-8 h-8 rounded-full flex items-center justify-center flex-shrink-0 ${d?"bg-green-500":"bg-red-500"}`,children:d?(0,t.jsx)(k.CheckIcon,{className:"h-4 w-4 text-white"}):(0,t.jsx)(A.XIcon,{className:"h-4 w-4 text-white"})}),(0,t.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,t.jsx)("div",{className:`text-sm font-semibold leading-tight ${d?"text-green-800":"text-red-800"}`,children:d?"All checks passed":`${c} check${1!==c?"s":""} failed`}),(0,t.jsxs)("div",{className:"text-xs text-gray-500 mt-0.5",children:[o," passing, ",c," failing"]})]}),(0,t.jsxs)("div",{className:"flex items-center gap-2 flex-shrink-0",children:["active"!==a&&"rejected"!==a&&(0,t.jsx)("button",{type:"button",onClick:s,className:"text-xs bg-green-600 hover:bg-green-700 text-white px-3 py-1.5 rounded-md transition-colors font-medium",children:"Approve"}),"rejected"===a&&(0,t.jsx)("button",{type:"button",onClick:s,className:"text-xs bg-green-600 hover:bg-green-700 text-white px-3 py-1.5 rounded-md transition-colors font-medium",children:"Re-approve"}),"rejected"!==a&&(0,t.jsx)("button",{type:"button",onClick:r,className:"text-xs border border-red-300 text-red-600 hover:bg-red-50 bg-white px-3 py-1.5 rounded-md transition-colors font-medium",children:"Reject"})]})]}),(0,t.jsx)("div",{className:"divide-y divide-gray-100",children:i.map(e=>(0,t.jsxs)("div",{className:"flex items-center gap-3 px-4 py-2.5",children:[(0,t.jsx)("div",{className:`w-5 h-5 rounded-full flex items-center justify-center flex-shrink-0 ${e.passed?"bg-green-100":"bg-red-100"}`,children:e.passed?(0,t.jsx)(k.CheckIcon,{className:"h-3 w-3 text-green-600"}):(0,t.jsx)(A.XIcon,{className:"h-3 w-3 text-red-600"})}),(0,t.jsx)("span",{className:`text-sm flex-1 ${e.passed?"text-gray-700":"text-gray-800"}`,children:e.label}),(0,t.jsx)("span",{className:`text-xs ${e.passed?"text-green-600":"text-red-500"}`,children:e.passed?"Passes":"Missing"})]},e.key))})]})]})}function $({accessToken:e}){let[s,r]=(0,b.useState)({total:0,pending_review:0,active:0,rejected:0,items:[]}),[l,a]=(0,b.useState)(""),[n,i]=(0,b.useState)("all"),[o,c]=(0,b.useState)(null),[d,m]=(0,b.useState)(!0),[u,x]=(0,b.useState)(null),[h,p]=(0,b.useState)([]),[g,f]=(0,b.useState)(!1),j=(0,b.useCallback)(async()=>{if(!e)return void m(!1);m(!0),x(null);try{let[t,s]=await Promise.all([(0,_.fetchMCPSubmissions)(e),(0,_.getGeneralSettingsCall)(e).catch(e=>(console.warn("MCPSubmissionsTab: failed to load general settings, compliance rules will be empty:",e),null))]);if(r(t),s?.data&&Array.isArray(s.data)){let e=s.data.find(e=>e.field_name===R);e&&Array.isArray(e.field_value)&&p(e.field_value)}}catch(e){x(e instanceof Error?e.message:"Failed to load submissions")}finally{m(!1)}},[e]);(0,b.useEffect)(()=>{j()},[j]);let y=async()=>{if(e){f(!0);try{await (0,_.updateConfigFieldSetting)(e,R,h),C.default.success("Submission rules saved")}catch{C.default.fromBackend("Failed to save submission rules")}finally{f(!1)}}},v=s.items.filter(e=>{if("all"!==n&&e.approval_status!==n)return!1;if(l.trim()){let t=l.toLowerCase(),s=(e.alias??e.server_name??e.server_id??"").toLowerCase(),r=(e.url??"").toLowerCase();return s.includes(t)||r.includes(t)}return!0});async function N(t,s){if(e)try{await (0,_.approveMCPServer)(e,t),await j(),C.default.success(`MCP server "${s}" approved`)}catch{C.default.fromBackend("Failed to approve MCP server")}finally{c(null)}}async function w(t,s,r){if(e)try{await (0,_.rejectMCPServer)(e,t,r),await j(),C.default.success(`MCP server "${s}" rejected`)}catch{C.default.fromBackend("Failed to reject MCP server")}finally{c(null)}}return(0,t.jsxs)("div",{className:"p-6",children:[(0,t.jsx)(q,{requiredFields:h,onChange:p,onSave:y,isSaving:g}),(0,t.jsxs)("div",{className:"grid grid-cols-4 gap-4 mb-6",children:[(0,t.jsx)(z,{label:"Total Submitted",value:s.total,color:"text-gray-900"}),(0,t.jsx)(z,{label:"Pending Review",value:s.pending_review,color:"text-yellow-600"}),(0,t.jsx)(z,{label:"Active",value:s.active,color:"text-green-600"}),(0,t.jsx)(z,{label:"Rejected",value:s.rejected,color:"text-red-600"})]}),(0,t.jsxs)("div",{className:"flex items-center gap-3 mb-5",children:[(0,t.jsxs)("div",{className:"relative flex-1 max-w-xs",children:[(0,t.jsx)(T.SearchIcon,{className:"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-400"}),(0,t.jsx)("input",{type:"text",placeholder:"Search MCP servers...",value:l,onChange:e=>a(e.target.value),className:"w-full pl-9 pr-4 py-2 border border-gray-200 rounded-md text-sm text-gray-700 placeholder-gray-400 focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500"})]}),(0,t.jsxs)("select",{value:n,onChange:e=>i(e.target.value),className:"border border-gray-200 rounded-md px-3 py-2 text-sm text-gray-700 focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500 bg-white",children:[(0,t.jsx)("option",{value:"all",children:"All Status"}),(0,t.jsx)("option",{value:"pending_review",children:"Pending Review"}),(0,t.jsx)("option",{value:"active",children:"Active"}),(0,t.jsx)("option",{value:"rejected",children:"Rejected"})]})]}),(0,t.jsxs)("div",{className:"space-y-3",children:[d&&(0,t.jsx)("div",{className:"text-center py-12 text-gray-500 text-sm",children:"Loading submissions…"}),u&&(0,t.jsx)("div",{className:"text-center py-12 text-red-600 text-sm",children:u}),!d&&!u&&0===v.length&&(0,t.jsx)("div",{className:"text-center py-12 text-gray-400 text-sm",children:"No MCP server submissions match your filters."}),!d&&!u&&v.map(e=>(0,t.jsx)(V,{server:e,requiredFields:h,onApprove:()=>c({serverId:e.server_id,serverName:e.alias??e.server_name??e.server_id,action:"approve"}),onReject:()=>c({serverId:e.server_id,serverName:e.alias??e.server_name??e.server_id,action:"reject",isCurrentlyActive:"active"===e.approval_status})},e.server_id))]}),o&&(0,t.jsx)(B,{action:o.action,serverName:o.serverName,isCurrentlyActive:o.isCurrentlyActive,onConfirm:e=>"approve"===o.action?N(o.serverId,o.serverName):w(o.serverId,o.serverName,e),onCancel:()=>c(null)})]})}var D=e.i(808613),H=e.i(311451),K=e.i(998573),W=e.i(482725),J=e.i(988297),Y=e.i(797672),G=e.i(68155),Q=e.i(699857),Z=e.i(149121);let{Text:X}=f.Typography;function ee({serverId:e,serverName:s,accessToken:r,selectedTools:l,onToggle:a}){let[n,i]=(0,b.useState)([]),[o,c]=(0,b.useState)(!1),[d,m]=(0,b.useState)(!1),u=new Set(l.filter(t=>t.server_id===e).map(e=>e.tool_name)),x=(0,b.useCallback)(async()=>{if(r&&!(n.length>0)){c(!0);try{let t=await (0,_.listMCPTools)(r,e),s=Array.isArray(t)?t:t?.tools??[];i(s.map(e=>({name:e.name??e.tool_name??e,description:e.description??""})))}catch{i([])}finally{c(!1)}}},[r,e,n.length]);return(0,t.jsxs)("div",{className:"border border-gray-200 rounded-lg overflow-hidden",children:[(0,t.jsxs)("button",{type:"button",className:"w-full flex items-center justify-between px-4 py-3 bg-gray-50 hover:bg-gray-100 transition-colors",onClick:()=>{d||x(),m(!d)},children:[(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center gap-2",children:[(0,t.jsx)("span",{className:"inline-block w-2 h-2 rounded-full bg-blue-500 flex-shrink-0"}),s,u.size>0&&(0,t.jsxs)("span",{className:"ml-1 text-xs text-purple-600 font-semibold",children:[u.size," selected"]})]}),(0,t.jsx)("span",{className:"text-gray-400 text-xs",children:d?"▲":"▼"})]}),d&&(0,t.jsx)("div",{className:"p-2",children:o?(0,t.jsx)("div",{className:"flex justify-center py-3",children:(0,t.jsx)(W.Spin,{size:"small"})}):0===n.length?(0,t.jsx)("p",{className:"text-xs text-gray-400 px-2 py-2",children:"No tools found for this server."}):(0,t.jsx)("div",{className:"flex flex-col gap-1",children:n.map(s=>{let r=u.has(s.name);return(0,t.jsxs)("button",{type:"button",onClick:()=>a({server_id:e,tool_name:s.name}),className:`flex items-start justify-between px-3 py-2 rounded-lg text-left transition-colors ${r?"bg-purple-50 border border-purple-300":"bg-white border border-gray-100 hover:bg-gray-50"}`,children:[(0,t.jsxs)("div",{className:"min-w-0 flex-1",children:[(0,t.jsx)("p",{className:`text-sm font-medium leading-tight ${r?"text-purple-800":"text-gray-800"}`,children:s.name}),s.description&&(0,t.jsx)("p",{className:"text-xs text-gray-400 mt-0.5 leading-tight line-clamp-2",children:s.description})]}),r&&(0,t.jsx)("span",{className:"text-purple-500 text-xs font-semibold ml-2 flex-shrink-0 mt-0.5",children:"✓"})]},s.name)})})})]})}function et({open:e,onClose:s,onSave:r,accessToken:a,initialToolset:n}){let[i]=D.Form.useForm(),[o,c]=(0,b.useState)(n?.tools||[]),[m,u]=(0,b.useState)(!1),[x,p]=(0,b.useState)(""),{data:g=[]}=(0,j.useMCPServers)();b.default.useEffect(()=>{e&&(i.setFieldsValue({toolset_name:n?.toolset_name||"",description:n?.description||""}),c(n?.tools||[]),p(""))},[e,n]);let f=e=>{c(t=>t.some(t=>t.server_id===e.server_id&&t.tool_name===e.tool_name)?t.filter(t=>t.server_id!==e.server_id||t.tool_name!==e.tool_name):[...t,e])},y=async()=>{let e=await i.validateFields();u(!0);try{await r(e.toolset_name,e.description,o),s()}finally{u(!1)}},v=g.filter(e=>{let t=x.toLowerCase();return!t||(e.alias||"").toLowerCase().includes(t)||(e.server_name||"").toLowerCase().includes(t)});return(0,t.jsxs)(h.Modal,{open:e,onCancel:s,title:n?"Edit Toolset":"New Toolset",width:960,footer:null,forceRender:!0,children:[(0,t.jsx)(D.Form,{form:i,layout:"vertical",className:"mt-2",children:(0,t.jsxs)("div",{className:"flex gap-4 mb-4",children:[(0,t.jsx)(D.Form.Item,{label:"Toolset Name",name:"toolset_name",rules:[{required:!0,message:"Please enter a toolset name"}],className:"flex-1 mb-0",children:(0,t.jsx)(H.Input,{placeholder:"e.g. github-linear-tools"})}),(0,t.jsx)(D.Form.Item,{label:"Description",name:"description",className:"flex-1 mb-0",children:(0,t.jsx)(H.Input,{placeholder:"Optional description"})})]})}),(0,t.jsxs)("div",{className:"flex gap-4 mt-2",style:{minHeight:360},children:[(0,t.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,t.jsx)("div",{className:"flex items-center justify-between mb-2",children:(0,t.jsx)(d.Text,{className:"text-sm font-semibold text-gray-700",children:"Available Tools"})}),(0,t.jsx)(H.Input,{placeholder:"Search MCP servers...",value:x,onChange:e=>p(e.target.value),className:"mb-2",allowClear:!0}),(0,t.jsx)("div",{className:"space-y-2 overflow-y-auto",style:{maxHeight:300},children:0===v.length?(0,t.jsx)(d.Text,{className:"text-gray-400 text-sm",children:0===g.length?"No MCP servers configured":"No servers match your search"}):v.map(e=>(0,t.jsx)(ee,{serverId:e.server_id,serverName:e.alias||e.server_name||e.server_id,accessToken:a,selectedTools:o,onToggle:f},e.server_id))})]}),(0,t.jsx)("div",{className:"w-px bg-gray-200 flex-shrink-0"}),(0,t.jsxs)("div",{className:"w-72 flex-shrink-0",children:[(0,t.jsxs)(d.Text,{className:"text-sm font-semibold text-gray-700 mb-2 block",children:["Your Toolset"," ",(0,t.jsxs)("span",{className:"text-xs font-normal text-gray-400",children:["(",o.length," tools)"]})]}),(0,t.jsx)("div",{className:"space-y-1 overflow-y-auto",style:{maxHeight:340},children:0===o.length?(0,t.jsx)(d.Text,{className:"text-gray-400 text-sm",children:"No tools added yet"}):o.map((e,s)=>(0,t.jsxs)("button",{type:"button",onClick:()=>f(e),className:"w-full flex items-center justify-between px-3 py-1.5 rounded-lg border border-purple-200 bg-purple-50 hover:bg-red-50 hover:border-red-200 group transition-colors",children:[(0,t.jsxs)("div",{className:"min-w-0 text-left",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-purple-800 group-hover:text-red-600 truncate block",children:e.tool_name}),(0,t.jsxs)("span",{className:"text-[10px] text-purple-400 truncate block",children:[e.server_id.slice(0,8),"…"]})]}),(0,t.jsx)("span",{className:"ml-2 text-purple-300 group-hover:text-red-400 text-xs flex-shrink-0",children:"✕"})]},s))})]})]}),(0,t.jsxs)("div",{className:"flex justify-end gap-2 mt-4 pt-4 border-t border-gray-200",children:[(0,t.jsx)(l.Button,{variant:"secondary",onClick:s,children:"Cancel"}),(0,t.jsx)(l.Button,{onClick:y,loading:m,children:n?"Save Changes":"Create Toolset"})]})]})}function es(){let[e,s]=(0,b.useState)(!1),r=(0,_.getProxyBaseUrl)(),l=`{ -======== (globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,111790,758472,280881,e=>{"use strict";e.s([],111790);var t=e.i(843476),s=e.i(708347),r=e.i(750113),l=e.i(994388),a=e.i(197647),n=e.i(653824),i=e.i(881073),o=e.i(404206),c=e.i(723731),d=e.i(599724),m=e.i(629569),u=e.i(844444),x=e.i(869216),h=e.i(212931),p=e.i(199133),g=e.i(592968),f=e.i(898586),b=e.i(271645),j=e.i(500727),y=e.i(266027),v=e.i(912598),N=e.i(243652),_=e.i(764205),w=e.i(135214);let S=(0,N.createQueryKeys)("mcpServerHealth");var C=e.i(727749),T=e.i(988846),k=e.i(678784),A=e.i(995926),I=e.i(328196),P=e.i(302202),O=e.i(409797),M=e.i(54131),F=e.i(440987);let E=[{label:"Documentation",fields:[{key:"description",label:"Description",description:"Must have a non-empty description",check:e=>!!e.description?.trim()},{key:"alias",label:"Alias",description:"Must have a display alias",check:e=>!!e.alias?.trim()}]},{label:"Source",fields:[{key:"source_url",label:"GitHub / Source URL",description:"Must link to a source repository",check:e=>!!e.source_url?.trim()}]},{label:"Connection",fields:[{key:"url",label:"Server URL",description:"Must have a URL configured",check:e=>!!e.url?.trim()}]},{label:"Security",fields:[{key:"auth_type",label:"Auth configured",description:"Must use authentication (not 'none')",check:e=>!!e.auth_type&&"none"!==e.auth_type}]}],L=E.flatMap(e=>e.fields),R="mcp_required_fields",z={active:{label:"Active",bg:"bg-green-50",text:"text-green-700",dot:"bg-green-500"},pending_review:{label:"Pending Review",bg:"bg-yellow-50",text:"text-yellow-700",dot:"bg-yellow-500"},rejected:{label:"Rejected",bg:"bg-red-50",text:"text-red-700",dot:"bg-red-500"}};function U({label:e,value:s,color:r}){return(0,t.jsxs)("div",{className:"bg-white border border-gray-200 rounded-lg px-4 py-3",children:[(0,t.jsx)("div",{className:`text-2xl font-bold ${r}`,children:s}),(0,t.jsx)("div",{className:"text-xs text-gray-500 mt-0.5",children:e})]})}function B({action:e,serverName:s,isCurrentlyActive:r,onConfirm:l,onCancel:a}){let[n,i]=(0,b.useState)(""),o="approve"===e;return(0,t.jsx)("div",{className:"fixed inset-0 bg-black/30 flex items-center justify-center z-50",children:(0,t.jsxs)("div",{className:"bg-white rounded-xl shadow-xl p-6 max-w-sm w-full mx-4",children:[(0,t.jsx)("div",{className:`w-10 h-10 rounded-full flex items-center justify-center mb-4 ${o?"bg-green-100":"bg-red-100"}`,children:o?(0,t.jsx)(k.CheckIcon,{className:"h-5 w-5 text-green-600"}):(0,t.jsx)(I.AlertCircleIcon,{className:"h-5 w-5 text-red-600"})}),(0,t.jsx)("h3",{className:"text-base font-semibold text-gray-900 mb-1",children:o?"Approve MCP Server":"Reject MCP Server"}),(0,t.jsxs)("p",{className:"text-sm text-gray-500 mb-4",children:["Are you sure you want to ",e," ",(0,t.jsxs)("span",{className:"font-medium text-gray-700",children:['"',s,'"']}),"?"," ",o?"This will make it active and available for use.":r?"This server is currently live. Rejecting it will immediately remove it from the proxy runtime.":"This will mark the submission as rejected."]}),!o&&(0,t.jsx)("textarea",{placeholder:"Reason for rejection (optional)",value:n,onChange:e=>i(e.target.value),className:"w-full border border-gray-200 rounded-md px-3 py-2 text-sm text-gray-700 placeholder-gray-400 focus:outline-none focus:ring-1 focus:ring-blue-500 mb-4 resize-none",rows:3}),(0,t.jsxs)("div",{className:"flex gap-3",children:[(0,t.jsx)("button",{type:"button",onClick:a,className:"flex-1 border border-gray-300 text-gray-700 hover:bg-gray-50 text-sm font-medium py-2 rounded-md transition-colors",children:"Cancel"}),(0,t.jsx)("button",{type:"button",onClick:()=>l(o?void 0:n||void 0),className:`flex-1 text-white text-sm font-medium py-2 rounded-md transition-colors ${o?"bg-green-500 hover:bg-green-600":"bg-red-500 hover:bg-red-600"}`,children:o?"Approve":"Reject"})]})]})})}function q({requiredFields:e,onChange:s,onSave:r,isSaving:l}){let[a,n]=(0,b.useState)(!1),i=L.filter(t=>e.includes(t.key));return(0,t.jsxs)("div",{className:"mb-5 border border-gray-200 rounded-lg bg-white overflow-hidden",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between px-4 py-3 cursor-pointer select-none",onClick:()=>n(e=>!e),children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(F.SettingsIcon,{className:"h-4 w-4 text-gray-400"}),(0,t.jsx)("span",{className:"text-sm font-semibold text-gray-800",children:"Submission Rules"}),i.length>0?(0,t.jsxs)("span",{className:"text-xs text-gray-500",children:["(",i.length," required field",1!==i.length?"s":"",")"]}):(0,t.jsx)("span",{className:"text-xs text-gray-400 italic",children:"no rules set"})]}),(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[!a&&i.length>0&&(0,t.jsx)("div",{className:"flex flex-wrap gap-1.5 max-w-md",children:i.map(e=>(0,t.jsxs)("span",{className:"inline-flex items-center gap-1 text-xs bg-blue-50 text-blue-700 border border-blue-200 px-2 py-0.5 rounded-full",children:[(0,t.jsx)(k.CheckIcon,{className:"h-3 w-3"}),e.label]},e.key))}),a?(0,t.jsx)(M.ChevronUpIcon,{className:"h-4 w-4 text-gray-400"}):(0,t.jsx)(O.ChevronDownIcon,{className:"h-4 w-4 text-gray-400"})]})]}),a&&(0,t.jsxs)("div",{className:"border-t border-gray-100 px-4 pt-4 pb-4",children:[(0,t.jsx)("p",{className:"text-xs text-gray-500 mb-4",children:"Select which fields must be filled in before a submission is considered compliant. LiteLLM will show ✓ / ✗ for each rule on every submission card below."}),(0,t.jsx)("div",{className:"grid grid-cols-2 gap-x-8 gap-y-5",children:E.map(r=>(0,t.jsxs)("div",{children:[(0,t.jsx)("div",{className:"text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2",children:r.label}),(0,t.jsx)("div",{className:"space-y-2",children:r.fields.map(r=>{let l=e.includes(r.key);return(0,t.jsxs)("label",{className:"flex items-start gap-2.5 cursor-pointer group",children:[(0,t.jsx)("input",{type:"checkbox",checked:l,onChange:()=>{var t;return t=r.key,void s(e.includes(t)?e.filter(e=>e!==t):[...e,t])},className:"mt-0.5 h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500 cursor-pointer"}),(0,t.jsxs)("div",{children:[(0,t.jsx)("div",{className:"text-sm font-medium text-gray-800 group-hover:text-blue-700 transition-colors",children:r.label}),(0,t.jsx)("div",{className:"text-xs text-gray-400",children:r.description})]})]},r.key)})})]},r.label))}),(0,t.jsxs)("div",{className:"mt-5 flex items-center gap-3",children:[(0,t.jsx)("button",{type:"button",disabled:l,onClick:async()=>{await r(),n(!1)},className:"px-4 py-1.5 text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 disabled:opacity-50 rounded-md transition-colors",children:l?"Saving…":"Save Rules"}),(0,t.jsx)("button",{type:"button",onClick:()=>n(!1),className:"px-4 py-1.5 text-sm font-medium text-gray-600 hover:text-gray-900 border border-gray-200 rounded-md hover:bg-gray-50 transition-colors",children:"Cancel"})]})]})]})}function V({server:e,onApprove:s,onReject:r,requiredFields:l}){let a=e.approval_status??"active",n=z[a]??z.active,i=L.filter(e=>l.includes(e.key)).map(t=>({key:t.key,label:t.label,description:t.description,passed:t.check(e)})),o=i.filter(e=>e.passed).length,c=i.length-o,d=i.length>0&&0===c;return(0,t.jsxs)("div",{className:"bg-white border border-gray-200 rounded-lg overflow-hidden",children:[(0,t.jsx)("div",{className:"px-4 pt-4 pb-3",children:(0,t.jsxs)("div",{className:"flex items-start justify-between gap-4",children:[(0,t.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,t.jsx)("div",{className:"flex items-center gap-2 mb-1.5",children:(0,t.jsxs)("span",{className:`inline-flex items-center gap-1.5 text-xs font-medium px-2 py-0.5 rounded-full ${n.bg} ${n.text}`,children:[(0,t.jsx)("span",{className:`w-1.5 h-1.5 rounded-full ${n.dot}`}),n.label]})}),(0,t.jsx)("h3",{className:"text-sm font-semibold text-gray-900",children:e.alias??e.server_name??e.server_id}),e.description&&(0,t.jsx)("p",{className:"text-xs text-gray-500 mt-0.5 line-clamp-1",children:e.description}),e.url&&(0,t.jsxs)("div",{className:"flex items-center gap-1.5 mt-1.5",children:[(0,t.jsx)(P.ServerIcon,{className:"h-3.5 w-3.5 text-gray-400 flex-shrink-0"}),(0,t.jsx)("code",{className:"text-xs text-gray-500 font-mono truncate",children:e.url})]}),(0,t.jsxs)("div",{className:"flex items-center gap-3 mt-1.5 text-xs text-gray-400",children:[(0,t.jsxs)("span",{children:["Transport: ",(0,t.jsx)("span",{className:"text-gray-600",children:e.transport??"sse"})]}),(0,t.jsx)("span",{children:"·"}),(0,t.jsxs)("span",{children:["Submitted by: ",(0,t.jsx)("span",{className:"text-gray-600",children:e.submitted_by??"—"})]}),(0,t.jsx)("span",{children:"·"}),(0,t.jsx)("span",{children:function(e){if(!e)return"—";try{let t=new Date(e);return isNaN(t.getTime())?e:t.toISOString().slice(0,10)}catch{return e}}(e.submitted_at)})]}),"rejected"===a&&e.review_notes&&(0,t.jsxs)("p",{className:"text-xs text-red-600 mt-1.5",children:["Rejection reason: ",e.review_notes]})]}),0===i.length&&"rejected"!==a&&(0,t.jsxs)("div",{className:"flex items-center gap-2 flex-shrink-0",children:["active"!==a&&(0,t.jsx)("button",{type:"button",onClick:s,className:"text-xs bg-green-500 hover:bg-green-600 text-white px-3 py-1.5 rounded-md transition-colors font-medium",children:"Approve"}),(0,t.jsx)("button",{type:"button",onClick:r,className:"text-xs border border-red-300 text-red-600 hover:bg-red-50 px-3 py-1.5 rounded-md transition-colors font-medium",children:"Reject"})]}),0===i.length&&"rejected"===a&&(0,t.jsx)("div",{className:"flex items-center gap-2 flex-shrink-0",children:(0,t.jsx)("button",{type:"button",onClick:s,className:"text-xs bg-green-500 hover:bg-green-600 text-white px-3 py-1.5 rounded-md transition-colors font-medium",children:"Re-approve"})})]})}),i.length>0&&(0,t.jsxs)("div",{className:"border-t border-gray-200",children:[(0,t.jsxs)("div",{className:`flex items-center gap-3 px-4 py-3 ${d?"bg-green-50 border-b border-green-100":"bg-red-50 border-b border-red-100"}`,children:[(0,t.jsx)("div",{className:`w-8 h-8 rounded-full flex items-center justify-center flex-shrink-0 ${d?"bg-green-500":"bg-red-500"}`,children:d?(0,t.jsx)(k.CheckIcon,{className:"h-4 w-4 text-white"}):(0,t.jsx)(A.XIcon,{className:"h-4 w-4 text-white"})}),(0,t.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,t.jsx)("div",{className:`text-sm font-semibold leading-tight ${d?"text-green-800":"text-red-800"}`,children:d?"All checks passed":`${c} check${1!==c?"s":""} failed`}),(0,t.jsxs)("div",{className:"text-xs text-gray-500 mt-0.5",children:[o," passing, ",c," failing"]})]}),(0,t.jsxs)("div",{className:"flex items-center gap-2 flex-shrink-0",children:["active"!==a&&"rejected"!==a&&(0,t.jsx)("button",{type:"button",onClick:s,className:"text-xs bg-green-600 hover:bg-green-700 text-white px-3 py-1.5 rounded-md transition-colors font-medium",children:"Approve"}),"rejected"===a&&(0,t.jsx)("button",{type:"button",onClick:s,className:"text-xs bg-green-600 hover:bg-green-700 text-white px-3 py-1.5 rounded-md transition-colors font-medium",children:"Re-approve"}),"rejected"!==a&&(0,t.jsx)("button",{type:"button",onClick:r,className:"text-xs border border-red-300 text-red-600 hover:bg-red-50 bg-white px-3 py-1.5 rounded-md transition-colors font-medium",children:"Reject"})]})]}),(0,t.jsx)("div",{className:"divide-y divide-gray-100",children:i.map(e=>(0,t.jsxs)("div",{className:"flex items-center gap-3 px-4 py-2.5",children:[(0,t.jsx)("div",{className:`w-5 h-5 rounded-full flex items-center justify-center flex-shrink-0 ${e.passed?"bg-green-100":"bg-red-100"}`,children:e.passed?(0,t.jsx)(k.CheckIcon,{className:"h-3 w-3 text-green-600"}):(0,t.jsx)(A.XIcon,{className:"h-3 w-3 text-red-600"})}),(0,t.jsx)("span",{className:`text-sm flex-1 ${e.passed?"text-gray-700":"text-gray-800"}`,children:e.label}),(0,t.jsx)("span",{className:`text-xs ${e.passed?"text-green-600":"text-red-500"}`,children:e.passed?"Passes":"Missing"})]},e.key))})]})]})}function $({accessToken:e}){let[s,r]=(0,b.useState)({total:0,pending_review:0,active:0,rejected:0,items:[]}),[l,a]=(0,b.useState)(""),[n,i]=(0,b.useState)("all"),[o,c]=(0,b.useState)(null),[d,m]=(0,b.useState)(!0),[u,x]=(0,b.useState)(null),[h,p]=(0,b.useState)([]),[g,f]=(0,b.useState)(!1),j=(0,b.useCallback)(async()=>{if(!e)return void m(!1);m(!0),x(null);try{let[t,s]=await Promise.all([(0,_.fetchMCPSubmissions)(e),(0,_.getGeneralSettingsCall)(e).catch(e=>(console.warn("MCPSubmissionsTab: failed to load general settings, compliance rules will be empty:",e),null))]);if(r(t),s?.data&&Array.isArray(s.data)){let e=s.data.find(e=>e.field_name===R);e&&Array.isArray(e.field_value)&&p(e.field_value)}}catch(e){x(e instanceof Error?e.message:"Failed to load submissions")}finally{m(!1)}},[e]);(0,b.useEffect)(()=>{j()},[j]);let y=async()=>{if(e){f(!0);try{await (0,_.updateConfigFieldSetting)(e,R,h),C.default.success("Submission rules saved")}catch{C.default.fromBackend("Failed to save submission rules")}finally{f(!1)}}},v=s.items.filter(e=>{if("all"!==n&&e.approval_status!==n)return!1;if(l.trim()){let t=l.toLowerCase(),s=(e.alias??e.server_name??e.server_id??"").toLowerCase(),r=(e.url??"").toLowerCase();return s.includes(t)||r.includes(t)}return!0});async function N(t,s){if(e)try{await (0,_.approveMCPServer)(e,t),await j(),C.default.success(`MCP server "${s}" approved`)}catch{C.default.fromBackend("Failed to approve MCP server")}finally{c(null)}}async function w(t,s,r){if(e)try{await (0,_.rejectMCPServer)(e,t,r),await j(),C.default.success(`MCP server "${s}" rejected`)}catch{C.default.fromBackend("Failed to reject MCP server")}finally{c(null)}}return(0,t.jsxs)("div",{className:"p-6",children:[(0,t.jsx)(q,{requiredFields:h,onChange:p,onSave:y,isSaving:g}),(0,t.jsxs)("div",{className:"grid grid-cols-4 gap-4 mb-6",children:[(0,t.jsx)(U,{label:"Total Submitted",value:s.total,color:"text-gray-900"}),(0,t.jsx)(U,{label:"Pending Review",value:s.pending_review,color:"text-yellow-600"}),(0,t.jsx)(U,{label:"Active",value:s.active,color:"text-green-600"}),(0,t.jsx)(U,{label:"Rejected",value:s.rejected,color:"text-red-600"})]}),(0,t.jsxs)("div",{className:"flex items-center gap-3 mb-5",children:[(0,t.jsxs)("div",{className:"relative flex-1 max-w-xs",children:[(0,t.jsx)(T.SearchIcon,{className:"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-400"}),(0,t.jsx)("input",{type:"text",placeholder:"Search MCP servers...",value:l,onChange:e=>a(e.target.value),className:"w-full pl-9 pr-4 py-2 border border-gray-200 rounded-md text-sm text-gray-700 placeholder-gray-400 focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500"})]}),(0,t.jsxs)("select",{value:n,onChange:e=>i(e.target.value),className:"border border-gray-200 rounded-md px-3 py-2 text-sm text-gray-700 focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500 bg-white",children:[(0,t.jsx)("option",{value:"all",children:"All Status"}),(0,t.jsx)("option",{value:"pending_review",children:"Pending Review"}),(0,t.jsx)("option",{value:"active",children:"Active"}),(0,t.jsx)("option",{value:"rejected",children:"Rejected"})]})]}),(0,t.jsxs)("div",{className:"space-y-3",children:[d&&(0,t.jsx)("div",{className:"text-center py-12 text-gray-500 text-sm",children:"Loading submissions…"}),u&&(0,t.jsx)("div",{className:"text-center py-12 text-red-600 text-sm",children:u}),!d&&!u&&0===v.length&&(0,t.jsx)("div",{className:"text-center py-12 text-gray-400 text-sm",children:"No MCP server submissions match your filters."}),!d&&!u&&v.map(e=>(0,t.jsx)(V,{server:e,requiredFields:h,onApprove:()=>c({serverId:e.server_id,serverName:e.alias??e.server_name??e.server_id,action:"approve"}),onReject:()=>c({serverId:e.server_id,serverName:e.alias??e.server_name??e.server_id,action:"reject",isCurrentlyActive:"active"===e.approval_status})},e.server_id))]}),o&&(0,t.jsx)(B,{action:o.action,serverName:o.serverName,isCurrentlyActive:o.isCurrentlyActive,onConfirm:e=>"approve"===o.action?N(o.serverId,o.serverName):w(o.serverId,o.serverName,e),onCancel:()=>c(null)})]})}var D=e.i(808613),H=e.i(311451),K=e.i(998573),W=e.i(482725),J=e.i(988297),Y=e.i(797672),G=e.i(68155),Q=e.i(699857),Z=e.i(149121);let{Text:X}=f.Typography;function ee({serverId:e,serverName:s,accessToken:r,selectedTools:l,onToggle:a}){let[n,i]=(0,b.useState)([]),[o,c]=(0,b.useState)(!1),[d,m]=(0,b.useState)(!1),u=new Set(l.filter(t=>t.server_id===e).map(e=>e.tool_name)),x=(0,b.useCallback)(async()=>{if(r&&!(n.length>0)){c(!0);try{let t=await (0,_.listMCPTools)(r,e),s=Array.isArray(t)?t:t?.tools??[];i(s.map(e=>({name:e.name??e.tool_name??e,description:e.description??""})))}catch{i([])}finally{c(!1)}}},[r,e,n.length]);return(0,t.jsxs)("div",{className:"border border-gray-200 rounded-lg overflow-hidden",children:[(0,t.jsxs)("button",{type:"button",className:"w-full flex items-center justify-between px-4 py-3 bg-gray-50 hover:bg-gray-100 transition-colors",onClick:()=>{d||x(),m(!d)},children:[(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center gap-2",children:[(0,t.jsx)("span",{className:"inline-block w-2 h-2 rounded-full bg-blue-500 flex-shrink-0"}),s,u.size>0&&(0,t.jsxs)("span",{className:"ml-1 text-xs text-purple-600 font-semibold",children:[u.size," selected"]})]}),(0,t.jsx)("span",{className:"text-gray-400 text-xs",children:d?"▲":"▼"})]}),d&&(0,t.jsx)("div",{className:"p-2",children:o?(0,t.jsx)("div",{className:"flex justify-center py-3",children:(0,t.jsx)(W.Spin,{size:"small"})}):0===n.length?(0,t.jsx)("p",{className:"text-xs text-gray-400 px-2 py-2",children:"No tools found for this server."}):(0,t.jsx)("div",{className:"flex flex-col gap-1",children:n.map(s=>{let r=u.has(s.name);return(0,t.jsxs)("button",{type:"button",onClick:()=>a({server_id:e,tool_name:s.name}),className:`flex items-start justify-between px-3 py-2 rounded-lg text-left transition-colors ${r?"bg-purple-50 border border-purple-300":"bg-white border border-gray-100 hover:bg-gray-50"}`,children:[(0,t.jsxs)("div",{className:"min-w-0 flex-1",children:[(0,t.jsx)("p",{className:`text-sm font-medium leading-tight ${r?"text-purple-800":"text-gray-800"}`,children:s.name}),s.description&&(0,t.jsx)("p",{className:"text-xs text-gray-400 mt-0.5 leading-tight line-clamp-2",children:s.description})]}),r&&(0,t.jsx)("span",{className:"text-purple-500 text-xs font-semibold ml-2 flex-shrink-0 mt-0.5",children:"✓"})]},s.name)})})})]})}function et({open:e,onClose:s,onSave:r,accessToken:a,initialToolset:n}){let[i]=D.Form.useForm(),[o,c]=(0,b.useState)(n?.tools||[]),[m,u]=(0,b.useState)(!1),[x,p]=(0,b.useState)(""),{data:g=[]}=(0,j.useMCPServers)();b.default.useEffect(()=>{e&&(i.setFieldsValue({toolset_name:n?.toolset_name||"",description:n?.description||""}),c(n?.tools||[]),p(""))},[e,n]);let f=e=>{c(t=>t.some(t=>t.server_id===e.server_id&&t.tool_name===e.tool_name)?t.filter(t=>t.server_id!==e.server_id||t.tool_name!==e.tool_name):[...t,e])},y=async()=>{let e=await i.validateFields();u(!0);try{await r(e.toolset_name,e.description,o),s()}finally{u(!1)}},v=g.filter(e=>{let t=x.toLowerCase();return!t||(e.alias||"").toLowerCase().includes(t)||(e.server_name||"").toLowerCase().includes(t)});return(0,t.jsxs)(h.Modal,{open:e,onCancel:s,title:n?"Edit Toolset":"New Toolset",width:960,footer:null,forceRender:!0,children:[(0,t.jsx)(D.Form,{form:i,layout:"vertical",className:"mt-2",children:(0,t.jsxs)("div",{className:"flex gap-4 mb-4",children:[(0,t.jsx)(D.Form.Item,{label:"Toolset Name",name:"toolset_name",rules:[{required:!0,message:"Please enter a toolset name"}],className:"flex-1 mb-0",children:(0,t.jsx)(H.Input,{placeholder:"e.g. github-linear-tools"})}),(0,t.jsx)(D.Form.Item,{label:"Description",name:"description",className:"flex-1 mb-0",children:(0,t.jsx)(H.Input,{placeholder:"Optional description"})})]})}),(0,t.jsxs)("div",{className:"flex gap-4 mt-2",style:{minHeight:360},children:[(0,t.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,t.jsx)("div",{className:"flex items-center justify-between mb-2",children:(0,t.jsx)(d.Text,{className:"text-sm font-semibold text-gray-700",children:"Available Tools"})}),(0,t.jsx)(H.Input,{placeholder:"Search MCP servers...",value:x,onChange:e=>p(e.target.value),className:"mb-2",allowClear:!0}),(0,t.jsx)("div",{className:"space-y-2 overflow-y-auto",style:{maxHeight:300},children:0===v.length?(0,t.jsx)(d.Text,{className:"text-gray-400 text-sm",children:0===g.length?"No MCP servers configured":"No servers match your search"}):v.map(e=>(0,t.jsx)(ee,{serverId:e.server_id,serverName:e.alias||e.server_name||e.server_id,accessToken:a,selectedTools:o,onToggle:f},e.server_id))})]}),(0,t.jsx)("div",{className:"w-px bg-gray-200 flex-shrink-0"}),(0,t.jsxs)("div",{className:"w-72 flex-shrink-0",children:[(0,t.jsxs)(d.Text,{className:"text-sm font-semibold text-gray-700 mb-2 block",children:["Your Toolset"," ",(0,t.jsxs)("span",{className:"text-xs font-normal text-gray-400",children:["(",o.length," tools)"]})]}),(0,t.jsx)("div",{className:"space-y-1 overflow-y-auto",style:{maxHeight:340},children:0===o.length?(0,t.jsx)(d.Text,{className:"text-gray-400 text-sm",children:"No tools added yet"}):o.map((e,s)=>(0,t.jsxs)("button",{type:"button",onClick:()=>f(e),className:"w-full flex items-center justify-between px-3 py-1.5 rounded-lg border border-purple-200 bg-purple-50 hover:bg-red-50 hover:border-red-200 group transition-colors",children:[(0,t.jsxs)("div",{className:"min-w-0 text-left",children:[(0,t.jsx)("span",{className:"text-xs font-medium text-purple-800 group-hover:text-red-600 truncate block",children:e.tool_name}),(0,t.jsxs)("span",{className:"text-[10px] text-purple-400 truncate block",children:[e.server_id.slice(0,8),"…"]})]}),(0,t.jsx)("span",{className:"ml-2 text-purple-300 group-hover:text-red-400 text-xs flex-shrink-0",children:"✕"})]},s))})]})]}),(0,t.jsxs)("div",{className:"flex justify-end gap-2 mt-4 pt-4 border-t border-gray-200",children:[(0,t.jsx)(l.Button,{variant:"secondary",onClick:s,children:"Cancel"}),(0,t.jsx)(l.Button,{onClick:y,loading:m,children:n?"Save Changes":"Create Toolset"})]})]})}function es(){let[e,s]=(0,b.useState)(!1),r=(0,_.getProxyBaseUrl)(),l=`{ ->>>>>>>> origin/litellm_internal_staging:litellm/proxy/_experimental/out/_next/static/chunks/e1a670efcb966aaa.js "mcpServers": { "my-toolset": { "url": "${r}/toolset//mcp", "headers": { "x-litellm-api-key": "Bearer " } } } -<<<<<<<< HEAD:litellm/proxy/_experimental/out/_next/static/chunks/0279e5299e9f6e98.js -}`,a=async()=>{try{await navigator.clipboard.writeText(l),s(!0),setTimeout(()=>s(!1),1500)}catch{}};return(0,t.jsxs)("div",{className:"mb-6 rounded-lg border border-gray-200 bg-gray-50 px-5 py-4",children:[(0,t.jsx)("p",{className:"text-sm font-medium text-gray-700 mb-1",children:"How toolsets work"}),(0,t.jsxs)("p",{className:"text-sm text-gray-500 mb-3",children:["Create a toolset, assign it to a key via ",(0,t.jsx)("span",{className:"font-medium text-gray-700",children:"API Keys → Edit Key → MCP Servers"}),", then point your MCP client at the toolset URL. The client only sees the tools you picked."]}),(0,t.jsx)("div",{className:"text-xs text-gray-400 mb-1",children:"Claude Code / Cursor config"}),(0,t.jsxs)("div",{className:"relative",children:[(0,t.jsx)("pre",{className:"bg-white border border-gray-200 rounded px-4 py-3 text-xs font-mono text-gray-700 overflow-x-auto leading-relaxed pr-14",children:l}),(0,t.jsx)("button",{type:"button",onClick:a,className:"absolute top-2 right-2 px-2 py-1 text-xs rounded border bg-white hover:bg-gray-50 text-gray-400 hover:text-gray-600 border-gray-200 transition-colors",children:e?"✓":"copy"})]})]})}function er({accessToken:e,userRole:s}){let r=(0,v.useQueryClient)(),{data:a=[],isLoading:n}=(0,Q.useMCPToolsets)(),[i,o]=(0,b.useState)(!1),[c,u]=(0,b.useState)(null),[x,p]=(0,b.useState)(null),[g,f]=(0,b.useState)(!1),j="Admin"===s||"proxy_admin"===s,y=async(t,s,l)=>{e&&(await (0,_.createMCPToolset)(e,{toolset_name:t,description:s,tools:l}),K.message.success("Toolset created"),r.invalidateQueries({queryKey:["mcpToolsets"]}))},N=async(t,s,l)=>{e&&c&&(await (0,_.updateMCPToolset)(e,{toolset_id:c.toolset_id,toolset_name:t,description:s,tools:l}),K.message.success("Toolset updated"),r.invalidateQueries({queryKey:["mcpToolsets"]}),u(null))},w=async()=>{if(e&&x){f(!0);try{await (0,_.deleteMCPToolset)(e,x),K.message.success("Toolset deleted"),r.invalidateQueries({queryKey:["mcpToolsets"]}),p(null)}finally{f(!1)}}},S=(0,_.getProxyBaseUrl)(),C=[{header:"Toolset ID",accessorKey:"toolset_id",cell:({row:e})=>(0,t.jsxs)("span",{className:"font-mono text-xs bg-gray-100 px-2 py-0.5 rounded text-gray-600",children:[e.original.toolset_id.slice(0,8),"…"]})},{header:"Name",accessorKey:"toolset_name",cell:({row:e})=>{let s=`${S}/toolset/${e.original.toolset_name}/mcp`;return(0,t.jsxs)("div",{className:"flex flex-col gap-0.5",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("span",{className:"inline-block w-2 h-2 rounded-full bg-purple-500 flex-shrink-0"}),(0,t.jsx)("span",{className:"font-medium text-gray-900",children:e.original.toolset_name})]}),(0,t.jsx)("button",{type:"button",className:"text-xs text-gray-400 hover:text-purple-600 font-mono truncate max-w-xs text-left transition-colors",onClick:()=>navigator.clipboard.writeText(s),title:"Click to copy endpoint URL",children:s})]})}},{header:"Description",accessorKey:"description",cell:({row:e})=>(0,t.jsx)("span",{className:"text-sm text-gray-500",children:e.original.description||"—"})},{header:"Tools",accessorKey:"tools",cell:({row:e})=>{let s=e.original.tools;return(0,t.jsxs)("div",{className:"flex flex-wrap gap-1 max-w-xs",children:[s.slice(0,4).map((e,s)=>(0,t.jsx)("span",{className:"inline-flex items-center px-1.5 py-0.5 rounded bg-purple-50 border border-purple-200 text-purple-700 text-xs",children:e.tool_name},s)),s.length>4&&(0,t.jsxs)("span",{className:"text-xs text-gray-400 self-center",children:["+",s.length-4," more"]})]})}},{header:"Created",accessorKey:"created_at",cell:({row:e})=>(0,t.jsx)("span",{className:"text-xs text-gray-500",children:e.original.created_at?new Date(e.original.created_at).toLocaleDateString():"—"})},...j?[{header:"",id:"actions",cell:({row:e})=>(0,t.jsxs)("div",{className:"flex items-center gap-1 justify-end",children:[(0,t.jsx)("button",{type:"button",className:"p-1.5 rounded-lg hover:bg-gray-100 text-gray-400 hover:text-gray-700 transition-colors",onClick:()=>u(e.original),children:(0,t.jsx)(Y.PencilIcon,{className:"h-4 w-4"})}),(0,t.jsx)("button",{type:"button",className:"p-1.5 rounded-lg hover:bg-red-50 text-gray-400 hover:text-red-500 transition-colors",onClick:()=>p(e.original.toolset_id),children:(0,t.jsx)(G.TrashIcon,{className:"h-4 w-4"})})]})}]:[]];return(0,t.jsxs)("div",{className:"mt-4",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between mb-4",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)(m.Title,{children:"MCP Toolsets"}),(0,t.jsx)(d.Text,{className:"text-gray-500 text-sm",children:"Curated collections of tools from one or more MCP servers. Assign toolsets to keys and teams via the MCP permissions dropdown."})]}),j&&(0,t.jsx)(l.Button,{icon:J.PlusIcon,onClick:()=>o(!0),children:"New Toolset"})]}),(0,t.jsx)(es,{}),(0,t.jsx)(Z.DataTable,{data:a,columns:C,renderSubComponent:()=>(0,t.jsx)("div",{}),getRowCanExpand:()=>!1,isLoading:n,noDataMessage:"No toolsets yet. Click 'New Toolset' to create one.",loadingMessage:"Loading toolsets...",enableSorting:!0}),(0,t.jsx)(et,{open:i,onClose:()=>o(!1),onSave:y,accessToken:e}),c&&(0,t.jsx)(et,{open:!!c,onClose:()=>u(null),onSave:N,accessToken:e,initialToolset:c}),(0,t.jsx)(h.Modal,{open:!!x,onCancel:()=>p(null),onOk:w,okText:"Delete",okButtonProps:{danger:!0,loading:g},title:"Delete Toolset",children:(0,t.jsx)("p",{children:"Are you sure you want to delete this toolset? Keys and teams using it will lose access to the scoped tools."})})]})}var el=e.i(790848),ea=e.i(362024),en=e.i(827252),ei=e.i(779241),eo=e.i(292335),ec=e.i(28651);let ed="rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500",em=({label:e,tooltip:s})=>(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:[e,(0,t.jsx)(g.Tooltip,{title:s,children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),eu=({isM2M:e,isEditing:s=!1,oauthFlow:r,initialFlowType:a,docsUrl:n})=>{let i=s?" (leave blank to keep existing)":"";return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(D.Form.Item,{label:(0,t.jsx)(em,{label:"OAuth Flow Type",tooltip:"Choose how the proxy authenticates with this MCP server. M2M is for server-to-server communication using client credentials. Interactive (PKCE) is for user-facing flows that require browser-based authorization."}),name:"oauth_flow_type",...a?{initialValue:a}:{},children:(0,t.jsxs)(p.Select,{className:"rounded-lg",size:"large",children:[(0,t.jsx)(p.Select.Option,{value:eo.OAUTH_FLOW.M2M,children:(0,t.jsxs)("div",{children:[(0,t.jsx)("span",{className:"font-medium",children:"Machine-to-Machine (M2M)"}),(0,t.jsx)("span",{className:"text-gray-400 text-xs ml-2",children:"server-to-server, no user interaction"})]})}),(0,t.jsx)(p.Select.Option,{value:eo.OAUTH_FLOW.INTERACTIVE,children:(0,t.jsxs)("div",{children:[(0,t.jsx)("span",{className:"font-medium",children:"Interactive (PKCE)"}),(0,t.jsx)("span",{className:"text-gray-400 text-xs ml-2",children:"browser-based user authorization"})]})})]})}),e?(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(D.Form.Item,{label:(0,t.jsx)(em,{label:"Client ID",tooltip:"OAuth2 client ID for the client_credentials grant."}),name:["credentials","client_id"],rules:[{required:!0,message:"Client ID is required for M2M OAuth"}],children:(0,t.jsx)(ei.TextInput,{type:"password",placeholder:`Enter OAuth client ID${i}`,className:ed})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsx)(em,{label:"Client Secret",tooltip:"OAuth2 client secret for the client_credentials grant."}),name:["credentials","client_secret"],rules:[{required:!0,message:"Client Secret is required for M2M OAuth"}],children:(0,t.jsx)(ei.TextInput,{type:"password",placeholder:`Enter OAuth client secret${i}`,className:ed})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsx)(em,{label:"Token URL",tooltip:"Token endpoint URL for the client_credentials grant."}),name:"token_url",rules:[{required:!0,message:"Token URL is required for M2M OAuth"}],children:(0,t.jsx)(ei.TextInput,{placeholder:"https://auth.example.com/oauth/token",className:ed})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsx)(em,{label:"Scopes (optional)",tooltip:"Optional scopes to request with the client_credentials grant."}),name:["credentials","scopes"],children:(0,t.jsx)(p.Select,{mode:"tags",tokenSeparators:[","],placeholder:"Add scopes",className:"rounded-lg",size:"large"})})]}):(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"flex items-center justify-between w-full",children:[(0,t.jsx)(em,{label:"Client ID (optional)",tooltip:"Provide only if your MCP server cannot handle dynamic client registration."}),n&&(0,t.jsx)("a",{href:n,target:"_blank",rel:"noopener noreferrer",className:"text-xs text-blue-500 hover:text-blue-700 ml-2 font-normal",onClick:e=>e.stopPropagation(),children:"Create OAuth App →"})]}),name:["credentials","client_id"],children:(0,t.jsx)(ei.TextInput,{type:"password",placeholder:`Enter client ID${i}`,className:ed})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsx)(em,{label:"Client Secret (optional)",tooltip:"Provide only if your MCP server cannot handle dynamic client registration."}),name:["credentials","client_secret"],children:(0,t.jsx)(ei.TextInput,{type:"password",placeholder:`Enter client secret${i}`,className:ed})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsx)(em,{label:"Scopes (optional)",tooltip:"Optional scopes requested during token exchange. Separate multiple scopes with enter or commas."}),name:["credentials","scopes"],children:(0,t.jsx)(p.Select,{mode:"tags",tokenSeparators:[","],placeholder:"Add scopes",className:"rounded-lg",size:"large"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsx)(em,{label:"Authorization URL (optional)",tooltip:"Optional override for the authorization endpoint."}),name:"authorization_url",children:(0,t.jsx)(ei.TextInput,{placeholder:"https://example.com/oauth/authorize",className:ed})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsx)(em,{label:"Token URL (optional)",tooltip:"Optional override for the token endpoint."}),name:"token_url",children:(0,t.jsx)(ei.TextInput,{placeholder:"https://example.com/oauth/token",className:ed})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsx)(em,{label:"Registration URL (optional)",tooltip:"Optional override for the dynamic client registration endpoint."}),name:"registration_url",children:(0,t.jsx)(ei.TextInput,{placeholder:"https://example.com/oauth/register",className:ed})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsx)(em,{label:"Token Validation Rules (optional)",tooltip:'JSON object of key-value rules checked against the OAuth token response before storing. Supports dot-notation for nested fields (e.g. {"organization": "my-org", "team.id": "123"}). Tokens that fail validation are rejected with HTTP 403.'}),name:"token_validation_json",rules:[{validator:(e,t)=>{if(!t||""===t.trim())return Promise.resolve();try{return JSON.parse(t),Promise.resolve()}catch{return Promise.reject(Error("Must be valid JSON"))}}}],children:(0,t.jsx)(H.Input.TextArea,{placeholder:'{\n "organization": "my-org",\n "team.id": "123"\n}',rows:4,className:"font-mono text-sm rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsx)(em,{label:"Token Storage TTL (seconds, optional)",tooltip:"How long to cache each user's OAuth access token in Redis before evicting it (regardless of the token's own expires_in). Leave blank to derive the TTL from the token's expires_in, or fall back to the 12-hour default."}),name:"token_storage_ttl_seconds",children:(0,t.jsx)(ec.InputNumber,{min:1,placeholder:"e.g. 3600",className:"w-full rounded-lg",style:{width:"100%"}})}),r&&(0,t.jsxs)("div",{className:"rounded-lg border border-dashed border-gray-300 p-4 space-y-2",children:[(0,t.jsx)("p",{className:"text-sm text-gray-600",children:"Use OAuth to fetch a fresh access token and temporarily save it in the session as the authentication value."}),(0,t.jsx)(l.Button,{variant:"secondary",onClick:r.startOAuthFlow,disabled:"authorizing"===r.status||"exchanging"===r.status,children:"authorizing"===r.status?"Waiting for authorization...":"exchanging"===r.status?"Exchanging authorization code...":"Authorize & Fetch Token"}),r.error&&(0,t.jsx)("p",{className:"text-sm text-red-500",children:r.error}),"success"===r.status&&r.tokenResponse?.access_token&&(0,t.jsxs)("p",{className:"text-sm text-green-600",children:["Token fetched. Expires in ",r.tokenResponse.expires_in??"?"," seconds."]})]})]})]})};var ex=e.i(906579),eh=e.i(458505),ep=e.i(366308),eg=e.i(304967);let ef=({value:e={},onChange:s,tools:r=[],disabled:l=!1})=>(0,t.jsx)(eg.Card,{children:(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2 mb-4",children:[(0,t.jsx)(eh.DollarOutlined,{className:"text-green-600"}),(0,t.jsx)(m.Title,{children:"Cost Configuration"}),(0,t.jsx)(g.Tooltip,{title:"Configure costs for this MCP server's tool calls. Set a default rate and per-tool overrides.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"text-gray-400"})})]}),(0,t.jsxs)("div",{className:"space-y-4",children:[(0,t.jsxs)("div",{children:[(0,t.jsxs)("label",{className:"block text-sm font-medium text-gray-700 mb-2",children:["Default Cost per Query ($)",(0,t.jsx)(g.Tooltip,{title:"Default cost charged for each tool call to this server.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-1 text-gray-400"})})]}),(0,t.jsx)(ec.InputNumber,{min:0,step:1e-4,precision:4,placeholder:"0.0000",value:e.default_cost_per_query,onChange:t=>{let r={...e,default_cost_per_query:t};s?.(r)},disabled:l,style:{width:"200px"},addonBefore:"$"}),(0,t.jsx)(d.Text,{className:"block mt-1 text-gray-500 text-sm",children:"Set a default cost for all tool calls to this server"})]}),r.length>0&&(0,t.jsxs)("div",{className:"space-y-4",children:[(0,t.jsxs)("label",{className:"block text-sm font-medium text-gray-700",children:["Tool-Specific Costs ($)",(0,t.jsx)(g.Tooltip,{title:"Override the default cost for specific tools. Leave blank to use the default rate.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-1 text-gray-400"})})]}),(0,t.jsx)(ea.Collapse,{items:[{key:"1",label:(0,t.jsxs)("div",{className:"flex items-center",children:[(0,t.jsx)(ep.ToolOutlined,{className:"mr-2 text-blue-500"}),(0,t.jsx)("span",{className:"font-medium",children:"Available Tools"}),(0,t.jsx)(ex.Badge,{count:r.length,style:{backgroundColor:"#52c41a",marginLeft:"8px"}})]}),children:(0,t.jsx)("div",{className:"space-y-3 max-h-64 overflow-y-auto",children:r.map((r,a)=>(0,t.jsxs)("div",{className:"flex items-center justify-between p-3 bg-gray-50 rounded-lg",children:[(0,t.jsxs)("div",{className:"flex-1",children:[(0,t.jsx)(d.Text,{className:"font-medium text-gray-900",children:r.name}),r.description&&(0,t.jsx)(d.Text,{className:"text-gray-500 text-sm block mt-1",children:r.description})]}),(0,t.jsx)("div",{className:"ml-4",children:(0,t.jsx)(ec.InputNumber,{min:0,step:1e-4,precision:4,placeholder:"Use default",value:e.tool_name_to_cost_per_query?.[r.name],onChange:t=>{var l;let a;return l=r.name,a={...e,tool_name_to_cost_per_query:{...e.tool_name_to_cost_per_query,[l]:t}},void s?.(a)},disabled:l,style:{width:"120px"},addonBefore:"$"})})]},a))})}]})]})]}),(e.default_cost_per_query||e.tool_name_to_cost_per_query&&Object.keys(e.tool_name_to_cost_per_query).length>0)&&(0,t.jsxs)("div",{className:"mt-6 p-4 bg-blue-50 border border-blue-200 rounded-lg",children:[(0,t.jsx)(d.Text,{className:"text-blue-800 font-medium",children:"Cost Summary:"}),(0,t.jsxs)("div",{className:"mt-2 space-y-1",children:[e.default_cost_per_query&&(0,t.jsxs)(d.Text,{className:"text-blue-700",children:["• Default cost: $",e.default_cost_per_query.toFixed(4)," per query"]}),e.tool_name_to_cost_per_query&&Object.entries(e.tool_name_to_cost_per_query).map(([e,s])=>null!=s&&(0,t.jsxs)(d.Text,{className:"text-blue-700",children:["• ",e,": $",s.toFixed(4)," per query"]},e))]})]})]})});var eb=e.i(464571),ej=e.i(560445),ey=e.i(245704),ev=e.i(270377),eN=e.i(91979);let e_=({formValues:e,tools:s,isLoadingTools:r,toolsError:l,toolsErrorStackTrace:a,canFetchTools:n,fetchTools:i})=>n||e.url||e.spec_path?(0,t.jsx)(eg.Card,{children:(0,t.jsxs)("div",{className:"space-y-4",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(ey.CheckCircleOutlined,{className:"text-blue-600"}),(0,t.jsx)(m.Title,{children:"Connection Status"})]}),!n&&(e.url||e.spec_path)&&(0,t.jsxs)("div",{className:"text-center py-6 text-gray-400 border rounded-lg border-dashed",children:[(0,t.jsx)(ep.ToolOutlined,{className:"text-2xl mb-2"}),(0,t.jsx)(d.Text,{children:"Complete required fields to test connection"}),(0,t.jsx)("br",{}),(0,t.jsx)(d.Text,{className:"text-sm",children:"Fill in URL, Transport, and Authentication to test MCP server connection"})]}),n&&(0,t.jsxs)("div",{children:[(0,t.jsxs)("div",{className:"flex items-center justify-between mb-4",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)(d.Text,{className:"text-gray-700 font-medium",children:r?"Testing connection to MCP server...":s.length>0?"Connection successful":l?"Connection failed":"Ready to test connection"}),(0,t.jsx)("br",{}),(0,t.jsxs)(d.Text,{className:"text-gray-500 text-sm",children:["Server: ",e.url||e.spec_path]})]}),r&&(0,t.jsxs)("div",{className:"flex items-center text-blue-600",children:[(0,t.jsx)(W.Spin,{size:"small",className:"mr-2"}),(0,t.jsx)(d.Text,{className:"text-blue-600",children:"Connecting..."})]}),!r&&!l&&s.length>0&&(0,t.jsxs)("div",{className:"flex items-center text-green-600",children:[(0,t.jsx)(ey.CheckCircleOutlined,{className:"mr-1"}),(0,t.jsx)(d.Text,{className:"text-green-600 font-medium",children:"Connected"})]}),l&&(0,t.jsxs)("div",{className:"flex items-center text-red-600",children:[(0,t.jsx)(ev.ExclamationCircleOutlined,{className:"mr-1"}),(0,t.jsx)(d.Text,{className:"text-red-600 font-medium",children:"Failed"})]})]}),r&&(0,t.jsxs)("div",{className:"flex items-center justify-center py-6",children:[(0,t.jsx)(W.Spin,{size:"large"}),(0,t.jsx)(d.Text,{className:"ml-3",children:"Testing connection and loading tools..."})]}),l&&(0,t.jsx)(ej.Alert,{message:"Connection Failed",description:(0,t.jsxs)("div",{children:[(0,t.jsx)("div",{children:l}),a&&(0,t.jsx)(ea.Collapse,{items:[{key:"stack-trace",label:"Stack Trace",children:(0,t.jsx)("pre",{style:{whiteSpace:"pre-wrap",wordBreak:"break-word",fontSize:"12px",fontFamily:"monospace",margin:0,padding:"8px",backgroundColor:"#f5f5f5",borderRadius:"4px",maxHeight:"400px",overflow:"auto"},children:a})}],style:{marginTop:"12px"}})]}),type:"error",showIcon:!0,action:(0,t.jsx)(eb.Button,{icon:(0,t.jsx)(eN.ReloadOutlined,{}),onClick:i,size:"small",children:"Retry"})}),!r&&0===s.length&&!l&&(0,t.jsxs)("div",{className:"text-center py-6 text-gray-500 border rounded-lg border-dashed",children:[(0,t.jsx)(ey.CheckCircleOutlined,{className:"text-2xl mb-2 text-green-500"}),(0,t.jsx)(d.Text,{className:"text-green-600 font-medium",children:"Connection successful!"}),(0,t.jsx)("br",{}),(0,t.jsx)(d.Text,{className:"text-gray-500",children:"No tools found for this MCP server"})]})]})]})}):null;var ew=e.i(928685),eS=e.i(751904),eC=e.i(536916),eT=e.i(91739);let ek=({accessToken:e,oauthAccessToken:t,formValues:s,enabled:r=!0})=>{let[l,a]=(0,b.useState)([]),[n,i]=(0,b.useState)(!1),[o,c]=(0,b.useState)(null),[d,m]=(0,b.useState)(null),[u,x]=(0,b.useState)(!1),h=s.auth_type===eo.AUTH_TYPE.OAUTH2&&s.oauth_flow_type===eo.OAUTH_FLOW.M2M,p=s.auth_type===eo.AUTH_TYPE.OAUTH2&&!h,g=s.transport===eo.TRANSPORT.OPENAPI,f=g?!!s.spec_path:!!s.url,j=g?!!(f&&e):!!(f&&s.transport&&s.auth_type&&e&&(!p||t)),y=JSON.stringify(s.static_headers??{}),v=JSON.stringify(s.credentials??{}),N=async()=>{if(e&&(s.url||s.spec_path)&&(!p||t||g)){i(!0),c(null);try{let r=Array.isArray(s.static_headers)?s.static_headers.reduce((e,t)=>{let s=t?.header?.trim();return s&&(e[s]=t?.value!=null?String(t.value):""),e},{}):!Array.isArray(s.static_headers)&&s.static_headers&&"object"==typeof s.static_headers?Object.entries(s.static_headers).reduce((e,[t,s])=>(t&&(e[t]=null!=s?String(s):""),e),{}):{},l=s.credentials&&"object"==typeof s.credentials?Object.entries(s.credentials).reduce((e,[t,s])=>{if(null==s||""===s)return e;if("scopes"===t){if(Array.isArray(s)){let r=s.filter(e=>null!=e&&""!==e);r.length>0&&(e[t]=r)}}else e[t]=s;return e},{}):void 0,n=s.transport===eo.TRANSPORT.OPENAPI?"http":s.transport,i={server_id:s.server_id||"",server_name:s.server_name||"",url:s.url,spec_path:s.spec_path,transport:n,auth_type:s.auth_type,authorization_url:s.authorization_url,token_url:s.token_url,registration_url:s.registration_url,mcp_info:s.mcp_info,static_headers:r};l&&Object.keys(l).length>0&&(i.credentials=l);let o=await (0,_.testMCPToolsListRequest)(e,i,t);if(o.tools&&!o.error)a(o.tools),c(null),m(null),o.tools.length>0&&!u&&x(!0);else{let e=o.message||"Failed to retrieve tools list";c(e),m(o.stack_trace||null),a([]),x(!1)}}catch(e){console.error("Tools fetch error:",e),c(e instanceof Error?e.message:String(e)),m(null),a([]),x(!1)}finally{i(!1)}}},w=()=>{a([]),c(null),m(null),x(!1)};return(0,b.useEffect)(()=>{r&&(j?N():w())},[s.url,s.spec_path,s.transport,s.auth_type,e,r,t,j,y,v]),{tools:l,isLoadingTools:n,toolsError:o,toolsErrorStackTrace:d,hasShownSuccessMessage:u,canFetchTools:j,fetchTools:N,clearTools:w}};var eA=e.i(531516);let eI=({tool:e,isEnabled:s,isEditExpanded:r,toolNameToDisplayName:l,toolNameToDescription:a,onToggle:n,onToggleExpand:i,onDisplayNameChange:o,onDescriptionChange:c})=>(0,t.jsxs)("div",{className:`rounded-lg border transition-colors ${s?"bg-blue-50 border-blue-300 hover:border-blue-400":"bg-gray-50 border-gray-200 hover:border-gray-300"}`,children:[(0,t.jsx)("div",{className:"p-4 cursor-pointer",onClick:()=>n(e.name),children:(0,t.jsxs)("div",{className:"flex items-start gap-3",children:[(0,t.jsx)(eC.Checkbox,{checked:s,onChange:()=>n(e.name)}),(0,t.jsxs)("div",{className:"flex-1",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(d.Text,{className:"font-medium text-gray-900",children:l[e.name]||e.name}),(0,t.jsx)("span",{className:`px-2 py-0.5 text-xs rounded-full font-medium ${s?"bg-green-100 text-green-800":"bg-red-100 text-red-800"}`,children:s?"Enabled":"Disabled"}),l[e.name]&&(0,t.jsx)("span",{className:"px-2 py-0.5 text-xs rounded-full font-medium bg-purple-100 text-purple-800",children:"Custom name"})]}),(a[e.name]||e.description)&&(0,t.jsx)(d.Text,{className:"text-gray-500 text-sm block mt-1",children:a[e.name]||e.description}),(0,t.jsx)(d.Text,{className:"text-gray-400 text-xs block mt-1",children:s?"✓ Users can call this tool":"✗ Users cannot call this tool"})]}),(0,t.jsx)("button",{type:"button",onClick:t=>i(e.name,t),className:`p-1.5 rounded-md transition-colors ${r?"bg-blue-100 text-blue-600":"text-gray-400 hover:text-gray-600 hover:bg-gray-100"}`,title:"Edit display name and description",children:(0,t.jsx)(eS.EditOutlined,{})})]})}),r&&(0,t.jsxs)("div",{className:"px-4 pb-4 pt-3 border-t border-gray-200 space-y-3 bg-gray-50 rounded-b-lg",onClick:e=>e.stopPropagation(),children:[(0,t.jsxs)("div",{children:[(0,t.jsx)(d.Text,{className:"text-xs font-medium text-gray-600 mb-1 block",children:"Display Name"}),(0,t.jsx)(H.Input,{placeholder:e.name,value:l[e.name]||"",onChange:t=>o(e.name,t.target.value)}),(0,t.jsx)(d.Text,{className:"text-xs text-gray-400 mt-1 block",children:"Override how this tool's name appears to users. Leave blank to use original."})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(d.Text,{className:"text-xs font-medium text-gray-600 mb-1 block",children:"Description"}),(0,t.jsx)(H.Input.TextArea,{placeholder:e.description||"No description",value:a[e.name]||"",onChange:t=>c(e.name,t.target.value),rows:2}),(0,t.jsx)(d.Text,{className:"text-xs text-gray-400 mt-1 block",children:"Override the tool description shown to users. Leave blank to use original."})]})]})]}),eP=({accessToken:e,oauthAccessToken:s,formValues:r,allowedTools:l,existingAllowedTools:a,onAllowedToolsChange:n,toolNameToDisplayName:i,toolNameToDescription:o,onToolNameToDisplayNameChange:c,onToolNameToDescriptionChange:u,keyTools:x,externalTools:h,externalIsLoading:p,externalError:g,externalCanFetch:f})=>{let j=(0,b.useRef)([]),[y,v]=(0,b.useState)(""),[N,_]=(0,b.useState)("crud"),w=(0,b.useRef)(!1),S=(0,b.useRef)(""),[C,T]=(0,b.useState)(new Set),k=void 0!==h,A=ek({accessToken:e,oauthAccessToken:s,formValues:r,enabled:!k}),I=k?h:A.tools,P=k?p??!1:A.isLoadingTools,O=k?g??null:A.toolsError,M=k?f??!1:A.canFetchTools,F=(0,b.useMemo)(()=>{if(!x||0===x.length||0===I.length)return[];let e=new Set,t=[];for(let s of x){let r=s.name.split("_").map(e=>e.toLowerCase()).filter(e=>e.length>1);if(0===r.length)continue;let l=e=>e.toLowerCase().replace(/[-_/]/g," "),a=I.find(t=>{if(e.has(t.name))return!1;let s=l(t.name);return r.every(e=>s.includes(e))});if(!a){let t=r.find(e=>e.length>3)??r[r.length-1];a=I.find(s=>!e.has(s.name)&&l(s.name).includes(t))}a&&(t.push(a),e.add(a.name))}return t},[x,I]),E=(0,b.useMemo)(()=>new Set(F.map(e=>e.name)),[F]),L=(0,b.useMemo)(()=>I.filter(e=>{let t=y.toLowerCase();return e.name.toLowerCase().includes(t)||e.description&&e.description.toLowerCase().includes(t)}),[I,y]),R=(0,b.useMemo)(()=>L.filter(e=>E.has(e.name)),[L,E]),U=(0,b.useMemo)(()=>L.filter(e=>!E.has(e.name)),[L,E]);(0,b.useEffect)(()=>{let e=I.map(e=>e.name).sort().join(","),t=j.current.map(e=>e.name).sort().join(","),s=F.map(e=>e.name).sort().join(",");if(s!==S.current&&(S.current=s,""!==s&&(w.current=!1)),I.length>0&&e!==t){let e=I.map(e=>e.name);w.current?n(l.filter(t=>e.includes(t))):(w.current=!0,a&&a.length>0?n(a.filter(t=>e.includes(t))):F.length>0?n(F.map(e=>e.name).filter(t=>e.includes(t))):n(e))}j.current=I},[I,l,a,n,F]);let z=e=>{l.includes(e)?n(l.filter(t=>t!==e)):n([...l,e])},B=(e,t)=>{t.stopPropagation(),T(t=>{let s=new Set(t);return s.has(e)?s.delete(e):s.add(e),s})},q=(e,t)=>{let s={...i};t?s[e]=t:delete s[e],c(s)},V=(e,t)=>{let s={...o};t?s[e]=t:delete s[e],u(s)};return M||r.url||r.spec_path?(0,t.jsx)(eg.Card,{children:(0,t.jsxs)("div",{className:"space-y-4",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(ep.ToolOutlined,{className:"text-blue-600"}),(0,t.jsx)(m.Title,{children:"Tool Configuration"}),I.length>0&&(0,t.jsx)(ex.Badge,{count:I.length,style:{backgroundColor:"#52c41a"}})]}),I.length>0&&(0,t.jsx)(eT.Radio.Group,{value:N,onChange:e=>_(e.target.value),size:"small",optionType:"button",buttonStyle:"solid",options:[{label:"Risk Groups",value:"crud"},{label:"Flat List",value:"flat"}]})]}),(0,t.jsx)("div",{className:"bg-blue-50 border border-blue-200 rounded-lg p-3",children:(0,t.jsxs)(d.Text,{className:"text-blue-800 text-sm",children:[(0,t.jsx)("strong",{children:"Select which tools users can call:"})," Only checked tools will be available for users to invoke. Unchecked tools will be blocked from execution."]})}),P&&(0,t.jsxs)("div",{className:"flex items-center justify-center py-6",children:[(0,t.jsx)(W.Spin,{size:"large"}),(0,t.jsx)(d.Text,{className:"ml-3",children:"Loading tools from spec..."})]}),O&&!P&&(0,t.jsxs)("div",{className:"text-center py-6 text-red-500 border rounded-lg border-dashed border-red-300 bg-red-50",children:[(0,t.jsx)(ep.ToolOutlined,{className:"text-2xl mb-2"}),(0,t.jsx)(d.Text,{className:"text-red-600 font-medium",children:"Unable to load tools"}),(0,t.jsx)("br",{}),(0,t.jsx)(d.Text,{className:"text-sm text-red-500",children:O})]}),!P&&!O&&0===I.length&&M&&(x&&x.length>0?(0,t.jsxs)("div",{className:"text-center py-4 text-gray-400 border rounded-lg border-dashed",children:[(0,t.jsx)(ep.ToolOutlined,{className:"text-2xl mb-2"}),(0,t.jsx)(d.Text,{children:"No tools loaded from spec"}),(0,t.jsxs)(d.Text,{className:"text-sm block mt-1",children:["Expected tools: ",x.map(e=>e.name).join(", ")]})]}):(0,t.jsxs)("div",{className:"text-center py-6 text-gray-400 border rounded-lg border-dashed",children:[(0,t.jsx)(ep.ToolOutlined,{className:"text-2xl mb-2"}),(0,t.jsx)(d.Text,{children:"No tools available for configuration"}),(0,t.jsx)("br",{}),(0,t.jsx)(d.Text,{className:"text-sm",children:"Connect to an MCP server with tools to configure them"})]})),!M&&(r.url||r.spec_path)&&(0,t.jsxs)("div",{className:"text-center py-6 text-gray-400 border rounded-lg border-dashed",children:[(0,t.jsx)(ep.ToolOutlined,{className:"text-2xl mb-2"}),(0,t.jsx)(d.Text,{children:"Complete required fields to configure tools"}),(0,t.jsx)("br",{}),(0,t.jsx)(d.Text,{className:"text-sm",children:"Fill in URL, Transport, and Authentication to load available tools"})]}),!P&&!O&&I.length>0&&(0,t.jsxs)("div",{className:"space-y-3",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2 p-3 bg-green-50 rounded-lg border border-green-200",children:[(0,t.jsx)(ey.CheckCircleOutlined,{className:"text-green-600"}),(0,t.jsxs)(d.Text,{className:"text-green-700 font-medium",children:[l.length," of ",I.length," ",1===I.length?"tool":"tools"," enabled for user access"]})]}),(0,t.jsx)(H.Input,{placeholder:"Search tools by name or description...",prefix:(0,t.jsx)(ew.SearchOutlined,{className:"text-gray-400"}),value:y,onChange:e=>v(e.target.value),allowClear:!0,className:"rounded-lg",size:"large"}),"crud"===N&&(0,t.jsx)(eA.default,{tools:I,searchFilter:y,value:0===l.length?void 0:l,onChange:e=>n(e)}),"flat"===N&&(0,t.jsx)(t.Fragment,{children:0===L.length?(0,t.jsxs)("div",{className:"text-center py-6 text-gray-400 border rounded-lg border-dashed",children:[(0,t.jsx)(ew.SearchOutlined,{className:"text-2xl mb-2"}),(0,t.jsxs)(d.Text,{children:['No tools found matching "',y,'"']})]}):(0,t.jsxs)("div",{className:"space-y-2",children:[R.length>0&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("div",{className:"flex items-center justify-between px-1",children:[(0,t.jsx)("p",{className:"text-xs font-semibold text-gray-500 uppercase tracking-wide",children:"Suggested tools"}),(0,t.jsxs)("div",{className:"flex gap-2",children:[(0,t.jsx)("button",{type:"button",onClick:()=>{let e=F.map(e=>e.name);n([...l.filter(e=>!E.has(e)),...e])},className:"text-xs text-blue-600 hover:text-blue-700",children:"Enable all"}),(0,t.jsx)("button",{type:"button",onClick:()=>{n(l.filter(e=>!E.has(e)))},className:"text-xs text-gray-500 hover:text-gray-700",children:"Disable all"})]})]}),R.map(e=>(0,t.jsx)(eI,{tool:e,isEnabled:l.includes(e.name),isEditExpanded:C.has(e.name),toolNameToDisplayName:i,toolNameToDescription:o,onToggle:z,onToggleExpand:B,onDisplayNameChange:q,onDescriptionChange:V},e.name))]}),U.length>0&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("div",{className:"flex items-center justify-between px-1 pt-2",children:[(0,t.jsx)("p",{className:"text-xs font-semibold text-gray-500 uppercase tracking-wide",children:R.length>0?"All tools":"Tools"}),(0,t.jsxs)("div",{className:"flex gap-2",children:[(0,t.jsx)("button",{type:"button",onClick:()=>{let e=I.filter(e=>!E.has(e.name)).map(e=>e.name),t=new Set(l);n([...l,...e.filter(e=>!t.has(e))])},className:"text-xs text-blue-600 hover:text-blue-700",children:"Enable all"}),(0,t.jsx)("button",{type:"button",onClick:()=>{n(l.filter(e=>E.has(e)))},className:"text-xs text-gray-500 hover:text-gray-700",children:"Disable all"})]})]}),U.map(e=>(0,t.jsx)(eI,{tool:e,isEnabled:l.includes(e.name),isEditExpanded:C.has(e.name),toolNameToDisplayName:i,toolNameToDescription:o,onToggle:z,onToggleExpand:B,onDisplayNameChange:q,onDescriptionChange:V},e.name))]})]})})]})]})}):null},eO=({isVisible:e,required:s=!0})=>e?(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["Stdio Configuration (JSON)",(0,t.jsx)(g.Tooltip,{title:"Paste your stdio MCP server configuration in JSON format. You can use the full mcpServers structure from config.yaml or just the inner server configuration.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:"stdio_config",rules:[...s?[{required:!0,message:"Please enter stdio configuration"}]:[],{validator:(e,t)=>{if(!t)return Promise.resolve();try{return JSON.parse(t),Promise.resolve()}catch{return Promise.reject("Please enter valid JSON")}}}],children:(0,t.jsx)(H.Input.TextArea,{placeholder:`{ -======== }`,a=async()=>{try{await navigator.clipboard.writeText(l),s(!0),setTimeout(()=>s(!1),1500)}catch{}};return(0,t.jsxs)("div",{className:"mb-6 rounded-lg border border-gray-200 bg-gray-50 px-5 py-4",children:[(0,t.jsx)("p",{className:"text-sm font-medium text-gray-700 mb-1",children:"How toolsets work"}),(0,t.jsxs)("p",{className:"text-sm text-gray-500 mb-3",children:["Create a toolset, assign it to a key via ",(0,t.jsx)("span",{className:"font-medium text-gray-700",children:"API Keys → Edit Key → MCP Servers"}),", then point your MCP client at the toolset URL. The client only sees the tools you picked."]}),(0,t.jsx)("div",{className:"text-xs text-gray-400 mb-1",children:"Claude Code / Cursor config"}),(0,t.jsxs)("div",{className:"relative",children:[(0,t.jsx)("pre",{className:"bg-white border border-gray-200 rounded px-4 py-3 text-xs font-mono text-gray-700 overflow-x-auto leading-relaxed pr-14",children:l}),(0,t.jsx)("button",{type:"button",onClick:a,className:"absolute top-2 right-2 px-2 py-1 text-xs rounded border bg-white hover:bg-gray-50 text-gray-400 hover:text-gray-600 border-gray-200 transition-colors",children:e?"✓":"copy"})]})]})}function er({accessToken:e,userRole:s}){let r=(0,v.useQueryClient)(),{data:a=[],isLoading:n}=(0,Q.useMCPToolsets)(),[i,o]=(0,b.useState)(!1),[c,u]=(0,b.useState)(null),[x,p]=(0,b.useState)(null),[g,f]=(0,b.useState)(!1),j="Admin"===s||"proxy_admin"===s,y=async(t,s,l)=>{e&&(await (0,_.createMCPToolset)(e,{toolset_name:t,description:s,tools:l}),K.message.success("Toolset created"),r.invalidateQueries({queryKey:["mcpToolsets"]}))},N=async(t,s,l)=>{e&&c&&(await (0,_.updateMCPToolset)(e,{toolset_id:c.toolset_id,toolset_name:t,description:s,tools:l}),K.message.success("Toolset updated"),r.invalidateQueries({queryKey:["mcpToolsets"]}),u(null))},w=async()=>{if(e&&x){f(!0);try{await (0,_.deleteMCPToolset)(e,x),K.message.success("Toolset deleted"),r.invalidateQueries({queryKey:["mcpToolsets"]}),p(null)}finally{f(!1)}}},S=(0,_.getProxyBaseUrl)(),C=[{header:"Toolset ID",accessorKey:"toolset_id",cell:({row:e})=>(0,t.jsxs)("span",{className:"font-mono text-xs bg-gray-100 px-2 py-0.5 rounded text-gray-600",children:[e.original.toolset_id.slice(0,8),"…"]})},{header:"Name",accessorKey:"toolset_name",cell:({row:e})=>{let s=`${S}/toolset/${e.original.toolset_name}/mcp`;return(0,t.jsxs)("div",{className:"flex flex-col gap-0.5",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("span",{className:"inline-block w-2 h-2 rounded-full bg-purple-500 flex-shrink-0"}),(0,t.jsx)("span",{className:"font-medium text-gray-900",children:e.original.toolset_name})]}),(0,t.jsx)("button",{type:"button",className:"text-xs text-gray-400 hover:text-purple-600 font-mono truncate max-w-xs text-left transition-colors",onClick:()=>navigator.clipboard.writeText(s),title:"Click to copy endpoint URL",children:s})]})}},{header:"Description",accessorKey:"description",cell:({row:e})=>(0,t.jsx)("span",{className:"text-sm text-gray-500",children:e.original.description||"—"})},{header:"Tools",accessorKey:"tools",cell:({row:e})=>{let s=e.original.tools;return(0,t.jsxs)("div",{className:"flex flex-wrap gap-1 max-w-xs",children:[s.slice(0,4).map((e,s)=>(0,t.jsx)("span",{className:"inline-flex items-center px-1.5 py-0.5 rounded bg-purple-50 border border-purple-200 text-purple-700 text-xs",children:e.tool_name},s)),s.length>4&&(0,t.jsxs)("span",{className:"text-xs text-gray-400 self-center",children:["+",s.length-4," more"]})]})}},{header:"Created",accessorKey:"created_at",cell:({row:e})=>(0,t.jsx)("span",{className:"text-xs text-gray-500",children:e.original.created_at?new Date(e.original.created_at).toLocaleDateString():"—"})},...j?[{header:"",id:"actions",cell:({row:e})=>(0,t.jsxs)("div",{className:"flex items-center gap-1 justify-end",children:[(0,t.jsx)("button",{type:"button",className:"p-1.5 rounded-lg hover:bg-gray-100 text-gray-400 hover:text-gray-700 transition-colors",onClick:()=>u(e.original),children:(0,t.jsx)(Y.PencilIcon,{className:"h-4 w-4"})}),(0,t.jsx)("button",{type:"button",className:"p-1.5 rounded-lg hover:bg-red-50 text-gray-400 hover:text-red-500 transition-colors",onClick:()=>p(e.original.toolset_id),children:(0,t.jsx)(G.TrashIcon,{className:"h-4 w-4"})})]})}]:[]];return(0,t.jsxs)("div",{className:"mt-4",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between mb-4",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)(m.Title,{children:"MCP Toolsets"}),(0,t.jsx)(d.Text,{className:"text-gray-500 text-sm",children:"Curated collections of tools from one or more MCP servers. Assign toolsets to keys and teams via the MCP permissions dropdown."})]}),j&&(0,t.jsx)(l.Button,{icon:J.PlusIcon,onClick:()=>o(!0),children:"New Toolset"})]}),(0,t.jsx)(es,{}),(0,t.jsx)(Z.DataTable,{data:a,columns:C,renderSubComponent:()=>(0,t.jsx)("div",{}),getRowCanExpand:()=>!1,isLoading:n,noDataMessage:"No toolsets yet. Click 'New Toolset' to create one.",loadingMessage:"Loading toolsets...",enableSorting:!0}),(0,t.jsx)(et,{open:i,onClose:()=>o(!1),onSave:y,accessToken:e}),c&&(0,t.jsx)(et,{open:!!c,onClose:()=>u(null),onSave:N,accessToken:e,initialToolset:c}),(0,t.jsx)(h.Modal,{open:!!x,onCancel:()=>p(null),onOk:w,okText:"Delete",okButtonProps:{danger:!0,loading:g},title:"Delete Toolset",children:(0,t.jsx)("p",{children:"Are you sure you want to delete this toolset? Keys and teams using it will lose access to the scoped tools."})})]})}var el=e.i(790848),ea=e.i(362024),en=e.i(827252),ei=e.i(779241),eo=e.i(292335),ec=e.i(28651);let ed="rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500",em=({label:e,tooltip:s})=>(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:[e,(0,t.jsx)(g.Tooltip,{title:s,children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),eu=({isM2M:e,isEditing:s=!1,oauthFlow:r,initialFlowType:a,docsUrl:n})=>{let i=s?" (leave blank to keep existing)":"";return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(D.Form.Item,{label:(0,t.jsx)(em,{label:"OAuth Flow Type",tooltip:"Choose how the proxy authenticates with this MCP server. M2M is for server-to-server communication using client credentials. Interactive (PKCE) is for user-facing flows that require browser-based authorization."}),name:"oauth_flow_type",...a?{initialValue:a}:{},children:(0,t.jsxs)(p.Select,{className:"rounded-lg",size:"large",children:[(0,t.jsx)(p.Select.Option,{value:eo.OAUTH_FLOW.M2M,children:(0,t.jsxs)("div",{children:[(0,t.jsx)("span",{className:"font-medium",children:"Machine-to-Machine (M2M)"}),(0,t.jsx)("span",{className:"text-gray-400 text-xs ml-2",children:"server-to-server, no user interaction"})]})}),(0,t.jsx)(p.Select.Option,{value:eo.OAUTH_FLOW.INTERACTIVE,children:(0,t.jsxs)("div",{children:[(0,t.jsx)("span",{className:"font-medium",children:"Interactive (PKCE)"}),(0,t.jsx)("span",{className:"text-gray-400 text-xs ml-2",children:"browser-based user authorization"})]})})]})}),e?(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(D.Form.Item,{label:(0,t.jsx)(em,{label:"Client ID",tooltip:"OAuth2 client ID for the client_credentials grant."}),name:["credentials","client_id"],rules:[{required:!0,message:"Client ID is required for M2M OAuth"}],children:(0,t.jsx)(ei.TextInput,{type:"password",placeholder:`Enter OAuth client ID${i}`,className:ed})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsx)(em,{label:"Client Secret",tooltip:"OAuth2 client secret for the client_credentials grant."}),name:["credentials","client_secret"],rules:[{required:!0,message:"Client Secret is required for M2M OAuth"}],children:(0,t.jsx)(ei.TextInput,{type:"password",placeholder:`Enter OAuth client secret${i}`,className:ed})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsx)(em,{label:"Token URL",tooltip:"Token endpoint URL for the client_credentials grant."}),name:"token_url",rules:[{required:!0,message:"Token URL is required for M2M OAuth"}],children:(0,t.jsx)(ei.TextInput,{placeholder:"https://auth.example.com/oauth/token",className:ed})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsx)(em,{label:"Scopes (optional)",tooltip:"Optional scopes to request with the client_credentials grant."}),name:["credentials","scopes"],children:(0,t.jsx)(p.Select,{mode:"tags",tokenSeparators:[","],placeholder:"Add scopes",className:"rounded-lg",size:"large"})})]}):(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"flex items-center justify-between w-full",children:[(0,t.jsx)(em,{label:"Client ID (optional)",tooltip:"Provide only if your MCP server cannot handle dynamic client registration."}),n&&(0,t.jsx)("a",{href:n,target:"_blank",rel:"noopener noreferrer",className:"text-xs text-blue-500 hover:text-blue-700 ml-2 font-normal",onClick:e=>e.stopPropagation(),children:"Create OAuth App →"})]}),name:["credentials","client_id"],children:(0,t.jsx)(ei.TextInput,{type:"password",placeholder:`Enter client ID${i}`,className:ed})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsx)(em,{label:"Client Secret (optional)",tooltip:"Provide only if your MCP server cannot handle dynamic client registration."}),name:["credentials","client_secret"],children:(0,t.jsx)(ei.TextInput,{type:"password",placeholder:`Enter client secret${i}`,className:ed})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsx)(em,{label:"Scopes (optional)",tooltip:"Optional scopes requested during token exchange. Separate multiple scopes with enter or commas."}),name:["credentials","scopes"],children:(0,t.jsx)(p.Select,{mode:"tags",tokenSeparators:[","],placeholder:"Add scopes",className:"rounded-lg",size:"large"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsx)(em,{label:"Authorization URL (optional)",tooltip:"Optional override for the authorization endpoint."}),name:"authorization_url",children:(0,t.jsx)(ei.TextInput,{placeholder:"https://example.com/oauth/authorize",className:ed})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsx)(em,{label:"Token URL (optional)",tooltip:"Optional override for the token endpoint."}),name:"token_url",children:(0,t.jsx)(ei.TextInput,{placeholder:"https://example.com/oauth/token",className:ed})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsx)(em,{label:"Registration URL (optional)",tooltip:"Optional override for the dynamic client registration endpoint."}),name:"registration_url",children:(0,t.jsx)(ei.TextInput,{placeholder:"https://example.com/oauth/register",className:ed})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsx)(em,{label:"Token Validation Rules (optional)",tooltip:'JSON object of key-value rules checked against the OAuth token response before storing. Supports dot-notation for nested fields (e.g. {"organization": "my-org", "team.id": "123"}). Tokens that fail validation are rejected with HTTP 403.'}),name:"token_validation_json",rules:[{validator:(e,t)=>{if(!t||""===t.trim())return Promise.resolve();try{return JSON.parse(t),Promise.resolve()}catch{return Promise.reject(Error("Must be valid JSON"))}}}],children:(0,t.jsx)(H.Input.TextArea,{placeholder:'{\n "organization": "my-org",\n "team.id": "123"\n}',rows:4,className:"font-mono text-sm rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsx)(em,{label:"Token Storage TTL (seconds, optional)",tooltip:"How long to cache each user's OAuth access token in Redis before evicting it (regardless of the token's own expires_in). Leave blank to derive the TTL from the token's expires_in, or fall back to the 12-hour default."}),name:"token_storage_ttl_seconds",children:(0,t.jsx)(ec.InputNumber,{min:1,placeholder:"e.g. 3600",className:"w-full rounded-lg",style:{width:"100%"}})}),r&&(0,t.jsxs)("div",{className:"rounded-lg border border-dashed border-gray-300 p-4 space-y-2",children:[(0,t.jsx)("p",{className:"text-sm text-gray-600",children:"Use OAuth to fetch a fresh access token and temporarily save it in the session as the authentication value."}),(0,t.jsx)(l.Button,{variant:"secondary",onClick:r.startOAuthFlow,disabled:"authorizing"===r.status||"exchanging"===r.status,children:"authorizing"===r.status?"Waiting for authorization...":"exchanging"===r.status?"Exchanging authorization code...":"Authorize & Fetch Token"}),r.error&&(0,t.jsx)("p",{className:"text-sm text-red-500",children:r.error}),"success"===r.status&&r.tokenResponse?.access_token&&(0,t.jsxs)("p",{className:"text-sm text-green-600",children:["Token fetched. Expires in ",r.tokenResponse.expires_in??"?"," seconds."]})]})]})]})};var ex=e.i(906579),eh=e.i(458505),ep=e.i(366308),eg=e.i(304967);let ef=({value:e={},onChange:s,tools:r=[],disabled:l=!1})=>(0,t.jsx)(eg.Card,{children:(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2 mb-4",children:[(0,t.jsx)(eh.DollarOutlined,{className:"text-green-600"}),(0,t.jsx)(m.Title,{children:"Cost Configuration"}),(0,t.jsx)(g.Tooltip,{title:"Configure costs for this MCP server's tool calls. Set a default rate and per-tool overrides.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"text-gray-400"})})]}),(0,t.jsxs)("div",{className:"space-y-4",children:[(0,t.jsxs)("div",{children:[(0,t.jsxs)("label",{className:"block text-sm font-medium text-gray-700 mb-2",children:["Default Cost per Query ($)",(0,t.jsx)(g.Tooltip,{title:"Default cost charged for each tool call to this server.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-1 text-gray-400"})})]}),(0,t.jsx)(ec.InputNumber,{min:0,step:1e-4,precision:4,placeholder:"0.0000",value:e.default_cost_per_query,onChange:t=>{let r={...e,default_cost_per_query:t};s?.(r)},disabled:l,style:{width:"200px"},addonBefore:"$"}),(0,t.jsx)(d.Text,{className:"block mt-1 text-gray-500 text-sm",children:"Set a default cost for all tool calls to this server"})]}),r.length>0&&(0,t.jsxs)("div",{className:"space-y-4",children:[(0,t.jsxs)("label",{className:"block text-sm font-medium text-gray-700",children:["Tool-Specific Costs ($)",(0,t.jsx)(g.Tooltip,{title:"Override the default cost for specific tools. Leave blank to use the default rate.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-1 text-gray-400"})})]}),(0,t.jsx)(ea.Collapse,{items:[{key:"1",label:(0,t.jsxs)("div",{className:"flex items-center",children:[(0,t.jsx)(ep.ToolOutlined,{className:"mr-2 text-blue-500"}),(0,t.jsx)("span",{className:"font-medium",children:"Available Tools"}),(0,t.jsx)(ex.Badge,{count:r.length,style:{backgroundColor:"#52c41a",marginLeft:"8px"}})]}),children:(0,t.jsx)("div",{className:"space-y-3 max-h-64 overflow-y-auto",children:r.map((r,a)=>(0,t.jsxs)("div",{className:"flex items-center justify-between p-3 bg-gray-50 rounded-lg",children:[(0,t.jsxs)("div",{className:"flex-1",children:[(0,t.jsx)(d.Text,{className:"font-medium text-gray-900",children:r.name}),r.description&&(0,t.jsx)(d.Text,{className:"text-gray-500 text-sm block mt-1",children:r.description})]}),(0,t.jsx)("div",{className:"ml-4",children:(0,t.jsx)(ec.InputNumber,{min:0,step:1e-4,precision:4,placeholder:"Use default",value:e.tool_name_to_cost_per_query?.[r.name],onChange:t=>{var l;let a;return l=r.name,a={...e,tool_name_to_cost_per_query:{...e.tool_name_to_cost_per_query,[l]:t}},void s?.(a)},disabled:l,style:{width:"120px"},addonBefore:"$"})})]},a))})}]})]})]}),(e.default_cost_per_query||e.tool_name_to_cost_per_query&&Object.keys(e.tool_name_to_cost_per_query).length>0)&&(0,t.jsxs)("div",{className:"mt-6 p-4 bg-blue-50 border border-blue-200 rounded-lg",children:[(0,t.jsx)(d.Text,{className:"text-blue-800 font-medium",children:"Cost Summary:"}),(0,t.jsxs)("div",{className:"mt-2 space-y-1",children:[e.default_cost_per_query&&(0,t.jsxs)(d.Text,{className:"text-blue-700",children:["• Default cost: $",e.default_cost_per_query.toFixed(4)," per query"]}),e.tool_name_to_cost_per_query&&Object.entries(e.tool_name_to_cost_per_query).map(([e,s])=>null!=s&&(0,t.jsxs)(d.Text,{className:"text-blue-700",children:["• ",e,": $",s.toFixed(4)," per query"]},e))]})]})]})});var eb=e.i(464571),ej=e.i(560445),ey=e.i(245704),ev=e.i(270377),eN=e.i(91979);let e_=({formValues:e,tools:s,isLoadingTools:r,toolsError:l,toolsErrorStackTrace:a,canFetchTools:n,fetchTools:i})=>n||e.url||e.spec_path?(0,t.jsx)(eg.Card,{children:(0,t.jsxs)("div",{className:"space-y-4",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(ey.CheckCircleOutlined,{className:"text-blue-600"}),(0,t.jsx)(m.Title,{children:"Connection Status"})]}),!n&&(e.url||e.spec_path)&&(0,t.jsxs)("div",{className:"text-center py-6 text-gray-400 border rounded-lg border-dashed",children:[(0,t.jsx)(ep.ToolOutlined,{className:"text-2xl mb-2"}),(0,t.jsx)(d.Text,{children:"Complete required fields to test connection"}),(0,t.jsx)("br",{}),(0,t.jsx)(d.Text,{className:"text-sm",children:"Fill in URL, Transport, and Authentication to test MCP server connection"})]}),n&&(0,t.jsxs)("div",{children:[(0,t.jsxs)("div",{className:"flex items-center justify-between mb-4",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)(d.Text,{className:"text-gray-700 font-medium",children:r?"Testing connection to MCP server...":s.length>0?"Connection successful":l?"Connection failed":"Ready to test connection"}),(0,t.jsx)("br",{}),(0,t.jsxs)(d.Text,{className:"text-gray-500 text-sm",children:["Server: ",e.url||e.spec_path]})]}),r&&(0,t.jsxs)("div",{className:"flex items-center text-blue-600",children:[(0,t.jsx)(W.Spin,{size:"small",className:"mr-2"}),(0,t.jsx)(d.Text,{className:"text-blue-600",children:"Connecting..."})]}),!r&&!l&&s.length>0&&(0,t.jsxs)("div",{className:"flex items-center text-green-600",children:[(0,t.jsx)(ey.CheckCircleOutlined,{className:"mr-1"}),(0,t.jsx)(d.Text,{className:"text-green-600 font-medium",children:"Connected"})]}),l&&(0,t.jsxs)("div",{className:"flex items-center text-red-600",children:[(0,t.jsx)(ev.ExclamationCircleOutlined,{className:"mr-1"}),(0,t.jsx)(d.Text,{className:"text-red-600 font-medium",children:"Failed"})]})]}),r&&(0,t.jsxs)("div",{className:"flex items-center justify-center py-6",children:[(0,t.jsx)(W.Spin,{size:"large"}),(0,t.jsx)(d.Text,{className:"ml-3",children:"Testing connection and loading tools..."})]}),l&&(0,t.jsx)(ej.Alert,{message:"Connection Failed",description:(0,t.jsxs)("div",{children:[(0,t.jsx)("div",{children:l}),a&&(0,t.jsx)(ea.Collapse,{items:[{key:"stack-trace",label:"Stack Trace",children:(0,t.jsx)("pre",{style:{whiteSpace:"pre-wrap",wordBreak:"break-word",fontSize:"12px",fontFamily:"monospace",margin:0,padding:"8px",backgroundColor:"#f5f5f5",borderRadius:"4px",maxHeight:"400px",overflow:"auto"},children:a})}],style:{marginTop:"12px"}})]}),type:"error",showIcon:!0,action:(0,t.jsx)(eb.Button,{icon:(0,t.jsx)(eN.ReloadOutlined,{}),onClick:i,size:"small",children:"Retry"})}),!r&&0===s.length&&!l&&(0,t.jsxs)("div",{className:"text-center py-6 text-gray-500 border rounded-lg border-dashed",children:[(0,t.jsx)(ey.CheckCircleOutlined,{className:"text-2xl mb-2 text-green-500"}),(0,t.jsx)(d.Text,{className:"text-green-600 font-medium",children:"Connection successful!"}),(0,t.jsx)("br",{}),(0,t.jsx)(d.Text,{className:"text-gray-500",children:"No tools found for this MCP server"})]})]})]})}):null;var ew=e.i(928685),eS=e.i(751904),eC=e.i(536916),eT=e.i(91739);let ek=({accessToken:e,oauthAccessToken:t,formValues:s,enabled:r=!0})=>{let[l,a]=(0,b.useState)([]),[n,i]=(0,b.useState)(!1),[o,c]=(0,b.useState)(null),[d,m]=(0,b.useState)(null),[u,x]=(0,b.useState)(!1),h=s.auth_type===eo.AUTH_TYPE.OAUTH2&&s.oauth_flow_type===eo.OAUTH_FLOW.M2M,p=s.auth_type===eo.AUTH_TYPE.OAUTH2&&!h,g=s.transport===eo.TRANSPORT.OPENAPI,f=g?!!s.spec_path:!!s.url,j=g?!!(f&&e):!!(f&&s.transport&&s.auth_type&&e&&(!p||t)),y=JSON.stringify(s.static_headers??{}),v=JSON.stringify(s.credentials??{}),N=async()=>{if(e&&(s.url||s.spec_path)&&(!p||t||g)){i(!0),c(null);try{let r=Array.isArray(s.static_headers)?s.static_headers.reduce((e,t)=>{let s=t?.header?.trim();return s&&(e[s]=t?.value!=null?String(t.value):""),e},{}):!Array.isArray(s.static_headers)&&s.static_headers&&"object"==typeof s.static_headers?Object.entries(s.static_headers).reduce((e,[t,s])=>(t&&(e[t]=null!=s?String(s):""),e),{}):{},l=s.credentials&&"object"==typeof s.credentials?Object.entries(s.credentials).reduce((e,[t,s])=>{if(null==s||""===s)return e;if("scopes"===t){if(Array.isArray(s)){let r=s.filter(e=>null!=e&&""!==e);r.length>0&&(e[t]=r)}}else e[t]=s;return e},{}):void 0,n=s.transport===eo.TRANSPORT.OPENAPI?"http":s.transport,i={server_id:s.server_id||"",server_name:s.server_name||"",url:s.url,spec_path:s.spec_path,transport:n,auth_type:s.auth_type,authorization_url:s.authorization_url,token_url:s.token_url,registration_url:s.registration_url,mcp_info:s.mcp_info,static_headers:r};l&&Object.keys(l).length>0&&(i.credentials=l);let o=await (0,_.testMCPToolsListRequest)(e,i,t);if(o.tools&&!o.error)a(o.tools),c(null),m(null),o.tools.length>0&&!u&&x(!0);else{let e=o.message||"Failed to retrieve tools list";c(e),m(o.stack_trace||null),a([]),x(!1)}}catch(e){console.error("Tools fetch error:",e),c(e instanceof Error?e.message:String(e)),m(null),a([]),x(!1)}finally{i(!1)}}},w=()=>{a([]),c(null),m(null),x(!1)};return(0,b.useEffect)(()=>{r&&(j?N():w())},[s.url,s.spec_path,s.transport,s.auth_type,e,r,t,j,y,v]),{tools:l,isLoadingTools:n,toolsError:o,toolsErrorStackTrace:d,hasShownSuccessMessage:u,canFetchTools:j,fetchTools:N,clearTools:w}};var eA=e.i(531516);let eI=({tool:e,isEnabled:s,isEditExpanded:r,toolNameToDisplayName:l,toolNameToDescription:a,onToggle:n,onToggleExpand:i,onDisplayNameChange:o,onDescriptionChange:c})=>(0,t.jsxs)("div",{className:`rounded-lg border transition-colors ${s?"bg-blue-50 border-blue-300 hover:border-blue-400":"bg-gray-50 border-gray-200 hover:border-gray-300"}`,children:[(0,t.jsx)("div",{className:"p-4 cursor-pointer",onClick:()=>n(e.name),children:(0,t.jsxs)("div",{className:"flex items-start gap-3",children:[(0,t.jsx)(eC.Checkbox,{checked:s,onChange:()=>n(e.name)}),(0,t.jsxs)("div",{className:"flex-1",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(d.Text,{className:"font-medium text-gray-900",children:l[e.name]||e.name}),(0,t.jsx)("span",{className:`px-2 py-0.5 text-xs rounded-full font-medium ${s?"bg-green-100 text-green-800":"bg-red-100 text-red-800"}`,children:s?"Enabled":"Disabled"}),l[e.name]&&(0,t.jsx)("span",{className:"px-2 py-0.5 text-xs rounded-full font-medium bg-purple-100 text-purple-800",children:"Custom name"})]}),(a[e.name]||e.description)&&(0,t.jsx)(d.Text,{className:"text-gray-500 text-sm block mt-1",children:a[e.name]||e.description}),(0,t.jsx)(d.Text,{className:"text-gray-400 text-xs block mt-1",children:s?"✓ Users can call this tool":"✗ Users cannot call this tool"})]}),(0,t.jsx)("button",{type:"button",onClick:t=>i(e.name,t),className:`p-1.5 rounded-md transition-colors ${r?"bg-blue-100 text-blue-600":"text-gray-400 hover:text-gray-600 hover:bg-gray-100"}`,title:"Edit display name and description",children:(0,t.jsx)(eS.EditOutlined,{})})]})}),r&&(0,t.jsxs)("div",{className:"px-4 pb-4 pt-3 border-t border-gray-200 space-y-3 bg-gray-50 rounded-b-lg",onClick:e=>e.stopPropagation(),children:[(0,t.jsxs)("div",{children:[(0,t.jsx)(d.Text,{className:"text-xs font-medium text-gray-600 mb-1 block",children:"Display Name"}),(0,t.jsx)(H.Input,{placeholder:e.name,value:l[e.name]||"",onChange:t=>o(e.name,t.target.value)}),(0,t.jsx)(d.Text,{className:"text-xs text-gray-400 mt-1 block",children:"Override how this tool's name appears to users. Leave blank to use original."})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)(d.Text,{className:"text-xs font-medium text-gray-600 mb-1 block",children:"Description"}),(0,t.jsx)(H.Input.TextArea,{placeholder:e.description||"No description",value:a[e.name]||"",onChange:t=>c(e.name,t.target.value),rows:2}),(0,t.jsx)(d.Text,{className:"text-xs text-gray-400 mt-1 block",children:"Override the tool description shown to users. Leave blank to use original."})]})]})]}),eP=({accessToken:e,oauthAccessToken:s,formValues:r,allowedTools:l,existingAllowedTools:a,onAllowedToolsChange:n,toolNameToDisplayName:i,toolNameToDescription:o,onToolNameToDisplayNameChange:c,onToolNameToDescriptionChange:u,keyTools:x,externalTools:h,externalIsLoading:p,externalError:g,externalCanFetch:f})=>{let j=(0,b.useRef)([]),[y,v]=(0,b.useState)(""),[N,_]=(0,b.useState)("crud"),w=(0,b.useRef)(!1),S=(0,b.useRef)(""),[C,T]=(0,b.useState)(new Set),k=void 0!==h,A=ek({accessToken:e,oauthAccessToken:s,formValues:r,enabled:!k}),I=k?h:A.tools,P=k?p??!1:A.isLoadingTools,O=k?g??null:A.toolsError,M=k?f??!1:A.canFetchTools,F=(0,b.useMemo)(()=>{if(!x||0===x.length||0===I.length)return[];let e=new Set,t=[];for(let s of x){let r=s.name.split("_").map(e=>e.toLowerCase()).filter(e=>e.length>1);if(0===r.length)continue;let l=e=>e.toLowerCase().replace(/[-_/]/g," "),a=I.find(t=>{if(e.has(t.name))return!1;let s=l(t.name);return r.every(e=>s.includes(e))});if(!a){let t=r.find(e=>e.length>3)??r[r.length-1];a=I.find(s=>!e.has(s.name)&&l(s.name).includes(t))}a&&(t.push(a),e.add(a.name))}return t},[x,I]),E=(0,b.useMemo)(()=>new Set(F.map(e=>e.name)),[F]),L=(0,b.useMemo)(()=>I.filter(e=>{let t=y.toLowerCase();return e.name.toLowerCase().includes(t)||e.description&&e.description.toLowerCase().includes(t)}),[I,y]),R=(0,b.useMemo)(()=>L.filter(e=>E.has(e.name)),[L,E]),z=(0,b.useMemo)(()=>L.filter(e=>!E.has(e.name)),[L,E]);(0,b.useEffect)(()=>{let e=I.map(e=>e.name).sort().join(","),t=j.current.map(e=>e.name).sort().join(","),s=F.map(e=>e.name).sort().join(",");if(s!==S.current&&(S.current=s,""!==s&&(w.current=!1)),I.length>0&&e!==t){let e=I.map(e=>e.name);w.current?n(l.filter(t=>e.includes(t))):(w.current=!0,a&&a.length>0?n(a.filter(t=>e.includes(t))):F.length>0?n(F.map(e=>e.name).filter(t=>e.includes(t))):n(e))}j.current=I},[I,l,a,n,F]);let U=e=>{l.includes(e)?n(l.filter(t=>t!==e)):n([...l,e])},B=(e,t)=>{t.stopPropagation(),T(t=>{let s=new Set(t);return s.has(e)?s.delete(e):s.add(e),s})},q=(e,t)=>{let s={...i};t?s[e]=t:delete s[e],c(s)},V=(e,t)=>{let s={...o};t?s[e]=t:delete s[e],u(s)};return M||r.url||r.spec_path?(0,t.jsx)(eg.Card,{children:(0,t.jsxs)("div",{className:"space-y-4",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(ep.ToolOutlined,{className:"text-blue-600"}),(0,t.jsx)(m.Title,{children:"Tool Configuration"}),I.length>0&&(0,t.jsx)(ex.Badge,{count:I.length,style:{backgroundColor:"#52c41a"}})]}),I.length>0&&(0,t.jsx)(eT.Radio.Group,{value:N,onChange:e=>_(e.target.value),size:"small",optionType:"button",buttonStyle:"solid",options:[{label:"Risk Groups",value:"crud"},{label:"Flat List",value:"flat"}]})]}),(0,t.jsx)("div",{className:"bg-blue-50 border border-blue-200 rounded-lg p-3",children:(0,t.jsxs)(d.Text,{className:"text-blue-800 text-sm",children:[(0,t.jsx)("strong",{children:"Select which tools users can call:"})," Only checked tools will be available for users to invoke. Unchecked tools will be blocked from execution."]})}),P&&(0,t.jsxs)("div",{className:"flex items-center justify-center py-6",children:[(0,t.jsx)(W.Spin,{size:"large"}),(0,t.jsx)(d.Text,{className:"ml-3",children:"Loading tools from spec..."})]}),O&&!P&&(0,t.jsxs)("div",{className:"text-center py-6 text-red-500 border rounded-lg border-dashed border-red-300 bg-red-50",children:[(0,t.jsx)(ep.ToolOutlined,{className:"text-2xl mb-2"}),(0,t.jsx)(d.Text,{className:"text-red-600 font-medium",children:"Unable to load tools"}),(0,t.jsx)("br",{}),(0,t.jsx)(d.Text,{className:"text-sm text-red-500",children:O})]}),!P&&!O&&0===I.length&&M&&(x&&x.length>0?(0,t.jsxs)("div",{className:"text-center py-4 text-gray-400 border rounded-lg border-dashed",children:[(0,t.jsx)(ep.ToolOutlined,{className:"text-2xl mb-2"}),(0,t.jsx)(d.Text,{children:"No tools loaded from spec"}),(0,t.jsxs)(d.Text,{className:"text-sm block mt-1",children:["Expected tools: ",x.map(e=>e.name).join(", ")]})]}):(0,t.jsxs)("div",{className:"text-center py-6 text-gray-400 border rounded-lg border-dashed",children:[(0,t.jsx)(ep.ToolOutlined,{className:"text-2xl mb-2"}),(0,t.jsx)(d.Text,{children:"No tools available for configuration"}),(0,t.jsx)("br",{}),(0,t.jsx)(d.Text,{className:"text-sm",children:"Connect to an MCP server with tools to configure them"})]})),!M&&(r.url||r.spec_path)&&(0,t.jsxs)("div",{className:"text-center py-6 text-gray-400 border rounded-lg border-dashed",children:[(0,t.jsx)(ep.ToolOutlined,{className:"text-2xl mb-2"}),(0,t.jsx)(d.Text,{children:"Complete required fields to configure tools"}),(0,t.jsx)("br",{}),(0,t.jsx)(d.Text,{className:"text-sm",children:"Fill in URL, Transport, and Authentication to load available tools"})]}),!P&&!O&&I.length>0&&(0,t.jsxs)("div",{className:"space-y-3",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2 p-3 bg-green-50 rounded-lg border border-green-200",children:[(0,t.jsx)(ey.CheckCircleOutlined,{className:"text-green-600"}),(0,t.jsxs)(d.Text,{className:"text-green-700 font-medium",children:[l.length," of ",I.length," ",1===I.length?"tool":"tools"," enabled for user access"]})]}),(0,t.jsx)(H.Input,{placeholder:"Search tools by name or description...",prefix:(0,t.jsx)(ew.SearchOutlined,{className:"text-gray-400"}),value:y,onChange:e=>v(e.target.value),allowClear:!0,className:"rounded-lg",size:"large"}),"crud"===N&&(0,t.jsx)(eA.default,{tools:I,searchFilter:y,value:0===l.length?void 0:l,onChange:e=>n(e)}),"flat"===N&&(0,t.jsx)(t.Fragment,{children:0===L.length?(0,t.jsxs)("div",{className:"text-center py-6 text-gray-400 border rounded-lg border-dashed",children:[(0,t.jsx)(ew.SearchOutlined,{className:"text-2xl mb-2"}),(0,t.jsxs)(d.Text,{children:['No tools found matching "',y,'"']})]}):(0,t.jsxs)("div",{className:"space-y-2",children:[R.length>0&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("div",{className:"flex items-center justify-between px-1",children:[(0,t.jsx)("p",{className:"text-xs font-semibold text-gray-500 uppercase tracking-wide",children:"Suggested tools"}),(0,t.jsxs)("div",{className:"flex gap-2",children:[(0,t.jsx)("button",{type:"button",onClick:()=>{let e=F.map(e=>e.name);n([...l.filter(e=>!E.has(e)),...e])},className:"text-xs text-blue-600 hover:text-blue-700",children:"Enable all"}),(0,t.jsx)("button",{type:"button",onClick:()=>{n(l.filter(e=>!E.has(e)))},className:"text-xs text-gray-500 hover:text-gray-700",children:"Disable all"})]})]}),R.map(e=>(0,t.jsx)(eI,{tool:e,isEnabled:l.includes(e.name),isEditExpanded:C.has(e.name),toolNameToDisplayName:i,toolNameToDescription:o,onToggle:U,onToggleExpand:B,onDisplayNameChange:q,onDescriptionChange:V},e.name))]}),z.length>0&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("div",{className:"flex items-center justify-between px-1 pt-2",children:[(0,t.jsx)("p",{className:"text-xs font-semibold text-gray-500 uppercase tracking-wide",children:R.length>0?"All tools":"Tools"}),(0,t.jsxs)("div",{className:"flex gap-2",children:[(0,t.jsx)("button",{type:"button",onClick:()=>{let e=I.filter(e=>!E.has(e.name)).map(e=>e.name),t=new Set(l);n([...l,...e.filter(e=>!t.has(e))])},className:"text-xs text-blue-600 hover:text-blue-700",children:"Enable all"}),(0,t.jsx)("button",{type:"button",onClick:()=>{n(l.filter(e=>E.has(e)))},className:"text-xs text-gray-500 hover:text-gray-700",children:"Disable all"})]})]}),z.map(e=>(0,t.jsx)(eI,{tool:e,isEnabled:l.includes(e.name),isEditExpanded:C.has(e.name),toolNameToDisplayName:i,toolNameToDescription:o,onToggle:U,onToggleExpand:B,onDisplayNameChange:q,onDescriptionChange:V},e.name))]})]})})]})]})}):null},eO=({isVisible:e,required:s=!0})=>e?(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["Stdio Configuration (JSON)",(0,t.jsx)(g.Tooltip,{title:"Paste your stdio MCP server configuration in JSON format. You can use the full mcpServers structure from config.yaml or just the inner server configuration.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:"stdio_config",rules:[...s?[{required:!0,message:"Please enter stdio configuration"}]:[],{validator:(e,t)=>{if(!t)return Promise.resolve();try{return JSON.parse(t),Promise.resolve()}catch{return Promise.reject("Please enter valid JSON")}}}],children:(0,t.jsx)(H.Input.TextArea,{placeholder:`{ ->>>>>>>> origin/litellm_internal_staging:litellm/proxy/_experimental/out/_next/static/chunks/e1a670efcb966aaa.js "mcpServers": { "circleci-mcp-server": { "command": "npx", @@ -24,15 +16,9 @@ } } } -<<<<<<<< HEAD:litellm/proxy/_experimental/out/_next/static/chunks/0279e5299e9f6e98.js -}`,rows:12,className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500 font-mono text-sm"})}):null;var eM=e.i(770914),eF=e.i(564897),eE=e.i(646563);let{Panel:eL}=ea.Collapse,eR=({availableAccessGroups:e,mcpServer:s,searchValue:r,setSearchValue:l,getAccessGroupOptions:a})=>{let n=D.Form.useFormInstance(),i=D.Form.useWatch("auth_type",n)===eo.AUTH_TYPE.OAUTH2;return(0,b.useEffect)(()=>{if(s){if(s.static_headers){let e=Object.entries(s.static_headers).map(([e,t])=>({header:e,value:null!=t?String(t):""}));n.setFieldValue("static_headers",e)}"boolean"==typeof s.allow_all_keys&&n.setFieldValue("allow_all_keys",s.allow_all_keys),"boolean"==typeof s.available_on_public_internet&&n.setFieldValue("available_on_public_internet",s.available_on_public_internet),"boolean"==typeof s.delegate_auth_to_upstream&&n.setFieldValue("delegate_auth_to_upstream",s.delegate_auth_to_upstream)}else n.setFieldValue("allow_all_keys",!1),n.setFieldValue("available_on_public_internet",!0),n.setFieldValue("delegate_auth_to_upstream",!1)},[s,n]),(0,b.useEffect)(()=>{i||n.setFieldValue("delegate_auth_to_upstream",!1)},[i,n]),(0,t.jsx)(ea.Collapse,{className:"bg-gray-50 border border-gray-200 rounded-lg",expandIconPosition:"end",ghost:!1,children:(0,t.jsx)(eL,{header:(0,t.jsxs)("div",{className:"flex items-center",children:[(0,t.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,t.jsx)("div",{className:"w-2 h-2 bg-blue-500 rounded-full"}),(0,t.jsx)("h3",{className:"text-lg font-semibold text-gray-900",children:"Permission Management / Access Control"})]}),(0,t.jsx)("p",{className:"text-sm text-gray-600 ml-4",children:"Configure access permissions and security settings (Optional)"})]}),className:"border-0",forceRender:!0,children:(0,t.jsxs)("div",{className:"space-y-6 pt-4",children:[(0,t.jsxs)("div",{className:"flex items-start justify-between gap-4",children:[(0,t.jsxs)("div",{children:[(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["Allow All LiteLLM Keys",(0,t.jsx)(g.Tooltip,{title:"When enabled, every API key can access this MCP server.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),(0,t.jsx)("p",{className:"text-sm text-gray-600 mt-1",children:'Enable if this server should be "public" to all keys.'})]}),(0,t.jsx)(D.Form.Item,{name:"allow_all_keys",valuePropName:"checked",initialValue:s?.allow_all_keys??!1,className:"mb-0",children:(0,t.jsx)(el.Switch,{})})]}),(0,t.jsxs)("div",{className:"flex items-start justify-between gap-4",children:[(0,t.jsxs)("div",{children:[(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["Internal network only",(0,t.jsx)(g.Tooltip,{title:"When on, only requests from within your internal network are accepted. Turn off to allow external clients (other clusters, ChatGPT, etc). API key authentication is always required regardless of this setting.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),(0,t.jsx)("p",{className:"text-sm text-gray-600 mt-1",children:"Turn on to restrict access to callers within your internal network only."})]}),(0,t.jsx)(D.Form.Item,{name:"available_on_public_internet",valuePropName:"checked",getValueProps:e=>({checked:!e}),getValueFromEvent:e=>!e,initialValue:!0,className:"mb-0",children:(0,t.jsx)(el.Switch,{})})]}),i&&(0,t.jsxs)("div",{className:"flex items-start justify-between gap-4",children:[(0,t.jsxs)("div",{children:[(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["Delegate auth to upstream (PKCE passthrough)",(0,t.jsx)(g.Tooltip,{title:"When on, LiteLLM skips its own API key/SSO check for this server and lets the client complete PKCE directly with the upstream MCP server. Only honored when Auth Type is oauth2. No spend tracking or per-key rate limiting will run on this route.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),(0,t.jsx)("p",{className:"text-sm text-gray-600 mt-1",children:"Bypass LiteLLM auth so clients authenticate directly with the upstream OAuth MCP server."})]}),(0,t.jsx)(D.Form.Item,{name:"delegate_auth_to_upstream",valuePropName:"checked",initialValue:s?.delegate_auth_to_upstream??!1,className:"mb-0",children:(0,t.jsx)(el.Switch,{})})]}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["MCP Access Groups",(0,t.jsx)(g.Tooltip,{title:"Specify access groups for this MCP server. Users must be in at least one of these groups to access the server.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:"mcp_access_groups",className:"mb-4",children:(0,t.jsx)(p.Select,{mode:"tags",showSearch:!0,placeholder:"Select existing groups or type to create new ones",optionFilterProp:"value",filterOption:(e,t)=>(t?.value??"").toLowerCase().includes(e.toLowerCase()),onSearch:e=>l(e),tokenSeparators:[","],options:a(),maxTagCount:"responsive",allowClear:!0})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["Extra Headers",(0,t.jsx)(g.Tooltip,{title:"Forward custom headers from incoming requests to this MCP server (e.g., Authorization, X-Custom-Header, User-Agent)",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})}),s?.extra_headers&&s.extra_headers.length>0&&(0,t.jsxs)("span",{className:"ml-2 text-xs bg-blue-100 text-blue-700 px-2 py-1 rounded-full",children:[s.extra_headers.length," configured"]})]}),name:"extra_headers",children:(0,t.jsx)(p.Select,{mode:"tags",placeholder:s?.extra_headers&&s.extra_headers.length>0?`Currently: ${s.extra_headers.join(", ")}`:"Enter header names (e.g., Authorization, X-Custom-Header)",className:"rounded-lg",size:"large",tokenSeparators:[","],allowClear:!0})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["Static Headers",(0,t.jsx)(g.Tooltip,{title:"Send these key-value headers with every request to this MCP server.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),required:!1,children:(0,t.jsx)(D.Form.List,{name:"static_headers",children:(e,{add:s,remove:r})=>(0,t.jsxs)("div",{className:"space-y-3",children:[e.map(({key:e,name:s,...l})=>(0,t.jsxs)(eM.Space,{className:"flex w-full",align:"baseline",size:"middle",children:[(0,t.jsx)(D.Form.Item,{...l,name:[s,"header"],className:"flex-1",rules:[{required:!0,message:"Header name is required"}],children:(0,t.jsx)(H.Input,{size:"large",allowClear:!0,className:"rounded-lg",placeholder:"Header name (e.g., X-API-Key)"})}),(0,t.jsx)(D.Form.Item,{...l,name:[s,"value"],className:"flex-1",rules:[{required:!0,message:"Header value is required"}],children:(0,t.jsx)(H.Input,{size:"large",allowClear:!0,className:"rounded-lg",placeholder:"Header value"})}),(0,t.jsx)(eF.MinusCircleOutlined,{onClick:()=>r(s),className:"text-gray-500 hover:text-red-500 cursor-pointer"})]},e)),(0,t.jsx)(eb.Button,{type:"dashed",onClick:()=>s(),icon:(0,t.jsx)(eE.PlusOutlined,{}),block:!0,children:"Add Static Header"})]})})})]})},"permissions")})},eU=({accessToken:e,selectedName:s,onSelect:r})=>{let[l,a]=(0,b.useState)([]),[n,i]=(0,b.useState)(!1),[o,c]=(0,b.useState)(new Set);return((0,b.useEffect)(()=>{e&&(i(!0),(0,_.fetchOpenAPIRegistry)(e).then(e=>a(e.apis??[])).catch(()=>a([])).finally(()=>i(!1)))},[e]),n)?(0,t.jsxs)("div",{className:"mb-4",children:[(0,t.jsx)("span",{className:"text-sm font-medium text-gray-700",children:"Popular APIs"}),(0,t.jsx)("div",{className:"flex justify-center py-6",children:(0,t.jsx)(W.Spin,{size:"small"})})]}):0===l.length?null:(0,t.jsxs)("div",{className:"mb-4",children:[(0,t.jsx)("span",{className:"text-sm font-medium text-gray-700 block mb-2",children:"Popular APIs"}),(0,t.jsx)("div",{className:"grid grid-cols-5 gap-2",children:l.map(e=>{let l=s===e.name,a=o.has(e.name);return(0,t.jsxs)("button",{type:"button",title:e.description,onClick:()=>r(e),className:`flex flex-col items-center gap-1.5 p-3 rounded-lg border transition-all cursor-pointer - ${l?"border-blue-500 bg-blue-50 shadow-sm":"border-gray-200 hover:border-blue-300 hover:bg-gray-50"}`,children:[a?(0,t.jsx)("span",{className:"w-7 h-7 rounded-full bg-gray-200 flex items-center justify-center text-sm font-bold text-gray-600",children:e.title.charAt(0)}):(0,t.jsx)("img",{src:e.icon_url,alt:e.title,className:"w-7 h-7 object-contain",onError:()=>{var t;return t=e.name,void c(e=>new Set(e).add(t))}}),(0,t.jsx)("span",{className:"text-xs text-gray-600 text-center leading-tight font-medium",children:e.title})]},e.name)})}),(0,t.jsx)("p",{className:"text-xs text-gray-400 mt-2",children:"Select an API to pre-fill the spec URL and OAuth 2.0 settings, or enter your own spec URL below."})]})},ez=({form:e,accessToken:s,onValuesChange:r,onKeyToolsChange:l,onLogoUrlChange:a,onOAuthDocsUrlChange:n})=>{let[i,o]=(0,b.useState)(null);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(eU,{accessToken:s,selectedName:i,onSelect:t=>{o(t.name),l?.(t.key_tools??[]),a?.(t.icon_url||void 0);let s={spec_path:t.spec_url};t.oauth?(s.auth_type=eo.AUTH_TYPE.OAUTH2,s.oauth_flow_type=eo.OAUTH_FLOW.INTERACTIVE,s.authorization_url=t.oauth.authorization_url,s.token_url=t.oauth.token_url,e.setFieldsValue(s),n?.(t.oauth.docs_url??null)):(e.resetFields(["auth_type","authorization_url","token_url"]),e.setFieldsValue(s),n?.(null)),r(s)}}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["OpenAPI Spec URL",(0,t.jsx)(g.Tooltip,{title:"URL to an OpenAPI specification (JSON or YAML). MCP tools will be automatically generated from the API endpoints defined in the spec.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:"spec_path",rules:[{required:!0,message:"Please enter an OpenAPI spec URL"}],children:(0,t.jsx)(H.Input,{placeholder:"https://petstore3.swagger.io/api/v3/openapi.json",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500",onChange:()=>{o(null),l?.([]),n?.(null)}})})]})};var eB=e.i(596239);let eq="/ui/assets/logos/",eV=[{name:"GitHub",url:`${eq}github.svg`},{name:"Slack",url:`${eq}slack.svg`},{name:"Notion",url:`${eq}notion.svg`},{name:"Linear",url:`${eq}linear.svg`},{name:"Jira",url:`${eq}jira.svg`},{name:"Figma",url:`${eq}figma.svg`},{name:"Gmail",url:`${eq}gmail.svg`},{name:"Google Drive",url:`${eq}google_drive.svg`},{name:"Stripe",url:`${eq}stripe.svg`},{name:"Shopify",url:`${eq}shopify.svg`},{name:"Salesforce",url:`${eq}salesforce.svg`},{name:"HubSpot",url:`${eq}hubspot.svg`},{name:"Twilio",url:`${eq}twilio.svg`},{name:"Cloudflare",url:`${eq}cloudflare.svg`},{name:"Sentry",url:`${eq}sentry.svg`},{name:"PostgreSQL",url:`${eq}postgresql.svg`},{name:"Snowflake",url:`${eq}snowflake.svg`},{name:"Zapier",url:`${eq}zapier.svg`},{name:"Google",url:`${eq}google.svg`},{name:"GitLab",url:`${eq}gitlab.svg`}],e$=({value:e,onChange:s})=>{let[r,l]=(0,b.useState)(new Set);return(0,t.jsxs)("div",{children:[(0,t.jsxs)("div",{className:"flex items-center gap-2 mb-2",children:[(0,t.jsx)("span",{className:"text-sm font-medium text-gray-700",children:"Logo"}),(0,t.jsx)(g.Tooltip,{title:"Select a well-known logo or paste a URL to any image. The logo is shown on the admin and chat pages.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"text-blue-400 hover:text-blue-600 cursor-help"})})]}),e&&(0,t.jsxs)("div",{className:"flex items-center gap-3 mb-3 p-3 bg-gray-50 rounded-lg border border-gray-200",children:[(0,t.jsx)("img",{src:e,alt:"Selected logo",className:"w-10 h-10 object-contain rounded",onError:e=>{e.target.style.display="none"}}),(0,t.jsx)("div",{className:"flex-1 min-w-0",children:(0,t.jsx)("div",{className:"text-xs text-gray-500 truncate",children:e})}),(0,t.jsx)("button",{type:"button",onClick:()=>s?.(void 0),className:"text-xs text-gray-400 hover:text-red-500 cursor-pointer bg-transparent border-none",children:"✕"})]}),(0,t.jsx)("div",{className:"grid grid-cols-10 gap-1.5 mb-3",children:eV.map(a=>{let n=e===a.url;return r.has(a.url)?null:(0,t.jsx)(g.Tooltip,{title:a.name,children:(0,t.jsx)("button",{type:"button",onClick:()=>{var t;return t=a.url,void s?.(e===t?void 0:t)},className:`flex items-center justify-center p-2 rounded-lg border transition-all cursor-pointer - ${n?"border-blue-500 bg-blue-50 shadow-sm":"border-gray-200 hover:border-blue-300 hover:bg-gray-50"}`,style:{width:40,height:40},children:(0,t.jsx)("img",{src:a.url,alt:a.name,className:"w-5 h-5 object-contain",onError:()=>{var e;return e=a.url,void l(t=>new Set(t).add(e))}})})},a.name)})}),(0,t.jsx)(H.Input,{prefix:(0,t.jsx)(eB.LinkOutlined,{className:"text-gray-400"}),placeholder:"Or paste a custom logo URL...",value:e&&!eV.some(t=>t.url===e)?e:"",onChange:e=>{let t=e.target.value.trim();s?.(t||void 0)},className:"rounded-lg",size:"small"})]})},eD=e=>{try{let t=e.indexOf("/mcp/");if(-1===t)return{token:null,baseUrl:e};let s=e.split("/mcp/");if(2!==s.length)return{token:null,baseUrl:e};let r=s[0]+"/mcp/",l=s[1];if(!l)return{token:null,baseUrl:e};return{token:l,baseUrl:r}}catch(t){return console.error("Error parsing MCP URL:",t),{token:null,baseUrl:e}}},eH=e=>{let{token:t}=eD(e);return{maskedUrl:(e=>{let{token:t,baseUrl:s}=eD(e);return t?s+"...":e})(e),hasToken:!!t}},eK=e=>e?/^https?:\/\/[^\s/$.?#].[^\s]*$/i.test(e)?Promise.resolve():Promise.reject("Please enter a valid URL (e.g., http://service-name.domain:1234/path or https://example.com)"):Promise.resolve(),eW=e=>e&&(e.includes("-")||e.includes(" "))?Promise.reject("Cannot contain '-' (hyphen) or spaces. Please use '_' (underscore) instead."):Promise.resolve();var eJ=e.i(122520),eY=e.i(165615),eG=e.i(434166);let eQ=({accessToken:e,getCredentials:t,getTemporaryPayload:s,onTokenReceived:r,onBeforeRedirect:l})=>{let[a,n]=(0,b.useState)("idle"),[i,o]=(0,b.useState)(null),[c,d]=(0,b.useState)(null),m=(0,b.useRef)(!1),u="litellm-mcp-oauth-flow-state",x="litellm-mcp-oauth-result",h="litellm-mcp-oauth-return-url",p=(e,t)=>{(0,eG.setSecureItem)(e,t)},g=e=>{try{return(0,eG.getSecureItem)(e)}catch(t){return console.warn(`Failed to get storage item ${e}`,t),null}},f=()=>{try{window.sessionStorage.removeItem(u),window.sessionStorage.removeItem(x),window.sessionStorage.removeItem(h),window.localStorage.removeItem(u),window.localStorage.removeItem(x),window.localStorage.removeItem(h)}catch(e){console.warn("Failed to clear OAuth storage",e)}},j=()=>{let e,t,s;return s=((t=(e=window.location.pathname||"").indexOf("/ui"))>=0?e.slice(0,t+3):"").replace(/\/+$/,""),`${window.location.origin}${s}/mcp/oauth/callback`},y=(0,b.useCallback)(async()=>{let r=t()||{};if(!e){o("Missing admin token"),C.default.error("Access token missing. Please re-authenticate and try again.");return}let a=s();if(!a||!a.url||!a.transport){let e="Please complete server URL and transport before starting OAuth.";o(e),C.default.error(e);return}try{n("authorizing"),o(null);let t=await (0,_.cacheTemporaryMcpServer)(e,a),s=t?.server_id?.trim();if(!s)throw Error("Temporary MCP server identifier missing. Please retry.");let i={};if(!(a.credentials?.client_id&&a.credentials?.client_secret)){let t=await (0,_.registerMcpOAuthClient)(e,s,{client_name:a.alias||a.server_name||s,grant_types:["authorization_code","refresh_token"],response_types:["code"],token_endpoint_auth_method:a.credentials&&a.credentials.client_secret?"client_secret_post":"none"});i={clientId:t?.client_id,clientSecret:t?.client_secret}}let c=(0,eY.generateCodeVerifier)(),d=await (0,eY.generateCodeChallenge)(c),m=crypto.randomUUID(),x=i.clientId||r.client_id,g=Array.isArray(r.scopes)?r.scopes.filter(e=>e&&e.trim().length>0).join(" "):void 0,f=(0,_.buildMcpOAuthAuthorizeUrl)({serverId:s,clientId:x,redirectUri:j(),state:m,codeChallenge:d,scope:g}),b={state:m,codeVerifier:c,clientId:x,clientSecret:i.clientSecret||r.client_secret,serverId:s,redirectUri:j()};if(l)try{l()}catch(e){console.error("Failed to prepare for OAuth redirect",e)}try{p(u,JSON.stringify(b)),p(h,window.location.href)}catch(e){throw Error("Unable to access browser storage for OAuth. Please enable storage and retry.")}window.location.href=f}catch(t){console.error("Failed to start OAuth flow",t),n("error");let e=(0,eJ.extractErrorMessage)(t);o(e),C.default.error(e)}},[e,t,s,l]),v=(0,b.useCallback)(async()=>{if(m.current)return;let t=null,s=null;try{let e=g(x);if(!e)return;m.current=!0,t=JSON.parse(e);let r=g(u);s=r?JSON.parse(r):null}catch(e){f(),m.current=!1,o("Failed to resume OAuth flow. Please retry."),n("error"),C.default.error("Failed to resume OAuth flow. Please retry.");return}if(!t){m.current=!1;return}try{window.sessionStorage.removeItem(x),window.localStorage.removeItem(x)}catch(e){}try{if(!s||!s.state||!s.codeVerifier||!s.serverId)throw Error("OAuth session state was lost. This can happen if you have strict browser privacy settings. Please try again and ensure cookies/storage is enabled.");if(!t.state||t.state!==s.state)throw Error("OAuth state mismatch. Please retry.");if(t.error)throw Error(t.error_description||t.error);if(!t.code)throw Error("Authorization code missing in callback.");n("exchanging");let l=await (0,_.exchangeMcpOAuthToken)({serverId:s.serverId,code:t.code,clientId:s.clientId,clientSecret:s.clientSecret,codeVerifier:s.codeVerifier,redirectUri:s.redirectUri,accessToken:e});r(l),d(l),n("success"),o(null),C.default.success("OAuth token retrieved successfully")}catch(t){let e=(0,eJ.extractErrorMessage)(t);o(e),n("error"),C.default.error(e)}finally{f(),setTimeout(()=>{m.current=!1},1e3)}},[r]);return(0,b.useEffect)(()=>{v()},[v]),{startOAuthFlow:y,status:a,error:i,tokenResponse:c}},eZ="../ui/assets/logos/mcp_logo.png",eX=[eo.AUTH_TYPE.API_KEY,eo.AUTH_TYPE.BEARER_TOKEN,eo.AUTH_TYPE.TOKEN,eo.AUTH_TYPE.BASIC],e0=[...eX,eo.AUTH_TYPE.OAUTH2,eo.AUTH_TYPE.AWS_SIGV4],e2="litellm-mcp-oauth-create-state",e1=e=>Array.isArray(e)?e.reduce((e,t)=>{let s=t?.header?.trim();return s&&(e[s]=t?.value??""),e},{}):{},e5=({userRole:e,accessToken:r,onCreateSuccess:a,isModalVisible:n,setModalVisible:i,availableAccessGroups:o,prefillData:c,onBackToDiscovery:d})=>{let[m]=D.Form.useForm(),[u,x]=(0,b.useState)(!1),[f,j]=(0,b.useState)({}),[y,v]=(0,b.useState)({}),[N,w]=(0,b.useState)(null),[S,T]=(0,b.useState)(!1),[k,A]=(0,b.useState)([]),[I,P]=(0,b.useState)({}),[O,M]=(0,b.useState)({}),[F,E]=(0,b.useState)(""),[L,R]=(0,b.useState)([]),[U,z]=(0,b.useState)(""),[B,q]=(0,b.useState)(null),[V,$]=(0,b.useState)(void 0),[K,W]=(0,b.useState)(null),{tools:J,isLoadingTools:Y,toolsError:G,toolsErrorStackTrace:Q,canFetchTools:Z,fetchTools:X,clearTools:ee}=ek({accessToken:r,oauthAccessToken:B,formValues:y,enabled:!0}),et=y.auth_type,es=!!et&&eX.includes(et),er=et===eo.AUTH_TYPE.OAUTH2,ec=et===eo.AUTH_TYPE.AWS_SIGV4,ed=er&&y.oauth_flow_type===eo.OAUTH_FLOW.M2M,{startOAuthFlow:em,status:ex,error:eh,tokenResponse:ep}=eQ({accessToken:r,getCredentials:()=>m.getFieldValue("credentials"),getTemporaryPayload:()=>{let e=m.getFieldsValue(!0),t=e.transport||F,s=e.url||(t===eo.TRANSPORT.OPENAPI?e.spec_path:void 0);if(!s||!t)return null;let r=e1(e.static_headers);return{server_id:void 0,server_name:e.server_name,alias:e.alias,description:e.description,url:s,transport:t===eo.TRANSPORT.OPENAPI?"http":t,auth_type:eo.AUTH_TYPE.OAUTH2,credentials:e.credentials,authorization_url:e.authorization_url,token_url:e.token_url,registration_url:e.registration_url,mcp_access_groups:e.mcp_access_groups,static_headers:r,command:e.command,args:e.args,env:e.env}},onTokenReceived:e=>{if(q(e?.access_token??null),e?.access_token){let t={access_token:e.access_token,...e.refresh_token&&{refresh_token:e.refresh_token},...e.expires_in&&{expires_in:e.expires_in},...e.scope&&{scope:e.scope}};m.setFieldsValue({credentials:t}),C.default.success("OAuth authorization successful! Please click 'Create MCP Server' to save the configuration.")}},onBeforeRedirect:()=>{try{let e=m.getFieldsValue(!0);(0,eG.setSecureItem)(e2,JSON.stringify({modalVisible:n,formValues:e,transportType:F,costConfig:f,allowedTools:k,searchValue:U,aliasManuallyEdited:S,logoUrl:V}))}catch(e){console.warn("Failed to persist MCP create state",e)}}});b.default.useEffect(()=>{let e=(0,eG.getSecureItem)(e2);if(e)try{let t=JSON.parse(e);t.modalVisible&&i(!0);let s=t.formValues?.transport||t.transportType||"";s&&E(s),t.formValues&&w({values:t.formValues,transport:s}),t.costConfig&&j(t.costConfig),t.allowedTools&&A(t.allowedTools),t.searchValue&&z(t.searchValue),"boolean"==typeof t.aliasManuallyEdited&&T(t.aliasManuallyEdited),t.logoUrl&&$(t.logoUrl)}catch(e){console.error("Failed to restore MCP create state",e)}finally{window.sessionStorage.removeItem(e2)}},[m,i]),b.default.useEffect(()=>{N&&(F||N.transport,(!N.transport||F)&&(m.setFieldsValue(N.values),v(N.values),w(null)))},[N,m,F]),b.default.useEffect(()=>{if(!n||!c)return;let e=(c.name||"").replace(/[^a-zA-Z0-9_]/g,"_").replace(/_+/g,"_").replace(/^_|_$/g,""),t=c.transport||"";E(t);let s={server_name:e,alias:e,description:c.description||"",transport:t};if("stdio"===t){let e={};if(c.command&&(e.command=c.command),c.args&&c.args.length>0&&(e.args=c.args),c.env_vars&&c.env_vars.length>0){let t={};for(let e of c.env_vars)t[e.name]=e.description?`<${e.description}>`:"";e.env=t}Object.keys(e).length>0&&(s.stdio_config=JSON.stringify(e,null,2))}else c.url&&(s.url=c.url);m.setFieldsValue(s),v(s),T(!1)},[n,c,m]);let eg=async e=>{x(!0);try{let{static_headers:t,stdio_config:s,credentials:l,allow_all_keys:n,available_on_public_internet:o,delegate_auth_to_upstream:c,token_validation_json:d,...u}=e,h=u.mcp_access_groups,p=e1(t),g=l&&"object"==typeof l?Object.entries(l).reduce((e,[t,s])=>{if(null==s||""===s)return e;if("scopes"===t){if(Array.isArray(s)){let r=s.filter(e=>null!=e&&""!==e);r.length>0&&(e[t]=r)}}else e[t]=s;return e},{}):void 0,b={};if(s&&"stdio"===F)try{let e=JSON.parse(s),t=e;if(e.mcpServers&&"object"==typeof e.mcpServers){let s=Object.keys(e.mcpServers);if(s.length>0){let r=s[0];t=e.mcpServers[r],u.server_name||(u.server_name=r.replace(/-/g,"_"))}}b={command:t.command,args:t.args,env:t.env},console.log("Parsed stdio config:",b)}catch(e){C.default.fromBackend("Invalid JSON in stdio configuration");return}u.transport===eo.TRANSPORT.OPENAPI&&(u.transport="http");let y=null;if(d&&""!==d.trim())try{y=JSON.parse(d)}catch{C.default.fromBackend("Invalid JSON in Token Validation Rules"),x(!1);return}let v={...u,...b,stdio_config:void 0,mcp_info:{server_name:u.server_name||u.url,description:u.description,logo_url:V||void 0,mcp_server_cost_info:Object.keys(f).length>0?f:null},mcp_access_groups:h,alias:u.alias,allowed_tools:k.length>0?k:null,tool_name_to_display_name:Object.keys(I).length>0?I:null,tool_name_to_description:Object.keys(O).length>0?O:null,allow_all_keys:!!n,available_on_public_internet:!!o,delegate_auth_to_upstream:!!c,static_headers:p,...null!==y&&{token_validation:y}};if(v.static_headers=p,u.auth_type&&e0.includes(u.auth_type)&&g&&Object.keys(g).length>0&&(v.credentials=g),console.log(`Payload: ${JSON.stringify(v)}`),null!=r){let e=ej?await (0,_.createMCPServer)(r,v):await (0,_.registerMCPServer)(r,v);C.default.success(ej?"MCP Server created successfully":"MCP Server submitted for admin review"),m.resetFields(),j({}),ee(),A([]),T(!1),$(void 0),i(!1),a(e)}}catch(t){let e=t instanceof Error?t.message:String(t);C.default.fromBackend(ej?`Error creating MCP Server: ${e}`:`Error submitting MCP Server: ${e}`)}finally{x(!1)}},eb=()=>{m.resetFields(),j({}),ee(),A([]),T(!1),$(void 0),i(!1)};b.default.useEffect(()=>{if(!S&&y.server_name){let e=y.server_name.replace(/\s+/g,"_");m.setFieldsValue({alias:e}),v(t=>({...t,alias:e}))}},[y.server_name]),b.default.useEffect(()=>{n||v({})},[n]);let ej=(0,s.isAdminRole)(e);return(0,t.jsx)(h.Modal,{title:(0,t.jsxs)("div",{className:"flex items-center pb-4 border-b border-gray-100",style:{gap:12},children:[d&&(0,t.jsx)("button",{onClick:d,className:"text-sm text-blue-600 hover:text-blue-800 cursor-pointer bg-transparent border-none",style:{flexShrink:0},children:"←"}),(0,t.jsx)("img",{src:eZ,alt:"MCP Logo",className:"w-8 h-8 object-contain",style:{height:"20px",width:"20px",objectFit:"contain"}}),(0,t.jsx)("h2",{className:"text-xl font-semibold text-gray-900",children:ej?"Add New MCP Server":"Submit MCP Server for Review"})]}),open:n,width:1e3,onCancel:eb,footer:null,forceRender:!0,className:"top-8",styles:{body:{padding:"24px"},header:{padding:"24px 24px 0 24px",border:"none"}},children:(0,t.jsx)("div",{className:"mt-6",children:(0,t.jsxs)(D.Form,{form:m,onFinish:eg,onValuesChange:(e,t)=>v(t),layout:"vertical",className:"space-y-6",children:[!ej&&(0,t.jsxs)("div",{className:"rounded-md bg-blue-50 border border-blue-200 px-4 py-3 text-sm text-blue-800",children:["Your submission will be sent for admin review before it becomes active."," ","Note: the request must be made with a team-scoped API key."]}),(0,t.jsxs)("div",{className:"grid grid-cols-1 gap-6",children:[(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["MCP Server Name",(0,t.jsx)(g.Tooltip,{title:"Best practice: Use a descriptive name that indicates the server's purpose (e.g., 'GitHub_MCP', 'Email_Service'). Cannot contain spaces or hyphens; use underscores instead. Names must comply with SEP-986 and will be rejected if invalid (https://modelcontextprotocol.io/specification/2025-11-25/server/tools#tool-names).",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:"server_name",rules:[{required:!1,message:"Please enter a server name"},{validator:(e,t)=>eW(t)}],children:(0,t.jsx)(ei.TextInput,{placeholder:"e.g., GitHub_MCP, Zapier_MCP, etc.",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["Alias",(0,t.jsx)(g.Tooltip,{title:"A short, unique identifier for this server. Defaults to the server name if not provided. Cannot contain spaces or hyphens; use underscores instead.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:"alias",rules:[{required:!1},{validator:(e,t)=>eW(t)}],children:(0,t.jsx)(ei.TextInput,{placeholder:"e.g., GitHub_MCP, Zapier_MCP, etc.",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500",onChange:()=>T(!0)})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsx)("span",{className:"text-sm font-medium text-gray-700",children:"Description"}),name:"description",rules:[{required:!1,message:"Please enter a server description"}],children:(0,t.jsx)(ei.TextInput,{placeholder:"Brief description of what this server does",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(e$,{value:V,onChange:$}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsx)("span",{className:"text-sm font-medium text-gray-700",children:"GitHub / Source URL"}),name:"source_url",children:(0,t.jsx)(ei.TextInput,{placeholder:"https://github.com/org/mcp-server",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsx)("span",{className:"text-sm font-medium text-gray-700",children:"Transport Type"}),name:"transport",rules:[{required:!0,message:"Please select a transport type"}],children:(0,t.jsxs)(p.Select,{placeholder:"Select transport",className:"rounded-lg",size:"large",onChange:e=>{E(e),"stdio"===e?m.setFieldsValue({url:void 0,spec_path:void 0,auth_type:void 0,credentials:void 0}):e===eo.TRANSPORT.OPENAPI?m.setFieldsValue({url:void 0,command:void 0,args:void 0,env:void 0}):m.setFieldsValue({spec_path:void 0,command:void 0,args:void 0,env:void 0})},value:F,children:[(0,t.jsx)(p.Select.Option,{value:"http",children:"Streamable HTTP (Recommended)"}),(0,t.jsx)(p.Select.Option,{value:"sse",children:"Server-Sent Events (SSE)"}),(0,t.jsx)(p.Select.Option,{value:"stdio",children:"Standard Input/Output (stdio)"}),(0,t.jsx)(p.Select.Option,{value:eo.TRANSPORT.OPENAPI,children:"OpenAPI Spec"})]})}),("http"===F||"sse"===F)&&(0,t.jsx)(D.Form.Item,{label:(0,t.jsx)("span",{className:"text-sm font-medium text-gray-700",children:"MCP Server URL"}),name:"url",rules:[{required:!0,message:"Please enter a server URL"},{validator:(e,t)=>eK(t)}],children:(0,t.jsx)(H.Input,{placeholder:"https://your-mcp-server.com",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),F===eo.TRANSPORT.OPENAPI&&(0,t.jsx)(ez,{form:m,accessToken:n?r:null,onValuesChange:e=>v(t=>({...t,...e})),onKeyToolsChange:R,onLogoUrlChange:$,onOAuthDocsUrlChange:W}),F===eo.TRANSPORT.OPENAPI&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center gap-2",children:["BYOK (Bring Your Own Key)",(0,t.jsx)(g.Tooltip,{title:"When enabled, each user provides their own API key for this service. Keys are stored per-user and never shared.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:"is_byok",valuePropName:"checked",children:(0,t.jsx)(el.Switch,{})}),(0,t.jsx)(D.Form.Item,{noStyle:!0,shouldUpdate:(e,t)=>e.is_byok!==t.is_byok||e.auth_type!==t.auth_type,children:({getFieldValue:e})=>e("is_byok")?(0,t.jsxs)(t.Fragment,{children:[e("auth_type")&&"none"!==e("auth_type")&&(0,t.jsxs)("div",{className:"mb-4 p-3 bg-blue-50 rounded-lg text-sm text-blue-700 flex items-start gap-2",children:[(0,t.jsx)(en.InfoCircleOutlined,{className:"mt-0.5 flex-shrink-0"}),(0,t.jsxs)("span",{children:["User keys will be sent as:"," ",(0,t.jsxs)("code",{className:"font-mono bg-blue-100 px-1 rounded",children:["bearer_token"===e("auth_type")&&"Authorization: Bearer {key}","token"===e("auth_type")&&"Authorization: token {key}","api_key"===e("auth_type")&&"x-api-key: {key}","basic"===e("auth_type")&&"Authorization: Basic {key}","authorization"===e("auth_type")&&"Authorization: {key}"]}),!e("auth_type")&&"Set Authentication Type below to specify the format."]})]}),!e("auth_type")&&(0,t.jsxs)("div",{className:"mb-4 p-3 bg-yellow-50 rounded-lg text-sm text-yellow-700 flex items-start gap-2",children:[(0,t.jsx)(en.InfoCircleOutlined,{className:"mt-0.5 flex-shrink-0"}),(0,t.jsxs)("span",{children:["Set the ",(0,t.jsx)("strong",{children:"Authentication Type"})," below to specify how user keys are sent (e.g., Bearer Token, API Key header)."]})]}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700",children:["Access Description",(0,t.jsx)(g.Tooltip,{title:"List of permissions shown to users in the connection modal (e.g. 'Create and manage Jira issues')",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:"byok_description",children:(0,t.jsx)(p.Select,{mode:"tags",placeholder:"Add access description items (press Enter after each)",className:"w-full",tokenSeparators:[","]})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700",children:["API Key Help URL",(0,t.jsx)(g.Tooltip,{title:"Optional link shown to users to help them find their API key",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:"byok_api_key_help_url",children:(0,t.jsx)(H.Input,{placeholder:"https://docs.example.com/api-keys"})})]}):null})]}),"stdio"!==F&&""!==F&&(0,t.jsx)(ea.Collapse,{defaultActiveKey:["auth"],className:"mb-4",items:[{key:"auth",label:(0,t.jsx)("span",{className:"text-sm font-semibold text-gray-700",children:"Authentication"}),children:(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(D.Form.Item,{name:"auth_type",rules:[{required:!0,message:"Please select an auth type"}],children:(0,t.jsxs)(p.Select,{placeholder:"Select auth type",className:"rounded-lg",size:"large",children:[(0,t.jsx)(p.Select.Option,{value:"none",children:"None"}),(0,t.jsx)(p.Select.Option,{value:"api_key",children:"API Key"}),(0,t.jsx)(p.Select.Option,{value:"bearer_token",children:"Bearer Token"}),(0,t.jsx)(p.Select.Option,{value:"token",children:"Token"}),(0,t.jsx)(p.Select.Option,{value:"basic",children:"Basic Auth"}),(0,t.jsx)(p.Select.Option,{value:"oauth2",children:"OAuth"}),(0,t.jsx)(p.Select.Option,{value:"aws_sigv4",children:"AWS SigV4 (Bedrock AgentCore MCPs)"})]})}),es&&(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["Authentication Value",(0,t.jsx)(g.Tooltip,{title:"Token, password, or header value to send with each request for the selected auth type.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","auth_value"],rules:[{validator:(e,t)=>t&&"string"==typeof t&&""===t.trim()?Promise.reject(Error("Authentication value cannot be empty whitespace")):Promise.resolve()}],children:(0,t.jsx)(ei.TextInput,{type:"password",placeholder:"Enter token or secret",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),er&&(0,t.jsx)(eu,{isM2M:ed,initialFlowType:eo.OAUTH_FLOW.INTERACTIVE,docsUrl:K,oauthFlow:{startOAuthFlow:em,status:ex,error:eh,tokenResponse:ep}})]})}]}),"stdio"!==F&&""!==F&&ec&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("p",{className:"text-sm text-gray-500 mb-2",children:["For MCP servers hosted on AWS Bedrock AgentCore."," ",(0,t.jsx)("a",{href:"https://docs.litellm.ai/docs/mcp_aws_sigv4",target:"_blank",rel:"noopener noreferrer",className:"text-blue-500 hover:text-blue-700",children:"View docs →"})]}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["AWS Region",(0,t.jsx)(g.Tooltip,{title:"AWS region for SigV4 signing (e.g., us-east-1)",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","aws_region_name"],rules:[{required:!0,message:"AWS region is required for SigV4 auth"}],children:(0,t.jsx)(H.Input,{placeholder:"us-east-1",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["AWS Service Name",(0,t.jsx)(g.Tooltip,{title:"AWS service name for SigV4 signing. Defaults to 'bedrock-agentcore'.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","aws_service_name"],children:(0,t.jsx)(H.Input,{placeholder:"bedrock-agentcore",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["AWS Access Key ID",(0,t.jsx)(g.Tooltip,{title:"Optional. If not provided, falls back to the boto3 credential chain (IAM role, env vars, etc.).",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","aws_access_key_id"],dependencies:[["credentials","aws_secret_access_key"]],rules:[({getFieldValue:e})=>({validator:(t,s)=>e(["credentials","aws_secret_access_key"])&&!s?Promise.reject(Error("Access Key ID is required when Secret Access Key is provided")):Promise.resolve()})],children:(0,t.jsx)(H.Input.Password,{placeholder:"AKIA... (optional — uses IAM role if blank)",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["AWS Secret Access Key",(0,t.jsx)(g.Tooltip,{title:"Optional. Required if AWS Access Key ID is provided.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","aws_secret_access_key"],dependencies:[["credentials","aws_access_key_id"]],rules:[({getFieldValue:e})=>({validator:(t,s)=>e(["credentials","aws_access_key_id"])&&!s?Promise.reject(Error("Secret Access Key is required when Access Key ID is provided")):Promise.resolve()})],children:(0,t.jsx)(H.Input.Password,{placeholder:"Enter secret key (optional — uses IAM role if blank)",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["AWS Session Token",(0,t.jsx)(g.Tooltip,{title:"Optional. Only needed for temporary STS credentials.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","aws_session_token"],children:(0,t.jsx)(H.Input.Password,{placeholder:"Enter session token (optional)",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["AWS Role ARN",(0,t.jsx)(g.Tooltip,{title:"Optional. IAM role ARN to assume via STS before signing. If set, LiteLLM calls sts:AssumeRole to get temporary credentials. Uses ambient credentials (IAM role, env vars) as the source identity unless explicit keys are also provided.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","aws_role_name"],children:(0,t.jsx)(H.Input,{placeholder:"arn:aws:iam::123456789012:role/MyRole (optional)",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["AWS Session Name",(0,t.jsx)(g.Tooltip,{title:"Optional. Session name for the AssumeRole call — appears in CloudTrail logs. Auto-generated if omitted.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","aws_session_name"],children:(0,t.jsx)(H.Input,{placeholder:"litellm-prod (optional, auto-generated if blank)",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})})]}),(0,t.jsx)(eO,{isVisible:"stdio"===F})]}),(0,t.jsx)("div",{className:"mt-8",children:(0,t.jsx)(eR,{availableAccessGroups:o,mcpServer:null,searchValue:U,setSearchValue:z,getAccessGroupOptions:()=>{let e=o.map(e=>({value:e,label:(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("div",{className:"w-2 h-2 bg-green-500 rounded-full"}),(0,t.jsx)("span",{className:"font-medium",children:e})]})}));return U&&!o.some(e=>e.toLowerCase().includes(U.toLowerCase()))&&e.push({value:U,label:(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("div",{className:"w-2 h-2 bg-blue-500 rounded-full"}),(0,t.jsx)("span",{className:"font-medium",children:U}),(0,t.jsx)("span",{className:"text-gray-400 text-xs ml-1",children:"create new group"})]})}),e}})}),(0,t.jsx)("div",{className:"mt-8 pt-6 border-t border-gray-200",children:(0,t.jsx)(e_,{formValues:y,tools:J,isLoadingTools:Y,toolsError:G,toolsErrorStackTrace:Q,canFetchTools:Z,fetchTools:X})}),(0,t.jsx)("div",{className:"mt-6",children:(0,t.jsx)(eP,{accessToken:r,oauthAccessToken:B,formValues:y,allowedTools:k,existingAllowedTools:null,onAllowedToolsChange:A,toolNameToDisplayName:I,toolNameToDescription:O,onToolNameToDisplayNameChange:P,onToolNameToDescriptionChange:M,keyTools:L,externalTools:J,externalIsLoading:Y,externalError:G,externalCanFetch:Z})}),(0,t.jsx)("div",{className:"mt-6",children:(0,t.jsx)(ef,{value:f,onChange:j,tools:J.filter(e=>k.includes(e.name)),disabled:!1})}),(0,t.jsxs)("div",{className:"flex items-center justify-end space-x-3 pt-6 border-t border-gray-100",children:[(0,t.jsx)(l.Button,{variant:"secondary",onClick:eb,children:"Cancel"}),(0,t.jsx)(l.Button,{variant:"primary",loading:u,children:u?"Creating...":"Add MCP Server"})]})]})})})};var e4=e.i(175712),e6=e.i(118366),e3=e.i(475254);let e7=(0,e3.default)("code",[["path",{d:"m16 18 6-6-6-6",key:"eg8j8"}],["path",{d:"m8 6-6 6 6 6",key:"ppft3o"}]]);e.s(["Code",()=>e7],758472);let e8=(0,e3.default)("terminal",[["path",{d:"M12 19h8",key:"baeox8"}],["path",{d:"m4 17 6-6-6-6",key:"1yngyt"}]]),e9=(0,e3.default)("globe",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20",key:"13o1zl"}],["path",{d:"M2 12h20",key:"9i4pu4"}]]);var te=e.i(634831),tt=e.i(438100);let ts=(0,e3.default)("zap",[["path",{d:"M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z",key:"1xq2db"}]]);var tr=e.i(500330);let{Title:tl,Text:ta}=f.Typography,{Panel:tn}=ea.Collapse,ti=({icon:e,title:s,description:r,children:l,serverName:a,accessGroups:n=["dev-group"]})=>{let[i,o]=(0,b.useState)(!1);return(0,t.jsxs)(e4.Card,{className:"border border-gray-200",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3 mb-3",children:[(0,t.jsx)("span",{className:"p-2 rounded-lg bg-gray-50",children:e}),(0,t.jsxs)("div",{children:[(0,t.jsx)(tl,{level:5,className:"mb-0",children:s}),(0,t.jsx)(ta,{className:"text-gray-600",children:r})]})]}),a&&("Implementation Example"===s||"Configuration"===s)&&(0,t.jsxs)(D.Form.Item,{className:"mb-4",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2 mb-2",children:[(0,t.jsx)(el.Switch,{size:"small",checked:i,onChange:o}),(0,t.jsxs)(ta,{className:"text-sm",children:["Limit tools to specific MCP servers or MCP groups by passing the ",(0,t.jsx)("code",{children:"x-mcp-servers"})," header"]})]}),i&&(0,t.jsx)(ej.Alert,{className:"mt-2",type:"info",showIcon:!0,message:"Two Options",description:(0,t.jsxs)("div",{children:[(0,t.jsxs)("p",{children:[(0,t.jsx)("strong",{children:"Option 1:"})," Get a specific server: ",(0,t.jsxs)("code",{children:['"',a.replace(/\s+/g,"_"),'"']})]}),(0,t.jsxs)("p",{children:[(0,t.jsx)("strong",{children:"Option 2:"})," Get a group of MCPs: ",(0,t.jsx)("code",{children:'"dev-group"'})]}),(0,t.jsxs)("p",{className:"mt-2 text-sm text-gray-600",children:["You can also mix both: ",(0,t.jsx)("code",{children:'"Server1,dev-group"'})]})]})})]}),b.default.Children.map(l,e=>{if(b.default.isValidElement(e)&&e.props.hasOwnProperty("code")&&e.props.hasOwnProperty("copyKey")){let t=e.props.code;if(t&&t.includes('"headers":'))return b.default.cloneElement(e,{code:t.replace(/"headers":\s*{[^}]*}/,`"headers": ${JSON.stringify((()=>{let e={"x-litellm-api-key":"Bearer YOUR_LITELLM_API_KEY"};if(i&&a){let t=[a.replace(/\s+/g,"_"),...n].join(",");e["x-mcp-servers"]=t}return e})(),null,8)}`)})}return e})]})},to=({currentServerAccessGroups:e=[]})=>{let s=(0,_.getProxyBaseUrl)(),[r,l]=(0,b.useState)({}),[u,x]=(0,b.useState)({openai:[],litellm:[],cursor:[],http:[]}),[h]=(0,b.useState)("Zapier_MCP"),p=async(e,t)=>{await (0,tr.copyToClipboard)(e)&&(l(e=>({...e,[t]:!0})),setTimeout(()=>{l(e=>({...e,[t]:!1}))},2e3))},g=({code:e,copyKey:s,title:l,className:a=""})=>(0,t.jsxs)("div",{className:"relative group",children:[l&&(0,t.jsxs)("div",{className:"flex items-center gap-2 mb-2",children:[(0,t.jsx)(e7,{size:16,className:"text-blue-600"}),(0,t.jsx)(ta,{strong:!0,className:"text-gray-700",children:l})]}),(0,t.jsxs)(e4.Card,{className:`bg-gray-50 border border-gray-200 relative ${a}`,children:[(0,t.jsx)(eb.Button,{type:"text",size:"small",icon:r[s]?(0,t.jsx)(k.CheckIcon,{size:12}):(0,t.jsx)(e6.CopyIcon,{size:12}),onClick:()=>p(e,s),className:`absolute top-2 right-2 z-10 transition-all duration-200 ${r[s]?"text-green-600 bg-green-50 border-green-200":"text-gray-500 hover:text-gray-700 hover:bg-gray-100"}`}),(0,t.jsx)("pre",{className:"text-sm overflow-x-auto pr-10 text-gray-800 font-mono leading-relaxed",children:e})]})]}),f=({step:e,title:s,children:r})=>(0,t.jsxs)("div",{className:"flex gap-4",children:[(0,t.jsx)("div",{className:"flex-shrink-0",children:(0,t.jsx)("div",{className:"w-8 h-8 bg-blue-600 text-white rounded-full flex items-center justify-center text-sm font-semibold",children:e})}),(0,t.jsxs)("div",{className:"flex-1",children:[(0,t.jsx)(ta,{strong:!0,className:"text-gray-800 block mb-2",children:s}),r]})]});return(0,t.jsx)("div",{children:(0,t.jsxs)(eM.Space,{direction:"vertical",size:"large",className:"w-full",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)(m.Title,{className:"text-3xl font-bold text-gray-900 mb-3",children:"Connect to your MCP client"}),(0,t.jsx)(d.Text,{className:"text-lg text-gray-600",children:"Use tools directly from any MCP client with LiteLLM MCP. Enable your AI assistant to perform real-world tasks through a simple, secure connection."})]}),(0,t.jsxs)(n.TabGroup,{className:"w-full",children:[(0,t.jsx)(i.TabList,{className:"flex justify-start mt-8 mb-6",children:(0,t.jsxs)("div",{className:"flex bg-gray-100 p-1 rounded-lg",children:[(0,t.jsx)(a.Tab,{className:"px-6 py-3 rounded-md transition-all duration-200",children:(0,t.jsxs)("span",{className:"flex items-center gap-2 font-medium",children:[(0,t.jsx)(e7,{size:18}),"OpenAI API"]})}),(0,t.jsx)(a.Tab,{className:"px-6 py-3 rounded-md transition-all duration-200",children:(0,t.jsxs)("span",{className:"flex items-center gap-2 font-medium",children:[(0,t.jsx)(ts,{size:18}),"LiteLLM Proxy"]})}),(0,t.jsx)(a.Tab,{className:"px-6 py-3 rounded-md transition-all duration-200",children:(0,t.jsxs)("span",{className:"flex items-center gap-2 font-medium",children:[(0,t.jsx)(e8,{size:18}),"Cursor"]})}),(0,t.jsx)(a.Tab,{className:"px-6 py-3 rounded-md transition-all duration-200",children:(0,t.jsxs)("span",{className:"flex items-center gap-2 font-medium",children:[(0,t.jsx)(e9,{size:18}),"Streamable HTTP"]})})]})}),(0,t.jsxs)(c.TabPanels,{children:[(0,t.jsx)(o.TabPanel,{className:"mt-6",children:(0,t.jsx)(()=>(0,t.jsxs)(eM.Space,{direction:"vertical",size:"large",className:"w-full",children:[(0,t.jsxs)("div",{className:"bg-gradient-to-r from-blue-50 to-indigo-50 p-6 rounded-lg border border-blue-100",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3 mb-3",children:[(0,t.jsx)(e7,{className:"text-blue-600",size:24}),(0,t.jsx)(tl,{level:4,className:"mb-0 text-blue-900",children:"OpenAI Responses API Integration"})]}),(0,t.jsx)(ta,{className:"text-blue-700",children:"Connect OpenAI Responses API to your LiteLLM MCP server for seamless tool integration"})]}),(0,t.jsxs)(eM.Space,{direction:"vertical",size:"large",className:"w-full",children:[(0,t.jsx)(ti,{icon:(0,t.jsx)(tt.KeyIcon,{className:"text-blue-600",size:16}),title:"API Key Setup",description:"Configure your OpenAI API key for authentication",children:(0,t.jsxs)(eM.Space,{direction:"vertical",size:"middle",className:"w-full",children:[(0,t.jsx)("div",{children:(0,t.jsxs)(ta,{children:["Get your API key from the"," ",(0,t.jsxs)("a",{href:"https://platform.openai.com/api-keys",target:"_blank",rel:"noopener noreferrer",className:"text-blue-600 hover:text-blue-700 inline-flex items-center gap-1",children:["OpenAI platform ",(0,t.jsx)(te.ExternalLinkIcon,{size:12})]})]})}),(0,t.jsx)(g,{title:"Environment Variable",code:'export OPENAI_API_KEY="sk-..."',copyKey:"openai-env"})]})}),(0,t.jsx)(ti,{icon:(0,t.jsx)(P.ServerIcon,{className:"text-blue-600",size:16}),title:"MCP Server Information",description:"Connection details for your LiteLLM MCP server",children:(0,t.jsx)(g,{title:"Server URL",code:`${s}/mcp`,copyKey:"openai-server-url"})}),(0,t.jsx)(ti,{icon:(0,t.jsx)(e7,{className:"text-blue-600",size:16}),title:"Implementation Example",description:"Complete cURL example for using the Responses API",serverName:"Zapier Gmail",accessGroups:["dev-group"],children:(0,t.jsx)(g,{code:`curl --location 'https://api.openai.com/v1/responses' \\ -======== }`,rows:12,className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500 font-mono text-sm"})}):null;var eM=e.i(770914),eF=e.i(564897),eE=e.i(646563);let{Panel:eL}=ea.Collapse,eR=({availableAccessGroups:e,mcpServer:s,searchValue:r,setSearchValue:l,getAccessGroupOptions:a})=>{let n=D.Form.useFormInstance(),i=D.Form.useWatch("auth_type",n)===eo.AUTH_TYPE.OAUTH2,o=D.Form.useWatch("delegate_auth_to_upstream",n),c=D.Form.useWatch("available_on_public_internet",n),d=i&&!0===o&&!1===c;return(0,b.useEffect)(()=>{if(s){if(s.static_headers){let e=Object.entries(s.static_headers).map(([e,t])=>({header:e,value:null!=t?String(t):""}));n.setFieldValue("static_headers",e)}"boolean"==typeof s.allow_all_keys&&n.setFieldValue("allow_all_keys",s.allow_all_keys),"boolean"==typeof s.available_on_public_internet&&n.setFieldValue("available_on_public_internet",s.available_on_public_internet),"boolean"==typeof s.delegate_auth_to_upstream&&n.setFieldValue("delegate_auth_to_upstream",s.delegate_auth_to_upstream)}else n.setFieldValue("allow_all_keys",!1),n.setFieldValue("available_on_public_internet",!0),n.setFieldValue("delegate_auth_to_upstream",!1)},[s,n]),(0,b.useEffect)(()=>{i||n.setFieldValue("delegate_auth_to_upstream",!1)},[i,n]),(0,t.jsx)(ea.Collapse,{className:"bg-gray-50 border border-gray-200 rounded-lg",expandIconPosition:"end",ghost:!1,children:(0,t.jsx)(eL,{header:(0,t.jsxs)("div",{className:"flex items-center",children:[(0,t.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,t.jsx)("div",{className:"w-2 h-2 bg-blue-500 rounded-full"}),(0,t.jsx)("h3",{className:"text-lg font-semibold text-gray-900",children:"Permission Management / Access Control"})]}),(0,t.jsx)("p",{className:"text-sm text-gray-600 ml-4",children:"Configure access permissions and security settings (Optional)"})]}),className:"border-0",forceRender:!0,children:(0,t.jsxs)("div",{className:"space-y-6 pt-4",children:[(0,t.jsxs)("div",{className:"flex items-start justify-between gap-4",children:[(0,t.jsxs)("div",{children:[(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["Allow All LiteLLM Keys",(0,t.jsx)(g.Tooltip,{title:"When enabled, every API key can access this MCP server.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),(0,t.jsx)("p",{className:"text-sm text-gray-600 mt-1",children:'Enable if this server should be "public" to all keys.'})]}),(0,t.jsx)(D.Form.Item,{name:"allow_all_keys",valuePropName:"checked",initialValue:s?.allow_all_keys??!1,className:"mb-0",children:(0,t.jsx)(el.Switch,{})})]}),(0,t.jsxs)("div",{className:"flex items-start justify-between gap-4",children:[(0,t.jsxs)("div",{children:[(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["Internal network only",(0,t.jsx)(g.Tooltip,{title:"When on, only requests from within your internal network are accepted. Turn off to allow external clients (other clusters, ChatGPT, etc). API key authentication is always required regardless of this setting.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),(0,t.jsx)("p",{className:"text-sm text-gray-600 mt-1",children:"Turn on to restrict access to callers within your internal network only."})]}),(0,t.jsx)(D.Form.Item,{name:"available_on_public_internet",valuePropName:"checked",getValueProps:e=>({checked:!e}),getValueFromEvent:e=>!e,initialValue:!0,className:"mb-0",children:(0,t.jsx)(el.Switch,{})})]}),i&&(0,t.jsxs)("div",{className:"flex items-start justify-between gap-4",children:[(0,t.jsxs)("div",{children:[(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["Delegate auth to upstream (PKCE passthrough)",(0,t.jsx)(g.Tooltip,{title:"When on, LiteLLM skips its own API key/SSO check for this server and lets the client complete PKCE directly with the upstream MCP server. Only honored when Auth Type is oauth2. No spend tracking or per-key rate limiting will run on this route.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),(0,t.jsx)("p",{className:"text-sm text-gray-600 mt-1",children:"Bypass LiteLLM auth so clients authenticate directly with the upstream OAuth MCP server."})]}),(0,t.jsx)(D.Form.Item,{name:"delegate_auth_to_upstream",valuePropName:"checked",initialValue:s?.delegate_auth_to_upstream??!1,className:"mb-0",children:(0,t.jsx)(el.Switch,{})})]}),d&&(0,t.jsx)(ej.Alert,{type:"warning",showIcon:!0,className:"mb-2",message:"Internal server with upstream OAuth delegation",description:"This MCP server is configured as internal-only but delegates auth to upstream. Anonymous users will be able to reach the upstream OAuth2 /authorize flow without a LiteLLM session. Ensure your upstream provider and network enforce access controls."}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["MCP Access Groups",(0,t.jsx)(g.Tooltip,{title:"Specify access groups for this MCP server. Users must be in at least one of these groups to access the server.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:"mcp_access_groups",className:"mb-4",children:(0,t.jsx)(p.Select,{mode:"tags",showSearch:!0,placeholder:"Select existing groups or type to create new ones",optionFilterProp:"value",filterOption:(e,t)=>(t?.value??"").toLowerCase().includes(e.toLowerCase()),onSearch:e=>l(e),tokenSeparators:[","],options:a(),maxTagCount:"responsive",allowClear:!0})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["Extra Headers",(0,t.jsx)(g.Tooltip,{title:"Forward custom headers from incoming requests to this MCP server (e.g., Authorization, X-Custom-Header, User-Agent)",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})}),s?.extra_headers&&s.extra_headers.length>0&&(0,t.jsxs)("span",{className:"ml-2 text-xs bg-blue-100 text-blue-700 px-2 py-1 rounded-full",children:[s.extra_headers.length," configured"]})]}),name:"extra_headers",children:(0,t.jsx)(p.Select,{mode:"tags",placeholder:s?.extra_headers&&s.extra_headers.length>0?`Currently: ${s.extra_headers.join(", ")}`:"Enter header names (e.g., Authorization, X-Custom-Header)",className:"rounded-lg",size:"large",tokenSeparators:[","],allowClear:!0})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["Static Headers",(0,t.jsx)(g.Tooltip,{title:"Send these key-value headers with every request to this MCP server.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),required:!1,children:(0,t.jsx)(D.Form.List,{name:"static_headers",children:(e,{add:s,remove:r})=>(0,t.jsxs)("div",{className:"space-y-3",children:[e.map(({key:e,name:s,...l})=>(0,t.jsxs)(eM.Space,{className:"flex w-full",align:"baseline",size:"middle",children:[(0,t.jsx)(D.Form.Item,{...l,name:[s,"header"],className:"flex-1",rules:[{required:!0,message:"Header name is required"}],children:(0,t.jsx)(H.Input,{size:"large",allowClear:!0,className:"rounded-lg",placeholder:"Header name (e.g., X-API-Key)"})}),(0,t.jsx)(D.Form.Item,{...l,name:[s,"value"],className:"flex-1",rules:[{required:!0,message:"Header value is required"}],children:(0,t.jsx)(H.Input,{size:"large",allowClear:!0,className:"rounded-lg",placeholder:"Header value"})}),(0,t.jsx)(eF.MinusCircleOutlined,{onClick:()=>r(s),className:"text-gray-500 hover:text-red-500 cursor-pointer"})]},e)),(0,t.jsx)(eb.Button,{type:"dashed",onClick:()=>s(),icon:(0,t.jsx)(eE.PlusOutlined,{}),block:!0,children:"Add Static Header"})]})})})]})},"permissions")})},ez=({accessToken:e,selectedName:s,onSelect:r})=>{let[l,a]=(0,b.useState)([]),[n,i]=(0,b.useState)(!1),[o,c]=(0,b.useState)(new Set);return((0,b.useEffect)(()=>{e&&(i(!0),(0,_.fetchOpenAPIRegistry)(e).then(e=>a(e.apis??[])).catch(()=>a([])).finally(()=>i(!1)))},[e]),n)?(0,t.jsxs)("div",{className:"mb-4",children:[(0,t.jsx)("span",{className:"text-sm font-medium text-gray-700",children:"Popular APIs"}),(0,t.jsx)("div",{className:"flex justify-center py-6",children:(0,t.jsx)(W.Spin,{size:"small"})})]}):0===l.length?null:(0,t.jsxs)("div",{className:"mb-4",children:[(0,t.jsx)("span",{className:"text-sm font-medium text-gray-700 block mb-2",children:"Popular APIs"}),(0,t.jsx)("div",{className:"grid grid-cols-5 gap-2",children:l.map(e=>{let l=s===e.name,a=o.has(e.name);return(0,t.jsxs)("button",{type:"button",title:e.description,onClick:()=>r(e),className:`flex flex-col items-center gap-1.5 p-3 rounded-lg border transition-all cursor-pointer ${l?"border-blue-500 bg-blue-50 shadow-sm":"border-gray-200 hover:border-blue-300 hover:bg-gray-50"}`,children:[a?(0,t.jsx)("span",{className:"w-7 h-7 rounded-full bg-gray-200 flex items-center justify-center text-sm font-bold text-gray-600",children:e.title.charAt(0)}):(0,t.jsx)("img",{src:e.icon_url,alt:e.title,className:"w-7 h-7 object-contain",onError:()=>{var t;return t=e.name,void c(e=>new Set(e).add(t))}}),(0,t.jsx)("span",{className:"text-xs text-gray-600 text-center leading-tight font-medium",children:e.title})]},e.name)})}),(0,t.jsx)("p",{className:"text-xs text-gray-400 mt-2",children:"Select an API to pre-fill the spec URL and OAuth 2.0 settings, or enter your own spec URL below."})]})},eU=({form:e,accessToken:s,onValuesChange:r,onKeyToolsChange:l,onLogoUrlChange:a,onOAuthDocsUrlChange:n})=>{let[i,o]=(0,b.useState)(null);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(ez,{accessToken:s,selectedName:i,onSelect:t=>{o(t.name),l?.(t.key_tools??[]),a?.(t.icon_url||void 0);let s={spec_path:t.spec_url};t.oauth?(s.auth_type=eo.AUTH_TYPE.OAUTH2,s.oauth_flow_type=eo.OAUTH_FLOW.INTERACTIVE,s.authorization_url=t.oauth.authorization_url,s.token_url=t.oauth.token_url,e.setFieldsValue(s),n?.(t.oauth.docs_url??null)):(e.resetFields(["auth_type","authorization_url","token_url"]),e.setFieldsValue(s),n?.(null)),r(s)}}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["OpenAPI Spec URL",(0,t.jsx)(g.Tooltip,{title:"URL to an OpenAPI specification (JSON or YAML). MCP tools will be automatically generated from the API endpoints defined in the spec.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:"spec_path",rules:[{required:!0,message:"Please enter an OpenAPI spec URL"}],children:(0,t.jsx)(H.Input,{placeholder:"https://petstore3.swagger.io/api/v3/openapi.json",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500",onChange:()=>{o(null),l?.([]),n?.(null)}})})]})};var eB=e.i(596239);let eq="/ui/assets/logos/",eV=[{name:"GitHub",url:`${eq}github.svg`},{name:"Slack",url:`${eq}slack.svg`},{name:"Notion",url:`${eq}notion.svg`},{name:"Linear",url:`${eq}linear.svg`},{name:"Jira",url:`${eq}jira.svg`},{name:"Figma",url:`${eq}figma.svg`},{name:"Gmail",url:`${eq}gmail.svg`},{name:"Google Drive",url:`${eq}google_drive.svg`},{name:"Stripe",url:`${eq}stripe.svg`},{name:"Shopify",url:`${eq}shopify.svg`},{name:"Salesforce",url:`${eq}salesforce.svg`},{name:"HubSpot",url:`${eq}hubspot.svg`},{name:"Twilio",url:`${eq}twilio.svg`},{name:"Cloudflare",url:`${eq}cloudflare.svg`},{name:"Sentry",url:`${eq}sentry.svg`},{name:"PostgreSQL",url:`${eq}postgresql.svg`},{name:"Snowflake",url:`${eq}snowflake.svg`},{name:"Zapier",url:`${eq}zapier.svg`},{name:"Google",url:`${eq}google.svg`},{name:"GitLab",url:`${eq}gitlab.svg`}],e$=({value:e,onChange:s})=>{let[r,l]=(0,b.useState)(new Set);return(0,t.jsxs)("div",{children:[(0,t.jsxs)("div",{className:"flex items-center gap-2 mb-2",children:[(0,t.jsx)("span",{className:"text-sm font-medium text-gray-700",children:"Logo"}),(0,t.jsx)(g.Tooltip,{title:"Select a well-known logo or paste a URL to any image. The logo is shown on the admin and chat pages.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"text-blue-400 hover:text-blue-600 cursor-help"})})]}),e&&(0,t.jsxs)("div",{className:"flex items-center gap-3 mb-3 p-3 bg-gray-50 rounded-lg border border-gray-200",children:[(0,t.jsx)("img",{src:e,alt:"Selected logo",className:"w-10 h-10 object-contain rounded",onError:e=>{e.target.style.display="none"}}),(0,t.jsx)("div",{className:"flex-1 min-w-0",children:(0,t.jsx)("div",{className:"text-xs text-gray-500 truncate",children:e})}),(0,t.jsx)("button",{type:"button",onClick:()=>s?.(void 0),className:"text-xs text-gray-400 hover:text-red-500 cursor-pointer bg-transparent border-none",children:"✕"})]}),(0,t.jsx)("div",{className:"grid grid-cols-10 gap-1.5 mb-3",children:eV.map(a=>{let n=e===a.url;return r.has(a.url)?null:(0,t.jsx)(g.Tooltip,{title:a.name,children:(0,t.jsx)("button",{type:"button",onClick:()=>{var t;return t=a.url,void s?.(e===t?void 0:t)},className:`flex items-center justify-center p-2 rounded-lg border transition-all cursor-pointer ${n?"border-blue-500 bg-blue-50 shadow-sm":"border-gray-200 hover:border-blue-300 hover:bg-gray-50"}`,style:{width:40,height:40},children:(0,t.jsx)("img",{src:a.url,alt:a.name,className:"w-5 h-5 object-contain",onError:()=>{var e;return e=a.url,void l(t=>new Set(t).add(e))}})})},a.name)})}),(0,t.jsx)(H.Input,{prefix:(0,t.jsx)(eB.LinkOutlined,{className:"text-gray-400"}),placeholder:"Or paste a custom logo URL...",value:e&&!eV.some(t=>t.url===e)?e:"",onChange:e=>{let t=e.target.value.trim();s?.(t||void 0)},className:"rounded-lg",size:"small"})]})},eD=e=>{try{let t=e.indexOf("/mcp/");if(-1===t)return{token:null,baseUrl:e};let s=e.split("/mcp/");if(2!==s.length)return{token:null,baseUrl:e};let r=s[0]+"/mcp/",l=s[1];if(!l)return{token:null,baseUrl:e};return{token:l,baseUrl:r}}catch(t){return console.error("Error parsing MCP URL:",t),{token:null,baseUrl:e}}},eH=e=>{let{token:t}=eD(e);return{maskedUrl:(e=>{let{token:t,baseUrl:s}=eD(e);return t?s+"...":e})(e),hasToken:!!t}},eK=e=>e?/^https?:\/\/[^\s/$.?#].[^\s]*$/i.test(e)?Promise.resolve():Promise.reject("Please enter a valid URL (e.g., http://service-name.domain:1234/path or https://example.com)"):Promise.resolve(),eW=e=>e&&(e.includes("-")||e.includes(" "))?Promise.reject("Cannot contain '-' (hyphen) or spaces. Please use '_' (underscore) instead."):Promise.resolve();var eJ=e.i(122520),eY=e.i(165615),eG=e.i(434166);let eQ=({accessToken:e,getCredentials:t,getTemporaryPayload:s,onTokenReceived:r,onBeforeRedirect:l})=>{let[a,n]=(0,b.useState)("idle"),[i,o]=(0,b.useState)(null),[c,d]=(0,b.useState)(null),m=(0,b.useRef)(!1),u="litellm-mcp-oauth-flow-state",x="litellm-mcp-oauth-result",h="litellm-mcp-oauth-return-url",p=(e,t)=>{(0,eG.setSecureItem)(e,t)},g=e=>{try{return(0,eG.getSecureItem)(e)}catch(t){return console.warn(`Failed to get storage item ${e}`,t),null}},f=()=>{try{window.sessionStorage.removeItem(u),window.sessionStorage.removeItem(x),window.sessionStorage.removeItem(h),window.localStorage.removeItem(u),window.localStorage.removeItem(x),window.localStorage.removeItem(h)}catch(e){console.warn("Failed to clear OAuth storage",e)}},j=()=>{let e,t,s;return s=((t=(e=window.location.pathname||"").indexOf("/ui"))>=0?e.slice(0,t+3):"").replace(/\/+$/,""),`${window.location.origin}${s}/mcp/oauth/callback`},y=(0,b.useCallback)(async()=>{let r=t()||{};if(!e){o("Missing admin token"),C.default.error("Access token missing. Please re-authenticate and try again.");return}let a=s();if(!a||!a.url||!a.transport){let e="Please complete server URL and transport before starting OAuth.";o(e),C.default.error(e);return}try{n("authorizing"),o(null);let t=await (0,_.cacheTemporaryMcpServer)(e,a),s=t?.server_id?.trim();if(!s)throw Error("Temporary MCP server identifier missing. Please retry.");let i={};if(!(a.credentials?.client_id&&a.credentials?.client_secret)){let t=await (0,_.registerMcpOAuthClient)(e,s,{client_name:a.alias||a.server_name||s,grant_types:["authorization_code","refresh_token"],response_types:["code"],token_endpoint_auth_method:a.credentials&&a.credentials.client_secret?"client_secret_post":"none"});i={clientId:t?.client_id,clientSecret:t?.client_secret}}let c=(0,eY.generateCodeVerifier)(),d=await (0,eY.generateCodeChallenge)(c),m=crypto.randomUUID(),x=i.clientId||r.client_id,g=Array.isArray(r.scopes)?r.scopes.filter(e=>e&&e.trim().length>0).join(" "):void 0,f=(0,_.buildMcpOAuthAuthorizeUrl)({serverId:s,clientId:x,redirectUri:j(),state:m,codeChallenge:d,scope:g}),b={state:m,codeVerifier:c,clientId:x,clientSecret:i.clientSecret||r.client_secret,serverId:s,redirectUri:j()};if(l)try{l()}catch(e){console.error("Failed to prepare for OAuth redirect",e)}try{p(u,JSON.stringify(b)),p(h,window.location.href)}catch(e){throw Error("Unable to access browser storage for OAuth. Please enable storage and retry.")}window.location.href=f}catch(t){console.error("Failed to start OAuth flow",t),n("error");let e=(0,eJ.extractErrorMessage)(t);o(e),C.default.error(e)}},[e,t,s,l]),v=(0,b.useCallback)(async()=>{if(m.current)return;let t=null,s=null;try{let e=g(x);if(!e)return;m.current=!0,t=JSON.parse(e);let r=g(u);s=r?JSON.parse(r):null}catch(e){f(),m.current=!1,o("Failed to resume OAuth flow. Please retry."),n("error"),C.default.error("Failed to resume OAuth flow. Please retry.");return}if(!t){m.current=!1;return}try{window.sessionStorage.removeItem(x),window.localStorage.removeItem(x)}catch(e){}try{if(!s||!s.state||!s.codeVerifier||!s.serverId)throw Error("OAuth session state was lost. This can happen if you have strict browser privacy settings. Please try again and ensure cookies/storage is enabled.");if(!t.state||t.state!==s.state)throw Error("OAuth state mismatch. Please retry.");if(t.error)throw Error(t.error_description||t.error);if(!t.code)throw Error("Authorization code missing in callback.");n("exchanging");let l=await (0,_.exchangeMcpOAuthToken)({serverId:s.serverId,code:t.code,clientId:s.clientId,clientSecret:s.clientSecret,codeVerifier:s.codeVerifier,redirectUri:s.redirectUri,accessToken:e});r(l),d(l),n("success"),o(null),C.default.success("OAuth token retrieved successfully")}catch(t){let e=(0,eJ.extractErrorMessage)(t);o(e),n("error"),C.default.error(e)}finally{f(),setTimeout(()=>{m.current=!1},1e3)}},[r]);return(0,b.useEffect)(()=>{v()},[v]),{startOAuthFlow:y,status:a,error:i,tokenResponse:c}},eZ="../ui/assets/logos/mcp_logo.png",eX=[eo.AUTH_TYPE.API_KEY,eo.AUTH_TYPE.BEARER_TOKEN,eo.AUTH_TYPE.TOKEN,eo.AUTH_TYPE.BASIC],e0=[...eX,eo.AUTH_TYPE.OAUTH2,eo.AUTH_TYPE.AWS_SIGV4],e2="litellm-mcp-oauth-create-state",e1=e=>Array.isArray(e)?e.reduce((e,t)=>{let s=t?.header?.trim();return s&&(e[s]=t?.value??""),e},{}):{},e5=({userRole:e,accessToken:r,onCreateSuccess:a,isModalVisible:n,setModalVisible:i,availableAccessGroups:o,prefillData:c,onBackToDiscovery:d})=>{let[m]=D.Form.useForm(),[u,x]=(0,b.useState)(!1),[f,j]=(0,b.useState)({}),[y,v]=(0,b.useState)({}),[N,w]=(0,b.useState)(null),[S,T]=(0,b.useState)(!1),[k,A]=(0,b.useState)([]),[I,P]=(0,b.useState)({}),[O,M]=(0,b.useState)({}),[F,E]=(0,b.useState)(""),[L,R]=(0,b.useState)([]),[z,U]=(0,b.useState)(""),[B,q]=(0,b.useState)(null),[V,$]=(0,b.useState)(void 0),[K,W]=(0,b.useState)(null),{tools:J,isLoadingTools:Y,toolsError:G,toolsErrorStackTrace:Q,canFetchTools:Z,fetchTools:X,clearTools:ee}=ek({accessToken:r,oauthAccessToken:B,formValues:y,enabled:!0}),et=y.auth_type,es=!!et&&eX.includes(et),er=et===eo.AUTH_TYPE.OAUTH2,ec=et===eo.AUTH_TYPE.AWS_SIGV4,ed=er&&y.oauth_flow_type===eo.OAUTH_FLOW.M2M,{startOAuthFlow:em,status:ex,error:eh,tokenResponse:ep}=eQ({accessToken:r,getCredentials:()=>m.getFieldValue("credentials"),getTemporaryPayload:()=>{let e=m.getFieldsValue(!0),t=e.transport||F,s=e.url||(t===eo.TRANSPORT.OPENAPI?e.spec_path:void 0);if(!s||!t)return null;let r=e1(e.static_headers);return{server_id:void 0,server_name:e.server_name,alias:e.alias,description:e.description,url:s,transport:t===eo.TRANSPORT.OPENAPI?"http":t,auth_type:eo.AUTH_TYPE.OAUTH2,credentials:e.credentials,authorization_url:e.authorization_url,token_url:e.token_url,registration_url:e.registration_url,mcp_access_groups:e.mcp_access_groups,static_headers:r,command:e.command,args:e.args,env:e.env}},onTokenReceived:e=>{if(q(e?.access_token??null),e?.access_token){let t={access_token:e.access_token,...e.refresh_token&&{refresh_token:e.refresh_token},...e.expires_in&&{expires_in:e.expires_in},...e.scope&&{scope:e.scope}};m.setFieldsValue({credentials:t}),C.default.success("OAuth authorization successful! Please click 'Create MCP Server' to save the configuration.")}},onBeforeRedirect:()=>{try{let e=m.getFieldsValue(!0);(0,eG.setSecureItem)(e2,JSON.stringify({modalVisible:n,formValues:e,transportType:F,costConfig:f,allowedTools:k,searchValue:z,aliasManuallyEdited:S,logoUrl:V}))}catch(e){console.warn("Failed to persist MCP create state",e)}}});b.default.useEffect(()=>{let e=(0,eG.getSecureItem)(e2);if(e)try{let t=JSON.parse(e);t.modalVisible&&i(!0);let s=t.formValues?.transport||t.transportType||"";s&&E(s),t.formValues&&w({values:t.formValues,transport:s}),t.costConfig&&j(t.costConfig),t.allowedTools&&A(t.allowedTools),t.searchValue&&U(t.searchValue),"boolean"==typeof t.aliasManuallyEdited&&T(t.aliasManuallyEdited),t.logoUrl&&$(t.logoUrl)}catch(e){console.error("Failed to restore MCP create state",e)}finally{window.sessionStorage.removeItem(e2)}},[m,i]),b.default.useEffect(()=>{N&&(F||N.transport,(!N.transport||F)&&(m.setFieldsValue(N.values),v(N.values),w(null)))},[N,m,F]),b.default.useEffect(()=>{if(!n||!c)return;let e=(c.name||"").replace(/[^a-zA-Z0-9_]/g,"_").replace(/_+/g,"_").replace(/^_|_$/g,""),t=c.transport||"";E(t);let s={server_name:e,alias:e,description:c.description||"",transport:t};if("stdio"===t){let e={};if(c.command&&(e.command=c.command),c.args&&c.args.length>0&&(e.args=c.args),c.env_vars&&c.env_vars.length>0){let t={};for(let e of c.env_vars)t[e.name]=e.description?`<${e.description}>`:"";e.env=t}Object.keys(e).length>0&&(s.stdio_config=JSON.stringify(e,null,2))}else c.url&&(s.url=c.url);m.setFieldsValue(s),v(s),T(!1)},[n,c,m]);let eg=async e=>{x(!0);try{let{static_headers:t,stdio_config:s,credentials:l,allow_all_keys:n,available_on_public_internet:o,delegate_auth_to_upstream:c,token_validation_json:d,...u}=e,h=u.mcp_access_groups,p=e1(t),g=l&&"object"==typeof l?Object.entries(l).reduce((e,[t,s])=>{if(null==s||""===s)return e;if("scopes"===t){if(Array.isArray(s)){let r=s.filter(e=>null!=e&&""!==e);r.length>0&&(e[t]=r)}}else e[t]=s;return e},{}):void 0,b={};if(s&&"stdio"===F)try{let e=JSON.parse(s),t=e;if(e.mcpServers&&"object"==typeof e.mcpServers){let s=Object.keys(e.mcpServers);if(s.length>0){let r=s[0];t=e.mcpServers[r],u.server_name||(u.server_name=r.replace(/-/g,"_"))}}b={command:t.command,args:t.args,env:t.env},console.log("Parsed stdio config:",b)}catch(e){C.default.fromBackend("Invalid JSON in stdio configuration");return}u.transport===eo.TRANSPORT.OPENAPI&&(u.transport="http");let y=null;if(d&&""!==d.trim())try{y=JSON.parse(d)}catch{C.default.fromBackend("Invalid JSON in Token Validation Rules"),x(!1);return}let v={...u,...b,stdio_config:void 0,mcp_info:{server_name:u.server_name||u.url,description:u.description,logo_url:V||void 0,mcp_server_cost_info:Object.keys(f).length>0?f:null},mcp_access_groups:h,alias:u.alias,allowed_tools:k.length>0?k:null,tool_name_to_display_name:Object.keys(I).length>0?I:null,tool_name_to_description:Object.keys(O).length>0?O:null,allow_all_keys:!!n,available_on_public_internet:!!o,delegate_auth_to_upstream:!!c,static_headers:p,...null!==y&&{token_validation:y}};if(v.static_headers=p,u.auth_type&&e0.includes(u.auth_type)&&g&&Object.keys(g).length>0&&(v.credentials=g),console.log(`Payload: ${JSON.stringify(v)}`),null!=r){let e=ej?await (0,_.createMCPServer)(r,v):await (0,_.registerMCPServer)(r,v);C.default.success(ej?"MCP Server created successfully":"MCP Server submitted for admin review"),m.resetFields(),j({}),ee(),A([]),T(!1),$(void 0),i(!1),a(e)}}catch(t){let e=t instanceof Error?t.message:String(t);C.default.fromBackend(ej?`Error creating MCP Server: ${e}`:`Error submitting MCP Server: ${e}`)}finally{x(!1)}},eb=()=>{m.resetFields(),j({}),ee(),A([]),T(!1),$(void 0),i(!1)};b.default.useEffect(()=>{if(!S&&y.server_name){let e=y.server_name.replace(/\s+/g,"_");m.setFieldsValue({alias:e}),v(t=>({...t,alias:e}))}},[y.server_name]),b.default.useEffect(()=>{n||v({})},[n]);let ej=(0,s.isAdminRole)(e);return(0,t.jsx)(h.Modal,{title:(0,t.jsxs)("div",{className:"flex items-center pb-4 border-b border-gray-100",style:{gap:12},children:[d&&(0,t.jsx)("button",{onClick:d,className:"text-sm text-blue-600 hover:text-blue-800 cursor-pointer bg-transparent border-none",style:{flexShrink:0},children:"←"}),(0,t.jsx)("img",{src:eZ,alt:"MCP Logo",className:"w-8 h-8 object-contain",style:{height:"20px",width:"20px",objectFit:"contain"}}),(0,t.jsx)("h2",{className:"text-xl font-semibold text-gray-900",children:ej?"Add New MCP Server":"Submit MCP Server for Review"})]}),open:n,width:1e3,onCancel:eb,footer:null,forceRender:!0,className:"top-8",styles:{body:{padding:"24px"},header:{padding:"24px 24px 0 24px",border:"none"}},children:(0,t.jsx)("div",{className:"mt-6",children:(0,t.jsxs)(D.Form,{form:m,onFinish:eg,onValuesChange:(e,t)=>v(t),layout:"vertical",className:"space-y-6",children:[!ej&&(0,t.jsxs)("div",{className:"rounded-md bg-blue-50 border border-blue-200 px-4 py-3 text-sm text-blue-800",children:["Your submission will be sent for admin review before it becomes active."," ","Note: the request must be made with a team-scoped API key."]}),(0,t.jsxs)("div",{className:"grid grid-cols-1 gap-6",children:[(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["MCP Server Name",(0,t.jsx)(g.Tooltip,{title:"Best practice: Use a descriptive name that indicates the server's purpose (e.g., 'GitHub_MCP', 'Email_Service'). Cannot contain spaces or hyphens; use underscores instead. Names must comply with SEP-986 and will be rejected if invalid (https://modelcontextprotocol.io/specification/2025-11-25/server/tools#tool-names).",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:"server_name",rules:[{required:!1,message:"Please enter a server name"},{validator:(e,t)=>eW(t)}],children:(0,t.jsx)(ei.TextInput,{placeholder:"e.g., GitHub_MCP, Zapier_MCP, etc.",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["Alias",(0,t.jsx)(g.Tooltip,{title:"A short, unique identifier for this server. Defaults to the server name if not provided. Cannot contain spaces or hyphens; use underscores instead.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:"alias",rules:[{required:!1},{validator:(e,t)=>eW(t)}],children:(0,t.jsx)(ei.TextInput,{placeholder:"e.g., GitHub_MCP, Zapier_MCP, etc.",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500",onChange:()=>T(!0)})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsx)("span",{className:"text-sm font-medium text-gray-700",children:"Description"}),name:"description",rules:[{required:!1,message:"Please enter a server description"}],children:(0,t.jsx)(ei.TextInput,{placeholder:"Brief description of what this server does",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(e$,{value:V,onChange:$}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsx)("span",{className:"text-sm font-medium text-gray-700",children:"GitHub / Source URL"}),name:"source_url",children:(0,t.jsx)(ei.TextInput,{placeholder:"https://github.com/org/mcp-server",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsx)("span",{className:"text-sm font-medium text-gray-700",children:"Transport Type"}),name:"transport",rules:[{required:!0,message:"Please select a transport type"}],children:(0,t.jsxs)(p.Select,{placeholder:"Select transport",className:"rounded-lg",size:"large",onChange:e=>{E(e),"stdio"===e?m.setFieldsValue({url:void 0,spec_path:void 0,auth_type:void 0,credentials:void 0}):e===eo.TRANSPORT.OPENAPI?m.setFieldsValue({url:void 0,command:void 0,args:void 0,env:void 0}):m.setFieldsValue({spec_path:void 0,command:void 0,args:void 0,env:void 0})},value:F,children:[(0,t.jsx)(p.Select.Option,{value:"http",children:"Streamable HTTP (Recommended)"}),(0,t.jsx)(p.Select.Option,{value:"sse",children:"Server-Sent Events (SSE)"}),(0,t.jsx)(p.Select.Option,{value:"stdio",children:"Standard Input/Output (stdio)"}),(0,t.jsx)(p.Select.Option,{value:eo.TRANSPORT.OPENAPI,children:"OpenAPI Spec"})]})}),("http"===F||"sse"===F)&&(0,t.jsx)(D.Form.Item,{label:(0,t.jsx)("span",{className:"text-sm font-medium text-gray-700",children:"MCP Server URL"}),name:"url",rules:[{required:!0,message:"Please enter a server URL"},{validator:(e,t)=>eK(t)}],children:(0,t.jsx)(H.Input,{placeholder:"https://your-mcp-server.com",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),F===eo.TRANSPORT.OPENAPI&&(0,t.jsx)(eU,{form:m,accessToken:n?r:null,onValuesChange:e=>v(t=>({...t,...e})),onKeyToolsChange:R,onLogoUrlChange:$,onOAuthDocsUrlChange:W}),F===eo.TRANSPORT.OPENAPI&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center gap-2",children:["BYOK (Bring Your Own Key)",(0,t.jsx)(g.Tooltip,{title:"When enabled, each user provides their own API key for this service. Keys are stored per-user and never shared.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:"is_byok",valuePropName:"checked",children:(0,t.jsx)(el.Switch,{})}),(0,t.jsx)(D.Form.Item,{noStyle:!0,shouldUpdate:(e,t)=>e.is_byok!==t.is_byok||e.auth_type!==t.auth_type,children:({getFieldValue:e})=>e("is_byok")?(0,t.jsxs)(t.Fragment,{children:[e("auth_type")&&"none"!==e("auth_type")&&(0,t.jsxs)("div",{className:"mb-4 p-3 bg-blue-50 rounded-lg text-sm text-blue-700 flex items-start gap-2",children:[(0,t.jsx)(en.InfoCircleOutlined,{className:"mt-0.5 flex-shrink-0"}),(0,t.jsxs)("span",{children:["User keys will be sent as:"," ",(0,t.jsxs)("code",{className:"font-mono bg-blue-100 px-1 rounded",children:["bearer_token"===e("auth_type")&&"Authorization: Bearer {key}","token"===e("auth_type")&&"Authorization: token {key}","api_key"===e("auth_type")&&"x-api-key: {key}","basic"===e("auth_type")&&"Authorization: Basic {key}","authorization"===e("auth_type")&&"Authorization: {key}"]}),!e("auth_type")&&"Set Authentication Type below to specify the format."]})]}),!e("auth_type")&&(0,t.jsxs)("div",{className:"mb-4 p-3 bg-yellow-50 rounded-lg text-sm text-yellow-700 flex items-start gap-2",children:[(0,t.jsx)(en.InfoCircleOutlined,{className:"mt-0.5 flex-shrink-0"}),(0,t.jsxs)("span",{children:["Set the ",(0,t.jsx)("strong",{children:"Authentication Type"})," below to specify how user keys are sent (e.g., Bearer Token, API Key header)."]})]}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700",children:["Access Description",(0,t.jsx)(g.Tooltip,{title:"List of permissions shown to users in the connection modal (e.g. 'Create and manage Jira issues')",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:"byok_description",children:(0,t.jsx)(p.Select,{mode:"tags",placeholder:"Add access description items (press Enter after each)",className:"w-full",tokenSeparators:[","]})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700",children:["API Key Help URL",(0,t.jsx)(g.Tooltip,{title:"Optional link shown to users to help them find their API key",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:"byok_api_key_help_url",children:(0,t.jsx)(H.Input,{placeholder:"https://docs.example.com/api-keys"})})]}):null})]}),"stdio"!==F&&""!==F&&(0,t.jsx)(ea.Collapse,{defaultActiveKey:["auth"],className:"mb-4",items:[{key:"auth",label:(0,t.jsx)("span",{className:"text-sm font-semibold text-gray-700",children:"Authentication"}),children:(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(D.Form.Item,{name:"auth_type",rules:[{required:!0,message:"Please select an auth type"}],children:(0,t.jsxs)(p.Select,{placeholder:"Select auth type",className:"rounded-lg",size:"large",children:[(0,t.jsx)(p.Select.Option,{value:"none",children:"None"}),(0,t.jsx)(p.Select.Option,{value:"api_key",children:"API Key"}),(0,t.jsx)(p.Select.Option,{value:"bearer_token",children:"Bearer Token"}),(0,t.jsx)(p.Select.Option,{value:"token",children:"Token"}),(0,t.jsx)(p.Select.Option,{value:"basic",children:"Basic Auth"}),(0,t.jsx)(p.Select.Option,{value:"oauth2",children:"OAuth"}),(0,t.jsx)(p.Select.Option,{value:"aws_sigv4",children:"AWS SigV4 (Bedrock AgentCore MCPs)"})]})}),es&&(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["Authentication Value",(0,t.jsx)(g.Tooltip,{title:"Token, password, or header value to send with each request for the selected auth type.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","auth_value"],rules:[{validator:(e,t)=>t&&"string"==typeof t&&""===t.trim()?Promise.reject(Error("Authentication value cannot be empty whitespace")):Promise.resolve()}],children:(0,t.jsx)(ei.TextInput,{type:"password",placeholder:"Enter token or secret",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),er&&(0,t.jsx)(eu,{isM2M:ed,initialFlowType:eo.OAUTH_FLOW.INTERACTIVE,docsUrl:K,oauthFlow:{startOAuthFlow:em,status:ex,error:eh,tokenResponse:ep}})]})}]}),"stdio"!==F&&""!==F&&ec&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("p",{className:"text-sm text-gray-500 mb-2",children:["For MCP servers hosted on AWS Bedrock AgentCore."," ",(0,t.jsx)("a",{href:"https://docs.litellm.ai/docs/mcp_aws_sigv4",target:"_blank",rel:"noopener noreferrer",className:"text-blue-500 hover:text-blue-700",children:"View docs →"})]}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["AWS Region",(0,t.jsx)(g.Tooltip,{title:"AWS region for SigV4 signing (e.g., us-east-1)",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","aws_region_name"],rules:[{required:!0,message:"AWS region is required for SigV4 auth"}],children:(0,t.jsx)(H.Input,{placeholder:"us-east-1",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["AWS Service Name",(0,t.jsx)(g.Tooltip,{title:"AWS service name for SigV4 signing. Defaults to 'bedrock-agentcore'.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","aws_service_name"],children:(0,t.jsx)(H.Input,{placeholder:"bedrock-agentcore",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["AWS Access Key ID",(0,t.jsx)(g.Tooltip,{title:"Optional. If not provided, falls back to the boto3 credential chain (IAM role, env vars, etc.).",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","aws_access_key_id"],dependencies:[["credentials","aws_secret_access_key"]],rules:[({getFieldValue:e})=>({validator:(t,s)=>e(["credentials","aws_secret_access_key"])&&!s?Promise.reject(Error("Access Key ID is required when Secret Access Key is provided")):Promise.resolve()})],children:(0,t.jsx)(H.Input.Password,{placeholder:"AKIA... (optional — uses IAM role if blank)",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["AWS Secret Access Key",(0,t.jsx)(g.Tooltip,{title:"Optional. Required if AWS Access Key ID is provided.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","aws_secret_access_key"],dependencies:[["credentials","aws_access_key_id"]],rules:[({getFieldValue:e})=>({validator:(t,s)=>e(["credentials","aws_access_key_id"])&&!s?Promise.reject(Error("Secret Access Key is required when Access Key ID is provided")):Promise.resolve()})],children:(0,t.jsx)(H.Input.Password,{placeholder:"Enter secret key (optional — uses IAM role if blank)",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["AWS Session Token",(0,t.jsx)(g.Tooltip,{title:"Optional. Only needed for temporary STS credentials.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","aws_session_token"],children:(0,t.jsx)(H.Input.Password,{placeholder:"Enter session token (optional)",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["AWS Role ARN",(0,t.jsx)(g.Tooltip,{title:"Optional. IAM role ARN to assume via STS before signing. If set, LiteLLM calls sts:AssumeRole to get temporary credentials. Uses ambient credentials (IAM role, env vars) as the source identity unless explicit keys are also provided.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","aws_role_name"],children:(0,t.jsx)(H.Input,{placeholder:"arn:aws:iam::123456789012:role/MyRole (optional)",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["AWS Session Name",(0,t.jsx)(g.Tooltip,{title:"Optional. Session name for the AssumeRole call — appears in CloudTrail logs. Auto-generated if omitted.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","aws_session_name"],children:(0,t.jsx)(H.Input,{placeholder:"litellm-prod (optional, auto-generated if blank)",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})})]}),(0,t.jsx)(eO,{isVisible:"stdio"===F})]}),(0,t.jsx)("div",{className:"mt-8",children:(0,t.jsx)(eR,{availableAccessGroups:o,mcpServer:null,searchValue:z,setSearchValue:U,getAccessGroupOptions:()=>{let e=o.map(e=>({value:e,label:(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("div",{className:"w-2 h-2 bg-green-500 rounded-full"}),(0,t.jsx)("span",{className:"font-medium",children:e})]})}));return z&&!o.some(e=>e.toLowerCase().includes(z.toLowerCase()))&&e.push({value:z,label:(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("div",{className:"w-2 h-2 bg-blue-500 rounded-full"}),(0,t.jsx)("span",{className:"font-medium",children:z}),(0,t.jsx)("span",{className:"text-gray-400 text-xs ml-1",children:"create new group"})]})}),e}})}),(0,t.jsx)("div",{className:"mt-8 pt-6 border-t border-gray-200",children:(0,t.jsx)(e_,{formValues:y,tools:J,isLoadingTools:Y,toolsError:G,toolsErrorStackTrace:Q,canFetchTools:Z,fetchTools:X})}),(0,t.jsx)("div",{className:"mt-6",children:(0,t.jsx)(eP,{accessToken:r,oauthAccessToken:B,formValues:y,allowedTools:k,existingAllowedTools:null,onAllowedToolsChange:A,toolNameToDisplayName:I,toolNameToDescription:O,onToolNameToDisplayNameChange:P,onToolNameToDescriptionChange:M,keyTools:L,externalTools:J,externalIsLoading:Y,externalError:G,externalCanFetch:Z})}),(0,t.jsx)("div",{className:"mt-6",children:(0,t.jsx)(ef,{value:f,onChange:j,tools:J.filter(e=>k.includes(e.name)),disabled:!1})}),(0,t.jsxs)("div",{className:"flex items-center justify-end space-x-3 pt-6 border-t border-gray-100",children:[(0,t.jsx)(l.Button,{variant:"secondary",onClick:eb,children:"Cancel"}),(0,t.jsx)(l.Button,{variant:"primary",loading:u,children:u?"Creating...":"Add MCP Server"})]})]})})})};var e4=e.i(175712),e6=e.i(118366),e3=e.i(475254);let e7=(0,e3.default)("code",[["path",{d:"m16 18 6-6-6-6",key:"eg8j8"}],["path",{d:"m8 6-6 6 6 6",key:"ppft3o"}]]);e.s(["Code",()=>e7],758472);let e8=(0,e3.default)("terminal",[["path",{d:"M12 19h8",key:"baeox8"}],["path",{d:"m4 17 6-6-6-6",key:"1yngyt"}]]),e9=(0,e3.default)("globe",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20",key:"13o1zl"}],["path",{d:"M2 12h20",key:"9i4pu4"}]]);var te=e.i(634831),tt=e.i(438100);let ts=(0,e3.default)("zap",[["path",{d:"M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z",key:"1xq2db"}]]);var tr=e.i(500330);let{Title:tl,Text:ta}=f.Typography,{Panel:tn}=ea.Collapse,ti=({icon:e,title:s,description:r,children:l,serverName:a,accessGroups:n=["dev-group"]})=>{let[i,o]=(0,b.useState)(!1);return(0,t.jsxs)(e4.Card,{className:"border border-gray-200",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3 mb-3",children:[(0,t.jsx)("span",{className:"p-2 rounded-lg bg-gray-50",children:e}),(0,t.jsxs)("div",{children:[(0,t.jsx)(tl,{level:5,className:"mb-0",children:s}),(0,t.jsx)(ta,{className:"text-gray-600",children:r})]})]}),a&&("Implementation Example"===s||"Configuration"===s)&&(0,t.jsxs)(D.Form.Item,{className:"mb-4",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2 mb-2",children:[(0,t.jsx)(el.Switch,{size:"small",checked:i,onChange:o}),(0,t.jsxs)(ta,{className:"text-sm",children:["Limit tools to specific MCP servers or MCP groups by passing the ",(0,t.jsx)("code",{children:"x-mcp-servers"})," header"]})]}),i&&(0,t.jsx)(ej.Alert,{className:"mt-2",type:"info",showIcon:!0,message:"Two Options",description:(0,t.jsxs)("div",{children:[(0,t.jsxs)("p",{children:[(0,t.jsx)("strong",{children:"Option 1:"})," Get a specific server: ",(0,t.jsxs)("code",{children:['"',a.replace(/\s+/g,"_"),'"']})]}),(0,t.jsxs)("p",{children:[(0,t.jsx)("strong",{children:"Option 2:"})," Get a group of MCPs: ",(0,t.jsx)("code",{children:'"dev-group"'})]}),(0,t.jsxs)("p",{className:"mt-2 text-sm text-gray-600",children:["You can also mix both: ",(0,t.jsx)("code",{children:'"Server1,dev-group"'})]})]})})]}),b.default.Children.map(l,e=>{if(b.default.isValidElement(e)&&e.props.hasOwnProperty("code")&&e.props.hasOwnProperty("copyKey")){let t=e.props.code;if(t&&t.includes('"headers":'))return b.default.cloneElement(e,{code:t.replace(/"headers":\s*{[^}]*}/,`"headers": ${JSON.stringify((()=>{let e={"x-litellm-api-key":"Bearer YOUR_LITELLM_API_KEY"};if(i&&a){let t=[a.replace(/\s+/g,"_"),...n].join(",");e["x-mcp-servers"]=t}return e})(),null,8)}`)})}return e})]})},to=({currentServerAccessGroups:e=[]})=>{let s=(0,_.getProxyBaseUrl)(),[r,l]=(0,b.useState)({}),[u,x]=(0,b.useState)({openai:[],litellm:[],cursor:[],http:[]}),[h]=(0,b.useState)("Zapier_MCP"),p=async(e,t)=>{await (0,tr.copyToClipboard)(e)&&(l(e=>({...e,[t]:!0})),setTimeout(()=>{l(e=>({...e,[t]:!1}))},2e3))},g=({code:e,copyKey:s,title:l,className:a=""})=>(0,t.jsxs)("div",{className:"relative group",children:[l&&(0,t.jsxs)("div",{className:"flex items-center gap-2 mb-2",children:[(0,t.jsx)(e7,{size:16,className:"text-blue-600"}),(0,t.jsx)(ta,{strong:!0,className:"text-gray-700",children:l})]}),(0,t.jsxs)(e4.Card,{className:`bg-gray-50 border border-gray-200 relative ${a}`,children:[(0,t.jsx)(eb.Button,{type:"text",size:"small",icon:r[s]?(0,t.jsx)(k.CheckIcon,{size:12}):(0,t.jsx)(e6.CopyIcon,{size:12}),onClick:()=>p(e,s),className:`absolute top-2 right-2 z-10 transition-all duration-200 ${r[s]?"text-green-600 bg-green-50 border-green-200":"text-gray-500 hover:text-gray-700 hover:bg-gray-100"}`}),(0,t.jsx)("pre",{className:"text-sm overflow-x-auto pr-10 text-gray-800 font-mono leading-relaxed",children:e})]})]}),f=({step:e,title:s,children:r})=>(0,t.jsxs)("div",{className:"flex gap-4",children:[(0,t.jsx)("div",{className:"flex-shrink-0",children:(0,t.jsx)("div",{className:"w-8 h-8 bg-blue-600 text-white rounded-full flex items-center justify-center text-sm font-semibold",children:e})}),(0,t.jsxs)("div",{className:"flex-1",children:[(0,t.jsx)(ta,{strong:!0,className:"text-gray-800 block mb-2",children:s}),r]})]});return(0,t.jsx)("div",{children:(0,t.jsxs)(eM.Space,{direction:"vertical",size:"large",className:"w-full",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)(m.Title,{className:"text-3xl font-bold text-gray-900 mb-3",children:"Connect to your MCP client"}),(0,t.jsx)(d.Text,{className:"text-lg text-gray-600",children:"Use tools directly from any MCP client with LiteLLM MCP. Enable your AI assistant to perform real-world tasks through a simple, secure connection."})]}),(0,t.jsxs)(n.TabGroup,{className:"w-full",children:[(0,t.jsx)(i.TabList,{className:"flex justify-start mt-8 mb-6",children:(0,t.jsxs)("div",{className:"flex bg-gray-100 p-1 rounded-lg",children:[(0,t.jsx)(a.Tab,{className:"px-6 py-3 rounded-md transition-all duration-200",children:(0,t.jsxs)("span",{className:"flex items-center gap-2 font-medium",children:[(0,t.jsx)(e7,{size:18}),"OpenAI API"]})}),(0,t.jsx)(a.Tab,{className:"px-6 py-3 rounded-md transition-all duration-200",children:(0,t.jsxs)("span",{className:"flex items-center gap-2 font-medium",children:[(0,t.jsx)(ts,{size:18}),"LiteLLM Proxy"]})}),(0,t.jsx)(a.Tab,{className:"px-6 py-3 rounded-md transition-all duration-200",children:(0,t.jsxs)("span",{className:"flex items-center gap-2 font-medium",children:[(0,t.jsx)(e8,{size:18}),"Cursor"]})}),(0,t.jsx)(a.Tab,{className:"px-6 py-3 rounded-md transition-all duration-200",children:(0,t.jsxs)("span",{className:"flex items-center gap-2 font-medium",children:[(0,t.jsx)(e9,{size:18}),"Streamable HTTP"]})})]})}),(0,t.jsxs)(c.TabPanels,{children:[(0,t.jsx)(o.TabPanel,{className:"mt-6",children:(0,t.jsx)(()=>(0,t.jsxs)(eM.Space,{direction:"vertical",size:"large",className:"w-full",children:[(0,t.jsxs)("div",{className:"bg-gradient-to-r from-blue-50 to-indigo-50 p-6 rounded-lg border border-blue-100",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3 mb-3",children:[(0,t.jsx)(e7,{className:"text-blue-600",size:24}),(0,t.jsx)(tl,{level:4,className:"mb-0 text-blue-900",children:"OpenAI Responses API Integration"})]}),(0,t.jsx)(ta,{className:"text-blue-700",children:"Connect OpenAI Responses API to your LiteLLM MCP server for seamless tool integration"})]}),(0,t.jsxs)(eM.Space,{direction:"vertical",size:"large",className:"w-full",children:[(0,t.jsx)(ti,{icon:(0,t.jsx)(tt.KeyIcon,{className:"text-blue-600",size:16}),title:"API Key Setup",description:"Configure your OpenAI API key for authentication",children:(0,t.jsxs)(eM.Space,{direction:"vertical",size:"middle",className:"w-full",children:[(0,t.jsx)("div",{children:(0,t.jsxs)(ta,{children:["Get your API key from the"," ",(0,t.jsxs)("a",{href:"https://platform.openai.com/api-keys",target:"_blank",rel:"noopener noreferrer",className:"text-blue-600 hover:text-blue-700 inline-flex items-center gap-1",children:["OpenAI platform ",(0,t.jsx)(te.ExternalLinkIcon,{size:12})]})]})}),(0,t.jsx)(g,{title:"Environment Variable",code:'export OPENAI_API_KEY="sk-..."',copyKey:"openai-env"})]})}),(0,t.jsx)(ti,{icon:(0,t.jsx)(P.ServerIcon,{className:"text-blue-600",size:16}),title:"MCP Server Information",description:"Connection details for your LiteLLM MCP server",children:(0,t.jsx)(g,{title:"Server URL",code:`${s}/mcp`,copyKey:"openai-server-url"})}),(0,t.jsx)(ti,{icon:(0,t.jsx)(e7,{className:"text-blue-600",size:16}),title:"Implementation Example",description:"Complete cURL example for using the Responses API",serverName:"Zapier Gmail",accessGroups:["dev-group"],children:(0,t.jsx)(g,{code:`curl --location 'https://api.openai.com/v1/responses' \\ ->>>>>>>> origin/litellm_internal_staging:litellm/proxy/_experimental/out/_next/static/chunks/e1a670efcb966aaa.js --header 'Content-Type: application/json' \\ --header "Authorization: Bearer $OPENAI_API_KEY" \\ --data '{ @@ -80,15 +66,9 @@ } } } -<<<<<<<< HEAD:litellm/proxy/_experimental/out/_next/static/chunks/0279e5299e9f6e98.js -}`,copyKey:"cursor-config",className:"text-xs"})})]})]})]})]}),{})}),(0,t.jsx)(o.TabPanel,{className:"mt-6",children:(0,t.jsx)(()=>(0,t.jsxs)(eM.Space,{direction:"vertical",size:"large",className:"w-full",children:[(0,t.jsxs)("div",{className:"bg-gradient-to-r from-green-50 to-teal-50 p-6 rounded-lg border border-green-100",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3 mb-3",children:[(0,t.jsx)(e9,{className:"text-green-600",size:24}),(0,t.jsx)(tl,{level:4,className:"mb-0 text-green-900",children:"Streamable HTTP Transport"})]}),(0,t.jsx)(ta,{className:"text-green-700",children:"Connect to LiteLLM MCP using HTTP transport. Compatible with any MCP client that supports HTTP streaming."})]}),(0,t.jsx)(ti,{icon:(0,t.jsx)(e9,{className:"text-green-600",size:16}),title:"Universal MCP Connection",description:"Use this URL with any MCP client that supports HTTP transport",children:(0,t.jsxs)(eM.Space,{direction:"vertical",size:"middle",className:"w-full",children:[(0,t.jsx)("div",{children:(0,t.jsx)(ta,{children:"Each MCP client supports different transports. Refer to your client documentation to determine the appropriate transport method."})}),(0,t.jsx)(g,{title:"Server URL",code:`${s}/mcp`,copyKey:"http-server-url"}),(0,t.jsx)(g,{title:"Headers Configuration",code:JSON.stringify({"x-litellm-api-key":"Bearer YOUR_LITELLM_API_KEY"},null,2),copyKey:"http-headers"}),(0,t.jsx)("div",{className:"mt-4",children:(0,t.jsx)(eb.Button,{type:"link",className:"p-0 h-auto text-blue-600 hover:text-blue-700",href:"https://modelcontextprotocol.io/docs/concepts/transports",icon:(0,t.jsx)(te.ExternalLinkIcon,{size:14}),children:"Learn more about MCP transports"})})]})})]}),{})})]})]})]})})};var tc=e.i(752978),td=e.i(591935),tm=e.i(492030);let tu=({server:e,isLoadingHealth:s,isRechecking:r,onRecheck:l})=>{let[a,n]=(0,b.useState)(!1),i=e.status||"unknown",o=e.last_health_check,c=e.health_check_error;if(s||r)return(0,t.jsxs)("span",{className:"inline-flex items-center gap-1.5 text-xs text-gray-400 px-2 py-0.5 rounded-full bg-gray-50 border border-gray-100",children:[(0,t.jsx)("span",{className:"h-1.5 w-1.5 rounded-full bg-gray-300 animate-pulse"}),"Checking"]});let d=!!l,m=(0,t.jsxs)("div",{className:"max-w-xs",children:[(0,t.jsxs)("div",{className:"font-semibold mb-1",children:["Health Status: ",i]}),o&&(0,t.jsxs)("div",{className:"text-xs mb-1",children:["Last Check: ",new Date(o).toLocaleString()]}),c&&(0,t.jsxs)("div",{className:"text-xs",children:[(0,t.jsx)("div",{className:"font-medium text-red-400 mb-1",children:"Error:"}),(0,t.jsx)("div",{className:"break-words",children:c})]}),!o&&!c&&(0,t.jsx)("div",{className:"text-xs text-gray-400",children:"No health check data available"}),d&&(0,t.jsx)("div",{className:"text-xs text-gray-400 mt-1",children:"Click to recheck"})]});return(0,t.jsx)(g.Tooltip,{title:m,placement:"top",children:(0,t.jsxs)("span",{className:`inline-flex items-center gap-1 text-xs font-medium px-2 py-0.5 rounded-full ${(e=>{switch(e){case"healthy":return"text-green-700 bg-green-50 border border-green-200";case"unhealthy":return"text-red-700 bg-red-50 border border-red-200";default:return"text-gray-600 bg-gray-50 border border-gray-200"}})(i)} ${d?"cursor-pointer hover:opacity-80":"cursor-default"}`,onMouseEnter:()=>n(!0),onMouseLeave:()=>n(!1),onClick:d?()=>l(e.server_id):void 0,children:[(0,t.jsx)("span",{children:a&&d?"↻":(e=>{switch(e){case"healthy":return"✓";case"unhealthy":return"✗";default:return"?"}})(i)}),a&&d?"Recheck":i.charAt(0).toUpperCase()+i.slice(1)]})})};var tx=e.i(530212),th=e.i(848725);let tp=b.forwardRef(function(e,t){return b.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",strokeWidth:2,stroke:"currentColor","aria-hidden":"true",ref:t},e),b.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21"}))});var tg=e.i(350967),tf=e.i(954616);function tb(e){if(!e)return[];if(Array.isArray(e))return e.map(e=>tj(e)).filter(e=>void 0!==e);let t=tj(e);return void 0===t?[]:[t]}function tj(e,t){if(!e)return;let s=void 0!==t?t:e.default;if("object"===e.type){let t="object"!=typeof s||null===s||Array.isArray(s)?{}:{...s};return e.properties&&Object.entries(e.properties).forEach(([e,s])=>{t[e]=tj(s,t[e])}),t}if("array"===e.type){if(Array.isArray(s)){let t=e.items;if(!t)return s;if(0===s.length){let e=tb(t);return e.length?e:s}return Array.isArray(t)?s.map((e,s)=>tj(t[s]??t[t.length-1],e)):s.map(e=>tj(t,e))}return void 0!==s?s:tb(e.items)}if(void 0!==s)return s;switch(e.type){case"integer":case"number":return 0;case"boolean":return!1;default:return""}}let ty=e=>{let t=tj(e);if("object"===e.type||"array"===e.type){let s="array"===e.type?[]:{};return JSON.stringify(t??s,null,2)}return t};function tv({tool:e,onSubmit:s,isLoading:r,result:a,error:n,onClose:i}){let[o]=D.Form.useForm(),[c,d]=b.default.useState("formatted"),[m,u]=b.default.useState(null),[x,h]=b.default.useState(null),f=b.default.useMemo(()=>"string"==typeof e.inputSchema?{type:"object",properties:{input:{type:"string",description:"Input for this tool"}},required:["input"]}:e.inputSchema,[e.inputSchema]),j=b.default.useMemo(()=>f.properties&&f.properties.params&&"object"===f.properties.params.type&&f.properties.params.properties?{type:"object",properties:f.properties.params.properties,required:f.properties.params.required||[]}:f,[f]);b.default.useEffect(()=>{if(o.resetFields(),!j.properties)return;let e={};Object.entries(j.properties).forEach(([t,s])=>{e[t]=ty(s)}),o.setFieldsValue(e)},[o,j,e]),b.default.useEffect(()=>{m&&(a||n)&&h(Date.now()-m)},[a,n,m]);let y=async e=>{try{if(navigator.clipboard&&window.isSecureContext)return await navigator.clipboard.writeText(e),!0;{let t=document.createElement("textarea");t.value=e,t.style.position="fixed",t.style.opacity="0",document.body.appendChild(t),t.focus(),t.select();let s=document.execCommand("copy");if(document.body.removeChild(t),!s)throw Error("execCommand failed");return!0}}catch(e){return console.error("Copy failed:",e),!1}},v=async()=>{await y(JSON.stringify(a,null,2))?C.default.success("Result copied to clipboard"):C.default.fromBackend("Failed to copy result")},N=async()=>{await y(e.name)?C.default.success("Tool name copied to clipboard"):C.default.fromBackend("Failed to copy tool name")};return(0,t.jsxs)("div",{className:"space-y-4 h-full",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between pb-3 border-b border-gray-200",children:[(0,t.jsxs)("div",{className:"flex items-center space-x-3",children:[e.mcp_info.logo_url&&(0,t.jsx)("img",{src:e.mcp_info.logo_url,alt:`${e.mcp_info.server_name} logo`,className:"w-6 h-6 object-contain"}),(0,t.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,t.jsxs)("div",{className:"flex items-center space-x-2 mb-1",children:[(0,t.jsx)("h2",{className:"text-lg font-semibold text-gray-900",children:"Test Tool:"}),(0,t.jsxs)("div",{className:"group inline-flex items-center space-x-1 bg-slate-50 hover:bg-slate-100 px-3 py-1 rounded-md cursor-pointer transition-colors border border-slate-200",onClick:N,title:"Click to copy tool name",children:[(0,t.jsx)("span",{className:"font-mono text-slate-700 font-medium text-sm",children:e.name}),(0,t.jsx)("svg",{className:"w-3 h-3 text-slate-400 group-hover:text-slate-600 transition-colors",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"})})]})]}),(0,t.jsx)("p",{className:"text-xs text-gray-600",children:e.description}),(0,t.jsxs)("p",{className:"text-xs text-gray-500",children:["Provider: ",e.mcp_info.server_name]})]})]}),(0,t.jsx)(l.Button,{onClick:i,variant:"light",size:"sm",className:"text-gray-500 hover:text-gray-700",children:(0,t.jsx)("svg",{className:"w-4 h-4",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M6 18L18 6M6 6l12 12"})})})]}),(0,t.jsxs)("div",{className:"grid grid-cols-2 gap-4 h-full",children:[(0,t.jsxs)("div",{className:"bg-white border border-gray-200 rounded-lg",children:[(0,t.jsx)("div",{className:"border-b border-gray-100 px-4 py-2",children:(0,t.jsxs)("div",{className:"flex items-center justify-between",children:[(0,t.jsx)("h3",{className:"text-sm font-semibold text-gray-900",children:"Input Parameters"}),(0,t.jsx)(g.Tooltip,{title:"Configure the input parameters for this tool call",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"text-gray-400 hover:text-gray-600"})})]})}),(0,t.jsx)("div",{className:"p-4",children:(0,t.jsxs)(D.Form,{form:o,onFinish:e=>{u(Date.now()),h(null);let t={};Object.entries(e).forEach(([e,s])=>{let r=j.properties?.[e];if(r&&null!=s&&""!==s)switch(r.type){case"boolean":t[e]="true"===s||!0===s;break;case"number":case"integer":{let l=Number(s);t[e]=Number.isNaN(l)?s:"integer"===r.type?Math.trunc(l):l;break}case"object":case"array":try{let l="string"==typeof s?JSON.parse(s):s,a="object"===r.type&&null!==l&&"object"==typeof l&&!Array.isArray(l),n="array"===r.type&&Array.isArray(l);"object"===r.type&&a||"array"===r.type&&n?t[e]=l:t[e]=s}catch(r){t[e]=s}break;case"string":t[e]=String(s);break;default:t[e]=s}else null!=s&&""!==s&&(t[e]=s)}),s(f.properties&&f.properties.params&&"object"===f.properties.params.type&&f.properties.params.properties?{params:t}:t)},layout:"vertical",className:"space-y-3",children:["string"==typeof e.inputSchema?(0,t.jsx)("div",{className:"space-y-3",children:(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700",children:["Input ",(0,t.jsx)("span",{className:"text-red-500",children:"*"})]}),name:"input",rules:[{required:!0,message:"Please enter input for this tool"}],className:"mb-3",children:(0,t.jsx)(ei.TextInput,{placeholder:"Enter input for this tool",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})})}):void 0===j.properties?(0,t.jsx)("div",{className:"text-center py-6 bg-gray-50 rounded-lg border border-gray-200",children:(0,t.jsxs)("div",{className:"max-w-sm mx-auto",children:[(0,t.jsx)("h4",{className:"text-sm font-medium text-gray-900 mb-1",children:"No Parameters Required"}),(0,t.jsx)("p",{className:"text-xs text-gray-500",children:"This tool can be called without any input parameters."})]})}):(0,t.jsx)("div",{className:"space-y-3",children:Object.entries(j.properties).map(([s,r])=>{let l=ty(r),a=`${e.name}-${s}`;return(0,t.jsxs)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:[s," ",j.required?.includes(s)&&(0,t.jsx)("span",{className:"text-red-500",children:"*"}),r.description&&(0,t.jsx)(g.Tooltip,{title:r.description,children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-gray-400 hover:text-gray-600"})})]}),name:s,initialValue:l,rules:[{required:j.required?.includes(s),message:`Please enter ${s}`},..."object"===r.type||"array"===r.type?[{validator:(e,t)=>{if((null==t||""===t)&&!j.required?.includes(s))return Promise.resolve();try{let e="string"==typeof t?JSON.parse(t):t,s="object"===r.type&&null!==e&&"object"==typeof e&&!Array.isArray(e),l="array"===r.type&&Array.isArray(e);if("object"===r.type&&s||"array"===r.type&&l)return Promise.resolve();return Promise.reject(Error("object"===r.type?"Please enter a JSON object":"Please enter a JSON array"))}catch(e){return Promise.reject(Error("Invalid JSON"))}}}]:[]],className:"mb-3",children:["string"===r.type&&r.enum&&(0,t.jsxs)("select",{className:"w-full px-3 py-2 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm transition-colors",defaultValue:l??"",children:[!j.required?.includes(s)&&(0,t.jsxs)("option",{value:"",children:["Select ",s]}),r.enum.map(e=>(0,t.jsx)("option",{value:e,children:e},e))]}),"string"===r.type&&!r.enum&&(0,t.jsx)(ei.TextInput,{placeholder:r.description||`Enter ${s}`,defaultValue:l??"",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"}),("number"===r.type||"integer"===r.type)&&(0,t.jsx)("input",{type:"number",step:"integer"===r.type?1:"any",placeholder:r.description||`Enter ${s}`,defaultValue:l??0,className:"w-full px-3 py-2 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm transition-colors"}),"boolean"===r.type&&(0,t.jsxs)(p.Select,{placeholder:`Select ${s}`,allowClear:!j.required?.includes(s),className:"w-full",children:[(0,t.jsx)(p.Select.Option,{value:!0,children:"True"}),(0,t.jsx)(p.Select.Option,{value:!1,children:"False"})]}),("object"===r.type||"array"===r.type)&&(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsx)("textarea",{rows:"object"===r.type?6:4,placeholder:r.description||("object"===r.type?`Enter JSON object for ${s}`:`Enter JSON array for ${s}`),defaultValue:l??("object"===r.type?"{}":"[]"),spellCheck:!1,"data-testid":`textarea-${s}`,className:"w-full px-3 py-2 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm font-mono"}),(0,t.jsx)("p",{className:"text-xs text-gray-500",children:"object"===r.type?"Provide a valid JSON object.":"Provide a valid JSON array."})]})]},a)})}),(0,t.jsx)("div",{className:"pt-3 border-t border-gray-100",children:(0,t.jsx)(l.Button,{onClick:()=>o.submit(),disabled:r,variant:"primary",className:"w-full",loading:r,children:r?"Calling Tool...":a||n?"Call Again":"Call Tool"})})]})})]}),(0,t.jsxs)("div",{className:"bg-white border border-gray-200 rounded-lg",children:[(0,t.jsx)("div",{className:"border-b border-gray-100 px-4 py-2",children:(0,t.jsx)("h3",{className:"text-sm font-semibold text-gray-900",children:"Tool Result"})}),(0,t.jsx)("div",{className:"p-4",children:a||n||r?(0,t.jsxs)("div",{className:"space-y-3",children:[a&&!r&&!n&&(0,t.jsx)("div",{className:"p-2 bg-green-50 border border-green-200 rounded-lg",children:(0,t.jsxs)("div",{className:"flex items-center justify-between",children:[(0,t.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,t.jsx)("svg",{className:"h-4 w-4 text-green-500",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"})}),(0,t.jsx)("h4",{className:"text-xs font-medium text-green-900",children:"Tool executed successfully"}),null!==x&&(0,t.jsxs)("span",{className:"text-xs text-green-600 ml-1",children:["• ",(x/1e3).toFixed(2),"s"]})]}),(0,t.jsxs)("div",{className:"flex items-center space-x-1",children:[(0,t.jsxs)("div",{className:"flex bg-white rounded border border-green-300 p-0.5",children:[(0,t.jsx)("button",{onClick:()=>d("formatted"),className:`px-2 py-1 text-xs font-medium rounded transition-colors ${"formatted"===c?"bg-green-100 text-green-800":"text-green-600 hover:text-green-800"}`,children:"Formatted"}),(0,t.jsx)("button",{onClick:()=>d("json"),className:`px-2 py-1 text-xs font-medium rounded transition-colors ${"json"===c?"bg-green-100 text-green-800":"text-green-600 hover:text-green-800"}`,children:"JSON"})]}),(0,t.jsx)("button",{onClick:v,className:"p-1 hover:bg-green-100 rounded text-green-700",title:"Copy response",children:(0,t.jsxs)("svg",{xmlns:"http://www.w3.org/2000/svg",width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[(0,t.jsx)("rect",{x:"9",y:"9",width:"13",height:"13",rx:"2",ry:"2"}),(0,t.jsx)("path",{d:"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"})]})})]})]})}),(0,t.jsxs)("div",{className:"max-h-96 overflow-y-auto",children:[r&&(0,t.jsxs)("div",{className:"flex flex-col justify-center items-center h-48 text-gray-500",children:[(0,t.jsxs)("div",{className:"relative",children:[(0,t.jsx)("div",{className:"animate-spin rounded-full h-8 w-8 border-2 border-gray-200"}),(0,t.jsx)("div",{className:"animate-spin rounded-full h-8 w-8 border-2 border-blue-600 border-t-transparent absolute top-0"})]}),(0,t.jsx)("p",{className:"text-sm font-medium mt-3",children:"Calling tool..."}),(0,t.jsx)("p",{className:"text-xs text-gray-400 mt-1",children:"Please wait while we process your request"})]}),n&&(0,t.jsx)("div",{className:"bg-red-50 border border-red-200 rounded-lg p-3",children:(0,t.jsxs)("div",{className:"flex items-start space-x-2",children:[(0,t.jsx)("div",{className:"flex-shrink-0",children:(0,t.jsx)("svg",{className:"h-4 w-4 text-red-400",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"})})}),(0,t.jsxs)("div",{className:"flex-1",children:[(0,t.jsxs)("div",{className:"flex items-center space-x-2 mb-1",children:[(0,t.jsx)("h4",{className:"text-xs font-medium text-red-900",children:"Tool Call Failed"}),null!==x&&(0,t.jsxs)("span",{className:"text-xs text-red-600",children:["• ",(x/1e3).toFixed(2),"s"]})]}),(0,t.jsx)("div",{className:"bg-white border border-red-200 rounded p-2 max-h-48 overflow-y-auto",children:(0,t.jsx)("pre",{className:"text-xs whitespace-pre-wrap text-red-700 font-mono",children:n.message})})]})]})}),a&&!r&&!n&&(0,t.jsx)("div",{className:"space-y-3",children:"formatted"===c?a.map((e,s)=>(0,t.jsxs)("div",{className:"border border-gray-200 rounded-lg overflow-hidden",children:["text"===e.type&&(0,t.jsxs)("div",{children:[(0,t.jsx)("div",{className:"bg-gray-50 px-3 py-1 border-b border-gray-200",children:(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:"Text Response"})}),(0,t.jsx)("div",{className:"p-3",children:(0,t.jsx)("div",{className:"bg-white rounded border border-gray-200 max-h-64 overflow-y-auto",children:(0,t.jsx)("div",{className:"p-3 space-y-2",children:e.text.split("\n\n").map((e,s)=>{if(""===e.trim())return null;if(e.startsWith("##")){let r=e.replace(/^#+\s/,"");return(0,t.jsx)("div",{className:"border-b border-gray-200 pb-1 mb-2",children:(0,t.jsx)("h3",{className:"text-sm font-semibold text-gray-900",children:r})},s)}let r=/(https?:\/\/[^\s\)]+)/g;if(r.test(e)){let l=e.split(r);return(0,t.jsx)("div",{className:"bg-blue-50 border border-blue-200 rounded p-2",children:(0,t.jsx)("div",{className:"text-xs text-gray-700 leading-relaxed whitespace-pre-wrap",children:l.map((e,s)=>r.test(e)?(0,t.jsx)("a",{href:e,target:"_blank",rel:"noopener noreferrer",className:"text-blue-600 hover:text-blue-800 underline break-all",children:e},s):e)})},s)}return e.includes("Score:")?(0,t.jsx)("div",{className:"bg-green-50 border-l-4 border-green-400 p-2 rounded-r",children:(0,t.jsx)("p",{className:"text-xs text-green-800 font-medium whitespace-pre-wrap",children:e})},s):(0,t.jsx)("div",{className:"bg-gray-50 rounded p-2 border border-gray-200",children:(0,t.jsx)("div",{className:"text-xs text-gray-700 leading-relaxed whitespace-pre-wrap font-mono",children:e})},s)}).filter(Boolean)})})})]}),"image"===e.type&&e.url&&(0,t.jsxs)("div",{children:[(0,t.jsx)("div",{className:"bg-gray-50 px-3 py-1 border-b border-gray-200",children:(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:"Image Response"})}),(0,t.jsx)("div",{className:"p-3",children:(0,t.jsx)("div",{className:"bg-gray-50 rounded p-3 border border-gray-200",children:(0,t.jsx)("img",{src:e.url,alt:"Tool result",className:"max-w-full h-auto rounded shadow-sm"})})})]}),"embedded_resource"===e.type&&(0,t.jsxs)("div",{children:[(0,t.jsx)("div",{className:"bg-gray-50 px-3 py-1 border-b border-gray-200",children:(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:"Embedded Resource"})}),(0,t.jsx)("div",{className:"p-3",children:(0,t.jsxs)("div",{className:"flex items-center space-x-2 p-3 bg-blue-50 border border-blue-200 rounded",children:[(0,t.jsx)("div",{className:"flex-shrink-0",children:(0,t.jsx)("svg",{className:"h-5 w-5 text-blue-500",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"})})}),(0,t.jsxs)("div",{className:"flex-1",children:[(0,t.jsxs)("p",{className:"text-xs font-medium text-blue-900",children:["Resource Type: ",e.resource_type]}),e.url&&(0,t.jsxs)("a",{href:e.url,target:"_blank",rel:"noopener noreferrer",className:"inline-flex items-center text-xs text-blue-600 hover:text-blue-800 hover:underline mt-1 transition-colors",children:["View Resource",(0,t.jsxs)("svg",{className:"ml-1 h-3 w-3",fill:"currentColor",viewBox:"0 0 20 20",children:[(0,t.jsx)("path",{d:"M11 3a1 1 0 100 2h2.586l-6.293 6.293a1 1 0 101.414 1.414L15 6.414V9a1 1 0 102 0V4a1 1 0 00-1-1h-5z"}),(0,t.jsx)("path",{d:"M5 5a2 2 0 00-2 2v8a2 2 0 002 2h8a2 2 0 002-2v-3a1 1 0 10-2 0v3H5V7h3a1 1 0 000-2H5z"})]})]})]})]})})]})]},s)):(0,t.jsx)("div",{className:"bg-white rounded border border-gray-200",children:(0,t.jsx)("div",{className:"p-3 overflow-auto max-h-80 bg-gray-50",children:(0,t.jsx)("pre",{className:"text-xs font-mono whitespace-pre-wrap break-all text-gray-800",children:JSON.stringify(a,null,2)})})})})]})]}):(0,t.jsx)("div",{className:"flex flex-col justify-center items-center h-48 text-gray-500",children:(0,t.jsxs)("div",{className:"text-center max-w-sm",children:[(0,t.jsx)("div",{className:"mb-3",children:(0,t.jsx)("svg",{className:"mx-auto h-12 w-12 text-gray-300",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:1,d:"M13 10V3L4 14h7v7l9-11h-7z"})})}),(0,t.jsx)("h4",{className:"text-sm font-medium text-gray-900 mb-1",children:"Ready to Call Tool"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 leading-relaxed",children:'Configure the input parameters and click "Call Tool" to see the results here.'})]})})})]})]})]})}var tN=e.i(983561),t_=e.i(438957);let tw=({serverId:e,accessToken:s,auth_type:r,userRole:l,userID:a,serverAlias:n,extraHeaders:i})=>{let[o,c]=(0,b.useState)(null),[u,x]=(0,b.useState)(null),[h,p]=(0,b.useState)(null),[g,f]=(0,b.useState)(""),[j,v]=(0,b.useState)({}),[N,w]=(0,b.useState)(!1),S=i&&i.length>0,C=()=>{if(!n||!S)return;let e={};return Object.entries(j).forEach(([t,s])=>{s&&s.trim()&&(e[`x-mcp-${n}-${t.toLowerCase()}`]=s)}),Object.keys(e).length>0?e:void 0},{data:T,isLoading:k,error:A,refetch:I}=(0,y.useQuery)({queryKey:["mcpTools",e,j],queryFn:()=>{if(!s)throw Error("Access Token required");return(0,_.listMCPTools)(s,e,C())},enabled:!!s,staleTime:3e4}),{mutate:P,isPending:O}=(0,tf.useMutation)({mutationFn:async t=>{if(!s)throw Error("Access Token required");try{return await (0,_.callMCPTool)(s,e,t.tool.name,t.arguments,{customHeaders:C()})}catch(e){throw e}},onSuccess:e=>{x(e.content),p(null)},onError:e=>{p(e),x(null)}}),M=T?.tools||[],F=M.filter(e=>{let t=g.toLowerCase();return e.name.toLowerCase().includes(t)||e.description&&e.description.toLowerCase().includes(t)||e.mcp_info.server_name&&e.mcp_info.server_name.toLowerCase().includes(t)});return(0,t.jsx)("div",{className:"w-full h-screen p-4 bg-white",children:(0,t.jsx)(eg.Card,{className:"w-full rounded-xl shadow-md overflow-hidden",children:(0,t.jsxs)("div",{className:"flex h-auto w-full gap-4",children:[(0,t.jsxs)("div",{className:"w-1/4 p-4 bg-gray-50 flex flex-col",children:[(0,t.jsx)(m.Title,{className:"text-xl font-semibold mb-6 mt-2",children:"MCP Tools"}),(0,t.jsxs)("div",{className:"flex flex-col flex-1",children:[S&&(0,t.jsxs)("div",{className:"mb-4 p-3 bg-blue-50 border border-blue-200 rounded-lg",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between mb-2",children:[(0,t.jsxs)("div",{className:"flex items-center",children:[(0,t.jsx)(t_.KeyOutlined,{className:"text-blue-600 mr-2"}),(0,t.jsx)(d.Text,{className:"text-sm font-medium text-blue-800",children:"Additional Headers"})]}),(0,t.jsx)(eb.Button,{size:"small",type:"link",onClick:()=>w(!N),className:"text-blue-700 p-0 h-auto",children:N?"Hide":"Configure"})]}),!N&&0===Object.keys(j).length&&(0,t.jsx)(d.Text,{className:"text-xs text-blue-700",children:'This server requires additional headers. Click "Configure" to provide values.'}),N&&(0,t.jsxs)("div",{className:"mt-3 space-y-2",children:[i?.map(e=>(0,t.jsxs)("div",{children:[(0,t.jsx)("label",{className:"block text-xs font-medium text-gray-700 mb-1",children:e}),(0,t.jsx)(H.Input,{size:"small",placeholder:`Enter ${e}`,value:j[e]||"",onChange:t=>{v({...j,[e]:t.target.value})},prefix:(0,t.jsx)(t_.KeyOutlined,{className:"text-gray-400"}),className:"rounded"})]},e)),(0,t.jsx)(eb.Button,{size:"small",type:"primary",onClick:()=>{I(),w(!1)},disabled:Object.values(j).every(e=>!e||!e.trim()),className:"w-full mt-2",children:"Load Tools"})]}),!N&&Object.keys(j).length>0&&(0,t.jsx)("div",{className:"mt-2",children:(0,t.jsxs)(d.Text,{className:"text-xs text-green-700 flex items-center",children:[(0,t.jsx)("span",{className:"inline-block w-2 h-2 bg-green-500 rounded-full mr-2"}),Object.keys(j).length," header(s) configured"]})})]}),(0,t.jsxs)("div",{className:"flex flex-col flex-1 min-h-0",children:[(0,t.jsxs)(d.Text,{className:"font-medium block mb-3 text-gray-700 flex items-center",children:[(0,t.jsx)(ep.ToolOutlined,{className:"mr-2"})," Available Tools",M.length>0&&(0,t.jsx)("span",{className:"ml-2 bg-blue-100 text-blue-800 text-xs font-medium px-2 py-0.5 rounded-full",children:M.length})]}),M.length>0&&(0,t.jsx)("div",{className:"mb-3",children:(0,t.jsx)(H.Input,{placeholder:"Search tools...",prefix:(0,t.jsx)(ew.SearchOutlined,{className:"text-gray-400"}),value:g,onChange:e=>f(e.target.value),allowClear:!0,className:"rounded-lg",size:"middle"})}),k&&(0,t.jsxs)("div",{className:"flex flex-col items-center justify-center py-8 bg-white border border-gray-200 rounded-lg",children:[(0,t.jsxs)("div",{className:"relative mb-3",children:[(0,t.jsx)("div",{className:"animate-spin rounded-full h-6 w-6 border-2 border-gray-200"}),(0,t.jsx)("div",{className:"animate-spin rounded-full h-6 w-6 border-2 border-blue-600 border-t-transparent absolute top-0"})]}),(0,t.jsx)("p",{className:"text-xs font-medium text-gray-700",children:"Loading tools..."})]}),T?.error&&!k&&!M.length&&(0,t.jsx)("div",{className:"p-3 text-xs text-red-800 rounded-lg bg-red-50 border border-red-200",children:(0,t.jsxs)("p",{className:"font-medium",children:["Error: ",T.message]})}),!k&&!T?.error&&(!M||0===M.length)&&(0,t.jsxs)("div",{className:"p-4 text-center bg-white border border-gray-200 rounded-lg",children:[(0,t.jsx)("div",{className:"mx-auto w-8 h-8 bg-gray-200 rounded-full flex items-center justify-center mb-2",children:(0,t.jsx)("svg",{className:"w-4 h-4 text-gray-400",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 8.172V5L8 4z"})})}),(0,t.jsx)("p",{className:"text-xs font-medium text-gray-700 mb-1",children:"No tools available"}),(0,t.jsx)("p",{className:"text-xs text-gray-500",children:"No tools found for this server"})]}),!k&&!T?.error&&M.length>0&&(0,t.jsx)(t.Fragment,{children:0===F.length?(0,t.jsxs)("div",{className:"p-4 text-center bg-white border border-gray-200 rounded-lg",children:[(0,t.jsx)(ew.SearchOutlined,{className:"text-2xl text-gray-400 mb-2"}),(0,t.jsx)("p",{className:"text-xs font-medium text-gray-700 mb-1",children:"No tools found"}),(0,t.jsxs)("p",{className:"text-xs text-gray-500",children:['No tools match "',g,'"']})]}):(0,t.jsx)("div",{className:"space-y-2 flex-1 overflow-y-auto min-h-0 mcp-tools-scrollable",style:{maxHeight:"400px",scrollbarWidth:"auto",scrollbarColor:"#cbd5e0 #f7fafc"},children:F.map(e=>(0,t.jsxs)("div",{className:`border rounded-lg p-3 cursor-pointer transition-all hover:shadow-sm ${o?.name===e.name?"border-blue-500 bg-blue-50 ring-1 ring-blue-200":"border-gray-200 bg-white hover:border-gray-300"}`,onClick:()=>{c(e),x(null),p(null)},children:[(0,t.jsxs)("div",{className:"flex items-start space-x-2",children:[e.mcp_info.logo_url&&(0,t.jsx)("img",{src:e.mcp_info.logo_url,alt:`${e.mcp_info.server_name} logo`,className:"w-4 h-4 object-contain flex-shrink-0 mt-0.5"}),(0,t.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,t.jsx)("h4",{className:"font-mono text-xs font-medium text-gray-900 truncate",children:e.name}),(0,t.jsx)("p",{className:"text-xs text-gray-500 truncate",children:e.mcp_info.server_name}),(0,t.jsx)("p",{className:"text-xs text-gray-600 mt-1 line-clamp-2 leading-relaxed",children:e.description})]})]}),o?.name===e.name&&(0,t.jsx)("div",{className:"mt-2 pt-2 border-t border-blue-200",children:(0,t.jsxs)("div",{className:"flex items-center text-xs font-medium text-blue-700",children:[(0,t.jsx)("svg",{className:"w-3 h-3 mr-1",fill:"currentColor",viewBox:"0 0 20 20",children:(0,t.jsx)("path",{fillRule:"evenodd",d:"M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z",clipRule:"evenodd"})}),"Selected"]})})]},e.name))})})]})]})]}),(0,t.jsxs)("div",{className:"w-3/4 flex flex-col bg-white",children:[(0,t.jsx)("div",{className:"p-4 border-b border-gray-200 flex justify-between items-center",children:(0,t.jsx)(m.Title,{className:"text-xl font-semibold mb-0",children:"Tool Testing Playground"})}),(0,t.jsx)("div",{className:"flex-1 overflow-auto p-4",children:o?(0,t.jsx)("div",{className:"h-full",children:(0,t.jsx)(tv,{tool:o,onSubmit:e=>{P({tool:o,arguments:e})},result:u,error:h,isLoading:O,onClose:()=>c(null)})}):(0,t.jsxs)("div",{className:"h-full flex flex-col items-center justify-center text-gray-400",children:[(0,t.jsx)(tN.RobotOutlined,{style:{fontSize:"48px",marginBottom:"16px"}}),(0,t.jsx)(d.Text,{className:"text-lg font-medium text-gray-600 mb-2",children:"Select a Tool to Test"}),(0,t.jsx)(d.Text,{className:"text-center text-gray-500 max-w-md",children:"Choose a tool from the left sidebar to start testing its functionality with custom inputs."})]})})]})]})})})},tS=[eo.AUTH_TYPE.API_KEY,eo.AUTH_TYPE.BEARER_TOKEN,eo.AUTH_TYPE.TOKEN,eo.AUTH_TYPE.BASIC],tC=[...tS,eo.AUTH_TYPE.OAUTH2,eo.AUTH_TYPE.AWS_SIGV4],tT="litellm-mcp-oauth-edit-state",tk=({mcpServer:e,accessToken:s,onCancel:r,onSuccess:d,availableAccessGroups:m})=>{let[u]=D.Form.useForm(),[x,h]=(0,b.useState)({}),[f,j]=(0,b.useState)([]),[y,v]=(0,b.useState)(!1),[N,w]=(0,b.useState)(null),[S,T]=(0,b.useState)(""),[k,A]=(0,b.useState)(!1),[I,P]=(0,b.useState)([]),[O,M]=(0,b.useState)({}),[F,E]=(0,b.useState)({}),[L,R]=(0,b.useState)(null),[U,z]=(0,b.useState)(e.mcp_info?.logo_url||void 0),B=D.Form.useWatch("auth_type",u),q=D.Form.useWatch("transport",u),V="stdio"===q,$=q===eo.TRANSPORT.OPENAPI,K=!!B&&tS.includes(B),W=B===eo.AUTH_TYPE.OAUTH2,J=B===eo.AUTH_TYPE.AWS_SIGV4,Y=D.Form.useWatch("oauth_flow_type",u),G=W&&Y===eo.OAUTH_FLOW.M2M,[Q,Z]=(0,b.useState)(null),X=D.Form.useWatch("url",u),ee=D.Form.useWatch("spec_path",u),et=D.Form.useWatch("server_name",u),es=D.Form.useWatch("auth_type",u),er=D.Form.useWatch("static_headers",u),el=D.Form.useWatch("credentials",u),ea=D.Form.useWatch("authorization_url",u),ei=D.Form.useWatch("token_url",u),ed=D.Form.useWatch("registration_url",u),{startOAuthFlow:em,status:eu,error:ex,tokenResponse:eh}=eQ({accessToken:s,getCredentials:()=>u.getFieldValue("credentials"),getTemporaryPayload:()=>{let t=u.getFieldsValue(!0),s=t.url||e.url,r=t.transport||e.transport;if(!s||!r)return null;let l=Array.isArray(t.static_headers)?t.static_headers.reduce((e,t)=>{let s=t?.header?.trim();return s&&(e[s]=t?.value??""),e},{}):{};return{server_id:e.server_id,server_name:t.server_name||e.server_name||e.alias,alias:t.alias||e.alias,description:t.description||e.description,url:s,transport:r,auth_type:eo.AUTH_TYPE.OAUTH2,credentials:t.credentials,mcp_access_groups:t.mcp_access_groups||e.mcp_access_groups,static_headers:l,command:t.command,args:t.args,env:t.env}},onTokenReceived:e=>{if(Z(e?.access_token??null),e?.access_token){let t={access_token:e.access_token,...e.refresh_token&&{refresh_token:e.refresh_token},...e.expires_in&&{expires_in:e.expires_in},...e.scope&&{scope:e.scope}};u.setFieldsValue({credentials:t}),C.default.success("OAuth authorization successful! Please click 'Update MCP Server' to save the credentials.")}},onBeforeRedirect:()=>{try{let t=u.getFieldsValue(!0);(0,eG.setSecureItem)(tT,JSON.stringify({serverId:e.server_id,formValues:t,costConfig:x,allowedTools:I,searchValue:S,aliasManuallyEdited:k}))}catch(e){console.warn("Failed to persist MCP edit state",e)}}}),ep=b.default.useMemo(()=>e.static_headers?Object.entries(e.static_headers).map(([e,t])=>({header:e,value:null!=t?String(t):""})):[],[e.static_headers]),eg=b.default.useMemo(()=>{let t=e.env??void 0;if(!t||0===Object.keys(t).length)return"";try{return JSON.stringify(t,null,2)}catch{return""}},[e.env]),ej=b.default.useMemo(()=>e.spec_path&&"stdio"!==e.transport?eo.TRANSPORT.OPENAPI:e.transport,[e]),ey=b.default.useMemo(()=>({...e,transport:ej,static_headers:ep,extra_headers:e.extra_headers||[],oauth_flow_type:e.token_url?eo.OAUTH_FLOW.M2M:eo.OAUTH_FLOW.INTERACTIVE,token_validation_json:e.token_validation?JSON.stringify(e.token_validation,null,2):void 0}),[e,ej,ep,eg]);(0,b.useEffect)(()=>{e.mcp_info?.mcp_server_cost_info&&h(e.mcp_info.mcp_server_cost_info)},[e]),(0,b.useEffect)(()=>{e.allowed_tools&&P(e.allowed_tools),M(e.tool_name_to_display_name??{}),E(e.tool_name_to_description??{})},[e]),(0,b.useEffect)(()=>{let t=(0,eG.getSecureItem)(tT);if(t)try{let s=JSON.parse(t);if(!s||s.serverId!==e.server_id)return;s.formValues&&R({...e,...s.formValues}),s.costConfig&&h(s.costConfig),s.allowedTools&&P(s.allowedTools),s.searchValue&&T(s.searchValue),"boolean"==typeof s.aliasManuallyEdited&&A(s.aliasManuallyEdited)}catch(e){console.error("Failed to restore MCP edit state",e)}finally{window.sessionStorage.removeItem(tT)}},[u,e]),(0,b.useEffect)(()=>{if(!L)return;let t=L.transport||e.transport;t&&t!==u.getFieldValue("transport")?u.setFieldsValue({transport:t}):(u.setFieldsValue(L),R(null))},[L,u,e.transport]),(0,b.useEffect)(()=>{if(e.mcp_access_groups){let t=e.mcp_access_groups.map(e=>"string"==typeof e?e:e.name||String(e));u.setFieldValue("mcp_access_groups",t)}},[e]),(0,b.useEffect)(()=>{e.server_id&&""!==e.server_id.trim()&&ev()},[e,s]);let ev=async()=>{if(s&&e.server_id){v(!0),w(null);try{let t=await (0,_.listMCPTools)(s,e.server_id);t.tools&&!t.error?j(t.tools):(console.error("Failed to fetch tools:",t.message),j([]),w(t.message||"Failed to load tools"))}catch(e){console.error("Tools fetch error:",e),j([]),w(e instanceof Error?e.message:"Failed to load tools")}finally{v(!1)}}},eN=async t=>{if(s)try{let{static_headers:r,credentials:l,stdio_config:a,env_json:n,command:i,args:o,allow_all_keys:c,available_on_public_internet:m,delegate_auth_to_upstream:u,token_validation_json:h,...p}=t,g=(p.mcp_access_groups||[]).map(e=>"string"==typeof e?e:e.name||String(e)),f=Array.isArray(r)?r.reduce((e,t)=>{let s=t?.header?.trim();return s&&(e[s]=t?.value??""),e},{}):{},b=l&&"object"==typeof l?Object.entries(l).reduce((e,[t,s])=>{if(null==s||""===s)return e;if("scopes"===t){if(Array.isArray(s)){let r=s.filter(e=>null!=e&&""!==e);r.length>0&&(e[t]=r)}}else e[t]=s;return e},{}):void 0,j={};if("stdio"===p.transport)if(a)try{let e=JSON.parse(a),t=e;if(e?.mcpServers&&"object"==typeof e.mcpServers){let s=Object.keys(e.mcpServers);s.length>0&&(t=e.mcpServers[s[0]])}let s=Array.isArray(t?.args)?t.args.map(e=>String(e)).filter(e=>""!==e.trim()):[],r=t?.env&&"object"==typeof t.env&&!Array.isArray(t.env)?Object.entries(t.env).reduce((e,[t,s])=>(null==t||""===String(t).trim()||(e[String(t)]=null==s?"":String(s)),e),{}):{};if(!(j={command:t?.command?String(t.command):void 0,args:s,env:r}).command)return void C.default.fromBackend("Stdio configuration must include a command")}catch{C.default.fromBackend("Invalid JSON in stdio configuration");return}else{let e={};if(n)try{let t=JSON.parse(n);t&&"object"==typeof t&&!Array.isArray(t)&&(e=Object.entries(t).reduce((e,[t,s])=>(null==t||""===String(t).trim()||(e[String(t)]=null==s?"":String(s)),e),{}))}catch{C.default.fromBackend("Invalid JSON in stdio env configuration");return}let t=Array.isArray(o)?o.map(e=>String(e)).filter(e=>""!==e.trim()):[],s=i?String(i).trim():"";if(!s)return void C.default.fromBackend("Stdio transport requires a command");j={command:s,args:t,env:e}}p.transport===eo.TRANSPORT.OPENAPI&&(p.transport="http");let y=null;if(h&&""!==h.trim())try{y=JSON.parse(h)}catch{C.default.fromBackend("Invalid JSON in Token Validation Rules");return}let v=p.server_name||p.url||e.server_name||e.url||p.alias||e.alias||"unknown",N={...p,...j,stdio_config:void 0,env_json:void 0,server_id:e.server_id,mcp_info:{server_name:v,description:p.description,logo_url:U||void 0,mcp_server_cost_info:Object.keys(x).length>0?x:null},mcp_access_groups:g,alias:p.alias,extra_headers:p.extra_headers||[],allowed_tools:I.length>0?I:null,tool_name_to_display_name:Object.keys(O).length>0?O:null,tool_name_to_description:Object.keys(F).length>0?F:null,disallowed_tools:p.disallowed_tools||[],static_headers:f,allow_all_keys:!!(c??e.allow_all_keys),available_on_public_internet:!!(m??e.available_on_public_internet),delegate_auth_to_upstream:p.auth_type===eo.AUTH_TYPE.OAUTH2&&!!(u??e.delegate_auth_to_upstream),...null!==y||e.token_validation?{token_validation:y}:{}};p.auth_type&&tC.includes(p.auth_type)&&b&&Object.keys(b).length>0&&(N.credentials=b);let w=await (0,_.updateMCPServer)(s,N);C.default.success("MCP Server updated successfully"),d(w)}catch(e){C.default.fromBackend("Failed to update MCP Server"+(e?.message?`: ${e.message}`:""))}};return(0,t.jsxs)(n.TabGroup,{children:[(0,t.jsxs)(i.TabList,{className:"grid w-full grid-cols-2",children:[(0,t.jsx)(a.Tab,{children:"Server Configuration"}),(0,t.jsx)(a.Tab,{children:"Cost Configuration"})]}),(0,t.jsxs)(c.TabPanels,{className:"mt-6",children:[(0,t.jsx)(o.TabPanel,{children:(0,t.jsxs)(D.Form,{form:u,onFinish:eN,initialValues:ey,layout:"vertical",children:[(0,t.jsx)(D.Form.Item,{label:"MCP Server Name",name:"server_name",rules:[{validator:(e,t)=>eW(t)}],children:(0,t.jsx)(H.Input,{className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:"Alias",name:"alias",rules:[{validator:(e,t)=>eW(t)}],children:(0,t.jsx)(H.Input,{onChange:()=>A(!0),className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:"Description",name:"description",children:(0,t.jsx)(H.Input,{className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(e$,{value:U,onChange:z}),(0,t.jsx)(D.Form.Item,{label:"Transport Type",name:"transport",rules:[{required:!0}],children:(0,t.jsxs)(p.Select,{onChange:e=>{"stdio"===e?u.setFieldsValue({url:void 0,spec_path:void 0,auth_type:void 0,credentials:void 0,authorization_url:void 0,token_url:void 0,registration_url:void 0}):e===eo.TRANSPORT.OPENAPI?u.setFieldsValue({url:void 0,command:void 0,args:void 0,env_json:void 0,stdio_config:void 0}):u.setFieldsValue({spec_path:void 0,command:void 0,args:void 0,env_json:void 0,stdio_config:void 0})},children:[(0,t.jsx)(p.Select.Option,{value:"http",children:"Streamable HTTP (Recommended)"}),(0,t.jsx)(p.Select.Option,{value:"sse",children:"Server-Sent Events (SSE)"}),(0,t.jsx)(p.Select.Option,{value:"stdio",children:"Standard Input/Output (stdio)"}),(0,t.jsx)(p.Select.Option,{value:eo.TRANSPORT.OPENAPI,children:"OpenAPI Spec"})]})}),!V&&!$&&(0,t.jsx)(D.Form.Item,{label:"MCP Server URL",name:"url",rules:[{required:!0,message:"Please enter a server URL"},{validator:(e,t)=>eK(t)}],children:(0,t.jsx)(H.Input,{placeholder:"https://your-mcp-server.com",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),$&&(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["OpenAPI Spec URL",(0,t.jsx)(g.Tooltip,{title:"URL to an OpenAPI specification (JSON or YAML). MCP tools will be automatically generated from the API endpoints defined in the spec.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:"spec_path",rules:[{required:!0,message:"Please enter an OpenAPI spec URL"}],children:(0,t.jsx)(H.Input,{placeholder:"https://petstore3.swagger.io/api/v3/openapi.json",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),!V&&(0,t.jsx)(D.Form.Item,{label:"Authentication",name:"auth_type",rules:[{required:!0}],children:(0,t.jsxs)(p.Select,{children:[(0,t.jsx)(p.Select.Option,{value:"none",children:"None"}),(0,t.jsx)(p.Select.Option,{value:"api_key",children:"API Key"}),(0,t.jsx)(p.Select.Option,{value:"bearer_token",children:"Bearer Token"}),(0,t.jsx)(p.Select.Option,{value:"token",children:"Token"}),(0,t.jsx)(p.Select.Option,{value:"basic",children:"Basic Auth"}),(0,t.jsx)(p.Select.Option,{value:"oauth2",children:"OAuth"}),(0,t.jsx)(p.Select.Option,{value:"aws_sigv4",children:"AWS SigV4 (Bedrock AgentCore MCPs)"})]})}),V&&(0,t.jsxs)("div",{className:"rounded-lg border border-gray-200 p-4 space-y-4",children:[(0,t.jsx)("p",{className:"text-sm text-gray-600",children:"Configure the stdio transport used to launch the MCP server process. You can either fill in the fields below or paste a JSON configuration."}),(0,t.jsx)(D.Form.Item,{label:"Command",name:"command",rules:[{required:!0,message:"Please enter a command for stdio transport"}],children:(0,t.jsx)(H.Input,{placeholder:"e.g., npx",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:"Args",name:"args",children:(0,t.jsx)(p.Select,{mode:"tags",size:"large",tokenSeparators:[","],placeholder:"Add args (press enter or comma)",className:"rounded-lg"})}),(0,t.jsx)(D.Form.Item,{label:"Environment (JSON object)",name:"env_json",rules:[{validator:(e,t)=>{if(!t)return Promise.resolve();try{let e=JSON.parse(t);if(e&&"object"==typeof e&&!Array.isArray(e))return Promise.resolve();return Promise.reject(Error("Env must be a JSON object"))}catch{return Promise.reject(Error("Please enter valid JSON"))}}}],children:(0,t.jsx)(H.Input.TextArea,{rows:6,className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500 font-mono text-sm",placeholder:`{ - "KEY": "value" -}`})}),(0,t.jsx)(eO,{isVisible:!0,required:!1})]}),!V&&K&&(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["Authentication Value",(0,t.jsx)(g.Tooltip,{title:"Token, password, or header value to send with each request for the selected auth type.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","auth_value"],rules:[{validator:(e,t)=>t&&"string"==typeof t&&""===t.trim()?Promise.reject(Error("Authentication value cannot be empty")):Promise.resolve()}],children:(0,t.jsx)(H.Input.Password,{placeholder:"Enter token or secret (leave blank to keep existing)",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),!V&&W&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["OAuth Client ID (optional)",(0,t.jsx)(g.Tooltip,{title:"Provide only if your MCP server cannot handle dynamic client registration.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","client_id"],children:(0,t.jsx)(H.Input.Password,{placeholder:"Enter OAuth client ID (leave blank to keep existing)",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["OAuth Client Secret (optional)",(0,t.jsx)(g.Tooltip,{title:"Provide only if your MCP server cannot handle dynamic client registration.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","client_secret"],children:(0,t.jsx)(H.Input.Password,{placeholder:"Enter OAuth client secret (leave blank to keep existing)",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["OAuth Scopes (optional)",(0,t.jsx)(g.Tooltip,{title:"Add scopes to override the default scope list used for this MCP server.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","scopes"],children:(0,t.jsx)(p.Select,{mode:"tags",tokenSeparators:[","],placeholder:"Add scopes",className:"rounded-lg",size:"large"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["Authorization URL Override (optional)",(0,t.jsx)(g.Tooltip,{title:"Optional override for the authorization endpoint.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:"authorization_url",children:(0,t.jsx)(H.Input,{placeholder:"https://example.com/oauth/authorize",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["Token URL Override (optional)",(0,t.jsx)(g.Tooltip,{title:"Optional override for the token endpoint.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:"token_url",children:(0,t.jsx)(H.Input,{placeholder:"https://example.com/oauth/token",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["Registration URL Override (optional)",(0,t.jsx)(g.Tooltip,{title:"Optional override for the dynamic client registration endpoint.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:"registration_url",children:(0,t.jsx)(H.Input,{placeholder:"https://example.com/oauth/register",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),!G&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["Token Validation Rules (optional)",(0,t.jsx)(g.Tooltip,{title:'JSON object of key-value rules checked against the OAuth token response before storing. Supports dot-notation for nested fields (e.g. {"organization": "my-org", "team.id": "123"}). Tokens that fail validation are rejected with HTTP 403.',children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:"token_validation_json",rules:[{validator:(e,t)=>{if(!t||""===t.trim())return Promise.resolve();try{return JSON.parse(t),Promise.resolve()}catch{return Promise.reject(Error("Must be valid JSON"))}}}],children:(0,t.jsx)(H.Input.TextArea,{placeholder:'{\n "organization": "my-org",\n "team.id": "123"\n}',rows:4,className:"font-mono text-sm rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["Token Storage TTL (seconds, optional)",(0,t.jsx)(g.Tooltip,{title:"How long to cache each user's OAuth access token in Redis before evicting it (regardless of the token's own expires_in). Leave blank to derive the TTL from the token's expires_in, or fall back to the 12-hour default.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:"token_storage_ttl_seconds",children:(0,t.jsx)(ec.InputNumber,{min:1,placeholder:"e.g. 3600",style:{width:"100%"},className:"rounded-lg"})})]}),(0,t.jsxs)("div",{className:"rounded-lg border border-dashed border-gray-300 p-4 space-y-2",children:[(0,t.jsx)("p",{className:"text-sm text-gray-600",children:"Use OAuth to fetch a fresh access token and temporarily save it in the session as the authentication value."}),(0,t.jsx)(l.Button,{variant:"secondary",onClick:em,disabled:"authorizing"===eu||"exchanging"===eu,children:"authorizing"===eu?"Waiting for authorization...":"exchanging"===eu?"Exchanging authorization code...":"Authorize & Fetch Token"}),ex&&(0,t.jsx)("p",{className:"text-sm text-red-500",children:ex}),"success"===eu&&eh?.access_token&&(0,t.jsxs)("p",{className:"text-sm text-green-600",children:["Token fetched. Expires in ",eh.expires_in??"?"," seconds."]})]})]}),!V&&J&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("p",{className:"text-sm text-gray-500 mb-2",children:["For MCP servers hosted on AWS Bedrock AgentCore."," ",(0,t.jsx)("a",{href:"https://docs.litellm.ai/docs/mcp_aws_sigv4",target:"_blank",rel:"noopener noreferrer",className:"text-blue-500 hover:text-blue-700",children:"View docs →"})]}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["AWS Region",(0,t.jsx)(g.Tooltip,{title:"AWS region for SigV4 signing (e.g., us-east-1)",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","aws_region_name"],rules:[],children:(0,t.jsx)(H.Input,{placeholder:"us-east-1 (leave blank to keep existing)",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["AWS Service Name",(0,t.jsx)(g.Tooltip,{title:"AWS service name for SigV4 signing. Defaults to 'bedrock-agentcore'.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","aws_service_name"],children:(0,t.jsx)(H.Input,{placeholder:"bedrock-agentcore (leave blank to keep existing)",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["AWS Access Key ID",(0,t.jsx)(g.Tooltip,{title:"Optional. If not provided, falls back to the boto3 credential chain (IAM role, env vars, etc.).",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","aws_access_key_id"],rules:[],children:(0,t.jsx)(H.Input.Password,{placeholder:"Leave blank to keep existing",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["AWS Secret Access Key",(0,t.jsx)(g.Tooltip,{title:"Optional. Required if AWS Access Key ID is provided.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","aws_secret_access_key"],rules:[],children:(0,t.jsx)(H.Input.Password,{placeholder:"Leave blank to keep existing",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["AWS Session Token",(0,t.jsx)(g.Tooltip,{title:"Optional. Only needed for temporary STS credentials.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","aws_session_token"],children:(0,t.jsx)(H.Input.Password,{placeholder:"Leave blank to keep existing",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["AWS Role ARN",(0,t.jsx)(g.Tooltip,{title:"Optional. IAM role ARN to assume via STS before signing. If set, LiteLLM calls sts:AssumeRole to get temporary credentials.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","aws_role_name"],children:(0,t.jsx)(H.Input,{placeholder:"Leave blank to keep existing",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["AWS Session Name",(0,t.jsx)(g.Tooltip,{title:"Optional. Session name for the AssumeRole call — appears in CloudTrail logs. Auto-generated if omitted.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","aws_session_name"],children:(0,t.jsx)(H.Input,{placeholder:"Leave blank to keep existing",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})})]}),(0,t.jsx)("div",{className:"mt-6",children:(0,t.jsx)(eR,{availableAccessGroups:m,mcpServer:e,searchValue:S,setSearchValue:T,getAccessGroupOptions:()=>{let e=m.map(e=>({value:e,label:(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("div",{className:"w-2 h-2 bg-green-500 rounded-full"}),(0,t.jsx)("span",{className:"font-medium",children:e})]})}));return S&&!m.some(e=>e.toLowerCase().includes(S.toLowerCase()))&&e.push({value:S,label:(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("div",{className:"w-2 h-2 bg-blue-500 rounded-full"}),(0,t.jsx)("span",{className:"font-medium",children:S}),(0,t.jsx)("span",{className:"text-gray-400 text-xs ml-1",children:"create new group"})]})}),e}})}),(0,t.jsx)("div",{className:"mt-6",children:(0,t.jsx)(eP,{accessToken:s,oauthAccessToken:Q,formValues:{server_id:e.server_id,server_name:et??e.server_name,url:X??e.url,spec_path:ee??e.spec_path,transport:q??e.transport,auth_type:es??e.auth_type,mcp_info:e.mcp_info,oauth_flow_type:ei??e.token_url?eo.OAUTH_FLOW.M2M:eo.OAUTH_FLOW.INTERACTIVE,static_headers:er??e.static_headers,credentials:el,authorization_url:ea??e.authorization_url,token_url:ei??e.token_url,registration_url:ed??e.registration_url},allowedTools:I,existingAllowedTools:e.allowed_tools||null,onAllowedToolsChange:P,toolNameToDisplayName:O,toolNameToDescription:F,onToolNameToDisplayNameChange:M,onToolNameToDescriptionChange:E})}),(0,t.jsxs)("div",{className:"flex justify-end gap-2",children:[(0,t.jsx)(eb.Button,{onClick:r,children:"Cancel"}),(0,t.jsx)(l.Button,{type:"submit",children:"Save Changes"})]})]})}),(0,t.jsx)(o.TabPanel,{children:(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsx)(ef,{value:x,onChange:h,tools:f,disabled:y}),(0,t.jsxs)("div",{className:"flex justify-end gap-2",children:[(0,t.jsx)(eb.Button,{onClick:r,children:"Cancel"}),(0,t.jsx)(l.Button,{onClick:()=>u.submit(),children:"Save Changes"})]})]})})]})]})},tA=({costConfig:e})=>{let s=e?.default_cost_per_query!==void 0&&e?.default_cost_per_query!==null,r=e?.tool_name_to_cost_per_query&&Object.keys(e.tool_name_to_cost_per_query).length>0;return s||r?(0,t.jsx)("div",{className:"mt-6 pt-6 border-t border-gray-200",children:(0,t.jsxs)("div",{className:"space-y-4",children:[s&&e?.default_cost_per_query!==void 0&&e?.default_cost_per_query!==null&&(0,t.jsxs)("div",{children:[(0,t.jsx)(d.Text,{className:"font-medium",children:"Default Cost per Query"}),(0,t.jsxs)("div",{className:"text-green-600 font-mono",children:["$",e.default_cost_per_query.toFixed(4)]})]}),r&&e?.tool_name_to_cost_per_query&&(0,t.jsxs)("div",{children:[(0,t.jsx)(d.Text,{className:"font-medium",children:"Tool-Specific Costs"}),(0,t.jsx)("div",{className:"mt-2 space-y-2",children:Object.entries(e.tool_name_to_cost_per_query).map(([e,s])=>null!=s&&(0,t.jsxs)("div",{className:"flex justify-between items-center p-3 bg-gray-50 rounded-lg",children:[(0,t.jsx)(d.Text,{className:"font-medium",children:e}),(0,t.jsxs)(d.Text,{className:"text-green-600 font-mono",children:["$",s.toFixed(4)," per query"]})]},e))})]}),(0,t.jsxs)("div",{className:"mt-4 p-4 bg-blue-50 border border-blue-200 rounded-lg",children:[(0,t.jsx)(d.Text,{className:"text-blue-800 font-medium",children:"Cost Summary:"}),(0,t.jsxs)("div",{className:"mt-2 space-y-1",children:[s&&e?.default_cost_per_query!==void 0&&e?.default_cost_per_query!==null&&(0,t.jsxs)(d.Text,{className:"text-blue-700",children:["• Default cost: $",e.default_cost_per_query.toFixed(4)," per query"]}),r&&e?.tool_name_to_cost_per_query&&(0,t.jsxs)(d.Text,{className:"text-blue-700",children:["• ",Object.keys(e.tool_name_to_cost_per_query).length," tool(s) with custom pricing"]})]})]})]})}):(0,t.jsx)("div",{className:"mt-6 pt-6 border-t border-gray-200",children:(0,t.jsx)("div",{className:"space-y-4",children:(0,t.jsx)("div",{className:"p-4 bg-gray-50 border border-gray-200 rounded-lg",children:(0,t.jsx)(d.Text,{className:"text-gray-600",children:"No cost configuration set for this server. Tool calls will be charged at $0.00 per tool call."})})})})},tI=({mcpServer:e,onBack:s,isEditing:r,isProxyAdmin:u,accessToken:x,userRole:h,userID:p,availableAccessGroups:g})=>{let[f,j]=(0,b.useState)(r),[y,v]=(0,b.useState)(!1),[N,_]=(0,b.useState)({}),[w,S]=(0,b.useState)(0),C=e.url??"",{maskedUrl:T,hasToken:A}=C?eH(C):{maskedUrl:"—",hasToken:!1},I=(e,t)=>e?A?t?e:T:e:"—",P=async(e,t)=>{await (0,tr.copyToClipboard)(e)&&(_(e=>({...e,[t]:!0})),setTimeout(()=>{_(e=>({...e,[t]:!1}))},2e3))},O=e=>{let s=e.toUpperCase();return(0,t.jsx)("span",{className:"inline-flex items-center text-sm font-medium px-2.5 py-0.5 rounded border bg-gray-50 text-gray-700 border-gray-200",children:s})},M=e=>(0,t.jsx)("span",{className:"inline-flex items-center text-sm font-medium px-2.5 py-0.5 rounded border bg-gray-50 text-gray-700 border-gray-200",children:e});return(0,t.jsxs)("div",{className:"p-4 max-w-full",children:[(0,t.jsxs)("div",{className:"mb-6",children:[(0,t.jsx)(l.Button,{icon:tx.ArrowLeftIcon,variant:"light",className:"mb-4",onClick:s,children:"Back to All Servers"}),(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(m.Title,{className:"text-2xl",children:e.server_name||e.alias||"Unnamed Server"}),(0,t.jsx)(eb.Button,{type:"text",size:"small",icon:N["mcp-server_name"]?(0,t.jsx)(k.CheckIcon,{size:12}):(0,t.jsx)(e6.CopyIcon,{size:12}),onClick:()=>P(e.server_name||e.alias,"mcp-server_name"),className:`transition-all duration-200 ${N["mcp-server_name"]?"text-green-600 bg-green-50 border-green-200":"text-gray-400 hover:text-gray-600 hover:bg-gray-100"}`}),e.alias&&e.server_name&&e.alias!==e.server_name&&(0,t.jsx)("span",{className:"ml-2 inline-flex items-center text-xs font-medium px-2 py-0.5 rounded bg-gray-100 text-gray-600 border border-gray-200 font-mono",children:e.alias})]}),(0,t.jsxs)("div",{className:"flex items-center gap-1.5 mt-1",children:[(0,t.jsx)(d.Text,{className:"text-gray-400 font-mono text-xs",children:e.server_id}),(0,t.jsx)(eb.Button,{type:"text",size:"small",icon:N["mcp-server-id"]?(0,t.jsx)(k.CheckIcon,{size:10}):(0,t.jsx)(e6.CopyIcon,{size:10}),onClick:()=>P(e.server_id,"mcp-server-id"),className:`transition-all duration-200 ${N["mcp-server-id"]?"text-green-600 bg-green-50 border-green-200":"text-gray-300 hover:text-gray-500 hover:bg-gray-50"}`})]}),e.description&&(0,t.jsx)(d.Text,{className:"text-gray-500 mt-2",children:e.description})]}),(0,t.jsxs)(n.TabGroup,{index:w,onIndexChange:S,children:[(0,t.jsx)(i.TabList,{className:"mb-4",children:[(0,t.jsx)(a.Tab,{children:"Overview"},"overview"),(0,t.jsx)(a.Tab,{children:"MCP Tools"},"tools"),...u?[(0,t.jsx)(a.Tab,{children:"Settings"},"settings")]:[]]}),(0,t.jsxs)(c.TabPanels,{children:[(0,t.jsxs)(o.TabPanel,{children:[(0,t.jsxs)(tg.Grid,{numItems:1,numItemsSm:2,numItemsLg:3,className:"gap-4",children:[(0,t.jsxs)(eg.Card,{className:"p-4",children:[(0,t.jsx)(d.Text,{className:"text-xs font-medium text-gray-500 uppercase tracking-wide",children:"Transport"}),(0,t.jsx)("div",{className:"mt-3",children:O((0,eo.handleTransport)(e.transport??void 0,e.spec_path??void 0))})]}),(0,t.jsxs)(eg.Card,{className:"p-4",children:[(0,t.jsx)(d.Text,{className:"text-xs font-medium text-gray-500 uppercase tracking-wide",children:"Authentication"}),(0,t.jsx)("div",{className:"mt-3",children:M((0,eo.handleAuth)(e.auth_type??void 0))})]}),(0,t.jsxs)(eg.Card,{className:"p-4",children:[(0,t.jsx)(d.Text,{className:"text-xs font-medium text-gray-500 uppercase tracking-wide",children:"Host URL"}),(0,t.jsxs)("div",{className:"mt-3 flex items-center gap-2",children:[(0,t.jsx)(d.Text,{className:"break-all overflow-wrap-anywhere font-mono text-sm",children:I(e.url,y)}),A&&u&&(0,t.jsx)("button",{onClick:()=>v(!y),className:"p-1 hover:bg-gray-100 rounded flex-shrink-0",children:(0,t.jsx)(tc.Icon,{icon:y?tp:th.EyeIcon,size:"sm",className:"text-gray-500"})})]})]})]}),(0,t.jsxs)(eg.Card,{className:"mt-4 p-4",children:[(0,t.jsx)(d.Text,{className:"text-xs font-medium text-gray-500 uppercase tracking-wide",children:"Cost Configuration"}),(0,t.jsx)("div",{className:"mt-3",children:(0,t.jsx)(tA,{costConfig:e.mcp_info?.mcp_server_cost_info})})]})]}),(0,t.jsx)(o.TabPanel,{children:(0,t.jsx)(tw,{serverId:e.server_id,accessToken:x,auth_type:e.auth_type,userRole:h,userID:p,serverAlias:e.alias,extraHeaders:e.extra_headers})}),(0,t.jsx)(o.TabPanel,{children:(0,t.jsxs)(eg.Card,{children:[(0,t.jsxs)("div",{className:"flex justify-between items-center mb-4",children:[(0,t.jsx)(m.Title,{children:"MCP Server Settings"}),f?null:(0,t.jsx)(l.Button,{variant:"light",onClick:()=>j(!0),children:"Edit Settings"})]}),f?(0,t.jsx)(tk,{mcpServer:e,accessToken:x,onCancel:()=>j(!1),onSuccess:e=>{j(!1),s()},availableAccessGroups:g}):(0,t.jsxs)("div",{className:"divide-y divide-gray-100",children:[(0,t.jsxs)("div",{className:"py-3 grid grid-cols-3 gap-4",children:[(0,t.jsx)(d.Text,{className:"text-sm font-medium text-gray-500",children:"Server Name"}),(0,t.jsx)("div",{className:"col-span-2 text-sm text-gray-900",children:e.server_name||(0,t.jsx)("span",{className:"text-gray-400",children:"—"})})]}),(0,t.jsxs)("div",{className:"py-3 grid grid-cols-3 gap-4",children:[(0,t.jsx)(d.Text,{className:"text-sm font-medium text-gray-500",children:"Alias"}),(0,t.jsx)("div",{className:"col-span-2 text-sm font-mono text-gray-900",children:e.alias||(0,t.jsx)("span",{className:"text-gray-400",children:"—"})})]}),(0,t.jsxs)("div",{className:"py-3 grid grid-cols-3 gap-4",children:[(0,t.jsx)(d.Text,{className:"text-sm font-medium text-gray-500",children:"Description"}),(0,t.jsx)("div",{className:"col-span-2 text-sm text-gray-900",children:e.description||(0,t.jsx)("span",{className:"text-gray-400",children:"—"})})]}),(0,t.jsxs)("div",{className:"py-3 grid grid-cols-3 gap-4",children:[(0,t.jsx)(d.Text,{className:"text-sm font-medium text-gray-500",children:"URL"}),(0,t.jsxs)("div",{className:"col-span-2 text-sm font-mono text-gray-900 break-all flex items-center gap-2",children:[I(e.url,y),A&&(0,t.jsx)("button",{onClick:()=>v(!y),className:"p-1 hover:bg-gray-100 rounded flex-shrink-0",children:(0,t.jsx)(tc.Icon,{icon:y?tp:th.EyeIcon,size:"sm",className:"text-gray-500"})})]})]}),(0,t.jsxs)("div",{className:"py-3 grid grid-cols-3 gap-4",children:[(0,t.jsx)(d.Text,{className:"text-sm font-medium text-gray-500",children:"Transport"}),(0,t.jsx)("div",{className:"col-span-2",children:O((0,eo.handleTransport)(e.transport,e.spec_path))})]}),(0,t.jsxs)("div",{className:"py-3 grid grid-cols-3 gap-4",children:[(0,t.jsx)(d.Text,{className:"text-sm font-medium text-gray-500",children:"Authentication"}),(0,t.jsx)("div",{className:"col-span-2",children:M((0,eo.handleAuth)(e.auth_type))})]}),(0,t.jsxs)("div",{className:"py-3 grid grid-cols-3 gap-4",children:[(0,t.jsx)(d.Text,{className:"text-sm font-medium text-gray-500",children:"Extra Headers"}),(0,t.jsx)("div",{className:"col-span-2 text-sm text-gray-900",children:e.extra_headers&&e.extra_headers.length>0?e.extra_headers.join(", "):(0,t.jsx)("span",{className:"text-gray-400",children:"—"})})]}),(0,t.jsxs)("div",{className:"py-3 grid grid-cols-3 gap-4",children:[(0,t.jsx)(d.Text,{className:"text-sm font-medium text-gray-500",children:"Allow All Keys"}),(0,t.jsx)("div",{className:"col-span-2",children:e.allow_all_keys?(0,t.jsxs)("span",{className:"inline-flex items-center gap-1 px-2 py-0.5 bg-green-50 text-green-700 rounded-full border border-green-200 text-xs font-medium",children:[(0,t.jsx)("span",{className:"h-1.5 w-1.5 rounded-full bg-green-500"}),"Enabled"]}):(0,t.jsx)("span",{className:"inline-flex items-center gap-1 px-2 py-0.5 bg-gray-50 text-gray-600 rounded-full border border-gray-200 text-xs font-medium",children:"Disabled"})})]}),(0,t.jsxs)("div",{className:"py-3 grid grid-cols-3 gap-4",children:[(0,t.jsx)(d.Text,{className:"text-sm font-medium text-gray-500",children:"Network Access"}),(0,t.jsx)("div",{className:"col-span-2",children:e.available_on_public_internet?(0,t.jsxs)("span",{className:"inline-flex items-center gap-1 px-2 py-0.5 bg-green-50 text-green-700 rounded-full border border-green-200 text-xs font-medium",children:[(0,t.jsx)("span",{className:"h-1.5 w-1.5 rounded-full bg-green-500"}),"Public"]}):(0,t.jsxs)("span",{className:"inline-flex items-center gap-1 px-2 py-0.5 bg-orange-50 text-orange-700 rounded-full border border-orange-200 text-xs font-medium",children:[(0,t.jsx)("span",{className:"h-1.5 w-1.5 rounded-full bg-orange-500"}),"Internal only"]})})]}),"oauth2"===(0,eo.handleAuth)(e.auth_type)&&(0,t.jsxs)("div",{className:"py-3 grid grid-cols-3 gap-4",children:[(0,t.jsx)(d.Text,{className:"text-sm font-medium text-gray-500",children:"Delegate Auth to Upstream"}),(0,t.jsx)("div",{className:"col-span-2",children:e.delegate_auth_to_upstream?(0,t.jsxs)("span",{className:"inline-flex items-center gap-1 px-2 py-0.5 bg-green-50 text-green-700 rounded-full border border-green-200 text-xs font-medium",children:[(0,t.jsx)("span",{className:"h-1.5 w-1.5 rounded-full bg-green-500"}),"Enabled (PKCE passthrough)"]}):(0,t.jsx)("span",{className:"inline-flex items-center gap-1 px-2 py-0.5 bg-gray-50 text-gray-600 rounded-full border border-gray-200 text-xs font-medium",children:"Disabled"})})]}),(0,t.jsxs)("div",{className:"py-3 grid grid-cols-3 gap-4",children:[(0,t.jsx)(d.Text,{className:"text-sm font-medium text-gray-500",children:"Access Groups"}),(0,t.jsx)("div",{className:"col-span-2",children:e.mcp_access_groups&&e.mcp_access_groups.length>0?(0,t.jsx)("div",{className:"flex flex-wrap gap-1.5",children:e.mcp_access_groups.map((e,s)=>(0,t.jsx)("span",{className:"inline-flex items-center text-xs font-medium px-2 py-0.5 rounded bg-gray-100 text-gray-700 border border-gray-200",children:"string"==typeof e?e:e?.name??""},s))}):(0,t.jsx)("span",{className:"text-sm text-gray-400",children:"—"})})]}),(0,t.jsxs)("div",{className:"py-3 grid grid-cols-3 gap-4",children:[(0,t.jsx)(d.Text,{className:"text-sm font-medium text-gray-500",children:"Allowed Tools"}),(0,t.jsx)("div",{className:"col-span-2",children:e.allowed_tools&&e.allowed_tools.length>0?(0,t.jsx)("div",{className:"flex flex-wrap gap-1.5",children:e.allowed_tools.map((e,s)=>(0,t.jsx)("span",{className:"inline-flex items-center text-xs font-mono font-medium px-2 py-0.5 rounded bg-blue-50 text-blue-700 border border-blue-200",children:e},s))}):(0,t.jsx)("span",{className:"inline-flex items-center text-xs font-medium px-2 py-0.5 rounded bg-green-50 text-green-700 border border-green-200",children:"All tools enabled"})})]}),(0,t.jsxs)("div",{className:"py-3 grid grid-cols-3 gap-4",children:[(0,t.jsx)(d.Text,{className:"text-sm font-medium text-gray-500",children:"Cost"}),(0,t.jsx)("div",{className:"col-span-2",children:(0,t.jsx)(tA,{costConfig:e.mcp_info?.mcp_server_cost_info})})]})]})]})})]})]})]})},tP=(0,N.createQueryKeys)("mcpSemanticFilterSettings"),tO=(0,N.createQueryKeys)("mcpSemanticFilterSettings");var tM=e.i(178654),tF=e.i(621192),tE=e.i(981339),tL=e.i(850627),tR=e.i(987432),tU=e.i(689020),tz=e.i(245094),tB=e.i(788191),tq=e.i(653496),tV=e.i(992619);function t$({accessToken:e,testQuery:s,setTestQuery:r,testModel:l,setTestModel:a,isTesting:n,onTest:i,filterEnabled:o,testResult:c,curlCommand:d}){return(0,t.jsx)(e4.Card,{title:"Test Configuration",style:{marginBottom:16},children:(0,t.jsx)(tq.Tabs,{defaultActiveKey:"test",items:[{key:"test",label:"Test",children:(0,t.jsxs)(eM.Space,{direction:"vertical",style:{width:"100%"},size:"large",children:[(0,t.jsxs)("div",{children:[(0,t.jsxs)(f.Typography.Text,{strong:!0,style:{display:"block",marginBottom:8},children:[(0,t.jsx)(tB.PlayCircleOutlined,{})," Test Query"]}),(0,t.jsx)(H.Input.TextArea,{placeholder:"Enter a test query to see which tools would be selected...",value:s,onChange:e=>r(e.target.value),rows:4,disabled:n})]}),(0,t.jsx)("div",{children:(0,t.jsx)(tV.default,{accessToken:e||"",value:l,onChange:a,disabled:n,showLabel:!0,labelText:"Select Model"})}),(0,t.jsx)(eb.Button,{type:"primary",icon:(0,t.jsx)(tB.PlayCircleOutlined,{}),onClick:i,loading:n,disabled:!s||!l||!o,block:!0,children:"Test Filter"}),!o&&(0,t.jsx)(ej.Alert,{type:"warning",message:"Semantic filtering is disabled",description:"Enable semantic filtering and save settings to test the filter.",showIcon:!0}),c&&(0,t.jsxs)("div",{children:[(0,t.jsx)(f.Typography.Title,{level:5,children:"Results"}),(0,t.jsx)(ej.Alert,{type:"success",message:`${c.selectedTools} tools selected`,description:`Filtered from ${c.totalTools} available tools`,showIcon:!0,style:{marginBottom:16}}),(0,t.jsxs)("div",{children:[(0,t.jsx)(f.Typography.Text,{strong:!0,style:{display:"block",marginBottom:8},children:"Selected Tools:"}),(0,t.jsx)("ul",{style:{paddingLeft:20,margin:0},children:c.tools.map((e,s)=>(0,t.jsx)("li",{style:{marginBottom:4},children:(0,t.jsx)(f.Typography.Text,{children:e})},s))})]})]})]})},{key:"api",label:"API Usage",children:(0,t.jsxs)("div",{children:[(0,t.jsxs)(eM.Space,{style:{marginBottom:8},children:[(0,t.jsx)(tz.CodeOutlined,{}),(0,t.jsx)(f.Typography.Text,{strong:!0,children:"API Usage"})]}),(0,t.jsx)(f.Typography.Text,{type:"secondary",style:{display:"block",marginBottom:8},children:"Use this curl command to test the semantic filter with your current configuration."}),(0,t.jsx)(f.Typography.Text,{strong:!0,style:{display:"block",marginBottom:8},children:"Response headers to check:"}),(0,t.jsxs)("ul",{style:{paddingLeft:20,margin:"0 0 12px 0"},children:[(0,t.jsxs)("li",{children:[(0,t.jsx)(f.Typography.Text,{children:"x-litellm-semantic-filter: shows total tools → selected tools"}),(0,t.jsx)(f.Typography.Text,{type:"secondary",style:{display:"block"},children:"Example: 10→3"})]}),(0,t.jsxs)("li",{children:[(0,t.jsx)(f.Typography.Text,{children:"x-litellm-semantic-filter-tools: CSV of selected tool names"}),(0,t.jsx)(f.Typography.Text,{type:"secondary",style:{display:"block"},children:"Example: wikipedia-fetch,github-search,slack-post"})]})]}),(0,t.jsx)("pre",{style:{background:"#f5f5f5",padding:12,borderRadius:4,overflow:"auto",fontSize:12,margin:0},children:d})]})}]})})}let tD=async({accessToken:e,testModel:t,testQuery:s,setIsTesting:r,setTestResult:l})=>{if(!s||!t||!e)return void C.default.error("Please enter a query and select a model");r(!0),l(null);try{let{headers:r}=await (0,_.testMCPSemanticFilter)(e,t,s),a=(e=>{if(!e.filter)return null;let[t,s]=e.filter.split("->").map(Number);return{totalTools:t,selectedTools:s,tools:e.tools?e.tools.split(",").map(e=>e.trim()):[]}})(r);if(!a)return void C.default.warning("Semantic filter is not enabled or no tools were filtered");l(a),C.default.success("Semantic filter test completed successfully")}catch(e){console.error("Test failed:",e),C.default.error("Failed to test semantic filter")}finally{r(!1)}};function tH({accessToken:e}){var s;let l,{data:a,isLoading:n,isError:i,error:o}=(()=>{let{accessToken:e}=(0,w.default)();return(0,y.useQuery)({queryKey:tP.list({}),queryFn:async()=>await (0,_.getMCPSemanticFilterSettings)(e),enabled:!!e,staleTime:36e5,gcTime:36e5})})(),{mutate:c,isPending:d,error:m}=(s=e||"",l=(0,v.useQueryClient)(),(0,tf.useMutation)({mutationFn:async e=>{if(!s)throw Error("Access token is required");return(0,_.updateMCPSemanticFilterSettings)(s,e)},onSuccess:()=>{l.invalidateQueries({queryKey:tO.all})}})),[u]=D.Form.useForm(),[x,h]=(0,b.useState)(!1),[j,N]=(0,b.useState)(!1),[S,T]=(0,b.useState)([]),[k,A]=(0,b.useState)(!0),[I,P]=(0,b.useState)(""),[O,M]=(0,b.useState)("gpt-4o"),[F,E]=(0,b.useState)(null),[L,R]=(0,b.useState)(!1),U=a?.field_schema,z=a?.values??{};(0,b.useEffect)(()=>{(async()=>{if(e)try{A(!0);let t=(await (0,tU.fetchAvailableModels)(e)).filter(e=>"embedding"===e.mode);T(t)}catch(e){console.error("Error fetching embedding models:",e)}finally{A(!1)}})()},[e]),(0,b.useEffect)(()=>{z&&(u.setFieldsValue({enabled:z.enabled??!1,embedding_model:z.embedding_model??"text-embedding-3-small",top_k:z.top_k??10,similarity_threshold:z.similarity_threshold??.3}),N(!1))},[z,u]);let B=async()=>{try{let e=await u.validateFields();c(e,{onSuccess:()=>{N(!1),h(!0),setTimeout(()=>h(!1),3e3),C.default.success("Settings updated successfully. Changes will be applied across all pods within 10 seconds.")},onError:e=>{C.default.fromBackend(e)}})}catch(e){console.error("Form validation failed:",e)}},q=async()=>{e&&await tD({accessToken:e,testModel:O,testQuery:I,setIsTesting:R,setTestResult:E})};return e?(0,t.jsx)("div",{style:{width:"100%"},children:n?(0,t.jsx)(tE.Skeleton,{active:!0}):i?(0,t.jsx)(ej.Alert,{type:"error",message:"Could not load MCP Semantic Filter settings",description:o instanceof Error?o.message:void 0,style:{marginBottom:24}}):(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(ej.Alert,{type:"info",message:"Semantic Tool Filtering",description:"Filter MCP tools semantically based on query relevance. This reduces context window size and improves tool selection accuracy. Click 'Save Settings' to apply changes across all pods (takes effect within 10 seconds).",showIcon:!0,style:{marginBottom:24}}),x&&(0,t.jsx)(ej.Alert,{type:"success",message:"Settings saved successfully",icon:(0,t.jsx)(ey.CheckCircleOutlined,{}),showIcon:!0,closable:!0,style:{marginBottom:16}}),m&&(0,t.jsx)(ej.Alert,{type:"error",message:"Could not update settings",description:m instanceof Error?m.message:void 0,style:{marginBottom:16}}),(0,t.jsxs)(tF.Row,{gutter:24,children:[(0,t.jsx)(tM.Col,{xs:24,lg:12,children:(0,t.jsxs)(D.Form,{form:u,layout:"vertical",disabled:d,onValuesChange:()=>{N(!0)},children:[(0,t.jsxs)(e4.Card,{style:{marginBottom:16},children:[(0,t.jsx)(D.Form.Item,{name:"enabled",label:(0,t.jsxs)(eM.Space,{children:[(0,t.jsx)(f.Typography.Text,{strong:!0,children:"Enable Semantic Filtering"}),(0,t.jsx)(g.Tooltip,{title:"When enabled, only the most relevant MCP tools will be included in requests based on semantic similarity",children:(0,t.jsx)(r.QuestionCircleOutlined,{style:{color:"#8c8c8c"}})})]}),valuePropName:"checked",children:(0,t.jsx)(el.Switch,{disabled:d})}),(0,t.jsx)(f.Typography.Text,{type:"secondary",style:{display:"block",marginTop:-16,marginBottom:16},children:U?.properties?.enabled?.description})]}),(0,t.jsxs)(e4.Card,{title:"Configuration",style:{marginBottom:16},children:[(0,t.jsx)(D.Form.Item,{name:"embedding_model",label:(0,t.jsxs)(eM.Space,{children:[(0,t.jsx)(f.Typography.Text,{strong:!0,children:"Embedding Model"}),(0,t.jsx)(g.Tooltip,{title:"The model used to generate embeddings for semantic matching",children:(0,t.jsx)(r.QuestionCircleOutlined,{style:{color:"#8c8c8c"}})})]}),children:(0,t.jsx)(p.Select,{options:S.map(e=>({label:e.model_group,value:e.model_group})),placeholder:k?"Loading models...":"Select embedding model",showSearch:!0,disabled:d||k,loading:k,notFoundContent:k?"Loading...":"No embedding models available"})}),(0,t.jsx)(D.Form.Item,{name:"top_k",label:(0,t.jsxs)(eM.Space,{children:[(0,t.jsx)(f.Typography.Text,{strong:!0,children:"Top K Results"}),(0,t.jsx)(g.Tooltip,{title:"Maximum number of tools to return after filtering",children:(0,t.jsx)(r.QuestionCircleOutlined,{style:{color:"#8c8c8c"}})})]}),children:(0,t.jsx)(ec.InputNumber,{min:1,max:100,style:{width:"100%"},disabled:d})}),(0,t.jsx)(D.Form.Item,{name:"similarity_threshold",label:(0,t.jsxs)(eM.Space,{children:[(0,t.jsx)(f.Typography.Text,{strong:!0,children:"Similarity Threshold"}),(0,t.jsx)(g.Tooltip,{title:"Minimum similarity score (0-1) for a tool to be included",children:(0,t.jsx)(r.QuestionCircleOutlined,{style:{color:"#8c8c8c"}})})]}),children:(0,t.jsx)(tL.Slider,{min:0,max:1,step:.05,marks:{0:"0.0",.3:"0.3",.5:"0.5",.7:"0.7",1:"1.0"},disabled:d})})]}),(0,t.jsx)("div",{style:{display:"flex",justifyContent:"flex-end",gap:8},children:(0,t.jsx)(eb.Button,{type:"primary",icon:(0,t.jsx)(tR.SaveOutlined,{}),onClick:B,loading:d,disabled:!j,children:"Save Settings"})})]})}),(0,t.jsx)(tM.Col,{xs:24,lg:12,children:(0,t.jsx)(t$,{accessToken:e,testQuery:I,setTestQuery:P,testModel:O,setTestModel:M,isTesting:L,onTest:q,filterEnabled:!!z.enabled,testResult:F,curlCommand:`curl --location 'http://localhost:4000/v1/responses' \\ -======== }`,copyKey:"cursor-config",className:"text-xs"})})]})]})]})]}),{})}),(0,t.jsx)(o.TabPanel,{className:"mt-6",children:(0,t.jsx)(()=>(0,t.jsxs)(eM.Space,{direction:"vertical",size:"large",className:"w-full",children:[(0,t.jsxs)("div",{className:"bg-gradient-to-r from-green-50 to-teal-50 p-6 rounded-lg border border-green-100",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3 mb-3",children:[(0,t.jsx)(e9,{className:"text-green-600",size:24}),(0,t.jsx)(tl,{level:4,className:"mb-0 text-green-900",children:"Streamable HTTP Transport"})]}),(0,t.jsx)(ta,{className:"text-green-700",children:"Connect to LiteLLM MCP using HTTP transport. Compatible with any MCP client that supports HTTP streaming."})]}),(0,t.jsx)(ti,{icon:(0,t.jsx)(e9,{className:"text-green-600",size:16}),title:"Universal MCP Connection",description:"Use this URL with any MCP client that supports HTTP transport",children:(0,t.jsxs)(eM.Space,{direction:"vertical",size:"middle",className:"w-full",children:[(0,t.jsx)("div",{children:(0,t.jsx)(ta,{children:"Each MCP client supports different transports. Refer to your client documentation to determine the appropriate transport method."})}),(0,t.jsx)(g,{title:"Server URL",code:`${s}/mcp`,copyKey:"http-server-url"}),(0,t.jsx)(g,{title:"Headers Configuration",code:JSON.stringify({"x-litellm-api-key":"Bearer YOUR_LITELLM_API_KEY"},null,2),copyKey:"http-headers"}),(0,t.jsx)("div",{className:"mt-4",children:(0,t.jsx)(eb.Button,{type:"link",className:"p-0 h-auto text-blue-600 hover:text-blue-700",href:"https://modelcontextprotocol.io/docs/concepts/transports",icon:(0,t.jsx)(te.ExternalLinkIcon,{size:14}),children:"Learn more about MCP transports"})})]})})]}),{})})]})]})]})})};var tc=e.i(752978),td=e.i(591935),tm=e.i(492030);let tu=({server:e,isLoadingHealth:s,isRechecking:r,onRecheck:l})=>{let[a,n]=(0,b.useState)(!1),i=e.status||"unknown",o=e.last_health_check,c=e.health_check_error;if(s||r)return(0,t.jsxs)("span",{className:"inline-flex items-center gap-1.5 text-xs text-gray-400 px-2 py-0.5 rounded-full bg-gray-50 border border-gray-100",children:[(0,t.jsx)("span",{className:"h-1.5 w-1.5 rounded-full bg-gray-300 animate-pulse"}),"Checking"]});let d=!!l,m=(0,t.jsxs)("div",{className:"max-w-xs",children:[(0,t.jsxs)("div",{className:"font-semibold mb-1",children:["Health Status: ",i]}),o&&(0,t.jsxs)("div",{className:"text-xs mb-1",children:["Last Check: ",new Date(o).toLocaleString()]}),c&&(0,t.jsxs)("div",{className:"text-xs",children:[(0,t.jsx)("div",{className:"font-medium text-red-400 mb-1",children:"Error:"}),(0,t.jsx)("div",{className:"break-words",children:c})]}),!o&&!c&&(0,t.jsx)("div",{className:"text-xs text-gray-400",children:"No health check data available"}),d&&(0,t.jsx)("div",{className:"text-xs text-gray-400 mt-1",children:"Click to recheck"})]});return(0,t.jsx)(g.Tooltip,{title:m,placement:"top",children:(0,t.jsxs)("span",{className:`inline-flex items-center gap-1 text-xs font-medium px-2 py-0.5 rounded-full ${(e=>{switch(e){case"healthy":return"text-green-700 bg-green-50 border border-green-200";case"unhealthy":return"text-red-700 bg-red-50 border border-red-200";default:return"text-gray-600 bg-gray-50 border border-gray-200"}})(i)} ${d?"cursor-pointer hover:opacity-80":"cursor-default"}`,onMouseEnter:()=>n(!0),onMouseLeave:()=>n(!1),onClick:d?()=>l(e.server_id):void 0,children:[(0,t.jsx)("span",{children:a&&d?"↻":(e=>{switch(e){case"healthy":return"✓";case"unhealthy":return"✗";default:return"?"}})(i)}),a&&d?"Recheck":i.charAt(0).toUpperCase()+i.slice(1)]})})};var tx=e.i(530212),th=e.i(848725);let tp=b.forwardRef(function(e,t){return b.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",strokeWidth:2,stroke:"currentColor","aria-hidden":"true",ref:t},e),b.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21"}))});var tg=e.i(350967),tf=e.i(954616);function tb(e){if(!e)return[];if(Array.isArray(e))return e.map(e=>tj(e)).filter(e=>void 0!==e);let t=tj(e);return void 0===t?[]:[t]}function tj(e,t){if(!e)return;let s=void 0!==t?t:e.default;if("object"===e.type){let t="object"!=typeof s||null===s||Array.isArray(s)?{}:{...s};return e.properties&&Object.entries(e.properties).forEach(([e,s])=>{t[e]=tj(s,t[e])}),t}if("array"===e.type){if(Array.isArray(s)){let t=e.items;if(!t)return s;if(0===s.length){let e=tb(t);return e.length?e:s}return Array.isArray(t)?s.map((e,s)=>tj(t[s]??t[t.length-1],e)):s.map(e=>tj(t,e))}return void 0!==s?s:tb(e.items)}if(void 0!==s)return s;switch(e.type){case"integer":case"number":return 0;case"boolean":return!1;default:return""}}let ty=e=>{let t=tj(e);if("object"===e.type||"array"===e.type){let s="array"===e.type?[]:{};return JSON.stringify(t??s,null,2)}return t};function tv({tool:e,onSubmit:s,isLoading:r,result:a,error:n,onClose:i}){let[o]=D.Form.useForm(),[c,d]=b.default.useState("formatted"),[m,u]=b.default.useState(null),[x,h]=b.default.useState(null),f=b.default.useMemo(()=>"string"==typeof e.inputSchema?{type:"object",properties:{input:{type:"string",description:"Input for this tool"}},required:["input"]}:e.inputSchema,[e.inputSchema]),j=b.default.useMemo(()=>f.properties&&f.properties.params&&"object"===f.properties.params.type&&f.properties.params.properties?{type:"object",properties:f.properties.params.properties,required:f.properties.params.required||[]}:f,[f]);b.default.useEffect(()=>{if(o.resetFields(),!j.properties)return;let e={};Object.entries(j.properties).forEach(([t,s])=>{e[t]=ty(s)}),o.setFieldsValue(e)},[o,j,e]),b.default.useEffect(()=>{m&&(a||n)&&h(Date.now()-m)},[a,n,m]);let y=async e=>{try{if(navigator.clipboard&&window.isSecureContext)return await navigator.clipboard.writeText(e),!0;{let t=document.createElement("textarea");t.value=e,t.style.position="fixed",t.style.opacity="0",document.body.appendChild(t),t.focus(),t.select();let s=document.execCommand("copy");if(document.body.removeChild(t),!s)throw Error("execCommand failed");return!0}}catch(e){return console.error("Copy failed:",e),!1}},v=async()=>{await y(JSON.stringify(a,null,2))?C.default.success("Result copied to clipboard"):C.default.fromBackend("Failed to copy result")},N=async()=>{await y(e.name)?C.default.success("Tool name copied to clipboard"):C.default.fromBackend("Failed to copy tool name")};return(0,t.jsxs)("div",{className:"space-y-4 h-full",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between pb-3 border-b border-gray-200",children:[(0,t.jsxs)("div",{className:"flex items-center space-x-3",children:[e.mcp_info.logo_url&&(0,t.jsx)("img",{src:e.mcp_info.logo_url,alt:`${e.mcp_info.server_name} logo`,className:"w-6 h-6 object-contain"}),(0,t.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,t.jsxs)("div",{className:"flex items-center space-x-2 mb-1",children:[(0,t.jsx)("h2",{className:"text-lg font-semibold text-gray-900",children:"Test Tool:"}),(0,t.jsxs)("div",{className:"group inline-flex items-center space-x-1 bg-slate-50 hover:bg-slate-100 px-3 py-1 rounded-md cursor-pointer transition-colors border border-slate-200",onClick:N,title:"Click to copy tool name",children:[(0,t.jsx)("span",{className:"font-mono text-slate-700 font-medium text-sm",children:e.name}),(0,t.jsx)("svg",{className:"w-3 h-3 text-slate-400 group-hover:text-slate-600 transition-colors",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"})})]})]}),(0,t.jsx)("p",{className:"text-xs text-gray-600",children:e.description}),(0,t.jsxs)("p",{className:"text-xs text-gray-500",children:["Provider: ",e.mcp_info.server_name]})]})]}),(0,t.jsx)(l.Button,{onClick:i,variant:"light",size:"sm",className:"text-gray-500 hover:text-gray-700",children:(0,t.jsx)("svg",{className:"w-4 h-4",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M6 18L18 6M6 6l12 12"})})})]}),(0,t.jsxs)("div",{className:"grid grid-cols-2 gap-4 h-full",children:[(0,t.jsxs)("div",{className:"bg-white border border-gray-200 rounded-lg",children:[(0,t.jsx)("div",{className:"border-b border-gray-100 px-4 py-2",children:(0,t.jsxs)("div",{className:"flex items-center justify-between",children:[(0,t.jsx)("h3",{className:"text-sm font-semibold text-gray-900",children:"Input Parameters"}),(0,t.jsx)(g.Tooltip,{title:"Configure the input parameters for this tool call",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"text-gray-400 hover:text-gray-600"})})]})}),(0,t.jsx)("div",{className:"p-4",children:(0,t.jsxs)(D.Form,{form:o,onFinish:e=>{u(Date.now()),h(null);let t={};Object.entries(e).forEach(([e,s])=>{let r=j.properties?.[e];if(r&&null!=s&&""!==s)switch(r.type){case"boolean":t[e]="true"===s||!0===s;break;case"number":case"integer":{let l=Number(s);t[e]=Number.isNaN(l)?s:"integer"===r.type?Math.trunc(l):l;break}case"object":case"array":try{let l="string"==typeof s?JSON.parse(s):s,a="object"===r.type&&null!==l&&"object"==typeof l&&!Array.isArray(l),n="array"===r.type&&Array.isArray(l);"object"===r.type&&a||"array"===r.type&&n?t[e]=l:t[e]=s}catch(r){t[e]=s}break;case"string":t[e]=String(s);break;default:t[e]=s}else null!=s&&""!==s&&(t[e]=s)}),s(f.properties&&f.properties.params&&"object"===f.properties.params.type&&f.properties.params.properties?{params:t}:t)},layout:"vertical",className:"space-y-3",children:["string"==typeof e.inputSchema?(0,t.jsx)("div",{className:"space-y-3",children:(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700",children:["Input ",(0,t.jsx)("span",{className:"text-red-500",children:"*"})]}),name:"input",rules:[{required:!0,message:"Please enter input for this tool"}],className:"mb-3",children:(0,t.jsx)(ei.TextInput,{placeholder:"Enter input for this tool",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})})}):void 0===j.properties?(0,t.jsx)("div",{className:"text-center py-6 bg-gray-50 rounded-lg border border-gray-200",children:(0,t.jsxs)("div",{className:"max-w-sm mx-auto",children:[(0,t.jsx)("h4",{className:"text-sm font-medium text-gray-900 mb-1",children:"No Parameters Required"}),(0,t.jsx)("p",{className:"text-xs text-gray-500",children:"This tool can be called without any input parameters."})]})}):(0,t.jsx)("div",{className:"space-y-3",children:Object.entries(j.properties).map(([s,r])=>{let l=ty(r),a=`${e.name}-${s}`;return(0,t.jsxs)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:[s," ",j.required?.includes(s)&&(0,t.jsx)("span",{className:"text-red-500",children:"*"}),r.description&&(0,t.jsx)(g.Tooltip,{title:r.description,children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-gray-400 hover:text-gray-600"})})]}),name:s,initialValue:l,rules:[{required:j.required?.includes(s),message:`Please enter ${s}`},..."object"===r.type||"array"===r.type?[{validator:(e,t)=>{if((null==t||""===t)&&!j.required?.includes(s))return Promise.resolve();try{let e="string"==typeof t?JSON.parse(t):t,s="object"===r.type&&null!==e&&"object"==typeof e&&!Array.isArray(e),l="array"===r.type&&Array.isArray(e);if("object"===r.type&&s||"array"===r.type&&l)return Promise.resolve();return Promise.reject(Error("object"===r.type?"Please enter a JSON object":"Please enter a JSON array"))}catch(e){return Promise.reject(Error("Invalid JSON"))}}}]:[]],className:"mb-3",children:["string"===r.type&&r.enum&&(0,t.jsxs)("select",{className:"w-full px-3 py-2 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm transition-colors",defaultValue:l??"",children:[!j.required?.includes(s)&&(0,t.jsxs)("option",{value:"",children:["Select ",s]}),r.enum.map(e=>(0,t.jsx)("option",{value:e,children:e},e))]}),"string"===r.type&&!r.enum&&(0,t.jsx)(ei.TextInput,{placeholder:r.description||`Enter ${s}`,defaultValue:l??"",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"}),("number"===r.type||"integer"===r.type)&&(0,t.jsx)("input",{type:"number",step:"integer"===r.type?1:"any",placeholder:r.description||`Enter ${s}`,defaultValue:l??0,className:"w-full px-3 py-2 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm transition-colors"}),"boolean"===r.type&&(0,t.jsxs)(p.Select,{placeholder:`Select ${s}`,allowClear:!j.required?.includes(s),className:"w-full",children:[(0,t.jsx)(p.Select.Option,{value:!0,children:"True"}),(0,t.jsx)(p.Select.Option,{value:!1,children:"False"})]}),("object"===r.type||"array"===r.type)&&(0,t.jsxs)("div",{className:"space-y-2",children:[(0,t.jsx)("textarea",{rows:"object"===r.type?6:4,placeholder:r.description||("object"===r.type?`Enter JSON object for ${s}`:`Enter JSON array for ${s}`),defaultValue:l??("object"===r.type?"{}":"[]"),spellCheck:!1,"data-testid":`textarea-${s}`,className:"w-full px-3 py-2 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm font-mono"}),(0,t.jsx)("p",{className:"text-xs text-gray-500",children:"object"===r.type?"Provide a valid JSON object.":"Provide a valid JSON array."})]})]},a)})}),(0,t.jsx)("div",{className:"pt-3 border-t border-gray-100",children:(0,t.jsx)(l.Button,{onClick:()=>o.submit(),disabled:r,variant:"primary",className:"w-full",loading:r,children:r?"Calling Tool...":a||n?"Call Again":"Call Tool"})})]})})]}),(0,t.jsxs)("div",{className:"bg-white border border-gray-200 rounded-lg",children:[(0,t.jsx)("div",{className:"border-b border-gray-100 px-4 py-2",children:(0,t.jsx)("h3",{className:"text-sm font-semibold text-gray-900",children:"Tool Result"})}),(0,t.jsx)("div",{className:"p-4",children:a||n||r?(0,t.jsxs)("div",{className:"space-y-3",children:[a&&!r&&!n&&(0,t.jsx)("div",{className:"p-2 bg-green-50 border border-green-200 rounded-lg",children:(0,t.jsxs)("div",{className:"flex items-center justify-between",children:[(0,t.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,t.jsx)("svg",{className:"h-4 w-4 text-green-500",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"})}),(0,t.jsx)("h4",{className:"text-xs font-medium text-green-900",children:"Tool executed successfully"}),null!==x&&(0,t.jsxs)("span",{className:"text-xs text-green-600 ml-1",children:["• ",(x/1e3).toFixed(2),"s"]})]}),(0,t.jsxs)("div",{className:"flex items-center space-x-1",children:[(0,t.jsxs)("div",{className:"flex bg-white rounded border border-green-300 p-0.5",children:[(0,t.jsx)("button",{onClick:()=>d("formatted"),className:`px-2 py-1 text-xs font-medium rounded transition-colors ${"formatted"===c?"bg-green-100 text-green-800":"text-green-600 hover:text-green-800"}`,children:"Formatted"}),(0,t.jsx)("button",{onClick:()=>d("json"),className:`px-2 py-1 text-xs font-medium rounded transition-colors ${"json"===c?"bg-green-100 text-green-800":"text-green-600 hover:text-green-800"}`,children:"JSON"})]}),(0,t.jsx)("button",{onClick:v,className:"p-1 hover:bg-green-100 rounded text-green-700",title:"Copy response",children:(0,t.jsxs)("svg",{xmlns:"http://www.w3.org/2000/svg",width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[(0,t.jsx)("rect",{x:"9",y:"9",width:"13",height:"13",rx:"2",ry:"2"}),(0,t.jsx)("path",{d:"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"})]})})]})]})}),(0,t.jsxs)("div",{className:"max-h-96 overflow-y-auto",children:[r&&(0,t.jsxs)("div",{className:"flex flex-col justify-center items-center h-48 text-gray-500",children:[(0,t.jsxs)("div",{className:"relative",children:[(0,t.jsx)("div",{className:"animate-spin rounded-full h-8 w-8 border-2 border-gray-200"}),(0,t.jsx)("div",{className:"animate-spin rounded-full h-8 w-8 border-2 border-blue-600 border-t-transparent absolute top-0"})]}),(0,t.jsx)("p",{className:"text-sm font-medium mt-3",children:"Calling tool..."}),(0,t.jsx)("p",{className:"text-xs text-gray-400 mt-1",children:"Please wait while we process your request"})]}),n&&(0,t.jsx)("div",{className:"bg-red-50 border border-red-200 rounded-lg p-3",children:(0,t.jsxs)("div",{className:"flex items-start space-x-2",children:[(0,t.jsx)("div",{className:"flex-shrink-0",children:(0,t.jsx)("svg",{className:"h-4 w-4 text-red-400",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"})})}),(0,t.jsxs)("div",{className:"flex-1",children:[(0,t.jsxs)("div",{className:"flex items-center space-x-2 mb-1",children:[(0,t.jsx)("h4",{className:"text-xs font-medium text-red-900",children:"Tool Call Failed"}),null!==x&&(0,t.jsxs)("span",{className:"text-xs text-red-600",children:["• ",(x/1e3).toFixed(2),"s"]})]}),(0,t.jsx)("div",{className:"bg-white border border-red-200 rounded p-2 max-h-48 overflow-y-auto",children:(0,t.jsx)("pre",{className:"text-xs whitespace-pre-wrap text-red-700 font-mono",children:n.message})})]})]})}),a&&!r&&!n&&(0,t.jsx)("div",{className:"space-y-3",children:"formatted"===c?a.map((e,s)=>(0,t.jsxs)("div",{className:"border border-gray-200 rounded-lg overflow-hidden",children:["text"===e.type&&(0,t.jsxs)("div",{children:[(0,t.jsx)("div",{className:"bg-gray-50 px-3 py-1 border-b border-gray-200",children:(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:"Text Response"})}),(0,t.jsx)("div",{className:"p-3",children:(0,t.jsx)("div",{className:"bg-white rounded border border-gray-200 max-h-64 overflow-y-auto",children:(0,t.jsx)("div",{className:"p-3 space-y-2",children:e.text.split("\n\n").map((e,s)=>{if(""===e.trim())return null;if(e.startsWith("##")){let r=e.replace(/^#+\s/,"");return(0,t.jsx)("div",{className:"border-b border-gray-200 pb-1 mb-2",children:(0,t.jsx)("h3",{className:"text-sm font-semibold text-gray-900",children:r})},s)}let r=/(https?:\/\/[^\s\)]+)/g;if(r.test(e)){let l=e.split(r);return(0,t.jsx)("div",{className:"bg-blue-50 border border-blue-200 rounded p-2",children:(0,t.jsx)("div",{className:"text-xs text-gray-700 leading-relaxed whitespace-pre-wrap",children:l.map((e,s)=>r.test(e)?(0,t.jsx)("a",{href:e,target:"_blank",rel:"noopener noreferrer",className:"text-blue-600 hover:text-blue-800 underline break-all",children:e},s):e)})},s)}return e.includes("Score:")?(0,t.jsx)("div",{className:"bg-green-50 border-l-4 border-green-400 p-2 rounded-r",children:(0,t.jsx)("p",{className:"text-xs text-green-800 font-medium whitespace-pre-wrap",children:e})},s):(0,t.jsx)("div",{className:"bg-gray-50 rounded p-2 border border-gray-200",children:(0,t.jsx)("div",{className:"text-xs text-gray-700 leading-relaxed whitespace-pre-wrap font-mono",children:e})},s)}).filter(Boolean)})})})]}),"image"===e.type&&e.url&&(0,t.jsxs)("div",{children:[(0,t.jsx)("div",{className:"bg-gray-50 px-3 py-1 border-b border-gray-200",children:(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:"Image Response"})}),(0,t.jsx)("div",{className:"p-3",children:(0,t.jsx)("div",{className:"bg-gray-50 rounded p-3 border border-gray-200",children:(0,t.jsx)("img",{src:e.url,alt:"Tool result",className:"max-w-full h-auto rounded shadow-sm"})})})]}),"embedded_resource"===e.type&&(0,t.jsxs)("div",{children:[(0,t.jsx)("div",{className:"bg-gray-50 px-3 py-1 border-b border-gray-200",children:(0,t.jsx)("span",{className:"text-xs font-medium text-gray-700 uppercase tracking-wide",children:"Embedded Resource"})}),(0,t.jsx)("div",{className:"p-3",children:(0,t.jsxs)("div",{className:"flex items-center space-x-2 p-3 bg-blue-50 border border-blue-200 rounded",children:[(0,t.jsx)("div",{className:"flex-shrink-0",children:(0,t.jsx)("svg",{className:"h-5 w-5 text-blue-500",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"})})}),(0,t.jsxs)("div",{className:"flex-1",children:[(0,t.jsxs)("p",{className:"text-xs font-medium text-blue-900",children:["Resource Type: ",e.resource_type]}),e.url&&(0,t.jsxs)("a",{href:e.url,target:"_blank",rel:"noopener noreferrer",className:"inline-flex items-center text-xs text-blue-600 hover:text-blue-800 hover:underline mt-1 transition-colors",children:["View Resource",(0,t.jsxs)("svg",{className:"ml-1 h-3 w-3",fill:"currentColor",viewBox:"0 0 20 20",children:[(0,t.jsx)("path",{d:"M11 3a1 1 0 100 2h2.586l-6.293 6.293a1 1 0 101.414 1.414L15 6.414V9a1 1 0 102 0V4a1 1 0 00-1-1h-5z"}),(0,t.jsx)("path",{d:"M5 5a2 2 0 00-2 2v8a2 2 0 002 2h8a2 2 0 002-2v-3a1 1 0 10-2 0v3H5V7h3a1 1 0 000-2H5z"})]})]})]})]})})]})]},s)):(0,t.jsx)("div",{className:"bg-white rounded border border-gray-200",children:(0,t.jsx)("div",{className:"p-3 overflow-auto max-h-80 bg-gray-50",children:(0,t.jsx)("pre",{className:"text-xs font-mono whitespace-pre-wrap break-all text-gray-800",children:JSON.stringify(a,null,2)})})})})]})]}):(0,t.jsx)("div",{className:"flex flex-col justify-center items-center h-48 text-gray-500",children:(0,t.jsxs)("div",{className:"text-center max-w-sm",children:[(0,t.jsx)("div",{className:"mb-3",children:(0,t.jsx)("svg",{className:"mx-auto h-12 w-12 text-gray-300",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:1,d:"M13 10V3L4 14h7v7l9-11h-7z"})})}),(0,t.jsx)("h4",{className:"text-sm font-medium text-gray-900 mb-1",children:"Ready to Call Tool"}),(0,t.jsx)("p",{className:"text-xs text-gray-500 leading-relaxed",children:'Configure the input parameters and click "Call Tool" to see the results here.'})]})})})]})]})]})}var tN=e.i(983561),t_=e.i(438957);let tw=({serverId:e,accessToken:s,auth_type:r,userRole:l,userID:a,serverAlias:n,extraHeaders:i})=>{let[o,c]=(0,b.useState)(null),[u,x]=(0,b.useState)(null),[h,p]=(0,b.useState)(null),[g,f]=(0,b.useState)(""),[j,v]=(0,b.useState)({}),[N,w]=(0,b.useState)(!1),S=i&&i.length>0,C=()=>{if(!n||!S)return;let e={};return Object.entries(j).forEach(([t,s])=>{s&&s.trim()&&(e[`x-mcp-${n}-${t.toLowerCase()}`]=s)}),Object.keys(e).length>0?e:void 0},{data:T,isLoading:k,error:A,refetch:I}=(0,y.useQuery)({queryKey:["mcpTools",e,j],queryFn:()=>{if(!s)throw Error("Access Token required");return(0,_.listMCPTools)(s,e,C())},enabled:!!s,staleTime:3e4}),{mutate:P,isPending:O}=(0,tf.useMutation)({mutationFn:async t=>{if(!s)throw Error("Access Token required");try{return await (0,_.callMCPTool)(s,e,t.tool.name,t.arguments,{customHeaders:C()})}catch(e){throw e}},onSuccess:e=>{x(e.content),p(null)},onError:e=>{p(e),x(null)}}),M=T?.tools||[],F=M.filter(e=>{let t=g.toLowerCase();return e.name.toLowerCase().includes(t)||e.description&&e.description.toLowerCase().includes(t)||e.mcp_info.server_name&&e.mcp_info.server_name.toLowerCase().includes(t)});return(0,t.jsx)("div",{className:"w-full h-screen p-4 bg-white",children:(0,t.jsx)(eg.Card,{className:"w-full rounded-xl shadow-md overflow-hidden",children:(0,t.jsxs)("div",{className:"flex h-auto w-full gap-4",children:[(0,t.jsxs)("div",{className:"w-1/4 p-4 bg-gray-50 flex flex-col",children:[(0,t.jsx)(m.Title,{className:"text-xl font-semibold mb-6 mt-2",children:"MCP Tools"}),(0,t.jsxs)("div",{className:"flex flex-col flex-1",children:[S&&(0,t.jsxs)("div",{className:"mb-4 p-3 bg-blue-50 border border-blue-200 rounded-lg",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between mb-2",children:[(0,t.jsxs)("div",{className:"flex items-center",children:[(0,t.jsx)(t_.KeyOutlined,{className:"text-blue-600 mr-2"}),(0,t.jsx)(d.Text,{className:"text-sm font-medium text-blue-800",children:"Additional Headers"})]}),(0,t.jsx)(eb.Button,{size:"small",type:"link",onClick:()=>w(!N),className:"text-blue-700 p-0 h-auto",children:N?"Hide":"Configure"})]}),!N&&0===Object.keys(j).length&&(0,t.jsx)(d.Text,{className:"text-xs text-blue-700",children:'This server requires additional headers. Click "Configure" to provide values.'}),N&&(0,t.jsxs)("div",{className:"mt-3 space-y-2",children:[i?.map(e=>(0,t.jsxs)("div",{children:[(0,t.jsx)("label",{className:"block text-xs font-medium text-gray-700 mb-1",children:e}),(0,t.jsx)(H.Input,{size:"small",placeholder:`Enter ${e}`,value:j[e]||"",onChange:t=>{v({...j,[e]:t.target.value})},prefix:(0,t.jsx)(t_.KeyOutlined,{className:"text-gray-400"}),className:"rounded"})]},e)),(0,t.jsx)(eb.Button,{size:"small",type:"primary",onClick:()=>{I(),w(!1)},disabled:Object.values(j).every(e=>!e||!e.trim()),className:"w-full mt-2",children:"Load Tools"})]}),!N&&Object.keys(j).length>0&&(0,t.jsx)("div",{className:"mt-2",children:(0,t.jsxs)(d.Text,{className:"text-xs text-green-700 flex items-center",children:[(0,t.jsx)("span",{className:"inline-block w-2 h-2 bg-green-500 rounded-full mr-2"}),Object.keys(j).length," header(s) configured"]})})]}),(0,t.jsxs)("div",{className:"flex flex-col flex-1 min-h-0",children:[(0,t.jsxs)(d.Text,{className:"font-medium block mb-3 text-gray-700 flex items-center",children:[(0,t.jsx)(ep.ToolOutlined,{className:"mr-2"})," Available Tools",M.length>0&&(0,t.jsx)("span",{className:"ml-2 bg-blue-100 text-blue-800 text-xs font-medium px-2 py-0.5 rounded-full",children:M.length})]}),M.length>0&&(0,t.jsx)("div",{className:"mb-3",children:(0,t.jsx)(H.Input,{placeholder:"Search tools...",prefix:(0,t.jsx)(ew.SearchOutlined,{className:"text-gray-400"}),value:g,onChange:e=>f(e.target.value),allowClear:!0,className:"rounded-lg",size:"middle"})}),k&&(0,t.jsxs)("div",{className:"flex flex-col items-center justify-center py-8 bg-white border border-gray-200 rounded-lg",children:[(0,t.jsxs)("div",{className:"relative mb-3",children:[(0,t.jsx)("div",{className:"animate-spin rounded-full h-6 w-6 border-2 border-gray-200"}),(0,t.jsx)("div",{className:"animate-spin rounded-full h-6 w-6 border-2 border-blue-600 border-t-transparent absolute top-0"})]}),(0,t.jsx)("p",{className:"text-xs font-medium text-gray-700",children:"Loading tools..."})]}),T?.error&&!k&&!M.length&&(0,t.jsx)("div",{className:"p-3 text-xs text-red-800 rounded-lg bg-red-50 border border-red-200",children:(0,t.jsxs)("p",{className:"font-medium",children:["Error: ",T.message]})}),!k&&!T?.error&&(!M||0===M.length)&&(0,t.jsxs)("div",{className:"p-4 text-center bg-white border border-gray-200 rounded-lg",children:[(0,t.jsx)("div",{className:"mx-auto w-8 h-8 bg-gray-200 rounded-full flex items-center justify-center mb-2",children:(0,t.jsx)("svg",{className:"w-4 h-4 text-gray-400",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 8.172V5L8 4z"})})}),(0,t.jsx)("p",{className:"text-xs font-medium text-gray-700 mb-1",children:"No tools available"}),(0,t.jsx)("p",{className:"text-xs text-gray-500",children:"No tools found for this server"})]}),!k&&!T?.error&&M.length>0&&(0,t.jsx)(t.Fragment,{children:0===F.length?(0,t.jsxs)("div",{className:"p-4 text-center bg-white border border-gray-200 rounded-lg",children:[(0,t.jsx)(ew.SearchOutlined,{className:"text-2xl text-gray-400 mb-2"}),(0,t.jsx)("p",{className:"text-xs font-medium text-gray-700 mb-1",children:"No tools found"}),(0,t.jsxs)("p",{className:"text-xs text-gray-500",children:['No tools match "',g,'"']})]}):(0,t.jsx)("div",{className:"space-y-2 flex-1 overflow-y-auto min-h-0 mcp-tools-scrollable",style:{maxHeight:"400px",scrollbarWidth:"auto",scrollbarColor:"#cbd5e0 #f7fafc"},children:F.map(e=>(0,t.jsxs)("div",{className:`border rounded-lg p-3 cursor-pointer transition-all hover:shadow-sm ${o?.name===e.name?"border-blue-500 bg-blue-50 ring-1 ring-blue-200":"border-gray-200 bg-white hover:border-gray-300"}`,onClick:()=>{c(e),x(null),p(null)},children:[(0,t.jsxs)("div",{className:"flex items-start space-x-2",children:[e.mcp_info.logo_url&&(0,t.jsx)("img",{src:e.mcp_info.logo_url,alt:`${e.mcp_info.server_name} logo`,className:"w-4 h-4 object-contain flex-shrink-0 mt-0.5"}),(0,t.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,t.jsx)("h4",{className:"font-mono text-xs font-medium text-gray-900 truncate",children:e.name}),(0,t.jsx)("p",{className:"text-xs text-gray-500 truncate",children:e.mcp_info.server_name}),(0,t.jsx)("p",{className:"text-xs text-gray-600 mt-1 line-clamp-2 leading-relaxed",children:e.description})]})]}),o?.name===e.name&&(0,t.jsx)("div",{className:"mt-2 pt-2 border-t border-blue-200",children:(0,t.jsxs)("div",{className:"flex items-center text-xs font-medium text-blue-700",children:[(0,t.jsx)("svg",{className:"w-3 h-3 mr-1",fill:"currentColor",viewBox:"0 0 20 20",children:(0,t.jsx)("path",{fillRule:"evenodd",d:"M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z",clipRule:"evenodd"})}),"Selected"]})})]},e.name))})})]})]})]}),(0,t.jsxs)("div",{className:"w-3/4 flex flex-col bg-white",children:[(0,t.jsx)("div",{className:"p-4 border-b border-gray-200 flex justify-between items-center",children:(0,t.jsx)(m.Title,{className:"text-xl font-semibold mb-0",children:"Tool Testing Playground"})}),(0,t.jsx)("div",{className:"flex-1 overflow-auto p-4",children:o?(0,t.jsx)("div",{className:"h-full",children:(0,t.jsx)(tv,{tool:o,onSubmit:e=>{P({tool:o,arguments:e})},result:u,error:h,isLoading:O,onClose:()=>c(null)})}):(0,t.jsxs)("div",{className:"h-full flex flex-col items-center justify-center text-gray-400",children:[(0,t.jsx)(tN.RobotOutlined,{style:{fontSize:"48px",marginBottom:"16px"}}),(0,t.jsx)(d.Text,{className:"text-lg font-medium text-gray-600 mb-2",children:"Select a Tool to Test"}),(0,t.jsx)(d.Text,{className:"text-center text-gray-500 max-w-md",children:"Choose a tool from the left sidebar to start testing its functionality with custom inputs."})]})})]})]})})})},tS=[eo.AUTH_TYPE.API_KEY,eo.AUTH_TYPE.BEARER_TOKEN,eo.AUTH_TYPE.TOKEN,eo.AUTH_TYPE.BASIC],tC=[...tS,eo.AUTH_TYPE.OAUTH2,eo.AUTH_TYPE.AWS_SIGV4],tT="litellm-mcp-oauth-edit-state",tk=({mcpServer:e,accessToken:s,onCancel:r,onSuccess:d,availableAccessGroups:m})=>{let[u]=D.Form.useForm(),[x,h]=(0,b.useState)({}),[f,j]=(0,b.useState)([]),[y,v]=(0,b.useState)(!1),[N,w]=(0,b.useState)(null),[S,T]=(0,b.useState)(""),[k,A]=(0,b.useState)(!1),[I,P]=(0,b.useState)([]),[O,M]=(0,b.useState)({}),[F,E]=(0,b.useState)({}),[L,R]=(0,b.useState)(null),[z,U]=(0,b.useState)(e.mcp_info?.logo_url||void 0),B=D.Form.useWatch("auth_type",u),q=D.Form.useWatch("transport",u),V="stdio"===q,$=q===eo.TRANSPORT.OPENAPI,K=!!B&&tS.includes(B),W=B===eo.AUTH_TYPE.OAUTH2,J=B===eo.AUTH_TYPE.AWS_SIGV4,Y=D.Form.useWatch("oauth_flow_type",u),G=W&&Y===eo.OAUTH_FLOW.M2M,[Q,Z]=(0,b.useState)(null),X=D.Form.useWatch("url",u),ee=D.Form.useWatch("spec_path",u),et=D.Form.useWatch("server_name",u),es=D.Form.useWatch("auth_type",u),er=D.Form.useWatch("static_headers",u),el=D.Form.useWatch("credentials",u),ea=D.Form.useWatch("authorization_url",u),ei=D.Form.useWatch("token_url",u),ed=D.Form.useWatch("registration_url",u),{startOAuthFlow:em,status:eu,error:ex,tokenResponse:eh}=eQ({accessToken:s,getCredentials:()=>u.getFieldValue("credentials"),getTemporaryPayload:()=>{let t=u.getFieldsValue(!0),s=t.url||e.url,r=t.transport||e.transport;if(!s||!r)return null;let l=Array.isArray(t.static_headers)?t.static_headers.reduce((e,t)=>{let s=t?.header?.trim();return s&&(e[s]=t?.value??""),e},{}):{};return{server_id:e.server_id,server_name:t.server_name||e.server_name||e.alias,alias:t.alias||e.alias,description:t.description||e.description,url:s,transport:r,auth_type:eo.AUTH_TYPE.OAUTH2,credentials:t.credentials,mcp_access_groups:t.mcp_access_groups||e.mcp_access_groups,static_headers:l,command:t.command,args:t.args,env:t.env}},onTokenReceived:e=>{if(Z(e?.access_token??null),e?.access_token){let t={access_token:e.access_token,...e.refresh_token&&{refresh_token:e.refresh_token},...e.expires_in&&{expires_in:e.expires_in},...e.scope&&{scope:e.scope}};u.setFieldsValue({credentials:t}),C.default.success("OAuth authorization successful! Please click 'Update MCP Server' to save the credentials.")}},onBeforeRedirect:()=>{try{let t=u.getFieldsValue(!0);(0,eG.setSecureItem)(tT,JSON.stringify({serverId:e.server_id,formValues:t,costConfig:x,allowedTools:I,searchValue:S,aliasManuallyEdited:k}))}catch(e){console.warn("Failed to persist MCP edit state",e)}}}),ep=b.default.useMemo(()=>e.static_headers?Object.entries(e.static_headers).map(([e,t])=>({header:e,value:null!=t?String(t):""})):[],[e.static_headers]),eg=b.default.useMemo(()=>{let t=e.env??void 0;if(!t||0===Object.keys(t).length)return"";try{return JSON.stringify(t,null,2)}catch{return""}},[e.env]),ej=b.default.useMemo(()=>e.spec_path&&"stdio"!==e.transport?eo.TRANSPORT.OPENAPI:e.transport,[e]),ey=b.default.useMemo(()=>({...e,transport:ej,static_headers:ep,extra_headers:e.extra_headers||[],oauth_flow_type:e.token_url?eo.OAUTH_FLOW.M2M:eo.OAUTH_FLOW.INTERACTIVE,token_validation_json:e.token_validation?JSON.stringify(e.token_validation,null,2):void 0}),[e,ej,ep,eg]);(0,b.useEffect)(()=>{e.mcp_info?.mcp_server_cost_info&&h(e.mcp_info.mcp_server_cost_info)},[e]),(0,b.useEffect)(()=>{e.allowed_tools&&P(e.allowed_tools),M(e.tool_name_to_display_name??{}),E(e.tool_name_to_description??{})},[e]),(0,b.useEffect)(()=>{let t=(0,eG.getSecureItem)(tT);if(t)try{let s=JSON.parse(t);if(!s||s.serverId!==e.server_id)return;s.formValues&&R({...e,...s.formValues}),s.costConfig&&h(s.costConfig),s.allowedTools&&P(s.allowedTools),s.searchValue&&T(s.searchValue),"boolean"==typeof s.aliasManuallyEdited&&A(s.aliasManuallyEdited)}catch(e){console.error("Failed to restore MCP edit state",e)}finally{window.sessionStorage.removeItem(tT)}},[u,e]),(0,b.useEffect)(()=>{if(!L)return;let t=L.transport||e.transport;t&&t!==u.getFieldValue("transport")?u.setFieldsValue({transport:t}):(u.setFieldsValue(L),R(null))},[L,u,e.transport]),(0,b.useEffect)(()=>{if(e.mcp_access_groups){let t=e.mcp_access_groups.map(e=>"string"==typeof e?e:e.name||String(e));u.setFieldValue("mcp_access_groups",t)}},[e]),(0,b.useEffect)(()=>{e.server_id&&""!==e.server_id.trim()&&ev()},[e,s]);let ev=async()=>{if(s&&e.server_id){v(!0),w(null);try{let t=await (0,_.listMCPTools)(s,e.server_id);t.tools&&!t.error?j(t.tools):(console.error("Failed to fetch tools:",t.message),j([]),w(t.message||"Failed to load tools"))}catch(e){console.error("Tools fetch error:",e),j([]),w(e instanceof Error?e.message:"Failed to load tools")}finally{v(!1)}}},eN=async t=>{if(s)try{let{static_headers:r,credentials:l,stdio_config:a,env_json:n,command:i,args:o,allow_all_keys:c,available_on_public_internet:m,delegate_auth_to_upstream:u,token_validation_json:h,...p}=t,g=(p.mcp_access_groups||[]).map(e=>"string"==typeof e?e:e.name||String(e)),f=Array.isArray(r)?r.reduce((e,t)=>{let s=t?.header?.trim();return s&&(e[s]=t?.value??""),e},{}):{},b=l&&"object"==typeof l?Object.entries(l).reduce((e,[t,s])=>{if(null==s||""===s)return e;if("scopes"===t){if(Array.isArray(s)){let r=s.filter(e=>null!=e&&""!==e);r.length>0&&(e[t]=r)}}else e[t]=s;return e},{}):void 0,j={};if("stdio"===p.transport)if(a)try{let e=JSON.parse(a),t=e;if(e?.mcpServers&&"object"==typeof e.mcpServers){let s=Object.keys(e.mcpServers);s.length>0&&(t=e.mcpServers[s[0]])}let s=Array.isArray(t?.args)?t.args.map(e=>String(e)).filter(e=>""!==e.trim()):[],r=t?.env&&"object"==typeof t.env&&!Array.isArray(t.env)?Object.entries(t.env).reduce((e,[t,s])=>(null==t||""===String(t).trim()||(e[String(t)]=null==s?"":String(s)),e),{}):{};if(!(j={command:t?.command?String(t.command):void 0,args:s,env:r}).command)return void C.default.fromBackend("Stdio configuration must include a command")}catch{C.default.fromBackend("Invalid JSON in stdio configuration");return}else{let e={};if(n)try{let t=JSON.parse(n);t&&"object"==typeof t&&!Array.isArray(t)&&(e=Object.entries(t).reduce((e,[t,s])=>(null==t||""===String(t).trim()||(e[String(t)]=null==s?"":String(s)),e),{}))}catch{C.default.fromBackend("Invalid JSON in stdio env configuration");return}let t=Array.isArray(o)?o.map(e=>String(e)).filter(e=>""!==e.trim()):[],s=i?String(i).trim():"";if(!s)return void C.default.fromBackend("Stdio transport requires a command");j={command:s,args:t,env:e}}p.transport===eo.TRANSPORT.OPENAPI&&(p.transport="http");let y=null;if(h&&""!==h.trim())try{y=JSON.parse(h)}catch{C.default.fromBackend("Invalid JSON in Token Validation Rules");return}let v=p.server_name||p.url||e.server_name||e.url||p.alias||e.alias||"unknown",N={...p,...j,stdio_config:void 0,env_json:void 0,server_id:e.server_id,mcp_info:{server_name:v,description:p.description,logo_url:z||void 0,mcp_server_cost_info:Object.keys(x).length>0?x:null},mcp_access_groups:g,alias:p.alias,extra_headers:p.extra_headers||[],allowed_tools:I.length>0?I:null,tool_name_to_display_name:Object.keys(O).length>0?O:null,tool_name_to_description:Object.keys(F).length>0?F:null,disallowed_tools:p.disallowed_tools||[],static_headers:f,allow_all_keys:!!(c??e.allow_all_keys),available_on_public_internet:!!(m??e.available_on_public_internet),delegate_auth_to_upstream:p.auth_type===eo.AUTH_TYPE.OAUTH2&&!!(u??e.delegate_auth_to_upstream),...null!==y||e.token_validation?{token_validation:y}:{}};p.auth_type&&tC.includes(p.auth_type)&&b&&Object.keys(b).length>0&&(N.credentials=b);let w=await (0,_.updateMCPServer)(s,N);C.default.success("MCP Server updated successfully"),d(w)}catch(e){C.default.fromBackend("Failed to update MCP Server"+(e?.message?`: ${e.message}`:""))}};return(0,t.jsxs)(n.TabGroup,{children:[(0,t.jsxs)(i.TabList,{className:"grid w-full grid-cols-2",children:[(0,t.jsx)(a.Tab,{children:"Server Configuration"}),(0,t.jsx)(a.Tab,{children:"Cost Configuration"})]}),(0,t.jsxs)(c.TabPanels,{className:"mt-6",children:[(0,t.jsx)(o.TabPanel,{children:(0,t.jsxs)(D.Form,{form:u,onFinish:eN,initialValues:ey,layout:"vertical",children:[(0,t.jsx)(D.Form.Item,{label:"MCP Server Name",name:"server_name",rules:[{validator:(e,t)=>eW(t)}],children:(0,t.jsx)(H.Input,{className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:"Alias",name:"alias",rules:[{validator:(e,t)=>eW(t)}],children:(0,t.jsx)(H.Input,{onChange:()=>A(!0),className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:"Description",name:"description",children:(0,t.jsx)(H.Input,{className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(e$,{value:z,onChange:U}),(0,t.jsx)(D.Form.Item,{label:"Transport Type",name:"transport",rules:[{required:!0}],children:(0,t.jsxs)(p.Select,{onChange:e=>{"stdio"===e?u.setFieldsValue({url:void 0,spec_path:void 0,auth_type:void 0,credentials:void 0,authorization_url:void 0,token_url:void 0,registration_url:void 0}):e===eo.TRANSPORT.OPENAPI?u.setFieldsValue({url:void 0,command:void 0,args:void 0,env_json:void 0,stdio_config:void 0}):u.setFieldsValue({spec_path:void 0,command:void 0,args:void 0,env_json:void 0,stdio_config:void 0})},children:[(0,t.jsx)(p.Select.Option,{value:"http",children:"Streamable HTTP (Recommended)"}),(0,t.jsx)(p.Select.Option,{value:"sse",children:"Server-Sent Events (SSE)"}),(0,t.jsx)(p.Select.Option,{value:"stdio",children:"Standard Input/Output (stdio)"}),(0,t.jsx)(p.Select.Option,{value:eo.TRANSPORT.OPENAPI,children:"OpenAPI Spec"})]})}),!V&&!$&&(0,t.jsx)(D.Form.Item,{label:"MCP Server URL",name:"url",rules:[{required:!0,message:"Please enter a server URL"},{validator:(e,t)=>eK(t)}],children:(0,t.jsx)(H.Input,{placeholder:"https://your-mcp-server.com",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),$&&(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["OpenAPI Spec URL",(0,t.jsx)(g.Tooltip,{title:"URL to an OpenAPI specification (JSON or YAML). MCP tools will be automatically generated from the API endpoints defined in the spec.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:"spec_path",rules:[{required:!0,message:"Please enter an OpenAPI spec URL"}],children:(0,t.jsx)(H.Input,{placeholder:"https://petstore3.swagger.io/api/v3/openapi.json",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),!V&&(0,t.jsx)(D.Form.Item,{label:"Authentication",name:"auth_type",rules:[{required:!0}],children:(0,t.jsxs)(p.Select,{children:[(0,t.jsx)(p.Select.Option,{value:"none",children:"None"}),(0,t.jsx)(p.Select.Option,{value:"api_key",children:"API Key"}),(0,t.jsx)(p.Select.Option,{value:"bearer_token",children:"Bearer Token"}),(0,t.jsx)(p.Select.Option,{value:"token",children:"Token"}),(0,t.jsx)(p.Select.Option,{value:"basic",children:"Basic Auth"}),(0,t.jsx)(p.Select.Option,{value:"oauth2",children:"OAuth"}),(0,t.jsx)(p.Select.Option,{value:"aws_sigv4",children:"AWS SigV4 (Bedrock AgentCore MCPs)"})]})}),V&&(0,t.jsxs)("div",{className:"rounded-lg border border-gray-200 p-4 space-y-4",children:[(0,t.jsx)("p",{className:"text-sm text-gray-600",children:"Configure the stdio transport used to launch the MCP server process. You can either fill in the fields below or paste a JSON configuration."}),(0,t.jsx)(D.Form.Item,{label:"Command",name:"command",rules:[{required:!0,message:"Please enter a command for stdio transport"}],children:(0,t.jsx)(H.Input,{placeholder:"e.g., npx",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:"Args",name:"args",children:(0,t.jsx)(p.Select,{mode:"tags",size:"large",tokenSeparators:[","],placeholder:"Add args (press enter or comma)",className:"rounded-lg"})}),(0,t.jsx)(D.Form.Item,{label:"Environment (JSON object)",name:"env_json",rules:[{validator:(e,t)=>{if(!t)return Promise.resolve();try{let e=JSON.parse(t);if(e&&"object"==typeof e&&!Array.isArray(e))return Promise.resolve();return Promise.reject(Error("Env must be a JSON object"))}catch{return Promise.reject(Error("Please enter valid JSON"))}}}],children:(0,t.jsx)(H.Input.TextArea,{rows:6,className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500 font-mono text-sm",placeholder:`{ "KEY": "value" }`})}),(0,t.jsx)(eO,{isVisible:!0,required:!1})]}),!V&&K&&(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["Authentication Value",(0,t.jsx)(g.Tooltip,{title:"Token, password, or header value to send with each request for the selected auth type.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","auth_value"],rules:[{validator:(e,t)=>t&&"string"==typeof t&&""===t.trim()?Promise.reject(Error("Authentication value cannot be empty")):Promise.resolve()}],children:(0,t.jsx)(H.Input.Password,{placeholder:"Enter token or secret (leave blank to keep existing)",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),!V&&W&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["OAuth Client ID (optional)",(0,t.jsx)(g.Tooltip,{title:"Provide only if your MCP server cannot handle dynamic client registration.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","client_id"],children:(0,t.jsx)(H.Input.Password,{placeholder:"Enter OAuth client ID (leave blank to keep existing)",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["OAuth Client Secret (optional)",(0,t.jsx)(g.Tooltip,{title:"Provide only if your MCP server cannot handle dynamic client registration.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","client_secret"],children:(0,t.jsx)(H.Input.Password,{placeholder:"Enter OAuth client secret (leave blank to keep existing)",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["OAuth Scopes (optional)",(0,t.jsx)(g.Tooltip,{title:"Add scopes to override the default scope list used for this MCP server.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","scopes"],children:(0,t.jsx)(p.Select,{mode:"tags",tokenSeparators:[","],placeholder:"Add scopes",className:"rounded-lg",size:"large"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["Authorization URL Override (optional)",(0,t.jsx)(g.Tooltip,{title:"Optional override for the authorization endpoint.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:"authorization_url",children:(0,t.jsx)(H.Input,{placeholder:"https://example.com/oauth/authorize",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["Token URL Override (optional)",(0,t.jsx)(g.Tooltip,{title:"Optional override for the token endpoint.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:"token_url",children:(0,t.jsx)(H.Input,{placeholder:"https://example.com/oauth/token",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["Registration URL Override (optional)",(0,t.jsx)(g.Tooltip,{title:"Optional override for the dynamic client registration endpoint.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:"registration_url",children:(0,t.jsx)(H.Input,{placeholder:"https://example.com/oauth/register",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),!G&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["Token Validation Rules (optional)",(0,t.jsx)(g.Tooltip,{title:'JSON object of key-value rules checked against the OAuth token response before storing. Supports dot-notation for nested fields (e.g. {"organization": "my-org", "team.id": "123"}). Tokens that fail validation are rejected with HTTP 403.',children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:"token_validation_json",rules:[{validator:(e,t)=>{if(!t||""===t.trim())return Promise.resolve();try{return JSON.parse(t),Promise.resolve()}catch{return Promise.reject(Error("Must be valid JSON"))}}}],children:(0,t.jsx)(H.Input.TextArea,{placeholder:'{\n "organization": "my-org",\n "team.id": "123"\n}',rows:4,className:"font-mono text-sm rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["Token Storage TTL (seconds, optional)",(0,t.jsx)(g.Tooltip,{title:"How long to cache each user's OAuth access token in Redis before evicting it (regardless of the token's own expires_in). Leave blank to derive the TTL from the token's expires_in, or fall back to the 12-hour default.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:"token_storage_ttl_seconds",children:(0,t.jsx)(ec.InputNumber,{min:1,placeholder:"e.g. 3600",style:{width:"100%"},className:"rounded-lg"})})]}),(0,t.jsxs)("div",{className:"rounded-lg border border-dashed border-gray-300 p-4 space-y-2",children:[(0,t.jsx)("p",{className:"text-sm text-gray-600",children:"Use OAuth to fetch a fresh access token and temporarily save it in the session as the authentication value."}),(0,t.jsx)(l.Button,{variant:"secondary",onClick:em,disabled:"authorizing"===eu||"exchanging"===eu,children:"authorizing"===eu?"Waiting for authorization...":"exchanging"===eu?"Exchanging authorization code...":"Authorize & Fetch Token"}),ex&&(0,t.jsx)("p",{className:"text-sm text-red-500",children:ex}),"success"===eu&&eh?.access_token&&(0,t.jsxs)("p",{className:"text-sm text-green-600",children:["Token fetched. Expires in ",eh.expires_in??"?"," seconds."]})]})]}),!V&&J&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("p",{className:"text-sm text-gray-500 mb-2",children:["For MCP servers hosted on AWS Bedrock AgentCore."," ",(0,t.jsx)("a",{href:"https://docs.litellm.ai/docs/mcp_aws_sigv4",target:"_blank",rel:"noopener noreferrer",className:"text-blue-500 hover:text-blue-700",children:"View docs →"})]}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["AWS Region",(0,t.jsx)(g.Tooltip,{title:"AWS region for SigV4 signing (e.g., us-east-1)",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","aws_region_name"],rules:[],children:(0,t.jsx)(H.Input,{placeholder:"us-east-1 (leave blank to keep existing)",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["AWS Service Name",(0,t.jsx)(g.Tooltip,{title:"AWS service name for SigV4 signing. Defaults to 'bedrock-agentcore'.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","aws_service_name"],children:(0,t.jsx)(H.Input,{placeholder:"bedrock-agentcore (leave blank to keep existing)",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["AWS Access Key ID",(0,t.jsx)(g.Tooltip,{title:"Optional. If not provided, falls back to the boto3 credential chain (IAM role, env vars, etc.).",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","aws_access_key_id"],rules:[],children:(0,t.jsx)(H.Input.Password,{placeholder:"Leave blank to keep existing",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["AWS Secret Access Key",(0,t.jsx)(g.Tooltip,{title:"Optional. Required if AWS Access Key ID is provided.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","aws_secret_access_key"],rules:[],children:(0,t.jsx)(H.Input.Password,{placeholder:"Leave blank to keep existing",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["AWS Session Token",(0,t.jsx)(g.Tooltip,{title:"Optional. Only needed for temporary STS credentials.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","aws_session_token"],children:(0,t.jsx)(H.Input.Password,{placeholder:"Leave blank to keep existing",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["AWS Role ARN",(0,t.jsx)(g.Tooltip,{title:"Optional. IAM role ARN to assume via STS before signing. If set, LiteLLM calls sts:AssumeRole to get temporary credentials.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","aws_role_name"],children:(0,t.jsx)(H.Input,{placeholder:"Leave blank to keep existing",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})}),(0,t.jsx)(D.Form.Item,{label:(0,t.jsxs)("span",{className:"text-sm font-medium text-gray-700 flex items-center",children:["AWS Session Name",(0,t.jsx)(g.Tooltip,{title:"Optional. Session name for the AssumeRole call — appears in CloudTrail logs. Auto-generated if omitted.",children:(0,t.jsx)(en.InfoCircleOutlined,{className:"ml-2 text-blue-400 hover:text-blue-600 cursor-help"})})]}),name:["credentials","aws_session_name"],children:(0,t.jsx)(H.Input,{placeholder:"Leave blank to keep existing",className:"rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"})})]}),(0,t.jsx)("div",{className:"mt-6",children:(0,t.jsx)(eR,{availableAccessGroups:m,mcpServer:e,searchValue:S,setSearchValue:T,getAccessGroupOptions:()=>{let e=m.map(e=>({value:e,label:(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("div",{className:"w-2 h-2 bg-green-500 rounded-full"}),(0,t.jsx)("span",{className:"font-medium",children:e})]})}));return S&&!m.some(e=>e.toLowerCase().includes(S.toLowerCase()))&&e.push({value:S,label:(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("div",{className:"w-2 h-2 bg-blue-500 rounded-full"}),(0,t.jsx)("span",{className:"font-medium",children:S}),(0,t.jsx)("span",{className:"text-gray-400 text-xs ml-1",children:"create new group"})]})}),e}})}),(0,t.jsx)("div",{className:"mt-6",children:(0,t.jsx)(eP,{accessToken:s,oauthAccessToken:Q,formValues:{server_id:e.server_id,server_name:et??e.server_name,url:X??e.url,spec_path:ee??e.spec_path,transport:q??e.transport,auth_type:es??e.auth_type,mcp_info:e.mcp_info,oauth_flow_type:ei??e.token_url?eo.OAUTH_FLOW.M2M:eo.OAUTH_FLOW.INTERACTIVE,static_headers:er??e.static_headers,credentials:el,authorization_url:ea??e.authorization_url,token_url:ei??e.token_url,registration_url:ed??e.registration_url},allowedTools:I,existingAllowedTools:e.allowed_tools||null,onAllowedToolsChange:P,toolNameToDisplayName:O,toolNameToDescription:F,onToolNameToDisplayNameChange:M,onToolNameToDescriptionChange:E})}),(0,t.jsxs)("div",{className:"flex justify-end gap-2",children:[(0,t.jsx)(eb.Button,{onClick:r,children:"Cancel"}),(0,t.jsx)(l.Button,{type:"submit",children:"Save Changes"})]})]})}),(0,t.jsx)(o.TabPanel,{children:(0,t.jsxs)("div",{className:"space-y-6",children:[(0,t.jsx)(ef,{value:x,onChange:h,tools:f,disabled:y}),(0,t.jsxs)("div",{className:"flex justify-end gap-2",children:[(0,t.jsx)(eb.Button,{onClick:r,children:"Cancel"}),(0,t.jsx)(l.Button,{onClick:()=>u.submit(),children:"Save Changes"})]})]})})]})]})},tA=({costConfig:e})=>{let s=e?.default_cost_per_query!==void 0&&e?.default_cost_per_query!==null,r=e?.tool_name_to_cost_per_query&&Object.keys(e.tool_name_to_cost_per_query).length>0;return s||r?(0,t.jsx)("div",{className:"mt-6 pt-6 border-t border-gray-200",children:(0,t.jsxs)("div",{className:"space-y-4",children:[s&&e?.default_cost_per_query!==void 0&&e?.default_cost_per_query!==null&&(0,t.jsxs)("div",{children:[(0,t.jsx)(d.Text,{className:"font-medium",children:"Default Cost per Query"}),(0,t.jsxs)("div",{className:"text-green-600 font-mono",children:["$",e.default_cost_per_query.toFixed(4)]})]}),r&&e?.tool_name_to_cost_per_query&&(0,t.jsxs)("div",{children:[(0,t.jsx)(d.Text,{className:"font-medium",children:"Tool-Specific Costs"}),(0,t.jsx)("div",{className:"mt-2 space-y-2",children:Object.entries(e.tool_name_to_cost_per_query).map(([e,s])=>null!=s&&(0,t.jsxs)("div",{className:"flex justify-between items-center p-3 bg-gray-50 rounded-lg",children:[(0,t.jsx)(d.Text,{className:"font-medium",children:e}),(0,t.jsxs)(d.Text,{className:"text-green-600 font-mono",children:["$",s.toFixed(4)," per query"]})]},e))})]}),(0,t.jsxs)("div",{className:"mt-4 p-4 bg-blue-50 border border-blue-200 rounded-lg",children:[(0,t.jsx)(d.Text,{className:"text-blue-800 font-medium",children:"Cost Summary:"}),(0,t.jsxs)("div",{className:"mt-2 space-y-1",children:[s&&e?.default_cost_per_query!==void 0&&e?.default_cost_per_query!==null&&(0,t.jsxs)(d.Text,{className:"text-blue-700",children:["• Default cost: $",e.default_cost_per_query.toFixed(4)," per query"]}),r&&e?.tool_name_to_cost_per_query&&(0,t.jsxs)(d.Text,{className:"text-blue-700",children:["• ",Object.keys(e.tool_name_to_cost_per_query).length," tool(s) with custom pricing"]})]})]})]})}):(0,t.jsx)("div",{className:"mt-6 pt-6 border-t border-gray-200",children:(0,t.jsx)("div",{className:"space-y-4",children:(0,t.jsx)("div",{className:"p-4 bg-gray-50 border border-gray-200 rounded-lg",children:(0,t.jsx)(d.Text,{className:"text-gray-600",children:"No cost configuration set for this server. Tool calls will be charged at $0.00 per tool call."})})})})},tI=({mcpServer:e,onBack:s,isEditing:r,isProxyAdmin:u,accessToken:x,userRole:h,userID:p,availableAccessGroups:g})=>{let[f,j]=(0,b.useState)(r),[y,v]=(0,b.useState)(!1),[N,_]=(0,b.useState)({}),[w,S]=(0,b.useState)(0),C=e.url??"",{maskedUrl:T,hasToken:A}=C?eH(C):{maskedUrl:"—",hasToken:!1},I=(e,t)=>e?A?t?e:T:e:"—",P=async(e,t)=>{await (0,tr.copyToClipboard)(e)&&(_(e=>({...e,[t]:!0})),setTimeout(()=>{_(e=>({...e,[t]:!1}))},2e3))},O=e=>{let s=e.toUpperCase();return(0,t.jsx)("span",{className:"inline-flex items-center text-sm font-medium px-2.5 py-0.5 rounded border bg-gray-50 text-gray-700 border-gray-200",children:s})},M=e=>(0,t.jsx)("span",{className:"inline-flex items-center text-sm font-medium px-2.5 py-0.5 rounded border bg-gray-50 text-gray-700 border-gray-200",children:e});return(0,t.jsxs)("div",{className:"p-4 max-w-full",children:[(0,t.jsxs)("div",{className:"mb-6",children:[(0,t.jsx)(l.Button,{icon:tx.ArrowLeftIcon,variant:"light",className:"mb-4",onClick:s,children:"Back to All Servers"}),(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(m.Title,{className:"text-2xl",children:e.server_name||e.alias||"Unnamed Server"}),(0,t.jsx)(eb.Button,{type:"text",size:"small",icon:N["mcp-server_name"]?(0,t.jsx)(k.CheckIcon,{size:12}):(0,t.jsx)(e6.CopyIcon,{size:12}),onClick:()=>P(e.server_name||e.alias,"mcp-server_name"),className:`transition-all duration-200 ${N["mcp-server_name"]?"text-green-600 bg-green-50 border-green-200":"text-gray-400 hover:text-gray-600 hover:bg-gray-100"}`}),e.alias&&e.server_name&&e.alias!==e.server_name&&(0,t.jsx)("span",{className:"ml-2 inline-flex items-center text-xs font-medium px-2 py-0.5 rounded bg-gray-100 text-gray-600 border border-gray-200 font-mono",children:e.alias})]}),(0,t.jsxs)("div",{className:"flex items-center gap-1.5 mt-1",children:[(0,t.jsx)(d.Text,{className:"text-gray-400 font-mono text-xs",children:e.server_id}),(0,t.jsx)(eb.Button,{type:"text",size:"small",icon:N["mcp-server-id"]?(0,t.jsx)(k.CheckIcon,{size:10}):(0,t.jsx)(e6.CopyIcon,{size:10}),onClick:()=>P(e.server_id,"mcp-server-id"),className:`transition-all duration-200 ${N["mcp-server-id"]?"text-green-600 bg-green-50 border-green-200":"text-gray-300 hover:text-gray-500 hover:bg-gray-50"}`})]}),e.description&&(0,t.jsx)(d.Text,{className:"text-gray-500 mt-2",children:e.description})]}),(0,t.jsxs)(n.TabGroup,{index:w,onIndexChange:S,children:[(0,t.jsx)(i.TabList,{className:"mb-4",children:[(0,t.jsx)(a.Tab,{children:"Overview"},"overview"),(0,t.jsx)(a.Tab,{children:"MCP Tools"},"tools"),...u?[(0,t.jsx)(a.Tab,{children:"Settings"},"settings")]:[]]}),(0,t.jsxs)(c.TabPanels,{children:[(0,t.jsxs)(o.TabPanel,{children:[(0,t.jsxs)(tg.Grid,{numItems:1,numItemsSm:2,numItemsLg:3,className:"gap-4",children:[(0,t.jsxs)(eg.Card,{className:"p-4",children:[(0,t.jsx)(d.Text,{className:"text-xs font-medium text-gray-500 uppercase tracking-wide",children:"Transport"}),(0,t.jsx)("div",{className:"mt-3",children:O((0,eo.handleTransport)(e.transport??void 0,e.spec_path??void 0))})]}),(0,t.jsxs)(eg.Card,{className:"p-4",children:[(0,t.jsx)(d.Text,{className:"text-xs font-medium text-gray-500 uppercase tracking-wide",children:"Authentication"}),(0,t.jsx)("div",{className:"mt-3",children:M((0,eo.handleAuth)(e.auth_type??void 0))})]}),(0,t.jsxs)(eg.Card,{className:"p-4",children:[(0,t.jsx)(d.Text,{className:"text-xs font-medium text-gray-500 uppercase tracking-wide",children:"Host URL"}),(0,t.jsxs)("div",{className:"mt-3 flex items-center gap-2",children:[(0,t.jsx)(d.Text,{className:"break-all overflow-wrap-anywhere font-mono text-sm",children:I(e.url,y)}),A&&u&&(0,t.jsx)("button",{onClick:()=>v(!y),className:"p-1 hover:bg-gray-100 rounded flex-shrink-0",children:(0,t.jsx)(tc.Icon,{icon:y?tp:th.EyeIcon,size:"sm",className:"text-gray-500"})})]})]})]}),(0,t.jsxs)(eg.Card,{className:"mt-4 p-4",children:[(0,t.jsx)(d.Text,{className:"text-xs font-medium text-gray-500 uppercase tracking-wide",children:"Cost Configuration"}),(0,t.jsx)("div",{className:"mt-3",children:(0,t.jsx)(tA,{costConfig:e.mcp_info?.mcp_server_cost_info})})]})]}),(0,t.jsx)(o.TabPanel,{children:(0,t.jsx)(tw,{serverId:e.server_id,accessToken:x,auth_type:e.auth_type,userRole:h,userID:p,serverAlias:e.alias,extraHeaders:e.extra_headers})}),(0,t.jsx)(o.TabPanel,{children:(0,t.jsxs)(eg.Card,{children:[(0,t.jsxs)("div",{className:"flex justify-between items-center mb-4",children:[(0,t.jsx)(m.Title,{children:"MCP Server Settings"}),f?null:(0,t.jsx)(l.Button,{variant:"light",onClick:()=>j(!0),children:"Edit Settings"})]}),f?(0,t.jsx)(tk,{mcpServer:e,accessToken:x,onCancel:()=>j(!1),onSuccess:e=>{j(!1),s()},availableAccessGroups:g}):(0,t.jsxs)("div",{className:"divide-y divide-gray-100",children:[(0,t.jsxs)("div",{className:"py-3 grid grid-cols-3 gap-4",children:[(0,t.jsx)(d.Text,{className:"text-sm font-medium text-gray-500",children:"Server Name"}),(0,t.jsx)("div",{className:"col-span-2 text-sm text-gray-900",children:e.server_name||(0,t.jsx)("span",{className:"text-gray-400",children:"—"})})]}),(0,t.jsxs)("div",{className:"py-3 grid grid-cols-3 gap-4",children:[(0,t.jsx)(d.Text,{className:"text-sm font-medium text-gray-500",children:"Alias"}),(0,t.jsx)("div",{className:"col-span-2 text-sm font-mono text-gray-900",children:e.alias||(0,t.jsx)("span",{className:"text-gray-400",children:"—"})})]}),(0,t.jsxs)("div",{className:"py-3 grid grid-cols-3 gap-4",children:[(0,t.jsx)(d.Text,{className:"text-sm font-medium text-gray-500",children:"Description"}),(0,t.jsx)("div",{className:"col-span-2 text-sm text-gray-900",children:e.description||(0,t.jsx)("span",{className:"text-gray-400",children:"—"})})]}),(0,t.jsxs)("div",{className:"py-3 grid grid-cols-3 gap-4",children:[(0,t.jsx)(d.Text,{className:"text-sm font-medium text-gray-500",children:"URL"}),(0,t.jsxs)("div",{className:"col-span-2 text-sm font-mono text-gray-900 break-all flex items-center gap-2",children:[I(e.url,y),A&&(0,t.jsx)("button",{onClick:()=>v(!y),className:"p-1 hover:bg-gray-100 rounded flex-shrink-0",children:(0,t.jsx)(tc.Icon,{icon:y?tp:th.EyeIcon,size:"sm",className:"text-gray-500"})})]})]}),(0,t.jsxs)("div",{className:"py-3 grid grid-cols-3 gap-4",children:[(0,t.jsx)(d.Text,{className:"text-sm font-medium text-gray-500",children:"Transport"}),(0,t.jsx)("div",{className:"col-span-2",children:O((0,eo.handleTransport)(e.transport,e.spec_path))})]}),(0,t.jsxs)("div",{className:"py-3 grid grid-cols-3 gap-4",children:[(0,t.jsx)(d.Text,{className:"text-sm font-medium text-gray-500",children:"Authentication"}),(0,t.jsx)("div",{className:"col-span-2",children:M((0,eo.handleAuth)(e.auth_type))})]}),(0,t.jsxs)("div",{className:"py-3 grid grid-cols-3 gap-4",children:[(0,t.jsx)(d.Text,{className:"text-sm font-medium text-gray-500",children:"Extra Headers"}),(0,t.jsx)("div",{className:"col-span-2 text-sm text-gray-900",children:e.extra_headers&&e.extra_headers.length>0?e.extra_headers.join(", "):(0,t.jsx)("span",{className:"text-gray-400",children:"—"})})]}),(0,t.jsxs)("div",{className:"py-3 grid grid-cols-3 gap-4",children:[(0,t.jsx)(d.Text,{className:"text-sm font-medium text-gray-500",children:"Allow All Keys"}),(0,t.jsx)("div",{className:"col-span-2",children:e.allow_all_keys?(0,t.jsxs)("span",{className:"inline-flex items-center gap-1 px-2 py-0.5 bg-green-50 text-green-700 rounded-full border border-green-200 text-xs font-medium",children:[(0,t.jsx)("span",{className:"h-1.5 w-1.5 rounded-full bg-green-500"}),"Enabled"]}):(0,t.jsx)("span",{className:"inline-flex items-center gap-1 px-2 py-0.5 bg-gray-50 text-gray-600 rounded-full border border-gray-200 text-xs font-medium",children:"Disabled"})})]}),(0,t.jsxs)("div",{className:"py-3 grid grid-cols-3 gap-4",children:[(0,t.jsx)(d.Text,{className:"text-sm font-medium text-gray-500",children:"Network Access"}),(0,t.jsx)("div",{className:"col-span-2",children:e.available_on_public_internet?(0,t.jsxs)("span",{className:"inline-flex items-center gap-1 px-2 py-0.5 bg-green-50 text-green-700 rounded-full border border-green-200 text-xs font-medium",children:[(0,t.jsx)("span",{className:"h-1.5 w-1.5 rounded-full bg-green-500"}),"Public"]}):(0,t.jsxs)("span",{className:"inline-flex items-center gap-1 px-2 py-0.5 bg-orange-50 text-orange-700 rounded-full border border-orange-200 text-xs font-medium",children:[(0,t.jsx)("span",{className:"h-1.5 w-1.5 rounded-full bg-orange-500"}),"Internal only"]})})]}),"oauth2"===(0,eo.handleAuth)(e.auth_type)&&(0,t.jsxs)("div",{className:"py-3 grid grid-cols-3 gap-4",children:[(0,t.jsx)(d.Text,{className:"text-sm font-medium text-gray-500",children:"Delegate Auth to Upstream"}),(0,t.jsx)("div",{className:"col-span-2",children:e.delegate_auth_to_upstream?(0,t.jsxs)("span",{className:"inline-flex items-center gap-1 px-2 py-0.5 bg-green-50 text-green-700 rounded-full border border-green-200 text-xs font-medium",children:[(0,t.jsx)("span",{className:"h-1.5 w-1.5 rounded-full bg-green-500"}),"Enabled (PKCE passthrough)"]}):(0,t.jsx)("span",{className:"inline-flex items-center gap-1 px-2 py-0.5 bg-gray-50 text-gray-600 rounded-full border border-gray-200 text-xs font-medium",children:"Disabled"})})]}),(0,t.jsxs)("div",{className:"py-3 grid grid-cols-3 gap-4",children:[(0,t.jsx)(d.Text,{className:"text-sm font-medium text-gray-500",children:"Access Groups"}),(0,t.jsx)("div",{className:"col-span-2",children:e.mcp_access_groups&&e.mcp_access_groups.length>0?(0,t.jsx)("div",{className:"flex flex-wrap gap-1.5",children:e.mcp_access_groups.map((e,s)=>(0,t.jsx)("span",{className:"inline-flex items-center text-xs font-medium px-2 py-0.5 rounded bg-gray-100 text-gray-700 border border-gray-200",children:"string"==typeof e?e:e?.name??""},s))}):(0,t.jsx)("span",{className:"text-sm text-gray-400",children:"—"})})]}),(0,t.jsxs)("div",{className:"py-3 grid grid-cols-3 gap-4",children:[(0,t.jsx)(d.Text,{className:"text-sm font-medium text-gray-500",children:"Allowed Tools"}),(0,t.jsx)("div",{className:"col-span-2",children:e.allowed_tools&&e.allowed_tools.length>0?(0,t.jsx)("div",{className:"flex flex-wrap gap-1.5",children:e.allowed_tools.map((e,s)=>(0,t.jsx)("span",{className:"inline-flex items-center text-xs font-mono font-medium px-2 py-0.5 rounded bg-blue-50 text-blue-700 border border-blue-200",children:e},s))}):(0,t.jsx)("span",{className:"inline-flex items-center text-xs font-medium px-2 py-0.5 rounded bg-green-50 text-green-700 border border-green-200",children:"All tools enabled"})})]}),(0,t.jsxs)("div",{className:"py-3 grid grid-cols-3 gap-4",children:[(0,t.jsx)(d.Text,{className:"text-sm font-medium text-gray-500",children:"Cost"}),(0,t.jsx)("div",{className:"col-span-2",children:(0,t.jsx)(tA,{costConfig:e.mcp_info?.mcp_server_cost_info})})]})]})]})})]})]})]})},tP=(0,N.createQueryKeys)("mcpSemanticFilterSettings"),tO=(0,N.createQueryKeys)("mcpSemanticFilterSettings");var tM=e.i(178654),tF=e.i(621192),tE=e.i(981339),tL=e.i(850627),tR=e.i(987432),tz=e.i(689020),tU=e.i(245094),tB=e.i(788191),tq=e.i(653496),tV=e.i(992619);function t$({accessToken:e,testQuery:s,setTestQuery:r,testModel:l,setTestModel:a,isTesting:n,onTest:i,filterEnabled:o,testResult:c,curlCommand:d}){return(0,t.jsx)(e4.Card,{title:"Test Configuration",style:{marginBottom:16},children:(0,t.jsx)(tq.Tabs,{defaultActiveKey:"test",items:[{key:"test",label:"Test",children:(0,t.jsxs)(eM.Space,{direction:"vertical",style:{width:"100%"},size:"large",children:[(0,t.jsxs)("div",{children:[(0,t.jsxs)(f.Typography.Text,{strong:!0,style:{display:"block",marginBottom:8},children:[(0,t.jsx)(tB.PlayCircleOutlined,{})," Test Query"]}),(0,t.jsx)(H.Input.TextArea,{placeholder:"Enter a test query to see which tools would be selected...",value:s,onChange:e=>r(e.target.value),rows:4,disabled:n})]}),(0,t.jsx)("div",{children:(0,t.jsx)(tV.default,{accessToken:e||"",value:l,onChange:a,disabled:n,showLabel:!0,labelText:"Select Model"})}),(0,t.jsx)(eb.Button,{type:"primary",icon:(0,t.jsx)(tB.PlayCircleOutlined,{}),onClick:i,loading:n,disabled:!s||!l||!o,block:!0,children:"Test Filter"}),!o&&(0,t.jsx)(ej.Alert,{type:"warning",message:"Semantic filtering is disabled",description:"Enable semantic filtering and save settings to test the filter.",showIcon:!0}),c&&(0,t.jsxs)("div",{children:[(0,t.jsx)(f.Typography.Title,{level:5,children:"Results"}),(0,t.jsx)(ej.Alert,{type:"success",message:`${c.selectedTools} tools selected`,description:`Filtered from ${c.totalTools} available tools`,showIcon:!0,style:{marginBottom:16}}),(0,t.jsxs)("div",{children:[(0,t.jsx)(f.Typography.Text,{strong:!0,style:{display:"block",marginBottom:8},children:"Selected Tools:"}),(0,t.jsx)("ul",{style:{paddingLeft:20,margin:0},children:c.tools.map((e,s)=>(0,t.jsx)("li",{style:{marginBottom:4},children:(0,t.jsx)(f.Typography.Text,{children:e})},s))})]})]})]})},{key:"api",label:"API Usage",children:(0,t.jsxs)("div",{children:[(0,t.jsxs)(eM.Space,{style:{marginBottom:8},children:[(0,t.jsx)(tU.CodeOutlined,{}),(0,t.jsx)(f.Typography.Text,{strong:!0,children:"API Usage"})]}),(0,t.jsx)(f.Typography.Text,{type:"secondary",style:{display:"block",marginBottom:8},children:"Use this curl command to test the semantic filter with your current configuration."}),(0,t.jsx)(f.Typography.Text,{strong:!0,style:{display:"block",marginBottom:8},children:"Response headers to check:"}),(0,t.jsxs)("ul",{style:{paddingLeft:20,margin:"0 0 12px 0"},children:[(0,t.jsxs)("li",{children:[(0,t.jsx)(f.Typography.Text,{children:"x-litellm-semantic-filter: shows total tools → selected tools"}),(0,t.jsx)(f.Typography.Text,{type:"secondary",style:{display:"block"},children:"Example: 10→3"})]}),(0,t.jsxs)("li",{children:[(0,t.jsx)(f.Typography.Text,{children:"x-litellm-semantic-filter-tools: CSV of selected tool names"}),(0,t.jsx)(f.Typography.Text,{type:"secondary",style:{display:"block"},children:"Example: wikipedia-fetch,github-search,slack-post"})]})]}),(0,t.jsx)("pre",{style:{background:"#f5f5f5",padding:12,borderRadius:4,overflow:"auto",fontSize:12,margin:0},children:d})]})}]})})}let tD=async({accessToken:e,testModel:t,testQuery:s,setIsTesting:r,setTestResult:l})=>{if(!s||!t||!e)return void C.default.error("Please enter a query and select a model");r(!0),l(null);try{let{headers:r}=await (0,_.testMCPSemanticFilter)(e,t,s),a=(e=>{if(!e.filter)return null;let[t,s]=e.filter.split("->").map(Number);return{totalTools:t,selectedTools:s,tools:e.tools?e.tools.split(",").map(e=>e.trim()):[]}})(r);if(!a)return void C.default.warning("Semantic filter is not enabled or no tools were filtered");l(a),C.default.success("Semantic filter test completed successfully")}catch(e){console.error("Test failed:",e),C.default.error("Failed to test semantic filter")}finally{r(!1)}};function tH({accessToken:e}){var s;let l,{data:a,isLoading:n,isError:i,error:o}=(()=>{let{accessToken:e}=(0,w.default)();return(0,y.useQuery)({queryKey:tP.list({}),queryFn:async()=>await (0,_.getMCPSemanticFilterSettings)(e),enabled:!!e,staleTime:36e5,gcTime:36e5})})(),{mutate:c,isPending:d,error:m}=(s=e||"",l=(0,v.useQueryClient)(),(0,tf.useMutation)({mutationFn:async e=>{if(!s)throw Error("Access token is required");return(0,_.updateMCPSemanticFilterSettings)(s,e)},onSuccess:()=>{l.invalidateQueries({queryKey:tO.all})}})),[u]=D.Form.useForm(),[x,h]=(0,b.useState)(!1),[j,N]=(0,b.useState)(!1),[S,T]=(0,b.useState)([]),[k,A]=(0,b.useState)(!0),[I,P]=(0,b.useState)(""),[O,M]=(0,b.useState)("gpt-4o"),[F,E]=(0,b.useState)(null),[L,R]=(0,b.useState)(!1),z=a?.field_schema,U=a?.values??{};(0,b.useEffect)(()=>{(async()=>{if(e)try{A(!0);let t=(await (0,tz.fetchAvailableModels)(e)).filter(e=>"embedding"===e.mode);T(t)}catch(e){console.error("Error fetching embedding models:",e)}finally{A(!1)}})()},[e]),(0,b.useEffect)(()=>{U&&(u.setFieldsValue({enabled:U.enabled??!1,embedding_model:U.embedding_model??"text-embedding-3-small",top_k:U.top_k??10,similarity_threshold:U.similarity_threshold??.3}),N(!1))},[U,u]);let B=async()=>{try{let e=await u.validateFields();c(e,{onSuccess:()=>{N(!1),h(!0),setTimeout(()=>h(!1),3e3),C.default.success("Settings updated successfully. Changes will be applied across all pods within 10 seconds.")},onError:e=>{C.default.fromBackend(e)}})}catch(e){console.error("Form validation failed:",e)}},q=async()=>{e&&await tD({accessToken:e,testModel:O,testQuery:I,setIsTesting:R,setTestResult:E})};return e?(0,t.jsx)("div",{style:{width:"100%"},children:n?(0,t.jsx)(tE.Skeleton,{active:!0}):i?(0,t.jsx)(ej.Alert,{type:"error",message:"Could not load MCP Semantic Filter settings",description:o instanceof Error?o.message:void 0,style:{marginBottom:24}}):(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(ej.Alert,{type:"info",message:"Semantic Tool Filtering",description:"Filter MCP tools semantically based on query relevance. This reduces context window size and improves tool selection accuracy. Click 'Save Settings' to apply changes across all pods (takes effect within 10 seconds).",showIcon:!0,style:{marginBottom:24}}),x&&(0,t.jsx)(ej.Alert,{type:"success",message:"Settings saved successfully",icon:(0,t.jsx)(ey.CheckCircleOutlined,{}),showIcon:!0,closable:!0,style:{marginBottom:16}}),m&&(0,t.jsx)(ej.Alert,{type:"error",message:"Could not update settings",description:m instanceof Error?m.message:void 0,style:{marginBottom:16}}),(0,t.jsxs)(tF.Row,{gutter:24,children:[(0,t.jsx)(tM.Col,{xs:24,lg:12,children:(0,t.jsxs)(D.Form,{form:u,layout:"vertical",disabled:d,onValuesChange:()=>{N(!0)},children:[(0,t.jsxs)(e4.Card,{style:{marginBottom:16},children:[(0,t.jsx)(D.Form.Item,{name:"enabled",label:(0,t.jsxs)(eM.Space,{children:[(0,t.jsx)(f.Typography.Text,{strong:!0,children:"Enable Semantic Filtering"}),(0,t.jsx)(g.Tooltip,{title:"When enabled, only the most relevant MCP tools will be included in requests based on semantic similarity",children:(0,t.jsx)(r.QuestionCircleOutlined,{style:{color:"#8c8c8c"}})})]}),valuePropName:"checked",children:(0,t.jsx)(el.Switch,{disabled:d})}),(0,t.jsx)(f.Typography.Text,{type:"secondary",style:{display:"block",marginTop:-16,marginBottom:16},children:z?.properties?.enabled?.description})]}),(0,t.jsxs)(e4.Card,{title:"Configuration",style:{marginBottom:16},children:[(0,t.jsx)(D.Form.Item,{name:"embedding_model",label:(0,t.jsxs)(eM.Space,{children:[(0,t.jsx)(f.Typography.Text,{strong:!0,children:"Embedding Model"}),(0,t.jsx)(g.Tooltip,{title:"The model used to generate embeddings for semantic matching",children:(0,t.jsx)(r.QuestionCircleOutlined,{style:{color:"#8c8c8c"}})})]}),children:(0,t.jsx)(p.Select,{options:S.map(e=>({label:e.model_group,value:e.model_group})),placeholder:k?"Loading models...":"Select embedding model",showSearch:!0,disabled:d||k,loading:k,notFoundContent:k?"Loading...":"No embedding models available"})}),(0,t.jsx)(D.Form.Item,{name:"top_k",label:(0,t.jsxs)(eM.Space,{children:[(0,t.jsx)(f.Typography.Text,{strong:!0,children:"Top K Results"}),(0,t.jsx)(g.Tooltip,{title:"Maximum number of tools to return after filtering",children:(0,t.jsx)(r.QuestionCircleOutlined,{style:{color:"#8c8c8c"}})})]}),children:(0,t.jsx)(ec.InputNumber,{min:1,max:100,style:{width:"100%"},disabled:d})}),(0,t.jsx)(D.Form.Item,{name:"similarity_threshold",label:(0,t.jsxs)(eM.Space,{children:[(0,t.jsx)(f.Typography.Text,{strong:!0,children:"Similarity Threshold"}),(0,t.jsx)(g.Tooltip,{title:"Minimum similarity score (0-1) for a tool to be included",children:(0,t.jsx)(r.QuestionCircleOutlined,{style:{color:"#8c8c8c"}})})]}),children:(0,t.jsx)(tL.Slider,{min:0,max:1,step:.05,marks:{0:"0.0",.3:"0.3",.5:"0.5",.7:"0.7",1:"1.0"},disabled:d})})]}),(0,t.jsx)("div",{style:{display:"flex",justifyContent:"flex-end",gap:8},children:(0,t.jsx)(eb.Button,{type:"primary",icon:(0,t.jsx)(tR.SaveOutlined,{}),onClick:B,loading:d,disabled:!j,children:"Save Settings"})})]})}),(0,t.jsx)(tM.Col,{xs:24,lg:12,children:(0,t.jsx)(t$,{accessToken:e,testQuery:I,setTestQuery:P,testModel:O,setTestModel:M,isTesting:L,onTest:q,filterEnabled:!!U.enabled,testResult:F,curlCommand:`curl --location 'http://localhost:4000/v1/responses' \\ ->>>>>>>> origin/litellm_internal_staging:litellm/proxy/_experimental/out/_next/static/chunks/e1a670efcb966aaa.js --header 'Content-Type: application/json' \\ --header 'Authorization: Bearer sk-1234' \\ --data '{ @@ -108,8 +88,4 @@ } ], "tool_choice": "required" -<<<<<<<< HEAD:litellm/proxy/_experimental/out/_next/static/chunks/0279e5299e9f6e98.js -}'`})})]})]})}):(0,t.jsx)("div",{className:"p-6 text-center text-gray-500",children:"Please log in to configure semantic filter settings."})}var tK=e.i(262218);let{Text:tW}=f.Typography,tJ=({accessToken:e})=>{let s,[r,l]=(0,b.useState)(!0),[a,n]=(0,b.useState)(!1),[i,o]=(0,b.useState)([]),[c,d]=(0,b.useState)(null);(0,b.useEffect)(()=>{m(),u()},[e]);let m=async()=>{if(e){l(!0);try{for(let t of(await (0,_.getGeneralSettingsCall)(e)))"mcp_internal_ip_ranges"===t.field_name&&t.field_value&&o(t.field_value)}catch(e){console.error("Failed to load MCP network settings:",e)}finally{l(!1)}}},u=async()=>{if(!e)return;let t=await (0,_.fetchMCPClientIp)(e);t&&d(t)},x=async()=>{if(e){n(!0);try{i.length>0?await (0,_.updateConfigFieldSetting)(e,"mcp_internal_ip_ranges",i):await (0,_.deleteConfigFieldSetting)(e,"mcp_internal_ip_ranges")}catch(e){console.error("Failed to save MCP network settings:",e)}finally{n(!1)}}};if(r)return(0,t.jsx)("div",{className:"flex justify-center py-12",children:(0,t.jsx)(W.Spin,{})});let h=c?4!==(s=c.split(".")).length?c+"/32":`${s[0]}.${s[1]}.${s[2]}.0/24`:null;return(0,t.jsxs)("div",{className:"space-y-6 p-4",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)(tW,{className:"text-lg font-semibold",children:"Private IP Ranges"}),(0,t.jsx)("p",{className:"text-sm text-gray-500 mt-1",children:'Define which IP ranges are part of your private network. Callers from these IPs can see all MCP servers. Callers from any other IP can only see servers marked "Available on Public Internet".'})]}),(0,t.jsxs)(e4.Card,{children:[c&&(0,t.jsxs)("div",{className:"mb-4 p-3 bg-blue-50 rounded-lg",children:[(0,t.jsxs)(tW,{className:"text-sm text-blue-700",children:["Your current IP: ",(0,t.jsx)("span",{className:"font-mono font-medium",children:c})]}),h&&!i.includes(h)&&(0,t.jsxs)("div",{className:"mt-1",children:[(0,t.jsx)(tW,{className:"text-sm text-blue-600",children:"Suggested range: "}),(0,t.jsx)(tK.Tag,{className:"cursor-pointer font-mono",color:"blue",icon:(0,t.jsx)(eE.PlusOutlined,{}),onClick:()=>{!i.includes(h)&&o([...i,h])},children:h})]})]}),(0,t.jsx)("div",{className:"flex items-center mb-2",children:(0,t.jsx)(tW,{className:"font-medium",children:"Your Private Network Ranges"})}),(0,t.jsx)(p.Select,{mode:"tags",value:i,onChange:o,placeholder:"Leave empty to use defaults: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.0/8",tokenSeparators:[","],className:"w-full",size:"large",allowClear:!0}),(0,t.jsx)("p",{className:"text-xs text-gray-400 mt-2",children:"Enter CIDR ranges (e.g., 10.0.0.0/8). When empty, standard private IP ranges are used."})]}),(0,t.jsx)("div",{className:"flex justify-end",children:(0,t.jsx)(eb.Button,{type:"primary",icon:(0,t.jsx)(tR.SaveOutlined,{}),onClick:x,loading:a,children:"Save"})})]})},{Search:tY}=H.Input,{Text:tG}=f.Typography,tQ=["#3B82F6","#10B981","#F59E0B","#EF4444","#8B5CF6","#EC4899","#06B6D4","#84CC16"],tZ=({isVisible:e,onClose:s,onSelectServer:r,onCustomServer:l,accessToken:a})=>{let[n,i]=(0,b.useState)([]),[o,c]=(0,b.useState)([]),[d,m]=(0,b.useState)(!1),[u,x]=(0,b.useState)(null),[p,g]=(0,b.useState)(""),[f,j]=(0,b.useState)("All");(0,b.useEffect)(()=>{e&&a&&(m(!0),x(null),(0,_.fetchDiscoverableMCPServers)(a).then(e=>{i(e.servers||[]),c(e.categories||[])}).catch(e=>{x(e.message||"Failed to load MCP servers")}).finally(()=>{m(!1)}))},[e,a]),(0,b.useEffect)(()=>{e&&(g(""),j("All"))},[e]);let y=(0,b.useMemo)(()=>{let e=n;if("All"!==f&&(e=e.filter(e=>e.category===f)),p.trim()){let t=p.toLowerCase();e=e.filter(e=>e.name.toLowerCase().includes(t)||e.title.toLowerCase().includes(t)||e.description.toLowerCase().includes(t))}return e},[n,f,p]),v=(0,b.useMemo)(()=>{let e={};for(let t of y){let s=t.category||"Other";e[s]||(e[s]=[]),e[s].push(t)}return e},[y]);return(0,t.jsxs)(h.Modal,{title:(0,t.jsxs)("div",{className:"flex items-center justify-between pb-4 border-b border-gray-100",children:[(0,t.jsxs)("div",{className:"flex items-center space-x-3",children:[(0,t.jsx)("img",{src:eZ,alt:"MCP Logo",className:"w-8 h-8 object-contain",style:{height:"20px",width:"20px",marginRight:"8px",objectFit:"contain"}}),(0,t.jsx)("h2",{className:"text-xl font-semibold text-gray-900",children:"Add MCP Server"})]}),(0,t.jsx)("button",{onClick:l,className:"text-sm text-blue-600 hover:text-blue-800 cursor-pointer bg-transparent border-none font-medium",children:"+ Custom Server"})]}),open:e,onCancel:s,footer:null,width:1e3,className:"top-8",styles:{body:{padding:"24px",maxHeight:"70vh",overflowY:"auto"},header:{padding:"24px 24px 0 24px",border:"none"}},children:[(0,t.jsx)("div",{style:{display:"flex",gap:6,flexWrap:"wrap",marginBottom:12},children:["All",...o].map(e=>{let s=f===e;return(0,t.jsx)("button",{onClick:()=>j(e),style:{padding:"4px 12px",borderRadius:4,border:s?"1px solid #111827":"1px solid #e5e7eb",background:s?"#111827":"#fff",color:s?"#fff":"#4b5563",cursor:"pointer",fontSize:12,fontWeight:s?500:400,lineHeight:"20px"},children:e},e)})}),(0,t.jsx)(tY,{placeholder:"Search servers...",value:p,onChange:e=>g(e.target.value),style:{marginBottom:16},allowClear:!0}),d&&(0,t.jsx)("div",{style:{display:"flex",flexDirection:"column",gap:4},children:Array.from({length:8}).map((e,s)=>(0,t.jsx)("div",{style:{height:36,borderRadius:6,background:"#f9fafb"}},s))}),u&&(0,t.jsx)("div",{style:{textAlign:"center",padding:"32px 0",color:"#9ca3af"},children:(0,t.jsxs)(tG,{children:["Failed to load servers: ",u]})}),!d&&!u&&0===y.length&&(0,t.jsx)("div",{style:{textAlign:"center",padding:"32px 0",color:"#9ca3af"},children:(0,t.jsxs)(tG,{children:["No servers found."," ",(0,t.jsx)("a",{onClick:l,style:{color:"#2563eb",cursor:"pointer"},children:"Add a custom server"})]})}),!d&&!u&&Object.entries(v).map(([e,s])=>(0,t.jsxs)("div",{style:{marginBottom:16},children:[(0,t.jsx)("div",{style:{fontSize:11,fontWeight:500,color:"#9ca3af",textTransform:"uppercase",letterSpacing:"0.05em",padding:"6px 0",borderBottom:"1px solid #f3f4f6",marginBottom:4},children:e}),(0,t.jsx)("div",{style:{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"0 16px"},children:s.map(e=>{var s;let l,a,n=(l=(s=e.title||e.name).charAt(0).toUpperCase(),a=s.split("").reduce((e,t)=>e+t.charCodeAt(0),0)%tQ.length,{initial:l,backgroundColor:tQ[a]});return(0,t.jsxs)("div",{onClick:()=>r(e),style:{display:"flex",alignItems:"center",padding:"8px 10px",borderRadius:6,cursor:"pointer",transition:"background 0.1s ease"},onMouseEnter:e=>{e.currentTarget.style.background="#f9fafb"},onMouseLeave:e=>{e.currentTarget.style.background="transparent"},children:[e.icon_url?(0,t.jsx)("img",{src:e.icon_url,alt:e.title,style:{width:20,height:20,objectFit:"contain",flexShrink:0,marginRight:12},onError:e=>{let t=e.currentTarget;t.style.display="none";let s=t.nextElementSibling;s&&(s.style.display="flex")}}):null,(0,t.jsx)("div",{style:{width:20,height:20,borderRadius:4,backgroundColor:n.backgroundColor,color:"#fff",display:e.icon_url?"none":"flex",alignItems:"center",justifyContent:"center",fontWeight:600,fontSize:11,flexShrink:0,marginRight:12},children:n.initial}),(0,t.jsx)("span",{style:{fontSize:14,fontWeight:400,color:"#111827",flex:1,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:e.title||e.name}),(0,t.jsx)("span",{style:{color:"#d1d5db",fontSize:14,flexShrink:0,marginLeft:8},children:"›"})]},e.name)})})]},e))]})};var tX=e.i(611052);let{Text:t0,Title:t2}=f.Typography,{Option:t1}=p.Select;e.s(["MCPServers",0,({accessToken:e,userRole:f,userID:N})=>{let{data:T,isLoading:k,refetch:A}=(0,j.useMCPServers)(),{data:I,isLoading:P,recheckServerHealth:O,recheckingServerIds:M}=(()=>{let{accessToken:e}=(0,w.default)(),t=(0,v.useQueryClient)(),[s,r]=(0,b.useState)(new Set),l=(0,y.useQuery)({queryKey:S.lists(),queryFn:async()=>await (0,_.fetchMCPServerHealth)(e),enabled:!!e,refetchInterval:3e4}),a=(0,b.useCallback)(async s=>{if(e){r(e=>new Set(e).add(s));try{let r=await (0,_.fetchMCPServerHealth)(e,[s]);t.setQueriesData({queryKey:S.lists()},e=>e?e.map(e=>r.find(t=>t.server_id===e.server_id)??e):r)}finally{r(e=>{let t=new Set(e);return t.delete(s),t})}}},[e,t]);return{...l,recheckServerHealth:a,recheckingServerIds:s}})(),F=(0,b.useMemo)(()=>{if(!T)return[];if(!I)return T;let e=new Map(I.map(e=>[e.server_id,e.status]));return T.map(t=>{let s=e.get(t.server_id);return{...t,status:s||t.status}})},[T,I]),[E,L]=(0,b.useState)(null),[R,U]=(0,b.useState)(!1),[z,B]=(0,b.useState)(null),[q,V]=(0,b.useState)(!1),[D,H]=(0,b.useState)("all"),[K,W]=(0,b.useState)("all"),[J,Y]=(0,b.useState)([]),[Q,X]=(0,b.useState)(!1),[ee,et]=(0,b.useState)(!1),[es,el]=(0,b.useState)(null),[ea,en]=(0,b.useState)(!1),[ei,eo]=(0,b.useState)(null),ec="Internal User"===f;(0,b.useEffect)(()=>{try{let e=(0,eG.getSecureItem)("litellm-mcp-oauth-edit-state");if(!e)return;let t=JSON.parse(e);t?.serverId&&(B(t.serverId),V(!0))}catch(e){console.error("Failed to restore MCP edit view state",e)}},[]);let ed=b.default.useMemo(()=>{if(!F)return[];let e=new Set,t=[];return F.forEach(s=>{s.teams&&s.teams.forEach(s=>{let r=s.team_id;e.has(r)||(e.add(r),t.push(s))})}),t},[F]),em=b.default.useMemo(()=>F?Array.from(new Set(F.flatMap(e=>e.mcp_access_groups).filter(e=>null!=e))):[],[F]),eu=(0,b.useCallback)((e,t)=>{if(!F)return Y([]);let s=F;"personal"===e?Y([]):("all"!==e&&(s=s.filter(t=>t.teams?.some(t=>t.team_id===e))),"all"!==t&&(s=s.filter(e=>e.mcp_access_groups?.some(e=>"string"==typeof e?e===t:e&&e.name===t))),Y([...s].sort((e,t)=>e.created_at||t.created_at?e.created_at?t.created_at?new Date(t.created_at).getTime()-new Date(e.created_at).getTime():-1:1:0)))},[F]);(0,b.useEffect)(()=>{eu(D,K)},[F,D,K,eu]);let ex=b.default.useMemo(()=>{let e,s,r,l;return e=e=>{B(e),V(!1)},s=e=>{B(e),V(!0)},r=eh,l=e=>eo(e),[{accessorKey:"server_id",header:"Server ID",enableSorting:!0,cell:({row:s})=>(0,t.jsxs)("button",{onClick:()=>e(s.original.server_id),className:"font-mono text-blue-600 bg-blue-50 hover:bg-blue-100 text-xs font-medium px-2 py-0.5 rounded-md border border-blue-200 text-left truncate whitespace-nowrap cursor-pointer max-w-[15ch] transition-colors",children:[s.original.server_id.slice(0,7),"..."]})},{accessorKey:"server_name",header:"Name",enableSorting:!0,cell:({row:e})=>{let s=e.original.mcp_info?.logo_url,r=e.original.server_name;return(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[s?(0,t.jsx)("img",{src:s,alt:`${r??"MCP"} logo`,className:"h-5 w-5 rounded object-contain flex-shrink-0",onError:e=>{e.target.style.display="none"}}):null,(0,t.jsx)("span",{children:r})]})}},{accessorKey:"alias",header:"Alias",enableSorting:!0},{id:"url",header:"URL",cell:({row:e})=>{let s=e.original.url;if(!s)return(0,t.jsx)("span",{className:"text-gray-400",children:"—"});let{maskedUrl:r}=eH(s);return(0,t.jsx)("span",{className:"font-mono text-sm",children:r})}},{accessorKey:"transport",header:"Transport",enableSorting:!0,cell:({row:e})=>{let s=e.original.transport||"http",r=(e.original.spec_path&&"stdio"!==s?"OPENAPI":s).toUpperCase();return(0,t.jsx)("span",{className:"inline-flex items-center text-xs font-medium px-2 py-0.5 rounded border bg-gray-50 text-gray-700 border-gray-200",children:r})}},{accessorKey:"auth_type",header:"Auth Type",enableSorting:!0,cell:({getValue:e})=>{let s=e()||"none";return(0,t.jsx)("span",{className:"inline-flex items-center text-xs font-medium px-2 py-0.5 rounded border bg-gray-50 text-gray-700 border-gray-200",children:s})}},{id:"health_status",header:"Health Status",cell:({row:e})=>(0,t.jsx)(tu,{server:e.original,isLoadingHealth:P,isRechecking:M?.has(e.original.server_id),onRecheck:O})},{id:"mcp_access_groups",header:"Access Groups",cell:({row:e})=>{let s=e.original.mcp_access_groups;if(Array.isArray(s)&&s.length>0&&"string"==typeof s[0]){let e=s.join(", ");return(0,t.jsx)(g.Tooltip,{title:e,children:(0,t.jsxs)("div",{className:"flex items-center gap-1 max-w-[200px]",children:[(0,t.jsx)("span",{className:"inline-flex items-center text-xs font-medium px-1.5 py-0.5 rounded bg-gray-100 text-gray-700 border border-gray-200 truncate max-w-[140px]",children:s[0]}),s.length>1&&(0,t.jsxs)("span",{className:"text-xs text-gray-400 font-medium",children:["+",s.length-1]})]})})}return(0,t.jsx)("span",{className:"text-xs text-gray-400",children:"—"})}},{id:"available_on_public_internet",header:"Network Access",cell:({row:e})=>e.original.available_on_public_internet?(0,t.jsxs)("span",{className:"inline-flex items-center gap-1 px-2 py-0.5 bg-green-50 text-green-700 rounded-full border border-green-200 text-xs font-medium",children:[(0,t.jsx)("span",{className:"h-1.5 w-1.5 rounded-full bg-green-500"}),"Public"]}):(0,t.jsxs)("span",{className:"inline-flex items-center gap-1 px-2 py-0.5 bg-orange-50 text-orange-700 rounded-full border border-orange-200 text-xs font-medium",children:[(0,t.jsx)("span",{className:"h-1.5 w-1.5 rounded-full bg-orange-500"}),"Internal"]})},{header:"Created",accessorKey:"created_at",enableSorting:!0,sortingFn:"datetime",cell:({row:e})=>{let s=e.original;if(!s.created_at)return(0,t.jsx)("span",{className:"text-xs text-gray-400",children:"—"});let r=new Date(s.created_at);return(0,t.jsx)(g.Tooltip,{title:r.toLocaleString(),children:(0,t.jsx)("span",{className:"text-xs text-gray-600",children:r.toLocaleDateString()})})}},{header:"Updated",accessorKey:"updated_at",enableSorting:!0,sortingFn:"datetime",cell:({row:e})=>{let s=e.original;if(!s.updated_at)return(0,t.jsx)("span",{className:"text-xs text-gray-400",children:"—"});let r=new Date(s.updated_at);return(0,t.jsx)(g.Tooltip,{title:r.toLocaleString(),children:(0,t.jsx)("span",{className:"text-xs text-gray-600",children:r.toLocaleDateString()})})}},{id:"byok_credential",header:"Credential",cell:({row:e})=>{let s=e.original;return s.is_byok?s.has_user_credential?(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsxs)("span",{className:"inline-flex items-center gap-1 text-xs font-medium px-2 py-0.5 rounded-full bg-green-50 text-green-700 border border-green-200",children:[(0,t.jsx)(tm.CheckOutlined,{style:{fontSize:10}})," Connected"]}),l&&(0,t.jsx)("button",{className:"text-xs text-gray-400 hover:text-blue-600 transition-colors",onClick:()=>l(s),children:"Update"})]}):l?(0,t.jsx)("button",{className:"text-xs bg-blue-600 hover:bg-blue-700 text-white px-3 py-1 rounded-md font-medium transition-colors shadow-sm",onClick:()=>l(s),children:"Connect"}):null:(0,t.jsx)("span",{className:"text-gray-300 text-xs",children:"—"})}},{id:"actions",header:"Actions",cell:({row:e})=>(0,t.jsxs)("div",{className:"flex items-center gap-1",children:[(0,t.jsx)(g.Tooltip,{title:"Edit",children:(0,t.jsx)("button",{onClick:()=>s(e.original.server_id),className:"p-1.5 rounded-md text-gray-400 hover:text-blue-600 hover:bg-blue-50 transition-colors",children:(0,t.jsx)(tc.Icon,{icon:td.PencilAltIcon,size:"sm"})})}),(0,t.jsx)(g.Tooltip,{title:"Delete",children:(0,t.jsx)("button",{onClick:()=>r(e.original.server_id),className:"p-1.5 rounded-md text-gray-400 hover:text-red-600 hover:bg-red-50 transition-colors",children:(0,t.jsx)(tc.Icon,{icon:G.TrashIcon,size:"sm"})})})]})}]},[f,P,O,M]);function eh(e){L(e),U(!0)}let ep=async()=>{if(null!=E&&null!=e)try{en(!0),await (0,_.deleteMCPServer)(e,E),C.default.success("Deleted MCP Server successfully"),A()}catch(e){console.error("Error deleting the mcp server:",e)}finally{en(!1),U(!1),L(null)}},eg=E?(T||[]).find(e=>e.server_id===E):null,ef=b.default.useMemo(()=>J.find(e=>e.server_id===z)||{server_id:"",server_name:"",alias:"",url:"",transport:"",auth_type:"",created_at:"",created_by:"",updated_at:"",updated_by:""},[J,z]),eb=b.default.useCallback(()=>{V(!1),B(null),A()},[A]);return e&&f&&N?(0,t.jsxs)("div",{className:"w-full h-full p-6",children:[(0,t.jsx)(h.Modal,{open:R,title:"Delete MCP Server?",onOk:ep,okText:ea?"Deleting...":"Delete",onCancel:()=>{U(!1),L(null)},cancelText:"Cancel",cancelButtonProps:{disabled:ea},okButtonProps:{danger:!0},confirmLoading:ea,children:(0,t.jsxs)("div",{className:"space-y-4",children:[(0,t.jsx)(t0,{className:"text-gray-600",children:"This action is permanent and cannot be undone. All associated configurations will be removed."}),eg&&(0,t.jsx)("div",{className:"mt-3 p-4 bg-gray-50 rounded-lg border border-gray-200",children:(0,t.jsxs)(x.Descriptions,{column:1,size:"small",colon:!1,children:[eg.server_name&&(0,t.jsx)(x.Descriptions.Item,{label:(0,t.jsx)("span",{className:"text-gray-500 text-sm",children:"Name"}),children:(0,t.jsx)(t0,{strong:!0,className:"text-sm",children:eg.server_name})}),(0,t.jsx)(x.Descriptions.Item,{label:(0,t.jsx)("span",{className:"text-gray-500 text-sm",children:"ID"}),children:(0,t.jsx)(t0,{code:!0,className:"text-xs",children:eg.server_id})}),eg.url&&(0,t.jsx)(x.Descriptions.Item,{label:(0,t.jsx)("span",{className:"text-gray-500 text-sm",children:"URL"}),children:(0,t.jsx)(t0,{code:!0,className:"text-xs break-all",children:eg.url})})]})})]})}),(0,t.jsx)(e5,{userRole:f,accessToken:e,onCreateSuccess:e=>{Y(t=>[...t,e]),X(!1),A()},isModalVisible:Q,setModalVisible:X,availableAccessGroups:em,prefillData:es,onBackToDiscovery:()=>{X(!1),el(null),et(!0)}}),(0,t.jsxs)("div",{className:"flex items-center justify-between",children:[(0,t.jsxs)("div",{children:[(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[(0,t.jsx)(m.Title,{children:"MCP Servers"}),J.length>0&&(0,t.jsx)("span",{className:"inline-flex items-center text-xs font-medium px-2 py-0.5 rounded-full bg-gray-100 text-gray-600 border border-gray-200",children:J.length})]}),(0,t.jsx)(d.Text,{className:"text-tremor-content mt-1",children:"Configure and manage your MCP servers"})]}),(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,s.isAdminRole)(f)&&(0,t.jsx)(l.Button,{className:"flex-shrink-0",onClick:()=>et(!0),children:"+ Add New MCP Server"}),!(0,s.isAdminRole)(f)&&(0,t.jsx)(l.Button,{className:"flex-shrink-0",onClick:()=>{el(null),X(!0)},variant:"secondary",children:"+ Submit MCP Server"})]})]}),(0,t.jsx)(tZ,{isVisible:ee,onClose:()=>et(!1),onSelectServer:e=>{el(e),et(!1),X(!0)},onCustomServer:()=>{el(null),et(!1),X(!0)},accessToken:e}),(0,t.jsxs)(n.TabGroup,{className:"w-full h-full",children:[(0,t.jsx)(i.TabList,{className:"flex justify-between mt-2 w-full items-center",children:(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)(a.Tab,{children:"All Servers"}),(0,t.jsx)(a.Tab,{children:"Toolsets"}),(0,t.jsx)(a.Tab,{children:"Connect"}),(0,t.jsx)(a.Tab,{children:"Semantic Filter"}),(0,t.jsx)(a.Tab,{children:"Network Settings"}),(0,s.isAdminRole)(f)&&(0,t.jsx)(a.Tab,{children:(0,t.jsxs)("span",{className:"flex items-center gap-2",children:["Submitted MCPs ",(0,t.jsx)(u.default,{})]})})]})}),(0,t.jsxs)(c.TabPanels,{children:[(0,t.jsx)(o.TabPanel,{children:z?(0,t.jsx)(tI,{mcpServer:ef,onBack:eb,isProxyAdmin:(0,s.isAdminRole)(f),isEditing:q,accessToken:e,userID:N,userRole:f,availableAccessGroups:em},z):(0,t.jsxs)("div",{className:"w-full h-full",children:[(0,t.jsx)("div",{className:"w-full",children:(0,t.jsx)("div",{className:"flex flex-col space-y-4",children:(0,t.jsxs)("div",{className:"flex items-center gap-6 bg-white rounded-lg px-4 py-3 border border-gray-200",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(d.Text,{className:"text-sm font-medium text-gray-600 whitespace-nowrap",children:"Team"}),(0,t.jsxs)(p.Select,{value:D,onChange:e=>{H(e),eu(e,K)},style:{width:220},size:"middle",children:[(0,t.jsx)(t1,{value:"all",children:(0,t.jsx)("span",{className:"font-medium",children:ec?"All Available Servers":"All Servers"})}),(0,t.jsx)(t1,{value:"personal",children:(0,t.jsx)("span",{className:"font-medium",children:"Personal"})}),ed.map(e=>(0,t.jsx)(t1,{value:e.team_id,children:(0,t.jsx)("span",{className:"font-medium",children:e.team_alias||e.team_id})},e.team_id))]})]}),(0,t.jsx)("div",{className:"h-6 w-px bg-gray-200"}),(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsxs)(d.Text,{className:"text-sm font-medium text-gray-600 whitespace-nowrap",children:["Access Group",(0,t.jsx)(g.Tooltip,{title:"An MCP Access Group is a set of users or teams that have permission to access specific MCP servers. Use access groups to control and organize who can connect to which servers.",children:(0,t.jsx)(r.QuestionCircleOutlined,{style:{marginLeft:4,color:"#9ca3af"}})})]}),(0,t.jsxs)(p.Select,{value:K,onChange:e=>{W(e),eu(D,e)},style:{width:220},size:"middle",children:[(0,t.jsx)(t1,{value:"all",children:(0,t.jsx)("span",{className:"font-medium",children:"All Access Groups"})}),em.map(e=>(0,t.jsx)(t1,{value:e,children:(0,t.jsx)("span",{className:"font-medium",children:e})},e))]})]})]})})}),(0,t.jsx)("div",{className:"w-full mt-6",children:(0,t.jsx)(Z.DataTable,{data:J,columns:ex,renderSubComponent:()=>(0,t.jsx)("div",{}),getRowCanExpand:()=>!1,isLoading:k,noDataMessage:"No MCP servers configured. Click '+ Add New MCP Server' to get started.",loadingMessage:"Loading MCP servers...",enableSorting:!0})})]})}),(0,t.jsx)(o.TabPanel,{children:(0,t.jsx)(er,{accessToken:e,userRole:f})}),(0,t.jsx)(o.TabPanel,{children:(0,t.jsx)(to,{})}),(0,t.jsx)(o.TabPanel,{children:(0,t.jsx)(tH,{accessToken:e})}),(0,t.jsx)(o.TabPanel,{children:(0,t.jsx)(tJ,{accessToken:e})}),(0,s.isAdminRole)(f)&&(0,t.jsx)(o.TabPanel,{children:(0,t.jsx)($,{accessToken:e})})]})]}),ei&&(0,t.jsx)(tX.ByokCredentialModal,{server:ei,open:!!ei,onClose:()=>eo(null),onSuccess:e=>{A(),eo(null)},accessToken:e||""})]}):(console.log("Missing required authentication parameters",{accessToken:e,userRole:f,userID:N}),(0,t.jsx)("div",{className:"p-6 text-center text-gray-500",children:"Missing required authentication parameters."}))}],280881)}]); -======== -}'`})})]})]})}):(0,t.jsx)("div",{className:"p-6 text-center text-gray-500",children:"Please log in to configure semantic filter settings."})}var tK=e.i(262218);let{Text:tW}=f.Typography,tJ=({accessToken:e})=>{let s,[r,l]=(0,b.useState)(!0),[a,n]=(0,b.useState)(!1),[i,o]=(0,b.useState)([]),[c,d]=(0,b.useState)(null);(0,b.useEffect)(()=>{m(),u()},[e]);let m=async()=>{if(e){l(!0);try{for(let t of(await (0,_.getGeneralSettingsCall)(e)))"mcp_internal_ip_ranges"===t.field_name&&t.field_value&&o(t.field_value)}catch(e){console.error("Failed to load MCP network settings:",e)}finally{l(!1)}}},u=async()=>{if(!e)return;let t=await (0,_.fetchMCPClientIp)(e);t&&d(t)},x=async()=>{if(e){n(!0);try{i.length>0?await (0,_.updateConfigFieldSetting)(e,"mcp_internal_ip_ranges",i):await (0,_.deleteConfigFieldSetting)(e,"mcp_internal_ip_ranges")}catch(e){console.error("Failed to save MCP network settings:",e)}finally{n(!1)}}};if(r)return(0,t.jsx)("div",{className:"flex justify-center py-12",children:(0,t.jsx)(W.Spin,{})});let h=c?4!==(s=c.split(".")).length?c+"/32":`${s[0]}.${s[1]}.${s[2]}.0/24`:null;return(0,t.jsxs)("div",{className:"space-y-6 p-4",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)(tW,{className:"text-lg font-semibold",children:"Private IP Ranges"}),(0,t.jsx)("p",{className:"text-sm text-gray-500 mt-1",children:'Define which IP ranges are part of your private network. Callers from these IPs can see all MCP servers. Callers from any other IP can only see servers marked "Available on Public Internet".'})]}),(0,t.jsxs)(e4.Card,{children:[c&&(0,t.jsxs)("div",{className:"mb-4 p-3 bg-blue-50 rounded-lg",children:[(0,t.jsxs)(tW,{className:"text-sm text-blue-700",children:["Your current IP: ",(0,t.jsx)("span",{className:"font-mono font-medium",children:c})]}),h&&!i.includes(h)&&(0,t.jsxs)("div",{className:"mt-1",children:[(0,t.jsx)(tW,{className:"text-sm text-blue-600",children:"Suggested range: "}),(0,t.jsx)(tK.Tag,{className:"cursor-pointer font-mono",color:"blue",icon:(0,t.jsx)(eE.PlusOutlined,{}),onClick:()=>{!i.includes(h)&&o([...i,h])},children:h})]})]}),(0,t.jsx)("div",{className:"flex items-center mb-2",children:(0,t.jsx)(tW,{className:"font-medium",children:"Your Private Network Ranges"})}),(0,t.jsx)(p.Select,{mode:"tags",value:i,onChange:o,placeholder:"Leave empty to use defaults: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.0/8",tokenSeparators:[","],className:"w-full",size:"large",allowClear:!0}),(0,t.jsx)("p",{className:"text-xs text-gray-400 mt-2",children:"Enter CIDR ranges (e.g., 10.0.0.0/8). When empty, standard private IP ranges are used."})]}),(0,t.jsx)("div",{className:"flex justify-end",children:(0,t.jsx)(eb.Button,{type:"primary",icon:(0,t.jsx)(tR.SaveOutlined,{}),onClick:x,loading:a,children:"Save"})})]})},{Search:tY}=H.Input,{Text:tG}=f.Typography,tQ=["#3B82F6","#10B981","#F59E0B","#EF4444","#8B5CF6","#EC4899","#06B6D4","#84CC16"],tZ=({isVisible:e,onClose:s,onSelectServer:r,onCustomServer:l,accessToken:a})=>{let[n,i]=(0,b.useState)([]),[o,c]=(0,b.useState)([]),[d,m]=(0,b.useState)(!1),[u,x]=(0,b.useState)(null),[p,g]=(0,b.useState)(""),[f,j]=(0,b.useState)("All");(0,b.useEffect)(()=>{e&&a&&(m(!0),x(null),(0,_.fetchDiscoverableMCPServers)(a).then(e=>{i(e.servers||[]),c(e.categories||[])}).catch(e=>{x(e.message||"Failed to load MCP servers")}).finally(()=>{m(!1)}))},[e,a]),(0,b.useEffect)(()=>{e&&(g(""),j("All"))},[e]);let y=(0,b.useMemo)(()=>{let e=n;if("All"!==f&&(e=e.filter(e=>e.category===f)),p.trim()){let t=p.toLowerCase();e=e.filter(e=>e.name.toLowerCase().includes(t)||e.title.toLowerCase().includes(t)||e.description.toLowerCase().includes(t))}return e},[n,f,p]),v=(0,b.useMemo)(()=>{let e={};for(let t of y){let s=t.category||"Other";e[s]||(e[s]=[]),e[s].push(t)}return e},[y]);return(0,t.jsxs)(h.Modal,{title:(0,t.jsxs)("div",{className:"flex items-center justify-between pb-4 border-b border-gray-100",children:[(0,t.jsxs)("div",{className:"flex items-center space-x-3",children:[(0,t.jsx)("img",{src:eZ,alt:"MCP Logo",className:"w-8 h-8 object-contain",style:{height:"20px",width:"20px",marginRight:"8px",objectFit:"contain"}}),(0,t.jsx)("h2",{className:"text-xl font-semibold text-gray-900",children:"Add MCP Server"})]}),(0,t.jsx)("button",{onClick:l,className:"text-sm text-blue-600 hover:text-blue-800 cursor-pointer bg-transparent border-none font-medium",children:"+ Custom Server"})]}),open:e,onCancel:s,footer:null,width:1e3,className:"top-8",styles:{body:{padding:"24px",maxHeight:"70vh",overflowY:"auto"},header:{padding:"24px 24px 0 24px",border:"none"}},children:[(0,t.jsx)("div",{style:{display:"flex",gap:6,flexWrap:"wrap",marginBottom:12},children:["All",...o].map(e=>{let s=f===e;return(0,t.jsx)("button",{onClick:()=>j(e),style:{padding:"4px 12px",borderRadius:4,border:s?"1px solid #111827":"1px solid #e5e7eb",background:s?"#111827":"#fff",color:s?"#fff":"#4b5563",cursor:"pointer",fontSize:12,fontWeight:s?500:400,lineHeight:"20px"},children:e},e)})}),(0,t.jsx)(tY,{placeholder:"Search servers...",value:p,onChange:e=>g(e.target.value),style:{marginBottom:16},allowClear:!0}),d&&(0,t.jsx)("div",{style:{display:"flex",flexDirection:"column",gap:4},children:Array.from({length:8}).map((e,s)=>(0,t.jsx)("div",{style:{height:36,borderRadius:6,background:"#f9fafb"}},s))}),u&&(0,t.jsx)("div",{style:{textAlign:"center",padding:"32px 0",color:"#9ca3af"},children:(0,t.jsxs)(tG,{children:["Failed to load servers: ",u]})}),!d&&!u&&0===y.length&&(0,t.jsx)("div",{style:{textAlign:"center",padding:"32px 0",color:"#9ca3af"},children:(0,t.jsxs)(tG,{children:["No servers found."," ",(0,t.jsx)("a",{onClick:l,style:{color:"#2563eb",cursor:"pointer"},children:"Add a custom server"})]})}),!d&&!u&&Object.entries(v).map(([e,s])=>(0,t.jsxs)("div",{style:{marginBottom:16},children:[(0,t.jsx)("div",{style:{fontSize:11,fontWeight:500,color:"#9ca3af",textTransform:"uppercase",letterSpacing:"0.05em",padding:"6px 0",borderBottom:"1px solid #f3f4f6",marginBottom:4},children:e}),(0,t.jsx)("div",{style:{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"0 16px"},children:s.map(e=>{var s;let l,a,n=(l=(s=e.title||e.name).charAt(0).toUpperCase(),a=s.split("").reduce((e,t)=>e+t.charCodeAt(0),0)%tQ.length,{initial:l,backgroundColor:tQ[a]});return(0,t.jsxs)("div",{onClick:()=>r(e),style:{display:"flex",alignItems:"center",padding:"8px 10px",borderRadius:6,cursor:"pointer",transition:"background 0.1s ease"},onMouseEnter:e=>{e.currentTarget.style.background="#f9fafb"},onMouseLeave:e=>{e.currentTarget.style.background="transparent"},children:[e.icon_url?(0,t.jsx)("img",{src:e.icon_url,alt:e.title,style:{width:20,height:20,objectFit:"contain",flexShrink:0,marginRight:12},onError:e=>{let t=e.currentTarget;t.style.display="none";let s=t.nextElementSibling;s&&(s.style.display="flex")}}):null,(0,t.jsx)("div",{style:{width:20,height:20,borderRadius:4,backgroundColor:n.backgroundColor,color:"#fff",display:e.icon_url?"none":"flex",alignItems:"center",justifyContent:"center",fontWeight:600,fontSize:11,flexShrink:0,marginRight:12},children:n.initial}),(0,t.jsx)("span",{style:{fontSize:14,fontWeight:400,color:"#111827",flex:1,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:e.title||e.name}),(0,t.jsx)("span",{style:{color:"#d1d5db",fontSize:14,flexShrink:0,marginLeft:8},children:"›"})]},e.name)})})]},e))]})};var tX=e.i(611052);let{Text:t0,Title:t2}=f.Typography,{Option:t1}=p.Select;e.s(["MCPServers",0,({accessToken:e,userRole:f,userID:N})=>{let{data:T,isLoading:k,refetch:A}=(0,j.useMCPServers)(),{data:I,isLoading:P,recheckServerHealth:O,recheckingServerIds:M}=(()=>{let{accessToken:e}=(0,w.default)(),t=(0,v.useQueryClient)(),[s,r]=(0,b.useState)(new Set),l=(0,y.useQuery)({queryKey:S.lists(),queryFn:async()=>await (0,_.fetchMCPServerHealth)(e),enabled:!!e,refetchInterval:3e4}),a=(0,b.useCallback)(async s=>{if(e){r(e=>new Set(e).add(s));try{let r=await (0,_.fetchMCPServerHealth)(e,[s]);t.setQueriesData({queryKey:S.lists()},e=>e?e.map(e=>r.find(t=>t.server_id===e.server_id)??e):r)}finally{r(e=>{let t=new Set(e);return t.delete(s),t})}}},[e,t]);return{...l,recheckServerHealth:a,recheckingServerIds:s}})(),F=(0,b.useMemo)(()=>{if(!T)return[];if(!I)return T;let e=new Map(I.map(e=>[e.server_id,e.status]));return T.map(t=>{let s=e.get(t.server_id);return{...t,status:s||t.status}})},[T,I]),[E,L]=(0,b.useState)(null),[R,z]=(0,b.useState)(!1),[U,B]=(0,b.useState)(null),[q,V]=(0,b.useState)(!1),[D,H]=(0,b.useState)("all"),[K,W]=(0,b.useState)("all"),[J,Y]=(0,b.useState)([]),[Q,X]=(0,b.useState)(!1),[ee,et]=(0,b.useState)(!1),[es,el]=(0,b.useState)(null),[ea,en]=(0,b.useState)(!1),[ei,eo]=(0,b.useState)(null),ec="Internal User"===f;(0,b.useEffect)(()=>{try{let e=(0,eG.getSecureItem)("litellm-mcp-oauth-edit-state");if(!e)return;let t=JSON.parse(e);t?.serverId&&(B(t.serverId),V(!0))}catch(e){console.error("Failed to restore MCP edit view state",e)}},[]);let ed=b.default.useMemo(()=>{if(!F)return[];let e=new Set,t=[];return F.forEach(s=>{s.teams&&s.teams.forEach(s=>{let r=s.team_id;e.has(r)||(e.add(r),t.push(s))})}),t},[F]),em=b.default.useMemo(()=>F?Array.from(new Set(F.flatMap(e=>e.mcp_access_groups).filter(e=>null!=e))):[],[F]),eu=(0,b.useCallback)((e,t)=>{if(!F)return Y([]);let s=F;"personal"===e?Y([]):("all"!==e&&(s=s.filter(t=>t.teams?.some(t=>t.team_id===e))),"all"!==t&&(s=s.filter(e=>e.mcp_access_groups?.some(e=>"string"==typeof e?e===t:e&&e.name===t))),Y([...s].sort((e,t)=>e.created_at||t.created_at?e.created_at?t.created_at?new Date(t.created_at).getTime()-new Date(e.created_at).getTime():-1:1:0)))},[F]);(0,b.useEffect)(()=>{eu(D,K)},[F,D,K,eu]);let ex=b.default.useMemo(()=>{let e,s,r,l;return e=e=>{B(e),V(!1)},s=e=>{B(e),V(!0)},r=eh,l=e=>eo(e),[{accessorKey:"server_id",header:"Server ID",enableSorting:!0,cell:({row:s})=>(0,t.jsxs)("button",{onClick:()=>e(s.original.server_id),className:"font-mono text-blue-600 bg-blue-50 hover:bg-blue-100 text-xs font-medium px-2 py-0.5 rounded-md border border-blue-200 text-left truncate whitespace-nowrap cursor-pointer max-w-[15ch] transition-colors",children:[s.original.server_id.slice(0,7),"..."]})},{accessorKey:"server_name",header:"Name",enableSorting:!0,cell:({row:e})=>{let s=e.original.mcp_info?.logo_url,r=e.original.server_name;return(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[s?(0,t.jsx)("img",{src:s,alt:`${r??"MCP"} logo`,className:"h-5 w-5 rounded object-contain flex-shrink-0",onError:e=>{e.target.style.display="none"}}):null,(0,t.jsx)("span",{children:r})]})}},{accessorKey:"alias",header:"Alias",enableSorting:!0},{id:"url",header:"URL",cell:({row:e})=>{let s=e.original.url;if(!s)return(0,t.jsx)("span",{className:"text-gray-400",children:"—"});let{maskedUrl:r}=eH(s);return(0,t.jsx)("span",{className:"font-mono text-sm",children:r})}},{accessorKey:"transport",header:"Transport",enableSorting:!0,cell:({row:e})=>{let s=e.original.transport||"http",r=(e.original.spec_path&&"stdio"!==s?"OPENAPI":s).toUpperCase();return(0,t.jsx)("span",{className:"inline-flex items-center text-xs font-medium px-2 py-0.5 rounded border bg-gray-50 text-gray-700 border-gray-200",children:r})}},{accessorKey:"auth_type",header:"Auth Type",enableSorting:!0,cell:({getValue:e})=>{let s=e()||"none";return(0,t.jsx)("span",{className:"inline-flex items-center text-xs font-medium px-2 py-0.5 rounded border bg-gray-50 text-gray-700 border-gray-200",children:s})}},{id:"health_status",header:"Health Status",cell:({row:e})=>(0,t.jsx)(tu,{server:e.original,isLoadingHealth:P,isRechecking:M?.has(e.original.server_id),onRecheck:O})},{id:"mcp_access_groups",header:"Access Groups",cell:({row:e})=>{let s=e.original.mcp_access_groups;if(Array.isArray(s)&&s.length>0&&"string"==typeof s[0]){let e=s.join(", ");return(0,t.jsx)(g.Tooltip,{title:e,children:(0,t.jsxs)("div",{className:"flex items-center gap-1 max-w-[200px]",children:[(0,t.jsx)("span",{className:"inline-flex items-center text-xs font-medium px-1.5 py-0.5 rounded bg-gray-100 text-gray-700 border border-gray-200 truncate max-w-[140px]",children:s[0]}),s.length>1&&(0,t.jsxs)("span",{className:"text-xs text-gray-400 font-medium",children:["+",s.length-1]})]})})}return(0,t.jsx)("span",{className:"text-xs text-gray-400",children:"—"})}},{id:"available_on_public_internet",header:"Network Access",cell:({row:e})=>e.original.available_on_public_internet?(0,t.jsxs)("span",{className:"inline-flex items-center gap-1 px-2 py-0.5 bg-green-50 text-green-700 rounded-full border border-green-200 text-xs font-medium",children:[(0,t.jsx)("span",{className:"h-1.5 w-1.5 rounded-full bg-green-500"}),"Public"]}):(0,t.jsxs)("span",{className:"inline-flex items-center gap-1 px-2 py-0.5 bg-orange-50 text-orange-700 rounded-full border border-orange-200 text-xs font-medium",children:[(0,t.jsx)("span",{className:"h-1.5 w-1.5 rounded-full bg-orange-500"}),"Internal"]})},{header:"Created",accessorKey:"created_at",enableSorting:!0,sortingFn:"datetime",cell:({row:e})=>{let s=e.original;if(!s.created_at)return(0,t.jsx)("span",{className:"text-xs text-gray-400",children:"—"});let r=new Date(s.created_at);return(0,t.jsx)(g.Tooltip,{title:r.toLocaleString(),children:(0,t.jsx)("span",{className:"text-xs text-gray-600",children:r.toLocaleDateString()})})}},{header:"Updated",accessorKey:"updated_at",enableSorting:!0,sortingFn:"datetime",cell:({row:e})=>{let s=e.original;if(!s.updated_at)return(0,t.jsx)("span",{className:"text-xs text-gray-400",children:"—"});let r=new Date(s.updated_at);return(0,t.jsx)(g.Tooltip,{title:r.toLocaleString(),children:(0,t.jsx)("span",{className:"text-xs text-gray-600",children:r.toLocaleDateString()})})}},{id:"byok_credential",header:"Credential",cell:({row:e})=>{let s=e.original;return s.is_byok?s.has_user_credential?(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsxs)("span",{className:"inline-flex items-center gap-1 text-xs font-medium px-2 py-0.5 rounded-full bg-green-50 text-green-700 border border-green-200",children:[(0,t.jsx)(tm.CheckOutlined,{style:{fontSize:10}})," Connected"]}),l&&(0,t.jsx)("button",{className:"text-xs text-gray-400 hover:text-blue-600 transition-colors",onClick:()=>l(s),children:"Update"})]}):l?(0,t.jsx)("button",{className:"text-xs bg-blue-600 hover:bg-blue-700 text-white px-3 py-1 rounded-md font-medium transition-colors shadow-sm",onClick:()=>l(s),children:"Connect"}):null:(0,t.jsx)("span",{className:"text-gray-300 text-xs",children:"—"})}},{id:"actions",header:"Actions",cell:({row:e})=>(0,t.jsxs)("div",{className:"flex items-center gap-1",children:[(0,t.jsx)(g.Tooltip,{title:"Edit",children:(0,t.jsx)("button",{onClick:()=>s(e.original.server_id),className:"p-1.5 rounded-md text-gray-400 hover:text-blue-600 hover:bg-blue-50 transition-colors",children:(0,t.jsx)(tc.Icon,{icon:td.PencilAltIcon,size:"sm"})})}),(0,t.jsx)(g.Tooltip,{title:"Delete",children:(0,t.jsx)("button",{onClick:()=>r(e.original.server_id),className:"p-1.5 rounded-md text-gray-400 hover:text-red-600 hover:bg-red-50 transition-colors",children:(0,t.jsx)(tc.Icon,{icon:G.TrashIcon,size:"sm"})})})]})}]},[f,P,O,M]);function eh(e){L(e),z(!0)}let ep=async()=>{if(null!=E&&null!=e)try{en(!0),await (0,_.deleteMCPServer)(e,E),C.default.success("Deleted MCP Server successfully"),A()}catch(e){console.error("Error deleting the mcp server:",e)}finally{en(!1),z(!1),L(null)}},eg=E?(T||[]).find(e=>e.server_id===E):null,ef=b.default.useMemo(()=>J.find(e=>e.server_id===U)||{server_id:"",server_name:"",alias:"",url:"",transport:"",auth_type:"",created_at:"",created_by:"",updated_at:"",updated_by:""},[J,U]),eb=b.default.useCallback(()=>{V(!1),B(null),A()},[A]);return e&&f&&N?(0,t.jsxs)("div",{className:"w-full h-full p-6",children:[(0,t.jsx)(h.Modal,{open:R,title:"Delete MCP Server?",onOk:ep,okText:ea?"Deleting...":"Delete",onCancel:()=>{z(!1),L(null)},cancelText:"Cancel",cancelButtonProps:{disabled:ea},okButtonProps:{danger:!0},confirmLoading:ea,children:(0,t.jsxs)("div",{className:"space-y-4",children:[(0,t.jsx)(t0,{className:"text-gray-600",children:"This action is permanent and cannot be undone. All associated configurations will be removed."}),eg&&(0,t.jsx)("div",{className:"mt-3 p-4 bg-gray-50 rounded-lg border border-gray-200",children:(0,t.jsxs)(x.Descriptions,{column:1,size:"small",colon:!1,children:[eg.server_name&&(0,t.jsx)(x.Descriptions.Item,{label:(0,t.jsx)("span",{className:"text-gray-500 text-sm",children:"Name"}),children:(0,t.jsx)(t0,{strong:!0,className:"text-sm",children:eg.server_name})}),(0,t.jsx)(x.Descriptions.Item,{label:(0,t.jsx)("span",{className:"text-gray-500 text-sm",children:"ID"}),children:(0,t.jsx)(t0,{code:!0,className:"text-xs",children:eg.server_id})}),eg.url&&(0,t.jsx)(x.Descriptions.Item,{label:(0,t.jsx)("span",{className:"text-gray-500 text-sm",children:"URL"}),children:(0,t.jsx)(t0,{code:!0,className:"text-xs break-all",children:eg.url})})]})})]})}),(0,t.jsx)(e5,{userRole:f,accessToken:e,onCreateSuccess:e=>{Y(t=>[...t,e]),X(!1),A()},isModalVisible:Q,setModalVisible:X,availableAccessGroups:em,prefillData:es,onBackToDiscovery:()=>{X(!1),el(null),et(!0)}}),(0,t.jsxs)("div",{className:"flex items-center justify-between",children:[(0,t.jsxs)("div",{children:[(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[(0,t.jsx)(m.Title,{children:"MCP Servers"}),J.length>0&&(0,t.jsx)("span",{className:"inline-flex items-center text-xs font-medium px-2 py-0.5 rounded-full bg-gray-100 text-gray-600 border border-gray-200",children:J.length})]}),(0,t.jsx)(d.Text,{className:"text-tremor-content mt-1",children:"Configure and manage your MCP servers"})]}),(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,s.isAdminRole)(f)&&(0,t.jsx)(l.Button,{className:"flex-shrink-0",onClick:()=>et(!0),children:"+ Add New MCP Server"}),!(0,s.isAdminRole)(f)&&(0,t.jsx)(l.Button,{className:"flex-shrink-0",onClick:()=>{el(null),X(!0)},variant:"secondary",children:"+ Submit MCP Server"})]})]}),(0,t.jsx)(tZ,{isVisible:ee,onClose:()=>et(!1),onSelectServer:e=>{el(e),et(!1),X(!0)},onCustomServer:()=>{el(null),et(!1),X(!0)},accessToken:e}),(0,t.jsxs)(n.TabGroup,{className:"w-full h-full",children:[(0,t.jsx)(i.TabList,{className:"flex justify-between mt-2 w-full items-center",children:(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)(a.Tab,{children:"All Servers"}),(0,t.jsx)(a.Tab,{children:"Toolsets"}),(0,t.jsx)(a.Tab,{children:"Connect"}),(0,t.jsx)(a.Tab,{children:"Semantic Filter"}),(0,t.jsx)(a.Tab,{children:"Network Settings"}),(0,s.isAdminRole)(f)&&(0,t.jsx)(a.Tab,{children:(0,t.jsxs)("span",{className:"flex items-center gap-2",children:["Submitted MCPs ",(0,t.jsx)(u.default,{})]})})]})}),(0,t.jsxs)(c.TabPanels,{children:[(0,t.jsx)(o.TabPanel,{children:U?(0,t.jsx)(tI,{mcpServer:ef,onBack:eb,isProxyAdmin:(0,s.isAdminRole)(f),isEditing:q,accessToken:e,userID:N,userRole:f,availableAccessGroups:em},U):(0,t.jsxs)("div",{className:"w-full h-full",children:[(0,t.jsx)("div",{className:"w-full",children:(0,t.jsx)("div",{className:"flex flex-col space-y-4",children:(0,t.jsxs)("div",{className:"flex items-center gap-6 bg-white rounded-lg px-4 py-3 border border-gray-200",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(d.Text,{className:"text-sm font-medium text-gray-600 whitespace-nowrap",children:"Team"}),(0,t.jsxs)(p.Select,{value:D,onChange:e=>{H(e),eu(e,K)},style:{width:220},size:"middle",children:[(0,t.jsx)(t1,{value:"all",children:(0,t.jsx)("span",{className:"font-medium",children:ec?"All Available Servers":"All Servers"})}),(0,t.jsx)(t1,{value:"personal",children:(0,t.jsx)("span",{className:"font-medium",children:"Personal"})}),ed.map(e=>(0,t.jsx)(t1,{value:e.team_id,children:(0,t.jsx)("span",{className:"font-medium",children:e.team_alias||e.team_id})},e.team_id))]})]}),(0,t.jsx)("div",{className:"h-6 w-px bg-gray-200"}),(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsxs)(d.Text,{className:"text-sm font-medium text-gray-600 whitespace-nowrap",children:["Access Group",(0,t.jsx)(g.Tooltip,{title:"An MCP Access Group is a set of users or teams that have permission to access specific MCP servers. Use access groups to control and organize who can connect to which servers.",children:(0,t.jsx)(r.QuestionCircleOutlined,{style:{marginLeft:4,color:"#9ca3af"}})})]}),(0,t.jsxs)(p.Select,{value:K,onChange:e=>{W(e),eu(D,e)},style:{width:220},size:"middle",children:[(0,t.jsx)(t1,{value:"all",children:(0,t.jsx)("span",{className:"font-medium",children:"All Access Groups"})}),em.map(e=>(0,t.jsx)(t1,{value:e,children:(0,t.jsx)("span",{className:"font-medium",children:e})},e))]})]})]})})}),(0,t.jsx)("div",{className:"w-full mt-6",children:(0,t.jsx)(Z.DataTable,{data:J,columns:ex,renderSubComponent:()=>(0,t.jsx)("div",{}),getRowCanExpand:()=>!1,isLoading:k,noDataMessage:"No MCP servers configured. Click '+ Add New MCP Server' to get started.",loadingMessage:"Loading MCP servers...",enableSorting:!0})})]})}),(0,t.jsx)(o.TabPanel,{children:(0,t.jsx)(er,{accessToken:e,userRole:f})}),(0,t.jsx)(o.TabPanel,{children:(0,t.jsx)(to,{})}),(0,t.jsx)(o.TabPanel,{children:(0,t.jsx)(tH,{accessToken:e})}),(0,t.jsx)(o.TabPanel,{children:(0,t.jsx)(tJ,{accessToken:e})}),(0,s.isAdminRole)(f)&&(0,t.jsx)(o.TabPanel,{children:(0,t.jsx)($,{accessToken:e})})]})]}),ei&&(0,t.jsx)(tX.ByokCredentialModal,{server:ei,open:!!ei,onClose:()=>eo(null),onSuccess:e=>{A(),eo(null)},accessToken:e||""})]}):(console.log("Missing required authentication parameters",{accessToken:e,userRole:f,userID:N}),(0,t.jsx)("div",{className:"p-6 text-center text-gray-500",children:"Missing required authentication parameters."}))}],280881)}]); ->>>>>>>> origin/litellm_internal_staging:litellm/proxy/_experimental/out/_next/static/chunks/e1a670efcb966aaa.js +}'`})})]})]})}):(0,t.jsx)("div",{className:"p-6 text-center text-gray-500",children:"Please log in to configure semantic filter settings."})}var tK=e.i(262218);let{Text:tW}=f.Typography,tJ=({accessToken:e})=>{let s,[r,l]=(0,b.useState)(!0),[a,n]=(0,b.useState)(!1),[i,o]=(0,b.useState)([]),[c,d]=(0,b.useState)(null);(0,b.useEffect)(()=>{m(),u()},[e]);let m=async()=>{if(e){l(!0);try{for(let t of(await (0,_.getGeneralSettingsCall)(e)))"mcp_internal_ip_ranges"===t.field_name&&t.field_value&&o(t.field_value)}catch(e){console.error("Failed to load MCP network settings:",e)}finally{l(!1)}}},u=async()=>{if(!e)return;let t=await (0,_.fetchMCPClientIp)(e);t&&d(t)},x=async()=>{if(e){n(!0);try{i.length>0?await (0,_.updateConfigFieldSetting)(e,"mcp_internal_ip_ranges",i):await (0,_.deleteConfigFieldSetting)(e,"mcp_internal_ip_ranges")}catch(e){console.error("Failed to save MCP network settings:",e)}finally{n(!1)}}};if(r)return(0,t.jsx)("div",{className:"flex justify-center py-12",children:(0,t.jsx)(W.Spin,{})});let h=c?4!==(s=c.split(".")).length?c+"/32":`${s[0]}.${s[1]}.${s[2]}.0/24`:null;return(0,t.jsxs)("div",{className:"space-y-6 p-4",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)(tW,{className:"text-lg font-semibold",children:"Private IP Ranges"}),(0,t.jsx)("p",{className:"text-sm text-gray-500 mt-1",children:'Define which IP ranges are part of your private network. Callers from these IPs can see all MCP servers. Callers from any other IP can only see servers marked "Available on Public Internet".'})]}),(0,t.jsxs)(e4.Card,{children:[c&&(0,t.jsxs)("div",{className:"mb-4 p-3 bg-blue-50 rounded-lg",children:[(0,t.jsxs)(tW,{className:"text-sm text-blue-700",children:["Your current IP: ",(0,t.jsx)("span",{className:"font-mono font-medium",children:c})]}),h&&!i.includes(h)&&(0,t.jsxs)("div",{className:"mt-1",children:[(0,t.jsx)(tW,{className:"text-sm text-blue-600",children:"Suggested range: "}),(0,t.jsx)(tK.Tag,{className:"cursor-pointer font-mono",color:"blue",icon:(0,t.jsx)(eE.PlusOutlined,{}),onClick:()=>{!i.includes(h)&&o([...i,h])},children:h})]})]}),(0,t.jsx)("div",{className:"flex items-center mb-2",children:(0,t.jsx)(tW,{className:"font-medium",children:"Your Private Network Ranges"})}),(0,t.jsx)(p.Select,{mode:"tags",value:i,onChange:o,placeholder:"Leave empty to use defaults: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.0/8",tokenSeparators:[","],className:"w-full",size:"large",allowClear:!0}),(0,t.jsx)("p",{className:"text-xs text-gray-400 mt-2",children:"Enter CIDR ranges (e.g., 10.0.0.0/8). When empty, standard private IP ranges are used."})]}),(0,t.jsx)("div",{className:"flex justify-end",children:(0,t.jsx)(eb.Button,{type:"primary",icon:(0,t.jsx)(tR.SaveOutlined,{}),onClick:x,loading:a,children:"Save"})})]})},{Search:tY}=H.Input,{Text:tG}=f.Typography,tQ=["#3B82F6","#10B981","#F59E0B","#EF4444","#8B5CF6","#EC4899","#06B6D4","#84CC16"],tZ=({isVisible:e,onClose:s,onSelectServer:r,onCustomServer:l,accessToken:a})=>{let[n,i]=(0,b.useState)([]),[o,c]=(0,b.useState)([]),[d,m]=(0,b.useState)(!1),[u,x]=(0,b.useState)(null),[p,g]=(0,b.useState)(""),[f,j]=(0,b.useState)("All");(0,b.useEffect)(()=>{e&&a&&(m(!0),x(null),(0,_.fetchDiscoverableMCPServers)(a).then(e=>{i(e.servers||[]),c(e.categories||[])}).catch(e=>{x(e.message||"Failed to load MCP servers")}).finally(()=>{m(!1)}))},[e,a]),(0,b.useEffect)(()=>{e&&(g(""),j("All"))},[e]);let y=(0,b.useMemo)(()=>{let e=n;if("All"!==f&&(e=e.filter(e=>e.category===f)),p.trim()){let t=p.toLowerCase();e=e.filter(e=>e.name.toLowerCase().includes(t)||e.title.toLowerCase().includes(t)||e.description.toLowerCase().includes(t))}return e},[n,f,p]),v=(0,b.useMemo)(()=>{let e={};for(let t of y){let s=t.category||"Other";e[s]||(e[s]=[]),e[s].push(t)}return e},[y]);return(0,t.jsxs)(h.Modal,{title:(0,t.jsxs)("div",{className:"flex items-center justify-between pb-4 border-b border-gray-100",children:[(0,t.jsxs)("div",{className:"flex items-center space-x-3",children:[(0,t.jsx)("img",{src:eZ,alt:"MCP Logo",className:"w-8 h-8 object-contain",style:{height:"20px",width:"20px",marginRight:"8px",objectFit:"contain"}}),(0,t.jsx)("h2",{className:"text-xl font-semibold text-gray-900",children:"Add MCP Server"})]}),(0,t.jsx)("button",{onClick:l,className:"text-sm text-blue-600 hover:text-blue-800 cursor-pointer bg-transparent border-none font-medium",children:"+ Custom Server"})]}),open:e,onCancel:s,footer:null,width:1e3,className:"top-8",styles:{body:{padding:"24px",maxHeight:"70vh",overflowY:"auto"},header:{padding:"24px 24px 0 24px",border:"none"}},children:[(0,t.jsx)("div",{style:{display:"flex",gap:6,flexWrap:"wrap",marginBottom:12},children:["All",...o].map(e=>{let s=f===e;return(0,t.jsx)("button",{onClick:()=>j(e),style:{padding:"4px 12px",borderRadius:4,border:s?"1px solid #111827":"1px solid #e5e7eb",background:s?"#111827":"#fff",color:s?"#fff":"#4b5563",cursor:"pointer",fontSize:12,fontWeight:s?500:400,lineHeight:"20px"},children:e},e)})}),(0,t.jsx)(tY,{placeholder:"Search servers...",value:p,onChange:e=>g(e.target.value),style:{marginBottom:16},allowClear:!0}),d&&(0,t.jsx)("div",{style:{display:"flex",flexDirection:"column",gap:4},children:Array.from({length:8}).map((e,s)=>(0,t.jsx)("div",{style:{height:36,borderRadius:6,background:"#f9fafb"}},s))}),u&&(0,t.jsx)("div",{style:{textAlign:"center",padding:"32px 0",color:"#9ca3af"},children:(0,t.jsxs)(tG,{children:["Failed to load servers: ",u]})}),!d&&!u&&0===y.length&&(0,t.jsx)("div",{style:{textAlign:"center",padding:"32px 0",color:"#9ca3af"},children:(0,t.jsxs)(tG,{children:["No servers found."," ",(0,t.jsx)("a",{onClick:l,style:{color:"#2563eb",cursor:"pointer"},children:"Add a custom server"})]})}),!d&&!u&&Object.entries(v).map(([e,s])=>(0,t.jsxs)("div",{style:{marginBottom:16},children:[(0,t.jsx)("div",{style:{fontSize:11,fontWeight:500,color:"#9ca3af",textTransform:"uppercase",letterSpacing:"0.05em",padding:"6px 0",borderBottom:"1px solid #f3f4f6",marginBottom:4},children:e}),(0,t.jsx)("div",{style:{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"0 16px"},children:s.map(e=>{var s;let l,a,n=(l=(s=e.title||e.name).charAt(0).toUpperCase(),a=s.split("").reduce((e,t)=>e+t.charCodeAt(0),0)%tQ.length,{initial:l,backgroundColor:tQ[a]});return(0,t.jsxs)("div",{onClick:()=>r(e),style:{display:"flex",alignItems:"center",padding:"8px 10px",borderRadius:6,cursor:"pointer",transition:"background 0.1s ease"},onMouseEnter:e=>{e.currentTarget.style.background="#f9fafb"},onMouseLeave:e=>{e.currentTarget.style.background="transparent"},children:[e.icon_url?(0,t.jsx)("img",{src:e.icon_url,alt:e.title,style:{width:20,height:20,objectFit:"contain",flexShrink:0,marginRight:12},onError:e=>{let t=e.currentTarget;t.style.display="none";let s=t.nextElementSibling;s&&(s.style.display="flex")}}):null,(0,t.jsx)("div",{style:{width:20,height:20,borderRadius:4,backgroundColor:n.backgroundColor,color:"#fff",display:e.icon_url?"none":"flex",alignItems:"center",justifyContent:"center",fontWeight:600,fontSize:11,flexShrink:0,marginRight:12},children:n.initial}),(0,t.jsx)("span",{style:{fontSize:14,fontWeight:400,color:"#111827",flex:1,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:e.title||e.name}),(0,t.jsx)("span",{style:{color:"#d1d5db",fontSize:14,flexShrink:0,marginLeft:8},children:"›"})]},e.name)})})]},e))]})};var tX=e.i(611052);let{Text:t0,Title:t2}=f.Typography,{Option:t1}=p.Select;e.s(["MCPServers",0,({accessToken:e,userRole:f,userID:N})=>{let{data:T,isLoading:k,refetch:A}=(0,j.useMCPServers)(),{data:I,isLoading:P,recheckServerHealth:O,recheckingServerIds:M}=(()=>{let{accessToken:e}=(0,w.default)(),t=(0,v.useQueryClient)(),[s,r]=(0,b.useState)(new Set),l=(0,y.useQuery)({queryKey:S.lists(),queryFn:async()=>await (0,_.fetchMCPServerHealth)(e),enabled:!!e,refetchInterval:3e4}),a=(0,b.useCallback)(async s=>{if(e){r(e=>new Set(e).add(s));try{let r=await (0,_.fetchMCPServerHealth)(e,[s]);t.setQueriesData({queryKey:S.lists()},e=>e?e.map(e=>r.find(t=>t.server_id===e.server_id)??e):r)}finally{r(e=>{let t=new Set(e);return t.delete(s),t})}}},[e,t]);return{...l,recheckServerHealth:a,recheckingServerIds:s}})(),F=(0,b.useMemo)(()=>{if(!T)return[];if(!I)return T;let e=new Map(I.map(e=>[e.server_id,e.status]));return T.map(t=>{let s=e.get(t.server_id);return{...t,status:s||t.status}})},[T,I]),[E,L]=(0,b.useState)(null),[R,z]=(0,b.useState)(!1),[U,B]=(0,b.useState)(null),[q,V]=(0,b.useState)(!1),[D,H]=(0,b.useState)("all"),[K,W]=(0,b.useState)("all"),[J,Y]=(0,b.useState)([]),[Q,X]=(0,b.useState)(!1),[ee,et]=(0,b.useState)(!1),[es,el]=(0,b.useState)(null),[ea,en]=(0,b.useState)(!1),[ei,eo]=(0,b.useState)(null),ec="Internal User"===f;(0,b.useEffect)(()=>{try{let e=(0,eG.getSecureItem)("litellm-mcp-oauth-edit-state");if(!e)return;let t=JSON.parse(e);t?.serverId&&(B(t.serverId),V(!0))}catch(e){console.error("Failed to restore MCP edit view state",e)}},[]);let ed=b.default.useMemo(()=>{if(!F)return[];let e=new Set,t=[];return F.forEach(s=>{s.teams&&s.teams.forEach(s=>{let r=s.team_id;e.has(r)||(e.add(r),t.push(s))})}),t},[F]),em=b.default.useMemo(()=>F?Array.from(new Set(F.flatMap(e=>e.mcp_access_groups).filter(e=>null!=e))):[],[F]),eu=(0,b.useCallback)((e,t)=>{if(!F)return Y([]);let s=F;"personal"===e?Y([]):("all"!==e&&(s=s.filter(t=>t.teams?.some(t=>t.team_id===e))),"all"!==t&&(s=s.filter(e=>e.mcp_access_groups?.some(e=>"string"==typeof e?e===t:e&&e.name===t))),Y([...s].sort((e,t)=>e.created_at||t.created_at?e.created_at?t.created_at?new Date(t.created_at).getTime()-new Date(e.created_at).getTime():-1:1:0)))},[F]);(0,b.useEffect)(()=>{eu(D,K)},[F,D,K,eu]);let ex=b.default.useMemo(()=>{let e,s,r,l;return e=e=>{B(e),V(!1)},s=e=>{B(e),V(!0)},r=eh,l=e=>eo(e),[{accessorKey:"server_id",header:"Server ID",enableSorting:!0,cell:({row:s})=>(0,t.jsxs)("button",{onClick:()=>e(s.original.server_id),className:"font-mono text-blue-600 bg-blue-50 hover:bg-blue-100 text-xs font-medium px-2 py-0.5 rounded-md border border-blue-200 text-left truncate whitespace-nowrap cursor-pointer max-w-[15ch] transition-colors",children:[s.original.server_id.slice(0,7),"..."]})},{accessorKey:"server_name",header:"Name",enableSorting:!0,cell:({row:e})=>{let s=e.original.mcp_info?.logo_url,r=e.original.server_name;return(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[s?(0,t.jsx)("img",{src:s,alt:`${r??"MCP"} logo`,className:"h-5 w-5 rounded object-contain flex-shrink-0",onError:e=>{e.target.style.display="none"}}):null,(0,t.jsx)("span",{children:r})]})}},{accessorKey:"alias",header:"Alias",enableSorting:!0},{id:"url",header:"URL",cell:({row:e})=>{let s=e.original.url;if(!s)return(0,t.jsx)("span",{className:"text-gray-400",children:"—"});let{maskedUrl:r}=eH(s);return(0,t.jsx)("span",{className:"font-mono text-sm",children:r})}},{accessorKey:"transport",header:"Transport",enableSorting:!0,cell:({row:e})=>{let s=e.original.transport||"http",r=(e.original.spec_path&&"stdio"!==s?"OPENAPI":s).toUpperCase();return(0,t.jsx)("span",{className:"inline-flex items-center text-xs font-medium px-2 py-0.5 rounded border bg-gray-50 text-gray-700 border-gray-200",children:r})}},{accessorKey:"auth_type",header:"Auth Type",enableSorting:!0,cell:({getValue:e})=>{let s=e()||"none";return(0,t.jsx)("span",{className:"inline-flex items-center text-xs font-medium px-2 py-0.5 rounded border bg-gray-50 text-gray-700 border-gray-200",children:s})}},{id:"health_status",header:"Health Status",cell:({row:e})=>(0,t.jsx)(tu,{server:e.original,isLoadingHealth:P,isRechecking:M?.has(e.original.server_id),onRecheck:O})},{id:"mcp_access_groups",header:"Access Groups",cell:({row:e})=>{let s=e.original.mcp_access_groups;if(Array.isArray(s)&&s.length>0&&"string"==typeof s[0]){let e=s.join(", ");return(0,t.jsx)(g.Tooltip,{title:e,children:(0,t.jsxs)("div",{className:"flex items-center gap-1 max-w-[200px]",children:[(0,t.jsx)("span",{className:"inline-flex items-center text-xs font-medium px-1.5 py-0.5 rounded bg-gray-100 text-gray-700 border border-gray-200 truncate max-w-[140px]",children:s[0]}),s.length>1&&(0,t.jsxs)("span",{className:"text-xs text-gray-400 font-medium",children:["+",s.length-1]})]})})}return(0,t.jsx)("span",{className:"text-xs text-gray-400",children:"—"})}},{id:"available_on_public_internet",header:"Network Access",cell:({row:e})=>e.original.available_on_public_internet?(0,t.jsxs)("span",{className:"inline-flex items-center gap-1 px-2 py-0.5 bg-green-50 text-green-700 rounded-full border border-green-200 text-xs font-medium",children:[(0,t.jsx)("span",{className:"h-1.5 w-1.5 rounded-full bg-green-500"}),"Public"]}):(0,t.jsxs)("span",{className:"inline-flex items-center gap-1 px-2 py-0.5 bg-orange-50 text-orange-700 rounded-full border border-orange-200 text-xs font-medium",children:[(0,t.jsx)("span",{className:"h-1.5 w-1.5 rounded-full bg-orange-500"}),"Internal"]})},{header:"Created",accessorKey:"created_at",enableSorting:!0,sortingFn:"datetime",cell:({row:e})=>{let s=e.original;if(!s.created_at)return(0,t.jsx)("span",{className:"text-xs text-gray-400",children:"—"});let r=new Date(s.created_at);return(0,t.jsx)(g.Tooltip,{title:r.toLocaleString(),children:(0,t.jsx)("span",{className:"text-xs text-gray-600",children:r.toLocaleDateString()})})}},{header:"Updated",accessorKey:"updated_at",enableSorting:!0,sortingFn:"datetime",cell:({row:e})=>{let s=e.original;if(!s.updated_at)return(0,t.jsx)("span",{className:"text-xs text-gray-400",children:"—"});let r=new Date(s.updated_at);return(0,t.jsx)(g.Tooltip,{title:r.toLocaleString(),children:(0,t.jsx)("span",{className:"text-xs text-gray-600",children:r.toLocaleDateString()})})}},{id:"byok_credential",header:"Credential",cell:({row:e})=>{let s=e.original;return s.is_byok?s.has_user_credential?(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsxs)("span",{className:"inline-flex items-center gap-1 text-xs font-medium px-2 py-0.5 rounded-full bg-green-50 text-green-700 border border-green-200",children:[(0,t.jsx)(tm.CheckOutlined,{style:{fontSize:10}})," Connected"]}),l&&(0,t.jsx)("button",{className:"text-xs text-gray-400 hover:text-blue-600 transition-colors",onClick:()=>l(s),children:"Update"})]}):l?(0,t.jsx)("button",{className:"text-xs bg-blue-600 hover:bg-blue-700 text-white px-3 py-1 rounded-md font-medium transition-colors shadow-sm",onClick:()=>l(s),children:"Connect"}):null:(0,t.jsx)("span",{className:"text-gray-300 text-xs",children:"—"})}},{id:"actions",header:"Actions",cell:({row:e})=>(0,t.jsxs)("div",{className:"flex items-center gap-1",children:[(0,t.jsx)(g.Tooltip,{title:"Edit",children:(0,t.jsx)("button",{onClick:()=>s(e.original.server_id),className:"p-1.5 rounded-md text-gray-400 hover:text-blue-600 hover:bg-blue-50 transition-colors",children:(0,t.jsx)(tc.Icon,{icon:td.PencilAltIcon,size:"sm"})})}),(0,t.jsx)(g.Tooltip,{title:"Delete",children:(0,t.jsx)("button",{onClick:()=>r(e.original.server_id),className:"p-1.5 rounded-md text-gray-400 hover:text-red-600 hover:bg-red-50 transition-colors",children:(0,t.jsx)(tc.Icon,{icon:G.TrashIcon,size:"sm"})})})]})}]},[f,P,O,M]);function eh(e){L(e),z(!0)}let ep=async()=>{if(null!=E&&null!=e)try{en(!0),await (0,_.deleteMCPServer)(e,E),C.default.success("Deleted MCP Server successfully"),A()}catch(e){console.error("Error deleting the mcp server:",e)}finally{en(!1),z(!1),L(null)}},eg=E?(T||[]).find(e=>e.server_id===E):null,ef=b.default.useMemo(()=>J.find(e=>e.server_id===U)||{server_id:"",server_name:"",alias:"",url:"",transport:"",auth_type:"",created_at:"",created_by:"",updated_at:"",updated_by:""},[J,U]),eb=b.default.useCallback(()=>{V(!1),B(null),A()},[A]);return e&&f&&N?(0,t.jsxs)("div",{className:"w-full h-full p-6",children:[(0,t.jsx)(h.Modal,{open:R,title:"Delete MCP Server?",onOk:ep,okText:ea?"Deleting...":"Delete",onCancel:()=>{z(!1),L(null)},cancelText:"Cancel",cancelButtonProps:{disabled:ea},okButtonProps:{danger:!0},confirmLoading:ea,children:(0,t.jsxs)("div",{className:"space-y-4",children:[(0,t.jsx)(t0,{className:"text-gray-600",children:"This action is permanent and cannot be undone. All associated configurations will be removed."}),eg&&(0,t.jsx)("div",{className:"mt-3 p-4 bg-gray-50 rounded-lg border border-gray-200",children:(0,t.jsxs)(x.Descriptions,{column:1,size:"small",colon:!1,children:[eg.server_name&&(0,t.jsx)(x.Descriptions.Item,{label:(0,t.jsx)("span",{className:"text-gray-500 text-sm",children:"Name"}),children:(0,t.jsx)(t0,{strong:!0,className:"text-sm",children:eg.server_name})}),(0,t.jsx)(x.Descriptions.Item,{label:(0,t.jsx)("span",{className:"text-gray-500 text-sm",children:"ID"}),children:(0,t.jsx)(t0,{code:!0,className:"text-xs",children:eg.server_id})}),eg.url&&(0,t.jsx)(x.Descriptions.Item,{label:(0,t.jsx)("span",{className:"text-gray-500 text-sm",children:"URL"}),children:(0,t.jsx)(t0,{code:!0,className:"text-xs break-all",children:eg.url})})]})})]})}),(0,t.jsx)(e5,{userRole:f,accessToken:e,onCreateSuccess:e=>{Y(t=>[...t,e]),X(!1),A()},isModalVisible:Q,setModalVisible:X,availableAccessGroups:em,prefillData:es,onBackToDiscovery:()=>{X(!1),el(null),et(!0)}}),(0,t.jsxs)("div",{className:"flex items-center justify-between",children:[(0,t.jsxs)("div",{children:[(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[(0,t.jsx)(m.Title,{children:"MCP Servers"}),J.length>0&&(0,t.jsx)("span",{className:"inline-flex items-center text-xs font-medium px-2 py-0.5 rounded-full bg-gray-100 text-gray-600 border border-gray-200",children:J.length})]}),(0,t.jsx)(d.Text,{className:"text-tremor-content mt-1",children:"Configure and manage your MCP servers"})]}),(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,s.isAdminRole)(f)&&(0,t.jsx)(l.Button,{className:"flex-shrink-0",onClick:()=>et(!0),children:"+ Add New MCP Server"}),!(0,s.isAdminRole)(f)&&(0,t.jsx)(l.Button,{className:"flex-shrink-0",onClick:()=>{el(null),X(!0)},variant:"secondary",children:"+ Submit MCP Server"})]})]}),(0,t.jsx)(tZ,{isVisible:ee,onClose:()=>et(!1),onSelectServer:e=>{el(e),et(!1),X(!0)},onCustomServer:()=>{el(null),et(!1),X(!0)},accessToken:e}),(0,t.jsxs)(n.TabGroup,{className:"w-full h-full",children:[(0,t.jsx)(i.TabList,{className:"flex justify-between mt-2 w-full items-center",children:(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)(a.Tab,{children:"All Servers"}),(0,t.jsx)(a.Tab,{children:"Toolsets"}),(0,t.jsx)(a.Tab,{children:"Connect"}),(0,t.jsx)(a.Tab,{children:"Semantic Filter"}),(0,t.jsx)(a.Tab,{children:"Network Settings"}),(0,s.isAdminRole)(f)&&(0,t.jsx)(a.Tab,{children:(0,t.jsxs)("span",{className:"flex items-center gap-2",children:["Submitted MCPs ",(0,t.jsx)(u.default,{})]})})]})}),(0,t.jsxs)(c.TabPanels,{children:[(0,t.jsx)(o.TabPanel,{children:U?(0,t.jsx)(tI,{mcpServer:ef,onBack:eb,isProxyAdmin:(0,s.isAdminRole)(f),isEditing:q,accessToken:e,userID:N,userRole:f,availableAccessGroups:em},U):(0,t.jsxs)("div",{className:"w-full h-full",children:[(0,t.jsx)("div",{className:"w-full",children:(0,t.jsx)("div",{className:"flex flex-col space-y-4",children:(0,t.jsxs)("div",{className:"flex items-center gap-6 bg-white rounded-lg px-4 py-3 border border-gray-200",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)(d.Text,{className:"text-sm font-medium text-gray-600 whitespace-nowrap",children:"Team"}),(0,t.jsxs)(p.Select,{value:D,onChange:e=>{H(e),eu(e,K)},style:{width:220},size:"middle",children:[(0,t.jsx)(t1,{value:"all",children:(0,t.jsx)("span",{className:"font-medium",children:ec?"All Available Servers":"All Servers"})}),(0,t.jsx)(t1,{value:"personal",children:(0,t.jsx)("span",{className:"font-medium",children:"Personal"})}),ed.map(e=>(0,t.jsx)(t1,{value:e.team_id,children:(0,t.jsx)("span",{className:"font-medium",children:e.team_alias||e.team_id})},e.team_id))]})]}),(0,t.jsx)("div",{className:"h-6 w-px bg-gray-200"}),(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsxs)(d.Text,{className:"text-sm font-medium text-gray-600 whitespace-nowrap",children:["Access Group",(0,t.jsx)(g.Tooltip,{title:"An MCP Access Group is a set of users or teams that have permission to access specific MCP servers. Use access groups to control and organize who can connect to which servers.",children:(0,t.jsx)(r.QuestionCircleOutlined,{style:{marginLeft:4,color:"#9ca3af"}})})]}),(0,t.jsxs)(p.Select,{value:K,onChange:e=>{W(e),eu(D,e)},style:{width:220},size:"middle",children:[(0,t.jsx)(t1,{value:"all",children:(0,t.jsx)("span",{className:"font-medium",children:"All Access Groups"})}),em.map(e=>(0,t.jsx)(t1,{value:e,children:(0,t.jsx)("span",{className:"font-medium",children:e})},e))]})]})]})})}),(0,t.jsx)("div",{className:"w-full mt-6",children:(0,t.jsx)(Z.DataTable,{data:J,columns:ex,renderSubComponent:()=>(0,t.jsx)("div",{}),getRowCanExpand:()=>!1,isLoading:k,noDataMessage:"No MCP servers configured. Click '+ Add New MCP Server' to get started.",loadingMessage:"Loading MCP servers...",enableSorting:!0})})]})}),(0,t.jsx)(o.TabPanel,{children:(0,t.jsx)(er,{accessToken:e,userRole:f})}),(0,t.jsx)(o.TabPanel,{children:(0,t.jsx)(to,{})}),(0,t.jsx)(o.TabPanel,{children:(0,t.jsx)(tH,{accessToken:e})}),(0,t.jsx)(o.TabPanel,{children:(0,t.jsx)(tJ,{accessToken:e})}),(0,s.isAdminRole)(f)&&(0,t.jsx)(o.TabPanel,{children:(0,t.jsx)($,{accessToken:e})})]})]}),ei&&(0,t.jsx)(tX.ByokCredentialModal,{server:ei,open:!!ei,onClose:()=>eo(null),onSuccess:e=>{A(),eo(null)},accessToken:e||""})]}):(console.log("Missing required authentication parameters",{accessToken:e,userRole:f,userID:N}),(0,t.jsx)("div",{className:"p-6 text-center text-gray-500",children:"Missing required authentication parameters."}))}],280881)}]); \ No newline at end of file From 7a93cceb9f63de29923e987d20dbbdb4b8d25ec6 Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Fri, 22 May 2026 21:30:39 +0530 Subject: [PATCH 2/3] Add error_description and hint for oauth flows (#28471) * Add error_description and hint for oauth flows * Fix tests * fix(mcp-oauth): improve redirect_uri errors without leaking internal config Use NoReturn on _oauth_invalid_request, structured errors for BYOK loopback validation, and refactor validate_trusted_redirect_uri to satisfy PLR0915. Keep PROXY_BASE_URL and raw proxy_base_url in server logs only, not in the HTTP 400 body returned to unauthenticated callers. Co-authored-by: Cursor * fix(mcp-oauth): stop leaking internal proxy origin in redirect_uri 400 body The trusted-redirect-uri rejection helper included the proxy's resolved scheme/host/port (e.g. http://litellm-internal:4000) in both the error_description and as a top-level proxy_origin field. Since the OAuth /authorize endpoint is unauthenticated, any caller could probe with a crafted redirect_uri and enumerate the internal network topology behind a reverse proxy. Keep full diagnostic detail in the server-side warning log (including the computed proxy base) but omit proxy-side values from the HTTP 400 body. Also drop the duplicated origin computation in _raise_trusted_redirect_uri_rejected now that those values are no longer needed by the response. Co-authored-by: Yassin Kortam * fix(mcp-oauth): remove dead userinfo check in redirect_uri validation The first check combined missing netloc with userinfo presence, making the second userinfo-only check unreachable. Split into two distinct checks so each error message reflects the actual failure mode. Co-authored-by: Yassin Kortam --------- Co-authored-by: Cursor Co-authored-by: Yassin Kortam --- .../_experimental/mcp_server/oauth_utils.py | 327 ++++++++++++------ .../mcp_server/test_discoverable_endpoints.py | 8 +- 2 files changed, 229 insertions(+), 106 deletions(-) diff --git a/litellm/proxy/_experimental/mcp_server/oauth_utils.py b/litellm/proxy/_experimental/mcp_server/oauth_utils.py index 09176f7253a..e8b591c39cf 100644 --- a/litellm/proxy/_experimental/mcp_server/oauth_utils.py +++ b/litellm/proxy/_experimental/mcp_server/oauth_utils.py @@ -3,8 +3,8 @@ import os from ipaddress import ip_address -from typing import List, Optional -from urllib.parse import urlparse, urlunparse +from typing import Any, Dict, List, NoReturn, Optional +from urllib.parse import ParseResult, urlparse, urlunparse from fastapi import HTTPException, Request @@ -43,6 +43,33 @@ _DEFAULT_NATIVE_REDIRECT_URIS: List[str] = [ _warned_invalid_proxy_base_url: Optional[str] = None +def _oauth_invalid_request( + error_description: str, + *, + hint: Optional[str] = None, + **extra: Any, +) -> NoReturn: + """Raise ``invalid_request`` (RFC 6749) with a debuggable description. + + FastAPI serializes ``detail`` as JSON. Callers still see ``error``: + ``invalid_request``; ``error_description`` and ``hint`` explain what + failed and how to fix it (e.g. reverse-proxy / PROXY_BASE_URL issues). + """ + detail: Dict[str, Any] = { + "error": "invalid_request", + "error_description": error_description, + } + if hint: + detail["hint"] = hint + detail.update(extra) + raise HTTPException(status_code=400, detail=detail) + + +def _origin_label(scheme: str, netloc: str) -> str: + """Human-readable origin for error messages (scheme + host[:port]).""" + return f"{scheme}://{netloc}" if netloc else f"{scheme}://" + + def _resolve_proxy_base_url_env() -> Optional[str]: global _warned_invalid_proxy_base_url configured = os.environ.get("PROXY_BASE_URL", "").strip() @@ -118,17 +145,15 @@ def validate_loopback_redirect_uri(redirect_uri: str) -> None: ``"127.0.0.1"`` alone would miss ``127.0.0.2`` and the full-form IPv6 loopback ``0:0:0:0:0:0:0:1``. """ - try: - parsed = urlparse(redirect_uri) - except ValueError: - raise HTTPException(status_code=400, detail="invalid_request") + parsed = _parse_redirect_uri_for_validation(redirect_uri) if parsed.scheme not in ("http", "https"): - raise HTTPException(status_code=400, detail="invalid_request") - # Fragments are not allowed in OAuth redirect URIs (RFC 6749 §3.1.2) - # — rejecting them prevents a ``http://127.0.0.1/cb#frag?code=...`` - # from silently eating the authorization code. + _oauth_invalid_request( + f"redirect_uri scheme {parsed.scheme!r} is not allowed; use http or https.", + ) if parsed.fragment: - raise HTTPException(status_code=400, detail="invalid_request") + _oauth_invalid_request( + "redirect_uri must not contain a URL fragment (#...).", + ) host = (parsed.hostname or "").lower() if host == "localhost": return @@ -139,7 +164,10 @@ def validate_loopback_redirect_uri(redirect_uri: str) -> None: # Unparseable host (malformed IPv6, etc.) — treat as invalid, # don't let it bubble up as a 500. pass - raise HTTPException(status_code=400, detail="invalid_request") + _oauth_invalid_request( + "redirect_uri must use a loopback host (localhost or 127.0.0.0/8).", + hint="Native MCP clients should register a callback on http://127.0.0.1:/...", + ) def _strip_default_port(scheme: str, netloc: str) -> str: @@ -293,6 +321,180 @@ def _matches_trusted_native_redirect_uri(parsed) -> bool: return False +def _parse_redirect_uri_for_validation(redirect_uri: str) -> ParseResult: + try: + return urlparse(redirect_uri) + except ValueError: + _oauth_invalid_request( + "redirect_uri is not a valid URL.", + hint="Use a full absolute URL for redirect_uri (e.g. https://your-host/ui/mcp/oauth/callback).", + ) + + +def _validate_trusted_http_redirect_shape(parsed: ParseResult) -> bool: + """Return True when ``parsed`` is an allowlisted native callback (caller may return).""" + if parsed.scheme not in ("http", "https"): + if _matches_trusted_native_redirect_uri(parsed): + return True + _oauth_invalid_request( + f"redirect_uri scheme {parsed.scheme!r} is not allowed; use http/https " + "or a registered native callback (e.g. cursor://).", + hint="Add the full URI to MCP_TRUSTED_NATIVE_REDIRECT_URIS for custom native clients.", + ) + if parsed.fragment: + _oauth_invalid_request( + "redirect_uri must not contain a URL fragment (#...).", + ) + if not parsed.netloc: + _oauth_invalid_request( + "redirect_uri must include a host (e.g. https://your-host/path).", + ) + if parsed.username is not None or parsed.password is not None: + _oauth_invalid_request( + "redirect_uri must not contain userinfo (user:pass@host).", + ) + if "\\" in parsed.netloc: + _oauth_invalid_request( + "redirect_uri host must not contain backslashes.", + ) + return False + + +def _resolve_proxy_base_for_redirect(request: Request) -> Optional[str]: + try: + return get_request_base_url(request) + except Exception as exc: + verbose_logger.warning( + "validate_trusted_redirect_uri: could not determine proxy origin, " + "falling back to loopback + allowlist. error=%s", + exc, + ) + return None + + +def _trusted_redirect_uri_is_allowed( + parsed: ParseResult, + redirect_netloc: str, + proxy_base: Optional[str], +) -> bool: + if proxy_base: + proxy_parsed = urlparse(proxy_base) + if ( + parsed.scheme == proxy_parsed.scheme + and redirect_netloc + == _strip_default_port(proxy_parsed.scheme, proxy_parsed.netloc) + ): + return True + + host = (parsed.hostname or "").lower() + if host == "localhost": + return True + try: + if ip_address(host).is_loopback: + return True + except ValueError: + pass + + if parsed.scheme == "https": + for entry in _parse_trusted_redirect_origins(): + if _matches_trusted_origin_entry(redirect_netloc, entry): + return True + return False + + +def _build_trusted_redirect_rejection_message( + redirect_uri: str, + parsed: ParseResult, + redirect_netloc: str, + proxy_base: Optional[str], +) -> str: + """Build a client-facing rejection message. + + Intentionally omits the proxy's resolved scheme / host / port to avoid + leaking internal network topology (e.g. ``http://litellm-internal:4000``) + through an unauthenticated endpoint. Full diagnostic detail — including + the computed proxy base — is logged server-side by the caller. + """ + redirect_origin = _origin_label(parsed.scheme, redirect_netloc) + proxy_parsed = urlparse(proxy_base) if proxy_base else None + proxy_netloc_norm = ( + _strip_default_port(proxy_parsed.scheme, proxy_parsed.netloc) + if proxy_parsed and proxy_parsed.netloc + else "" + ) + + mismatch_parts: List[str] = [] + if proxy_parsed and proxy_parsed.netloc: + if parsed.scheme != proxy_parsed.scheme: + mismatch_parts.append( + f"scheme: redirect_uri uses {parsed.scheme!r}, but the proxy " + "resolved a different scheme " + "(TLS often terminates at ingress — set PROXY_BASE_URL to https://… " + "or trust X-Forwarded-Proto from your ingress)" + ) + if redirect_netloc != proxy_netloc_norm: + mismatch_parts.append( + f"host/port: redirect_uri {redirect_netloc!r} does not match " + "the proxy origin" + ) + + if mismatch_parts: + return ( + f"redirect_uri origin ({redirect_origin}) does not match the proxy " + "origin. " + "; ".join(mismatch_parts) + ) + return ( + f"redirect_uri ({redirect_uri!r}) is not allowed: not same-origin with " + f"the proxy origin, not loopback, and not listed in " + f"{_TRUSTED_REDIRECT_ORIGINS_ENV}." + ) + + +def _raise_trusted_redirect_uri_rejected( + request: Request, + redirect_uri: str, + parsed: ParseResult, + redirect_netloc: str, + proxy_base: Optional[str], +) -> NoReturn: + description = _build_trusted_redirect_rejection_message( + redirect_uri, parsed, redirect_netloc, proxy_base + ) + + hint = ( + "Align the proxy public URL with the browser URL. Set PROXY_BASE_URL to your " + "HTTPS origin (e.g. https://litellm.example.com), or enable " + "general_settings.use_x_forwarded_for with mcp_trusted_proxy_ranges for your " + "ingress. Verify: curl https:///.well-known/oauth-authorization-server " + "| jq .issuer — issuer must match window.location.origin in the UI." + ) + + verbose_logger.warning( + "MCP OAuth: rejecting redirect_uri %r. %s " + "Computed proxy base=%r (PROXY_BASE_URL=%r). " + "Inbound headers: X-Forwarded-Proto=%r X-Forwarded-Host=%r " + "X-Forwarded-Port=%r Host=%r. " + "Trusted-redirect-origins env=%r. " + "Trusted-native-redirect-uris env=%r.", + redirect_uri, + description, + proxy_base, + os.environ.get("PROXY_BASE_URL"), + request.headers.get("X-Forwarded-Proto"), + request.headers.get("X-Forwarded-Host"), + request.headers.get("X-Forwarded-Port"), + request.headers.get("Host"), + os.environ.get(_TRUSTED_REDIRECT_ORIGINS_ENV), + os.environ.get(_TRUSTED_NATIVE_REDIRECT_URIS_ENV), + ) + + _oauth_invalid_request( + description, + hint=hint, + redirect_uri=redirect_uri, + ) + + def validate_trusted_redirect_uri(request: Request, redirect_uri: str) -> None: """Accept ``redirect_uri`` when it is (a) same-origin with the proxy's own request origin, (b) loopback, (c) listed in the @@ -316,98 +518,13 @@ def validate_trusted_redirect_uri(request: Request, redirect_uri: str) -> None: BYOK endpoints, which only serve native MCP clients, retain :func:`validate_loopback_redirect_uri`. """ - try: - parsed = urlparse(redirect_uri) - except ValueError: - raise HTTPException(status_code=400, detail="invalid_request") - if parsed.scheme not in ("http", "https"): - if _matches_trusted_native_redirect_uri(parsed): - return - raise HTTPException(status_code=400, detail="invalid_request") - if parsed.fragment: - raise HTTPException(status_code=400, detail="invalid_request") - if not parsed.netloc or parsed.username is not None or parsed.password is not None: - raise HTTPException(status_code=400, detail="invalid_request") - # Reject userinfo (``user:pass@host``) outright: OAuth redirect_uris - # have no legitimate reason to carry credentials, and allowing them - # opens a host-confusion attack where the netloc *looks* allowlisted - # (``app.example.com:443@attacker.example``) but the browser navigates - # to the post-``@`` host and hands the authorization code to the - # attacker. We compare against ``hostname`` after this, but defense in - # depth keeps malformed netloc strings from reaching the wildcard - # splitter. - if parsed.username is not None or parsed.password is not None: - raise HTTPException(status_code=400, detail="invalid_request") - # Reject backslash in netloc: urlparse keeps ``\`` as part of netloc, - # but browsers normalize ``\`` to ``/`` for http(s) URLs and treat it - # as the start of the path. An attacker can exploit that split by - # crafting ``https://attacker.net\app.example.com/cb`` — urlparse sees - # ``attacker.net\app.example.com`` (matches ``*.example.com``) while - # the browser navigates to ``attacker.net`` with the auth code. - if "\\" in parsed.netloc: - raise HTTPException(status_code=400, detail="invalid_request") - - redirect_netloc = _strip_default_port(parsed.scheme, parsed.netloc) - - # (a) Same-origin. Swallow ``get_request_base_url`` failures so the - # loopback + allowlist paths remain reachable when the origin can't - # be determined (e.g. request came from an untrusted proxy and - # ``get_request_base_url`` raised). - proxy_base: Optional[str] = None - try: - proxy_base = get_request_base_url(request) - except Exception as exc: - verbose_logger.warning( - "validate_trusted_redirect_uri: could not determine proxy origin, " - "falling back to loopback + allowlist. error=%s", - exc, - ) - proxy_base = None - if proxy_base: - proxy_parsed = urlparse(proxy_base) - if ( - parsed.scheme == proxy_parsed.scheme - and redirect_netloc - == _strip_default_port(proxy_parsed.scheme, proxy_parsed.netloc) - ): - return - - # (b) Loopback — same rule as validate_loopback_redirect_uri. - host = (parsed.hostname or "").lower() - if host == "localhost": + parsed = _parse_redirect_uri_for_validation(redirect_uri) + if _validate_trusted_http_redirect_shape(parsed): return - try: - if ip_address(host).is_loopback: - return - except ValueError: - pass - - # (c) Ops allowlist. https only. - if parsed.scheme == "https": - for entry in _parse_trusted_redirect_origins(): - if _matches_trusted_origin_entry(redirect_netloc, entry): - return - - verbose_logger.warning( - "MCP OAuth: rejecting redirect_uri %r as invalid_request. " - "Computed proxy base=%r (PROXY_BASE_URL=%r). " - "Inbound headers: X-Forwarded-Proto=%r X-Forwarded-Host=%r " - "X-Forwarded-Port=%r Host=%r. " - "Trusted-redirect-origins env=%r. " - "Trusted-native-redirect-uris env=%r. " - "If this should be accepted, either align ingress X-Forwarded-* " - "with the browser URL, set PROXY_BASE_URL to your public origin, " - "add the redirect_uri host to MCP_TRUSTED_REDIRECT_ORIGINS, or " - "for native MCP clients (cursor://, etc.) add the full redirect_uri " - "to MCP_TRUSTED_NATIVE_REDIRECT_URIS.", - redirect_uri, - proxy_base, - os.environ.get("PROXY_BASE_URL"), - request.headers.get("X-Forwarded-Proto"), - request.headers.get("X-Forwarded-Host"), - request.headers.get("X-Forwarded-Port"), - request.headers.get("Host"), - os.environ.get(_TRUSTED_REDIRECT_ORIGINS_ENV), - os.environ.get(_TRUSTED_NATIVE_REDIRECT_URIS_ENV), + redirect_netloc = _strip_default_port(parsed.scheme, parsed.netloc) + proxy_base = _resolve_proxy_base_for_redirect(request) + if _trusted_redirect_uri_is_allowed(parsed, redirect_netloc, proxy_base): + return + _raise_trusted_redirect_uri_rejected( + request, redirect_uri, parsed, redirect_netloc, proxy_base ) - raise HTTPException(status_code=400, detail="invalid_request") diff --git a/tests/test_litellm/proxy/_experimental/mcp_server/test_discoverable_endpoints.py b/tests/test_litellm/proxy/_experimental/mcp_server/test_discoverable_endpoints.py index b06cc7f0f12..c8789e0b0a6 100644 --- a/tests/test_litellm/proxy/_experimental/mcp_server/test_discoverable_endpoints.py +++ b/tests/test_litellm/proxy/_experimental/mcp_server/test_discoverable_endpoints.py @@ -1345,7 +1345,13 @@ def test_validate_trusted_redirect_uri_logs_diagnostic_on_rejection( "https://litellm.example.com/ui/mcp/oauth/callback", ) assert exc_info.value.status_code == 400 - assert exc_info.value.detail == "invalid_request" + detail = exc_info.value.detail + assert isinstance(detail, dict) + assert detail.get("error") == "invalid_request" + assert "error_description" in detail + assert "redirect_uri origin" in detail["error_description"] + assert "proxy origin" in detail["error_description"] + assert "hint" in detail matching = [r for r in caplog.records if "rejecting redirect_uri" in r.getMessage()] assert len(matching) == 1, ( From ef36e89638130e0607ef609385fe55198558d3e2 Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Fri, 22 May 2026 21:34:04 +0530 Subject: [PATCH 3/3] feat(mcp): Add tool call and tool list support via UI for Oauth mcps (#28454) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(mcp): cache OAuth token client-side so Tools tab loads without re-auth After a user creates an OAuth MCP server and completes the authorization flow, the resulting access token is now stored in sessionStorage keyed by server_id. The MCP Tools tab reads this cached token and includes it as an MCP auth header when listing and invoking tools, so the user never sees an empty tool list. When the session ends (tab close / new browser) an Authorize button re-triggers the flow without leaving the Tools screen. Co-Authored-By: Claude Sonnet 4.6 (1M context) * fix(ui/mcp): surface listMCPTools 401 errors so auth gate reappears listMCPTools previously swallowed all errors (including HTTP 401) by returning a synthetic { tools: [], error: 'network_error', ... } payload. That made the useQuery retry-on-401 guard and mcpToolsError dead code, so expired OAuth tokens never re-triggered the auth gate. - Throw an enhanced Error with .status attached on non-2xx responses (still preserves the legacy shape for true network failures so the caller can render a generic message without crashing). - Clear the cached OAuth session token when the tools query fails with 401, mirroring callMCPTool's onError handler so the Authorize button is shown again. - Surface mcpToolsError in the existing error banner. Co-authored-by: Yassin Kortam * fix(mcp-tools): stable onSuccess + reuse parsed flow state - Pass stable setOauthToken setter directly as onSuccess to avoid recreating useToolsOAuthFlow's resumeOAuthFlow on every render. - Reuse the already-parsed FLOW_STATE_KEY value (peeked) instead of re-reading and re-parsing sessionStorage in resumeOAuthFlow. Co-authored-by: Yassin Kortam * fix(ui/mcp): restore listMCPTools never-throws contract The previous fix made listMCPTools throw on HTTP errors while still returning a synthetic object on network errors. This inconsistent contract broke existing callers (MCPToolPermissions, MCPAppsPanel, MCPConnectPicker) which inspect result.error / result.message and expect the function to never throw. - Return a normalized { tools: [], error, message, status, ... } object on HTTP errors (instead of throwing) so all callers see a consistent shape and the user-visible error text from result.message is preserved. - Convert the returned error object into a thrown Error inside the one caller that needs it — the useQuery in mcp_tools.tsx — so the 401 retry/onError handlers still trigger and clear the cached OAuth token. Co-authored-by: Yassin Kortam * fix greptile * fix(mcp): align OAuth header alias lookup with dashboard sanitization Backend auth header resolution now matches x-mcp-{alias} keys produced by the dashboard sanitizer, and the Tools tab re-syncs OAuth tokens when serverId changes. Co-authored-by: Cursor * fix(mcp): widen auth header lookup types for list_tools Accept legacy str | dict server auth maps and annotate list_tools server_auth_header as Union[str, dict] for mypy. Co-authored-by: Cursor * refactor(ui): extract shared buildCallbackUrl/clearStorage for MCP OAuth hooks Hoist the duplicate buildCallbackUrl and clearStorage helpers out of useToolsOAuthFlow and useUserMcpOAuthFlow into a new shared module src/hooks/mcpOAuthUtils.ts so the two hooks cannot drift if the URL construction or storage cleanup logic needs to change. Co-authored-by: Yassin Kortam * fix(ui): don't gate M2M OAuth MCP servers behind interactive authorize M2M (client_credentials) OAuth servers share auth_type="oauth2" with interactive PKCE servers, but the backend fetches their token internally and they typically lack a user authorization endpoint. Gating tool listing on them rendered an Authorize button that would fail or redirect incorrectly. Detect M2M via the presence of token_url (matching the existing heuristic in mcp_server_edit.tsx) and skip the auth gate. Co-authored-by: Yassin Kortam * fix(ui/mcp): return error shape when listMCPTools JSON parse fails Restore the never-throws contract when response.json() fails on a 2xx body so callers do not receive null and crash on result.tools. Co-authored-by: Cursor --------- Co-authored-by: Claude Sonnet 4.6 (1M context) Co-authored-by: Cursor Agent Co-authored-by: Yassin Kortam --- .../mcp_server/mcp_server_manager.py | 33 +-- .../mcp_server/rest_endpoints.py | 24 +- .../proxy/_experimental/mcp_server/server.py | 14 +- .../proxy/_experimental/mcp_server/utils.py | 47 +++- tests/mcp_tests/test_mcp_server.py | 20 ++ .../mcp_server/test_mcp_header_alias_utils.py | 18 ++ .../src/app/mcp/oauth/callback/page.tsx | 12 +- .../mcp_tools/create_mcp_server.tsx | 18 ++ .../components/mcp_tools/mcp_server_view.tsx | 1 + .../src/components/mcp_tools/mcp_servers.tsx | 1 + .../src/components/mcp_tools/mcp_tools.tsx | 178 ++++++++++++-- .../src/components/mcp_tools/types.tsx | 7 + .../src/components/networking.tsx | 91 ++++--- .../src/hooks/mcpOAuthUtils.ts | 39 +++ .../src/hooks/useMcpOAuthFlow.tsx | 15 +- .../src/hooks/useToolsOAuthFlow.tsx | 232 ++++++++++++++++++ .../src/hooks/useUserMcpOAuthFlow.tsx | 39 +-- .../src/utils/cookieUtils.test.ts | 10 + ui/litellm-dashboard/src/utils/cookieUtils.ts | 3 + .../src/utils/mcpHeaderUtils.test.ts | 16 ++ .../src/utils/mcpHeaderUtils.ts | 14 ++ .../src/utils/mcpTokenStore.test.ts | 46 ++++ .../src/utils/mcpTokenStore.ts | 93 +++++++ 23 files changed, 846 insertions(+), 125 deletions(-) create mode 100644 tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_header_alias_utils.py create mode 100644 ui/litellm-dashboard/src/hooks/mcpOAuthUtils.ts create mode 100644 ui/litellm-dashboard/src/hooks/useToolsOAuthFlow.tsx create mode 100644 ui/litellm-dashboard/src/utils/mcpHeaderUtils.test.ts create mode 100644 ui/litellm-dashboard/src/utils/mcpHeaderUtils.ts create mode 100644 ui/litellm-dashboard/src/utils/mcpTokenStore.test.ts create mode 100644 ui/litellm-dashboard/src/utils/mcpTokenStore.ts diff --git a/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py b/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py index bbf40f6e9ef..a72e8e34a49 100644 --- a/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py +++ b/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py @@ -1212,11 +1212,17 @@ class MCPServerManager: return [] # Get server-specific auth header if available - server_auth_header = None - if mcp_server_auth_headers and server.alias: - server_auth_header = mcp_server_auth_headers.get(server.alias) - elif mcp_server_auth_headers and server.server_name: - server_auth_header = mcp_server_auth_headers.get(server.server_name) + server_auth_header: Optional[Union[str, Dict[str, str]]] = None + if mcp_server_auth_headers: + from litellm.proxy._experimental.mcp_server.utils import ( + lookup_mcp_server_auth_in_headers, + ) + + server_auth_header = lookup_mcp_server_auth_in_headers( + mcp_server_auth_headers, + alias=server.alias, + server_name=server.server_name, + ) # Fall back to deprecated mcp_auth_header if no server-specific header found if server_auth_header is None: @@ -2707,16 +2713,15 @@ class MCPServerManager: server_auth_header: Optional[Union[Dict[str, str], str]] = None if mcp_server_auth_headers: # Normalize keys for case-insensitive lookup - normalized_headers = { - k.lower(): v for k, v in mcp_server_auth_headers.items() - } + from litellm.proxy._experimental.mcp_server.utils import ( + lookup_mcp_server_auth_in_headers, + ) - if mcp_server.alias: - server_auth_header = normalized_headers.get(mcp_server.alias.lower()) - if server_auth_header is None and mcp_server.server_name: - server_auth_header = normalized_headers.get( - mcp_server.server_name.lower() - ) + server_auth_header = lookup_mcp_server_auth_in_headers( + mcp_server_auth_headers, + alias=mcp_server.alias, + server_name=mcp_server.server_name, + ) # Fall back to deprecated mcp_auth_header if no server-specific header found if server_auth_header is None: diff --git a/litellm/proxy/_experimental/mcp_server/rest_endpoints.py b/litellm/proxy/_experimental/mcp_server/rest_endpoints.py index 7150dee10cf..cec5224e183 100644 --- a/litellm/proxy/_experimental/mcp_server/rest_endpoints.py +++ b/litellm/proxy/_experimental/mcp_server/rest_endpoints.py @@ -62,20 +62,16 @@ if MCP_AVAILABLE: mcp_auth_header: Optional[str], ) -> Optional[Union[Dict[str, str], str]]: """Helper function to get server-specific auth header with case-insensitive matching.""" - if mcp_server_auth_headers and server.alias: - normalized_server_alias = server.alias.lower() - normalized_headers = { - k.lower(): v for k, v in mcp_server_auth_headers.items() - } - server_auth = normalized_headers.get(normalized_server_alias) - if server_auth is not None: - return server_auth - elif mcp_server_auth_headers and server.server_name: - normalized_server_name = server.server_name.lower() - normalized_headers = { - k.lower(): v for k, v in mcp_server_auth_headers.items() - } - server_auth = normalized_headers.get(normalized_server_name) + from litellm.proxy._experimental.mcp_server.utils import ( + lookup_mcp_server_auth_in_headers, + ) + + if mcp_server_auth_headers: + server_auth = lookup_mcp_server_auth_in_headers( + mcp_server_auth_headers, + alias=getattr(server, "alias", None), + server_name=getattr(server, "server_name", None), + ) if server_auth is not None: return server_auth return mcp_auth_header diff --git a/litellm/proxy/_experimental/mcp_server/server.py b/litellm/proxy/_experimental/mcp_server/server.py index 5676aaf0d22..5205426edf3 100644 --- a/litellm/proxy/_experimental/mcp_server/server.py +++ b/litellm/proxy/_experimental/mcp_server/server.py @@ -1114,10 +1114,16 @@ if MCP_AVAILABLE: ) -> Tuple[Optional[Union[Dict[str, str], str]], Optional[Dict[str, str]]]: """Build auth and extra headers for a server.""" server_auth_header: Optional[Union[Dict[str, str], str]] = None - if mcp_server_auth_headers and server.alias is not None: - server_auth_header = mcp_server_auth_headers.get(server.alias) - elif mcp_server_auth_headers and server.server_name is not None: - server_auth_header = mcp_server_auth_headers.get(server.server_name) + if mcp_server_auth_headers: + from litellm.proxy._experimental.mcp_server.utils import ( + lookup_mcp_server_auth_in_headers, + ) + + server_auth_header = lookup_mcp_server_auth_in_headers( + mcp_server_auth_headers, + alias=server.alias, + server_name=server.server_name, + ) extra_headers: Optional[Dict[str, str]] = None if server.auth_type == MCPAuth.oauth2: diff --git a/litellm/proxy/_experimental/mcp_server/utils.py b/litellm/proxy/_experimental/mcp_server/utils.py index df5705c3425..b8b9207555e 100644 --- a/litellm/proxy/_experimental/mcp_server/utils.py +++ b/litellm/proxy/_experimental/mcp_server/utils.py @@ -2,7 +2,8 @@ MCP Server Utilities """ -from typing import Any, Dict, Iterator, Mapping, Optional, Tuple +import re +from typing import Any, Dict, Iterator, Mapping, Optional, Tuple, Union import hashlib import importlib @@ -117,6 +118,50 @@ def normalize_server_name(server_name: str) -> str: return server_name.replace(" ", "_") +_MCP_ALIAS_HEADER_INVALID_RE = re.compile(r"[^a-z0-9_]") + + +def sanitize_mcp_alias_for_header(alias: str) -> str: + """ + Sanitize an MCP server alias for x-mcp-{alias}-{header} HTTP headers. + + Must stay in sync with ui/litellm-dashboard/src/utils/mcpHeaderUtils.ts. + """ + sanitized = _MCP_ALIAS_HEADER_INVALID_RE.sub("_", alias.lower().strip()) + sanitized = re.sub(r"_+", "_", sanitized) + return sanitized.strip("_") + + +def lookup_mcp_server_auth_in_headers( + mcp_server_auth_headers: Mapping[str, Union[str, Dict[str, str]]], + *, + alias: Optional[str] = None, + server_name: Optional[str] = None, +) -> Optional[Union[str, Dict[str, str]]]: + """ + Resolve server-specific auth headers with case-insensitive matching. + + Tries the raw alias/server_name (lowercased) and the header-safe sanitized + alias so dashboard clients using sanitize_mcp_alias_for_header() still match. + """ + if not mcp_server_auth_headers: + return None + + normalized_headers = {k.lower(): v for k, v in mcp_server_auth_headers.items()} + + for identifier in (alias, server_name): + if not identifier: + continue + keys_to_try = [identifier.lower()] + sanitized = sanitize_mcp_alias_for_header(identifier) + if sanitized and sanitized not in keys_to_try: + keys_to_try.append(sanitized) + for key in keys_to_try: + if key in normalized_headers: + return normalized_headers[key] + return None + + def validate_and_normalize_mcp_server_payload(payload: Any) -> None: """ Validate and normalize MCP server payload fields (server_name and alias). diff --git a/tests/mcp_tests/test_mcp_server.py b/tests/mcp_tests/test_mcp_server.py index 809b13aeea6..c20fb09eeba 100644 --- a/tests/mcp_tests/test_mcp_server.py +++ b/tests/mcp_tests/test_mcp_server.py @@ -1770,6 +1770,26 @@ def test_get_server_auth_header_fallback_to_default(): assert result == "Bearer default_token" +def test_get_server_auth_header_hyphenated_alias_sanitized_header_key(): + """Header keys use sanitized alias; lookup must match legacy hyphenated aliases.""" + from litellm.proxy._experimental.mcp_server.rest_endpoints import ( + _get_server_auth_header, + ) + + mock_server = MagicMock() + mock_server.alias = "GitHub-MCP" + mock_server.server_name = "github_mcp_server" + + mcp_server_auth_headers = { + "github_mcp": {"Authorization": "Bearer github-mcp-token"}, + } + + result = _get_server_auth_header( + mock_server, mcp_server_auth_headers, "Bearer default_token" + ) + assert result == {"Authorization": "Bearer github-mcp-token"} + + def test_get_server_auth_header_no_auth_headers(): """Test _get_server_auth_header function with no auth headers.""" from litellm.proxy._experimental.mcp_server.rest_endpoints import ( diff --git a/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_header_alias_utils.py b/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_header_alias_utils.py new file mode 100644 index 00000000000..2627199570b --- /dev/null +++ b/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_header_alias_utils.py @@ -0,0 +1,18 @@ +"""Tests for MCP header alias sanitization and auth header lookup.""" + +from litellm.proxy._experimental.mcp_server.utils import ( + lookup_mcp_server_auth_in_headers, + sanitize_mcp_alias_for_header, +) + + +def test_sanitize_mcp_alias_for_header(): + assert sanitize_mcp_alias_for_header("My Server") == "my_server" + assert sanitize_mcp_alias_for_header("GitHub-MCP!") == "github_mcp" + assert sanitize_mcp_alias_for_header("github_mcp2") == "github_mcp2" + + +def test_lookup_mcp_server_auth_in_headers_sanitized_alias(): + headers = {"github_mcp": {"Authorization": "Bearer token"}} + result = lookup_mcp_server_auth_in_headers(headers, alias="GitHub-MCP") + assert result == {"Authorization": "Bearer token"} diff --git a/ui/litellm-dashboard/src/app/mcp/oauth/callback/page.tsx b/ui/litellm-dashboard/src/app/mcp/oauth/callback/page.tsx index 0539d6d8f19..3b3729c1ac9 100644 --- a/ui/litellm-dashboard/src/app/mcp/oauth/callback/page.tsx +++ b/ui/litellm-dashboard/src/app/mcp/oauth/callback/page.tsx @@ -4,11 +4,12 @@ import { Suspense, useEffect, useMemo } from "react"; import { useSearchParams } from "next/navigation"; import { getSecureItem, setSecureItem } from "@/utils/secureStorage"; -// Written to sessionStorage so both the admin hook (useMcpOAuthFlow) and the -// user hook (useUserMcpOAuthFlow) can pick up the result. Each hook reads -// its own namespace to avoid cross-flow collisions. +// Written to sessionStorage so the admin hook (useMcpOAuthFlow), the user hook +// (useUserMcpOAuthFlow), and the tools re-auth hook (useToolsOAuthFlow) can each +// pick up the result. Each hook reads its own namespace to avoid cross-flow collisions. const ADMIN_RESULT_KEY = "litellm-mcp-oauth-result"; const USER_RESULT_KEY = "litellm-user-mcp-oauth-result"; +const TOOLS_RESULT_KEY = "litellm-tools-mcp-oauth-result"; const RETURN_URL_STORAGE_KEY = "litellm-mcp-oauth-return-url"; const resolveDefaultRedirect = () => { @@ -50,11 +51,12 @@ const McpOAuthCallbackContent = () => { } try { - // Write to both namespace keys (admin and user) so whichever hook is - // active can consume the result. sessionStorage only — no localStorage. + // Write to all namespace keys so whichever hook is active can consume + // the result. sessionStorage only — no localStorage. const serialized = JSON.stringify(payload); setSecureItem(ADMIN_RESULT_KEY, serialized); setSecureItem(USER_RESULT_KEY, serialized); + setSecureItem(TOOLS_RESULT_KEY, serialized); } catch (err) { // Silently ignore storage errors } diff --git a/ui/litellm-dashboard/src/components/mcp_tools/create_mcp_server.tsx b/ui/litellm-dashboard/src/components/mcp_tools/create_mcp_server.tsx index f8b0141b25d..108911bdbf1 100644 --- a/ui/litellm-dashboard/src/components/mcp_tools/create_mcp_server.tsx +++ b/ui/litellm-dashboard/src/components/mcp_tools/create_mcp_server.tsx @@ -3,6 +3,7 @@ import { Modal, Tooltip, Form, Select, Input, Switch, Collapse } from "antd"; import { InfoCircleOutlined } from "@ant-design/icons"; import { Button, TextInput } from "@tremor/react"; import { createMCPServer, registerMCPServer } from "../networking"; +import { setToken } from "@/utils/mcpTokenStore"; import { AUTH_TYPE, DiscoverableMCPServer, OAUTH_FLOW, MCPServer, MCPServerCostInfo, TRANSPORT } from "./types"; import OAuthFormFields from "./OAuthFormFields"; import MCPServerCostConfig from "./mcp_server_cost_config"; @@ -24,6 +25,7 @@ export const mcpLogoImg = `${asset_logos_folder}mcp_logo.png`; interface CreateMCPServerProps { userRole: string; + userID?: string | null; accessToken: string | null; onCreateSuccess: (newMcpServer: MCPServer) => void; isModalVisible: boolean; @@ -47,6 +49,7 @@ const reduceStaticHeaders = (list: unknown): Record => { }; const CreateMCPServer: React.FC = ({ + userID, userRole, accessToken, onCreateSuccess, @@ -409,6 +412,21 @@ const CreateMCPServer: React.FC = ({ ? await createMCPServer(accessToken, payload) : await registerMCPServer(accessToken, payload); + // Cache the OAuth token in sessionStorage so the Tools tab can use it + // immediately without re-authenticating. No backend DB write. + if (oauthTokenResponse?.access_token && response?.server_id) { + setToken( + response.server_id, + { + access_token: oauthTokenResponse.access_token, + expires_in: oauthTokenResponse.expires_in, + refresh_token: oauthTokenResponse.refresh_token, + token_type: oauthTokenResponse.token_type, + }, + userID, + ); + } + NotificationsManager.success( isAdmin ? "MCP Server created successfully" diff --git a/ui/litellm-dashboard/src/components/mcp_tools/mcp_server_view.tsx b/ui/litellm-dashboard/src/components/mcp_tools/mcp_server_view.tsx index 1f8f7f68d33..5a8035d4e0b 100644 --- a/ui/litellm-dashboard/src/components/mcp_tools/mcp_server_view.tsx +++ b/ui/litellm-dashboard/src/components/mcp_tools/mcp_server_view.tsx @@ -174,6 +174,7 @@ export const MCPServerView: React.FC = ({ serverId={mcpServer.server_id} accessToken={accessToken} auth_type={mcpServer.auth_type} + tokenUrl={mcpServer.token_url} userRole={userRole} userID={userID} serverAlias={mcpServer.alias} diff --git a/ui/litellm-dashboard/src/components/mcp_tools/mcp_servers.tsx b/ui/litellm-dashboard/src/components/mcp_tools/mcp_servers.tsx index 72d5e4b5aa8..42583fdab07 100644 --- a/ui/litellm-dashboard/src/components/mcp_tools/mcp_servers.tsx +++ b/ui/litellm-dashboard/src/components/mcp_tools/mcp_servers.tsx @@ -287,6 +287,7 @@ const MCPServers: React.FC = ({ accessToken, userRole, userID }) (null); const [toolError, setToolError] = useState(null); const [toolSearchTerm, setToolSearchTerm] = useState(""); - + // State for passthrough headers const [passthroughHeaders, setPassthroughHeaders] = useState>({}); const [showHeaderInput, setShowHeaderInput] = useState(false); + // OAuth session token (sessionStorage-backed, cleared on tab/browser close). + // Only the interactive (authorization_code/PKCE) flow needs a user-facing + // auth gate. M2M (client_credentials) servers are also `auth_type === "oauth2"`, + // but the backend fetches their token internally — gating tool listing on + // them would force users through a non-existent authorization endpoint. + // We detect M2M via the presence of `tokenUrl`, matching the heuristic in + // `mcp_server_edit.tsx`. + const isOAuth = auth_type === "oauth2" && !tokenUrl; + const [oauthToken, setOauthToken] = useState(() => + isOAuth && isTokenValid(serverId, userID) + ? (getToken(serverId, userID)?.access_token ?? null) + : null + ); + + // Re-sync token when serverId/userID changes (useState initializer only runs on mount). + useEffect(() => { + if (!isOAuth) { + setOauthToken(null); + return; + } + setOauthToken( + isTokenValid(serverId, userID) + ? (getToken(serverId, userID)?.access_token ?? null) + : null + ); + }, [serverId, userID, isOAuth]); + + const { startOAuthFlow, status: oauthStatus, error: oauthError } = useToolsOAuthFlow({ + accessToken: accessToken ?? "", + serverId, + serverAlias, + userId: userID, + onSuccess: setOauthToken, + }); + // Check if this server has extra headers configured const hasExtraHeaders = extraHeaders && extraHeaders.length > 0; // Build custom headers for MCP server requests const buildCustomHeaders = () => { - if (!serverAlias || !hasExtraHeaders) return undefined; - const customHeaders: Record = {}; - - // Add passthrough headers with server-specific prefix - Object.entries(passthroughHeaders).forEach(([headerName, headerValue]) => { - if (headerValue && headerValue.trim()) { - // Format: x-mcp-{alias}-{header_name} - const mcpHeaderName = `x-mcp-${serverAlias}-${headerName.toLowerCase()}`; - customHeaders[mcpHeaderName] = headerValue; + + // Include the session OAuth token using MCP-specific headers so it doesn't + // conflict with the Authorization header used by the LiteLLM proxy itself. + // The backend's _get_mcp_server_auth_headers_from_headers() picks up the + // x-mcp-{alias}-{header} pattern and forwards it to the upstream MCP server. + // When no alias is available, fall back to x-mcp-auth (legacy but still supported). + if (oauthToken) { + if (serverAlias) { + const safeAlias = sanitizeMcpAliasForHeader(serverAlias); + if (safeAlias) { + customHeaders[`x-mcp-${safeAlias}-authorization`] = `Bearer ${oauthToken}`; + } else { + customHeaders["x-mcp-auth"] = `Bearer ${oauthToken}`; + } + } else { + customHeaders["x-mcp-auth"] = `Bearer ${oauthToken}`; } - }); - + } + + // Add passthrough headers with server-specific prefix + if (serverAlias && hasExtraHeaders) { + const safeAlias = sanitizeMcpAliasForHeader(serverAlias); + if (safeAlias) { + Object.entries(passthroughHeaders).forEach(([headerName, headerValue]) => { + if (headerValue && headerValue.trim()) { + // Format: x-mcp-{alias}-{header_name} + const mcpHeaderName = `x-mcp-${safeAlias}-${headerName.toLowerCase()}`; + customHeaders[mcpHeaderName] = headerValue; + } + }); + } + } + return Object.keys(customHeaders).length > 0 ? customHeaders : undefined; }; @@ -54,15 +114,55 @@ const MCPToolsViewer = ({ error: mcpToolsError, refetch: refetchTools, } = useQuery({ - queryKey: ["mcpTools", serverId, passthroughHeaders], - queryFn: () => { + queryKey: ["mcpTools", serverId, passthroughHeaders, oauthToken], + queryFn: async () => { if (!accessToken) throw new Error("Access Token required"); - return listMCPTools(accessToken, serverId, buildCustomHeaders()); + const result = await listMCPTools(accessToken, serverId, buildCustomHeaders()); + // listMCPTools never throws — surface error responses as thrown errors + // here so useQuery's retry/onError can react (e.g. clear the cached + // OAuth token on 401). + if (result?.error) { + const status = (result as { status?: number }).status; + if (status === 401) { + removeToken(serverId, userID); + } + const enhancedError = new Error( + result.message || result.error || "Failed to fetch MCP tools", + ) as Error & { + status?: number; + statusText?: string; + details?: any; + }; + enhancedError.status = status; + enhancedError.statusText = (result as any).statusText; + enhancedError.details = (result as any).details; + throw enhancedError; + } + return result; }, - enabled: !!accessToken, + // For OAuth servers, block the query until a session token is available + enabled: !!accessToken && (!isOAuth || oauthToken !== null), staleTime: 30000, // Consider data fresh for 30 seconds + retry: (failureCount, error: any) => { + // Don't retry on 401 — token is invalid, user must re-authenticate + if (error?.status === 401 || error?.response?.status === 401) return false; + return failureCount < 2; + }, }); + // If the tools query fails with 401, the cached OAuth token is invalid — + // clear it so the auth gate is shown again and the user can re-authenticate. + useEffect(() => { + const err = mcpToolsError as + | (Error & { status?: number; response?: { status?: number } }) + | null; + const status = err?.status ?? err?.response?.status; + if (status === 401) { + removeToken(serverId, userID); + setOauthToken(null); + } + }, [mcpToolsError, serverId, userID]); + // Mutation for calling a tool const { mutate: executeTool, isPending: isCallingTool } = useMutation({ mutationFn: async (args: { tool: MCPTool; arguments: Record }) => { @@ -85,9 +185,14 @@ const MCPToolsViewer = ({ setToolResult(data.content); setToolError(null); }, - onError: (error: Error) => { + onError: (error: Error & { status?: number; response?: { status?: number } }) => { setToolError(error); setToolResult(null); + // On 401, clear the cached token so the auth gate is shown again + if (error?.status === 401 || (error as any)?.response?.status === 401) { + removeToken(serverId, userID); + setOauthToken(null); + } }, }); @@ -197,7 +302,31 @@ const MCPToolsViewer = ({ )} - {/* Search Bar */} + {/* OAuth Auth Gate — shown when token is absent for OAuth servers */} + {isOAuth && !oauthToken && ( +
+ +

Authentication required

+

+ Authenticate to view available tools +

+ + Authorize + + {oauthError && ( +

{oauthError}

+ )} +
+ )} + + {/* Search Bar — only shown when tools are loaded */} + {!isOAuth || oauthToken ? <> {toolsData.length > 0 && (
-

Error: {mcpToolsResponse.message}

+

+ Error: {mcpToolsResponse?.message || (mcpToolsError as Error)?.message} +

)} {/* No Tools State */} - {!isLoadingTools && !mcpToolsResponse?.error && (!toolsData || toolsData.length === 0) && ( + {!isLoadingTools && !mcpToolsResponse?.error && !mcpToolsError && (!toolsData || toolsData.length === 0) && (
@@ -315,6 +446,7 @@ const MCPToolsViewer = ({ )} )} + : null}
diff --git a/ui/litellm-dashboard/src/components/mcp_tools/types.tsx b/ui/litellm-dashboard/src/components/mcp_tools/types.tsx index 7cfe08d9ee5..9a8f2e8f514 100644 --- a/ui/litellm-dashboard/src/components/mcp_tools/types.tsx +++ b/ui/litellm-dashboard/src/components/mcp_tools/types.tsx @@ -163,6 +163,13 @@ export interface MCPToolsViewerProps { serverId: string; accessToken: string | null; auth_type?: string | null; + /** + * When set, indicates the server uses the OAuth2 M2M (client_credentials) + * flow — the backend handles token acquisition internally, so the UI must + * not gate tool listing behind an interactive PKCE authorization. Mirrors + * the heuristic used in `mcp_server_edit.tsx` (`token_url` set => M2M). + */ + tokenUrl?: string | null; userRole: string | null; userID: string | null; serverAlias?: string | null; diff --git a/ui/litellm-dashboard/src/components/networking.tsx b/ui/litellm-dashboard/src/components/networking.tsx index 756348f4937..57e7d51123e 100644 --- a/ui/litellm-dashboard/src/components/networking.tsx +++ b/ui/litellm-dashboard/src/components/networking.tsx @@ -7068,46 +7068,33 @@ export const testSearchToolConnection = async (accessToken: string, litellmParam }; export const listMCPTools = async ( - accessToken: string, + accessToken: string, serverId: string, - customHeaders?: Record + customHeaders?: Record, ) => { + // Construct base URL + let url = proxyBaseUrl + ? `${proxyBaseUrl}/mcp-rest/tools/list?server_id=${serverId}` + : `/mcp-rest/tools/list?server_id=${serverId}`; + + console.log("Fetching MCP tools from:", url); + + const headers: Record = { + [globalLitellmHeaderName]: `Bearer ${accessToken}`, + "Content-Type": "application/json", + ...customHeaders, // Merge custom headers for passthrough auth + }; + + let response: Response; try { - // Construct base URL - let url = proxyBaseUrl - ? `${proxyBaseUrl}/mcp-rest/tools/list?server_id=${serverId}` - : `/mcp-rest/tools/list?server_id=${serverId}`; - - console.log("Fetching MCP tools from:", url); - - const headers: Record = { - [globalLitellmHeaderName]: `Bearer ${accessToken}`, - "Content-Type": "application/json", - ...customHeaders, // Merge custom headers for passthrough auth - }; - - const response = await fetch(url, { + response = await fetch(url, { method: "GET", headers, }); - - const data = await response.json(); - console.log("Fetched MCP tools response:", data); - - if (!response.ok) { - // If the server returned an error response, use it - if (data.error && data.message) { - throw new Error(data.message); - } - // Otherwise use a generic error - throw new Error("Failed to fetch MCP tools"); - } - - // Return the full response object which includes tools, error, message, and stack_trace - return data; } catch (error) { - console.error("Failed to fetch MCP tools:", error); - // Return an error response in the same format as the API + // Network-level failure (no HTTP response). Preserve legacy shape so the + // caller can render a generic error message without crashing. + console.error("Failed to fetch MCP tools (network error):", error); return { tools: [], error: "network_error", @@ -7115,6 +7102,44 @@ export const listMCPTools = async ( stack_trace: null, }; } + + let data: any = null; + try { + data = await response.json(); + } catch (parseError) { + console.error("Failed to parse MCP tools response:", parseError); + return { + tools: [], + error: "parse_error", + message: "Failed to parse MCP tools response", + status: response.status, + statusText: response.statusText, + stack_trace: null, + }; + } + console.log("Fetched MCP tools response:", data); + + if (!response.ok) { + // Preserve the legacy "never throws" contract so existing callers + // (e.g. MCPToolPermissions, MCPAppsPanel, MCPConnectPicker) can continue + // to inspect `result.error` / `result.message`. Attach `status` so + // callers that need to react to auth failures (e.g. the useQuery in + // mcp_tools.tsx) can still detect 401s from the returned object. + const errorMessage = + (data && (data.message || data.error)) || "Failed to fetch MCP tools"; + return { + tools: [], + error: (data && data.error) || `http_${response.status}`, + message: errorMessage, + status: response.status, + statusText: response.statusText, + details: data, + stack_trace: null, + }; + } + + // Return the full response object which includes tools, error, message, and stack_trace + return data; }; interface CallMCPToolOptions { diff --git a/ui/litellm-dashboard/src/hooks/mcpOAuthUtils.ts b/ui/litellm-dashboard/src/hooks/mcpOAuthUtils.ts new file mode 100644 index 00000000000..3aff8af6eef --- /dev/null +++ b/ui/litellm-dashboard/src/hooks/mcpOAuthUtils.ts @@ -0,0 +1,39 @@ +/** + * Shared utilities for MCP OAuth2 PKCE flow hooks. + * + * These helpers are used by both useToolsOAuthFlow and useUserMcpOAuthFlow + * to avoid divergence in URL construction and storage cleanup logic. + */ + +import { getProxyBaseUrl, serverRootPath } from "@/components/networking"; + +/** + * Build the OAuth callback URL for the current UI deployment. + * + * In the browser, derive the `/ui` prefix from the current pathname so the + * callback works regardless of how the proxy is mounted. Outside the browser + * (SSR), fall back to the configured proxy base URL and server root path. + */ +export const buildCallbackUrl = (): string => { + if (typeof window !== "undefined") { + const path = window.location.pathname || ""; + const idx = path.indexOf("/ui"); + const prefix = idx >= 0 ? path.slice(0, idx + 3).replace(/\/+$/, "") : ""; + return `${window.location.origin}${prefix}/mcp/oauth/callback`; + } + const base = (getProxyBaseUrl() || "").replace(/\/+$/, ""); + const root = serverRootPath && serverRootPath !== "/" ? serverRootPath : ""; + return `${base}${root}/ui/mcp/oauth/callback`; +}; + +/** + * Remove the given keys from sessionStorage, ignoring errors (e.g. storage + * disabled by browser privacy settings). + */ +export const clearStorage = (...keys: string[]): void => { + keys.forEach((k) => { + try { + window.sessionStorage.removeItem(k); + } catch (_) {} + }); +}; diff --git a/ui/litellm-dashboard/src/hooks/useMcpOAuthFlow.tsx b/ui/litellm-dashboard/src/hooks/useMcpOAuthFlow.tsx index 7edeade4cbd..11efaba53b3 100644 --- a/ui/litellm-dashboard/src/hooks/useMcpOAuthFlow.tsx +++ b/ui/litellm-dashboard/src/hooks/useMcpOAuthFlow.tsx @@ -224,12 +224,21 @@ export const useMcpOAuthFlow = ({ if (!storedPayload) { return; } - + + // Guard: the callback page writes to the admin result key for *all* OAuth + // flows (including the tools re-auth flow). Only proceed if this hook's + // own flow state exists, meaning startOAuthFlow() was actually called here. + // Without this guard, a tools re-auth redirect triggers a spurious + // "OAuth session state was lost" error from this hook. + const storedFlowState = getStorageItem(FLOW_STATE_KEY); + if (!storedFlowState) { + return; + } + // Mark as processing processingRef.current = true; payload = JSON.parse(storedPayload); - const storedFlowState = getStorageItem(FLOW_STATE_KEY); - flowState = storedFlowState ? JSON.parse(storedFlowState) : null; + flowState = JSON.parse(storedFlowState); } catch (err) { clearStoredFlow(); processingRef.current = false; diff --git a/ui/litellm-dashboard/src/hooks/useToolsOAuthFlow.tsx b/ui/litellm-dashboard/src/hooks/useToolsOAuthFlow.tsx new file mode 100644 index 00000000000..66e59b80db4 --- /dev/null +++ b/ui/litellm-dashboard/src/hooks/useToolsOAuthFlow.tsx @@ -0,0 +1,232 @@ +"use client"; + +/** + * OAuth2 PKCE flow for the Tools screen re-authentication path. + * + * Unlike useUserMcpOAuthFlow (used in the chat panel), this hook: + * - stores the resulting token in sessionStorage via mcpTokenStore only + * - does NOT call storeMCPOAuthUserCredential (no backend DB write) + * - uses "litellm-tools-mcp-oauth-result" as its result key to avoid + * collisions with the admin and user flows + * + * The OAuth callback page (src/app/mcp/oauth/callback/page.tsx) writes + * to this key so this hook can pick up the result after the redirect. + */ + +import { useCallback, useEffect, useRef, useState } from "react"; +import { + buildMcpOAuthAuthorizeUrl, + exchangeMcpOAuthToken, + registerMcpOAuthClient, +} from "@/components/networking"; +import NotificationsManager from "@/components/molecules/notifications_manager"; +import { extractErrorMessage } from "@/utils/errorUtils"; +import { generateCodeChallenge, generateCodeVerifier } from "@/utils/pkce"; +import { getSecureItem, setSecureItem } from "@/utils/secureStorage"; +import { setToken } from "@/utils/mcpTokenStore"; +import { buildCallbackUrl, clearStorage } from "./mcpOAuthUtils"; + +export type ToolsOAuthStatus = "idle" | "authorizing" | "exchanging" | "success" | "error"; + +interface UseToolsOAuthFlowOptions { + accessToken: string; + serverId: string; + serverAlias?: string | null; + userId?: string | null; + scopes?: string[]; + clientId?: string | null; + onSuccess: (accessToken: string) => void; +} + +interface UseToolsOAuthFlowResult { + startOAuthFlow: () => Promise; + status: ToolsOAuthStatus; + error: string | null; +} + +const FLOW_STATE_KEY = "litellm-tools-mcp-oauth-flow-state"; +const RESULT_KEY = "litellm-tools-mcp-oauth-result"; +const RETURN_URL_KEY = "litellm-mcp-oauth-return-url"; + +type StoredFlowState = { + state: string; + codeVerifier: string; + serverId: string; + redirectUri: string; + clientId?: string; + clientSecret?: string; + scopes?: string[]; +}; + +export const useToolsOAuthFlow = ({ + accessToken, + serverId, + serverAlias, + userId, + scopes, + clientId: preClientId, + onSuccess, +}: UseToolsOAuthFlowOptions): UseToolsOAuthFlowResult => { + const [status, setStatus] = useState("idle"); + const [error, setError] = useState(null); + const processingRef = useRef(false); + const onSuccessRef = useRef(onSuccess); + onSuccessRef.current = onSuccess; + + const startOAuthFlow = useCallback(async () => { + if (typeof window === "undefined") return; + try { + setStatus("authorizing"); + setError(null); + + let clientId: string | undefined = preClientId ?? undefined; + let clientSecret: string | undefined; + + if (!clientId) { + try { + const reg = await registerMcpOAuthClient(accessToken, serverId, { + client_name: serverAlias || serverId, + grant_types: ["authorization_code", "refresh_token"], + response_types: ["code"], + token_endpoint_auth_method: "none", + }); + clientId = reg?.client_id; + clientSecret = reg?.client_secret; + } catch (_) { + // Registration is optional; proceed without client_id + } + } + + const verifier = generateCodeVerifier(); + const challenge = await generateCodeChallenge(verifier); + const state = crypto.randomUUID(); + const redirectUri = buildCallbackUrl(); + const scopeString = scopes?.filter((s) => s.trim()).join(" "); + + const authorizeUrl = buildMcpOAuthAuthorizeUrl({ + serverId, + clientId, + redirectUri, + state, + codeChallenge: challenge, + scope: scopeString, + }); + + const flowState: StoredFlowState = { + state, + codeVerifier: verifier, + serverId, + redirectUri, + clientId, + clientSecret, + scopes, + }; + + setSecureItem(FLOW_STATE_KEY, JSON.stringify(flowState)); + // Return to the current page (Tools tab) after the OAuth redirect + setSecureItem(RETURN_URL_KEY, window.location.href); + + window.location.href = authorizeUrl; + } catch (err) { + const msg = extractErrorMessage(err); + setError(msg); + setStatus("error"); + NotificationsManager.error(msg); + } + }, [accessToken, serverId, serverAlias, scopes, preClientId]); + + const resumeOAuthFlow = useCallback(async () => { + if (typeof window === "undefined" || processingRef.current) return; + + const storedResult = getSecureItem(RESULT_KEY); + if (!storedResult) return; + + // The callback page writes to this result key for every OAuth flow (including + // the admin server-creation flow). Guard: only proceed if *this* hook's flow + // state exists, meaning startOAuthFlow() was actually called from the Tools screen. + // Without this guard, a stale result written during server creation would trigger + // "OAuth session state was lost" when the user navigates to the Tools tab. + const rawFlowState = getSecureItem(FLOW_STATE_KEY); + if (!rawFlowState) return; + + let peeked: StoredFlowState | null = null; + try { + peeked = JSON.parse(rawFlowState) as StoredFlowState; + if (peeked.serverId && peeked.serverId !== serverId) return; + } catch (_) {} + + processingRef.current = true; + clearStorage(RESULT_KEY); + + let payload: Record | null = null; + let flowState: StoredFlowState | null = null; + + try { + payload = JSON.parse(storedResult); + flowState = peeked; + } catch (_) { + setError("Failed to resume OAuth flow. Please retry."); + setStatus("error"); + processingRef.current = false; + clearStorage(FLOW_STATE_KEY); + return; + } + + try { + if (!flowState?.state || !flowState.codeVerifier || !flowState.serverId) { + throw new Error("OAuth session state was lost. Please retry."); + } + if (!payload?.state || payload.state !== flowState.state) { + throw new Error("OAuth state mismatch. Please retry."); + } + if (payload.error) { + throw new Error((payload.error_description as string) || (payload.error as string)); + } + if (!payload.code) { + throw new Error("Authorization code missing in callback."); + } + + setStatus("exchanging"); + const token = await exchangeMcpOAuthToken({ + serverId: flowState.serverId, + code: payload.code as string, + clientId: flowState.clientId, + clientSecret: flowState.clientSecret, + codeVerifier: flowState.codeVerifier, + redirectUri: flowState.redirectUri, + accessToken, + }); + + // Store in sessionStorage only — no backend DB write + setToken( + flowState.serverId, + { + access_token: token.access_token, + expires_in: token.expires_in, + refresh_token: token.refresh_token, + token_type: token.token_type, + }, + userId, + ); + + setStatus("success"); + setError(null); + NotificationsManager.success("Connected successfully"); + onSuccessRef.current(token.access_token); + } catch (err) { + const msg = extractErrorMessage(err); + setError(msg); + setStatus("error"); + NotificationsManager.error(msg); + } finally { + clearStorage(FLOW_STATE_KEY); + setTimeout(() => { processingRef.current = false; }, 1000); + } + }, [accessToken, serverId, userId]); + + useEffect(() => { + resumeOAuthFlow(); + }, [resumeOAuthFlow]); + + return { startOAuthFlow, status, error }; +}; diff --git a/ui/litellm-dashboard/src/hooks/useUserMcpOAuthFlow.tsx b/ui/litellm-dashboard/src/hooks/useUserMcpOAuthFlow.tsx index cf0a81dcadf..1dc7a5ee54a 100644 --- a/ui/litellm-dashboard/src/hooks/useUserMcpOAuthFlow.tsx +++ b/ui/litellm-dashboard/src/hooks/useUserMcpOAuthFlow.tsx @@ -16,15 +16,14 @@ import { useCallback, useEffect, useRef, useState } from "react"; import { buildMcpOAuthAuthorizeUrl, exchangeMcpOAuthToken, - getProxyBaseUrl, registerMcpOAuthClient, - serverRootPath, storeMCPOAuthUserCredential, } from "@/components/networking"; import NotificationsManager from "@/components/molecules/notifications_manager"; import { extractErrorMessage } from "@/utils/errorUtils"; import { generateCodeChallenge, generateCodeVerifier } from "@/utils/pkce"; import { getSecureItem, setSecureItem } from "@/utils/secureStorage"; +import { buildCallbackUrl, clearStorage } from "./mcpOAuthUtils"; export type UserMcpOAuthStatus = "idle" | "authorizing" | "exchanging" | "success" | "error"; @@ -69,26 +68,6 @@ const getStorage = (key: string): string | null => { return getSecureItem(key); }; -const clearStorage = (...keys: string[]) => { - keys.forEach((k) => { - try { - window.sessionStorage.removeItem(k); - } catch (_) {} - }); -}; - -const buildCallbackUrl = (): string => { - if (typeof window !== "undefined") { - const path = window.location.pathname || ""; - const idx = path.indexOf("/ui"); - const prefix = idx >= 0 ? path.slice(0, idx + 3).replace(/\/+$/, "") : ""; - return `${window.location.origin}${prefix}/mcp/oauth/callback`; - } - const base = (getProxyBaseUrl() || "").replace(/\/+$/, ""); - const root = serverRootPath && serverRootPath !== "/" ? serverRootPath : ""; - return `${base}${root}/ui/mcp/oauth/callback`; -}; - export const useUserMcpOAuthFlow = ({ accessToken, serverId, @@ -176,13 +155,17 @@ export const useUserMcpOAuthFlow = ({ // mount and would compete for the same RESULT_KEY. Peek at the stored // flow state first: only the hook instance whose serverId matches the one // that initiated the OAuth flow should consume the result. + // Guard: only proceed if this hook's flow state exists (startOAuthFlow was + // called from this hook). Without the guard, a tools re-auth redirect writes + // to the user result key too, and every OAuth2ConnectButton instance would try + // to resume a flow that was never started here. const rawFlowState = getStorage(FLOW_STATE_KEY); - if (rawFlowState) { - try { - const peeked = JSON.parse(rawFlowState) as StoredFlowState; - if (peeked.serverId && peeked.serverId !== serverId) return; - } catch (_) {} - } + if (!rawFlowState) return; + + try { + const peeked = JSON.parse(rawFlowState) as StoredFlowState; + if (peeked.serverId && peeked.serverId !== serverId) return; + } catch (_) {} processingRef.current = true; clearStorage(RESULT_KEY); diff --git a/ui/litellm-dashboard/src/utils/cookieUtils.test.ts b/ui/litellm-dashboard/src/utils/cookieUtils.test.ts index c7bd27a6a85..28e2fc771c2 100644 --- a/ui/litellm-dashboard/src/utils/cookieUtils.test.ts +++ b/ui/litellm-dashboard/src/utils/cookieUtils.test.ts @@ -1,5 +1,6 @@ import { describe, it, expect, beforeEach, vi } from "vitest"; import { clearTokenCookies, getCookie, storeLoginToken } from "./cookieUtils"; +import { getToken, setToken } from "./mcpTokenStore"; describe("cookieUtils", () => { beforeEach(() => { @@ -20,6 +21,15 @@ describe("cookieUtils", () => { expect(getCookie("token")).toBeNull(); }); + it("should clear MCP session tokens on logout", () => { + setToken("server-1", { access_token: "mcp-tok" }, "user-a"); + expect(getToken("server-1", "user-a")).not.toBeNull(); + + clearTokenCookies(); + + expect(getToken("server-1", "user-a")).toBeNull(); + }); + it("should clear token cookie from /ui path", () => { document.cookie = "token=test-token-value; path=/ui"; clearTokenCookies(); diff --git a/ui/litellm-dashboard/src/utils/cookieUtils.ts b/ui/litellm-dashboard/src/utils/cookieUtils.ts index b4493744ad4..da232e72e2a 100644 --- a/ui/litellm-dashboard/src/utils/cookieUtils.ts +++ b/ui/litellm-dashboard/src/utils/cookieUtils.ts @@ -2,6 +2,8 @@ * Utility functions for managing cookies */ +import { clearAllMcpTokens } from "./mcpTokenStore"; + /** * Returns the cookie path for the UI. * Derives the path from window.location.pathname so it works when @@ -67,6 +69,7 @@ export function clearTokenCookies() { // sessionStorage may be unavailable } + clearAllMcpTokens(); } /** diff --git a/ui/litellm-dashboard/src/utils/mcpHeaderUtils.test.ts b/ui/litellm-dashboard/src/utils/mcpHeaderUtils.test.ts new file mode 100644 index 00000000000..b730b9c097c --- /dev/null +++ b/ui/litellm-dashboard/src/utils/mcpHeaderUtils.test.ts @@ -0,0 +1,16 @@ +import { describe, expect, it } from "vitest"; +import { sanitizeMcpAliasForHeader } from "./mcpHeaderUtils"; + +describe("sanitizeMcpAliasForHeader", () => { + it("lowercases and replaces spaces with underscores", () => { + expect(sanitizeMcpAliasForHeader("My Server")).toBe("my_server"); + }); + + it("replaces invalid characters for header token segments", () => { + expect(sanitizeMcpAliasForHeader("GitHub-MCP!")).toBe("github_mcp"); + }); + + it("preserves underscores and digits", () => { + expect(sanitizeMcpAliasForHeader("github_mcp2")).toBe("github_mcp2"); + }); +}); diff --git a/ui/litellm-dashboard/src/utils/mcpHeaderUtils.ts b/ui/litellm-dashboard/src/utils/mcpHeaderUtils.ts new file mode 100644 index 00000000000..76c752a4b61 --- /dev/null +++ b/ui/litellm-dashboard/src/utils/mcpHeaderUtils.ts @@ -0,0 +1,14 @@ +/** + * Sanitize an MCP server alias for use in HTTP header names (x-mcp-{alias}-...). + * RFC 7230 tchar allows token chars; aliases with spaces or hyphens break parsing + * because the backend splits on the first dash after the x-mcp- prefix. + * Keep in sync with litellm.proxy._experimental.mcp_server.utils.sanitize_mcp_alias_for_header. + */ +export function sanitizeMcpAliasForHeader(alias: string): string { + return alias + .toLowerCase() + .trim() + .replace(/[^a-z0-9_]/g, "_") + .replace(/_+/g, "_") + .replace(/^_|_$/g, ""); +} diff --git a/ui/litellm-dashboard/src/utils/mcpTokenStore.test.ts b/ui/litellm-dashboard/src/utils/mcpTokenStore.test.ts new file mode 100644 index 00000000000..1c61e9b1a26 --- /dev/null +++ b/ui/litellm-dashboard/src/utils/mcpTokenStore.test.ts @@ -0,0 +1,46 @@ +import { afterEach, beforeEach, describe, expect, it } from "vitest"; +import { + clearAllMcpTokens, + getToken, + isTokenValid, + removeToken, + setToken, +} from "./mcpTokenStore"; + +describe("mcpTokenStore", () => { + beforeEach(() => { + sessionStorage.clear(); + }); + + afterEach(() => { + sessionStorage.clear(); + }); + + it("scopes tokens by user id", () => { + setToken("server-a", { access_token: "user1-token" }, "user-1"); + setToken("server-a", { access_token: "user2-token" }, "user-2"); + + expect(getToken("server-a", "user-1")?.access_token).toBe("user1-token"); + expect(getToken("server-a", "user-2")?.access_token).toBe("user2-token"); + expect(getToken("server-a", "user-3")).toBeNull(); + }); + + it("validates expiry per user scope", () => { + setToken("server-a", { access_token: "tok", expires_in: 3600 }, "user-1"); + expect(isTokenValid("server-a", "user-1")).toBe(true); + removeToken("server-a", "user-1"); + expect(isTokenValid("server-a", "user-1")).toBe(false); + }); + + it("clearAllMcpTokens removes every mcp-session-token entry", () => { + setToken("s1", { access_token: "a" }, "u1"); + setToken("s2", { access_token: "b" }, "u2"); + sessionStorage.setItem("unrelated", "keep"); + + clearAllMcpTokens(); + + expect(getToken("s1", "u1")).toBeNull(); + expect(getToken("s2", "u2")).toBeNull(); + expect(sessionStorage.getItem("unrelated")).toBe("keep"); + }); +}); diff --git a/ui/litellm-dashboard/src/utils/mcpTokenStore.ts b/ui/litellm-dashboard/src/utils/mcpTokenStore.ts new file mode 100644 index 00000000000..0279922cd07 --- /dev/null +++ b/ui/litellm-dashboard/src/utils/mcpTokenStore.ts @@ -0,0 +1,93 @@ +/** + * Session-storage-backed OAuth token store for MCP servers. + * Tokens are keyed by LiteLLM user id + server_id and cleared when the browser + * session ends (tab/window close). Never written to localStorage. + */ + +const KEY_PREFIX = "mcp-session-token:"; + +interface StoredToken { + access_token: string; + expires_at: number; + refresh_token?: string; + token_type: string; +} + +interface TokenInput { + access_token: string; + expires_in?: number; + refresh_token?: string; + token_type?: string; +} + +const DEFAULT_TTL_MS = 3600 * 1000; // 1 hour + +function storageKey(serverId: string, userId?: string | null): string { + const userPart = userId?.trim() || "_anonymous"; + return `${KEY_PREFIX}${userPart}:${serverId}`; +} + +export function setToken( + serverId: string, + data: TokenInput, + userId?: string | null, +): void { + if (typeof window === "undefined") return; + const stored: StoredToken = { + access_token: data.access_token, + expires_at: Date.now() + (data.expires_in != null ? data.expires_in * 1000 : DEFAULT_TTL_MS), + token_type: data.token_type ?? "bearer", + ...(data.refresh_token ? { refresh_token: data.refresh_token } : {}), + }; + try { + window.sessionStorage.setItem(storageKey(serverId, userId), JSON.stringify(stored)); + } catch { + // Silently ignore storage errors (private browsing, quota exceeded, etc.) + } +} + +export function getToken( + serverId: string, + userId?: string | null, +): StoredToken | null { + if (typeof window === "undefined") return null; + try { + const raw = window.sessionStorage.getItem(storageKey(serverId, userId)); + if (!raw) return null; + return JSON.parse(raw) as StoredToken; + } catch { + return null; + } +} + +export function removeToken(serverId: string, userId?: string | null): void { + if (typeof window === "undefined") return; + try { + window.sessionStorage.removeItem(storageKey(serverId, userId)); + } catch { + // Silently ignore + } +} + +export function isTokenValid(serverId: string, userId?: string | null): boolean { + const token = getToken(serverId, userId); + if (!token) return false; + return token.expires_at > Date.now(); +} + +/** Remove all MCP session tokens (e.g. on logout or user switch). */ +export function clearAllMcpTokens(): void { + if (typeof window === "undefined") return; + try { + const keysToRemove: string[] = []; + for (let i = 0; i < window.sessionStorage.length; i++) { + const key = window.sessionStorage.key(i); + if (key?.startsWith(KEY_PREFIX)) { + keysToRemove.push(key); + } + } + keysToRemove.forEach((key) => window.sessionStorage.removeItem(key)); + } catch { + // Silently ignore + } +}