@openhands/agent-canvas 1.0.0-alpha.9 → 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/bin/agent-canvas.mjs +22 -2
- package/build/assets/{QueryClientProvider-B7kl84Kj.js → QueryClientProvider-CkGuhXg-.js} +1 -1
- package/build/assets/{Trans-1j65oy9O.js → Trans-Cvm_-SMi.js} +1 -1
- package/build/assets/acp-providers-CbiRekh9.js +1 -0
- package/build/assets/{acp-route-guard-CQTmeJwM.js → acp-route-guard-B2yoBZ_4.js} +1 -1
- package/build/assets/{active-backend-context-TVbjnvmP.js → active-backend-context-cCM1vYYZ.js} +1 -1
- package/build/assets/add-backend-modal-DIUQzMPa.js +1 -0
- package/build/assets/agent-server-client-options-Bc5ZorQZ.js +1 -0
- package/build/assets/agent-server-compatibility-BlkUsrX2.js +1 -0
- package/build/assets/agent-server-conversation-service.api-DFvqqEDo.js +5 -0
- package/build/assets/{agent-settings-B247S9G3.js → agent-settings-CnGSCmK8.js} +1 -1
- package/build/assets/{alert-banner-BWoqueRw.js → alert-banner-DtzAX654.js} +1 -1
- package/build/assets/{analytics-consent-form-modal-C7sXfxRh.js → analytics-consent-form-modal-CHZ3I37v.js} +1 -1
- package/build/assets/api-key-entry-screen-B2gynaCp.js +1 -0
- package/build/assets/{app-settings-BVeSaty9.js → app-settings-Db9ITeJH.js} +1 -1
- package/build/assets/{automation-detail-R-99FUce.js → automation-detail-Di7EOIZD.js} +1 -1
- package/build/assets/{automations-list-Dfu2c-_D.js → automations-list-IsIWdDiw.js} +1 -1
- package/build/assets/{backend-form-modal-DxYjqqAK.js → backend-form-modal-Dnk33xA_.js} +1 -1
- package/build/assets/{backend-synced-settings-badge-nAfiUWvM.js → backend-synced-settings-badge-Dc6c7GT4.js} +1 -1
- package/build/assets/{base-modal-CQRvRHu1.js → base-modal-_dYTw1ri.js} +1 -1
- package/build/assets/{brand-button-C2nEKopC.js → brand-button-Br7f0kZJ.js} +1 -1
- package/build/assets/{browser-HrYc5Gce.js → browser-D810xUYt.js} +2 -2
- package/build/assets/browser-store-Couc4S5D.js +1 -0
- package/build/assets/browser-tab-B-aIqXRl.js +1 -0
- package/build/assets/{checkmark-BJJrZUF8.js → checkmark-DL7acQA7.js} +1 -1
- package/build/assets/{chevron-left-small-CSh-sE9L.js → chevron-left-small-CVWf8TI6.js} +1 -1
- package/build/assets/{circle-plus-check-toggle-qs8Va1cC.js → circle-plus-check-toggle-P7ZZToV4.js} +1 -1
- package/build/assets/{clock-ZR4Kn-_Y.js → clock-BRjCgHTc.js} +1 -1
- package/build/assets/{close-BdmyeRqS.js → close-B5LROHR3.js} +1 -1
- package/build/assets/{combobox-caret-B53O9Hsq.js → combobox-caret-to1O8irE.js} +1 -1
- package/build/assets/{condenser-settings-A35V3yng.js → condenser-settings-wnEKhBof.js} +1 -1
- package/build/assets/{confirmation-modal-C9-La0h3.js → confirmation-modal-Dau3w_sa.js} +1 -1
- package/build/assets/{context-menu-list-item-Buu9nc0q.js → context-menu-list-item-CWNFpuiC.js} +1 -1
- package/build/assets/conversation-HlncOV7n.js +19 -0
- package/build/assets/conversation-MtnkpqA9.js +1 -0
- package/build/assets/conversation-panel-DxnM6tRe.js +1 -0
- package/build/assets/{conversation-service.api--f8WglOC.js → conversation-service.api-nb5W1PqR.js} +1 -1
- package/build/assets/{conversation-tab-empty-state-D8dNvo-V.js → conversation-tab-empty-state-DyssnnWa.js} +1 -1
- package/build/assets/conversation-websocket-context-C8_PkGLi.js +3 -0
- package/build/assets/{copy-C7Ti2d8C.js → copy-DYgmUdIw.js} +1 -1
- package/build/assets/{custom-toast-handlers-BOc3qeQ7.js → custom-toast-handlers-C-SZFmto.js} +1 -1
- package/build/assets/declaration-BNMqORFE.js +1 -0
- package/build/assets/{device-verify-CMusn8nX.js → device-verify-DqDlphsG.js} +1 -1
- package/build/assets/{dist-DZHSA2e6.js → dist-C6t0EXL7.js} +1 -1
- package/build/assets/{edit-automation-modal-Dnjxbjn7.js → edit-automation-modal-BGzR3nfZ.js} +1 -1
- package/build/assets/{ellipsis-button-ugUATsNo.js → ellipsis-button-ZyLMPURn.js} +1 -1
- package/build/assets/{entry.client-CqqXOSvd.js → entry.client-1VMHpktY.js} +2 -2
- package/build/assets/{enum-filter-dropdown-1vpOGySB.js → enum-filter-dropdown-CEgCdu4A.js} +1 -1
- package/build/assets/{environment-switch-overlay-CTCTQikP.js → environment-switch-overlay-XL8yCGP6.js} +1 -1
- package/build/assets/{extensions-hub-BSUseHVF.js → extensions-hub-C651jsVh.js} +1 -1
- package/build/assets/{extensions-navigation-CT1kc1u_.js → extensions-navigation-BYR8Giqq.js} +1 -1
- package/build/assets/files-tab-BhnLgimi.js +1 -0
- package/build/assets/{folder-0WSMImNX.js → folder-ZZJVGgd7.js} +1 -1
- package/build/assets/{git-control-bar-branch-button-C8u5rzjc.js → git-control-bar-branch-button-M34A5_vX.js} +2 -2
- package/build/assets/{git-provider-icon-D-a-rcLm.js → git-provider-icon-D5dCNy-k.js} +1 -1
- package/build/assets/home-CYQv7yc_.js +1 -0
- package/build/assets/{i18n-DjAGhTis.js → i18n-CTohRuoO.js} +1 -1
- package/build/assets/install-server-modal-f31_CLrW.js +1 -0
- package/build/assets/{launch-B2mbfOSm.js → launch-DHEUYn2A.js} +1 -1
- package/build/assets/{lesson-plan-DRYG5SLI.js → lesson-plan-dH5Bj0pN.js} +1 -1
- package/build/assets/{link-external-C9d6Fo3x.js → link-external-D2POYx4c.js} +1 -1
- package/build/assets/{llm-client-ChQzg4wX.js → llm-client-DaH1TuyR.js} +1 -1
- package/build/assets/llm-settings-Bql-vydt.js +1 -0
- package/build/assets/llm-settings-C_tal6Ds.js +1 -0
- package/build/assets/{loading-spinner-C04FGh14.js → loading-spinner-BPtYORNK.js} +1 -1
- package/build/assets/{manage-backends-modal-s22zCdEW.js → manage-backends-modal-l7RkKfwX.js} +1 -1
- package/build/assets/{manage-workspaces-modal-C5EuW8m1.js → manage-workspaces-modal-DhKF_8z3.js} +1 -1
- package/build/assets/manifest-9fee01b9.js +1 -0
- package/build/assets/{markdown-renderer-CEX4Becj.js → markdown-renderer-DMzf2i4x.js} +1 -1
- package/build/assets/mcp-D2onbwVk.js +9 -0
- package/build/assets/{messages-6aOyUu3r.js → messages-BMzyOW2V.js} +1 -1
- package/build/assets/{modal-backdrop-DTYGVmOR.js → modal-backdrop-BAbgYsqB.js} +1 -1
- package/build/assets/{modal-body-YElmM1dV.js → modal-body-BI6Ru2Qr.js} +1 -1
- package/build/assets/{modal-close-button-C_GpQt9F.js → modal-close-button-t1Gh3qmL.js} +1 -1
- package/build/assets/{model-selector-DeMmw-Xa.js → model-selector-SM9IUz-q.js} +1 -1
- package/build/assets/{mutation-Cz7N4XAo.js → mutation-D0OogFCz.js} +1 -1
- package/build/assets/{navigation-context-DeIPtGPp.js → navigation-context-D0YWpT8d.js} +1 -1
- package/build/assets/{navigation-link-C9JD4PYD.js → navigation-link-Cn7KP3c5.js} +1 -1
- package/build/assets/{openhands-logo-CI5Fhn1W.js → openhands-logo-CnrF6LKb.js} +1 -1
- package/build/assets/{option-service.api-DsI1UW7N.js → option-service.api-KvY_mZMY.js} +1 -1
- package/build/assets/{organization-service.api-COwMPFg5.js → organization-service.api-DzYTHTYC.js} +1 -1
- package/build/assets/{path-utils-BVbe598W.js → path-utils-YohAYyMv.js} +1 -1
- package/build/assets/{plan-components-DEjMuDDG.js → plan-components-atxXCF0R.js} +1 -1
- package/build/assets/{planner-tab-bN6r1G-1.js → planner-tab-CFc-hV07.js} +1 -1
- package/build/assets/{profiles-client-BGkKEV9j.js → profiles-client-D6IkTJof.js} +1 -1
- package/build/assets/{providers-DXvCAN_u.js → providers-Bx6EfrzZ.js} +1 -1
- package/build/assets/{proxy-CurRmrqf.js → proxy-CxydCnis.js} +1 -1
- package/build/assets/{query-client-config-Ba7qAAoO.js → query-client-config-B7u9asM0.js} +1 -1
- package/build/assets/{recommended-automations-launcher-mJhK6Atl.js → recommended-automations-launcher-sgvfU62c.js} +3 -3
- package/build/assets/root-BXWU99D-.js +2 -0
- package/build/assets/{root-layout-BjVwHmta.js → root-layout-DVepR4To.js} +2 -2
- package/build/assets/sdk-section-page-DOIKvwSL.js +1 -0
- package/build/assets/{sdk-settings-schema-QBYH-ONX.js → sdk-settings-schema-DsUf9wu1.js} +1 -1
- package/build/assets/{search-Cq_cFrDt.js → search-27Owlc3A.js} +1 -1
- package/build/assets/{secrets-service-Bwd5DeUs.js → secrets-service-BsnKFc2x.js} +1 -1
- package/build/assets/secrets-settings-Bz_UohPJ.js +1 -0
- package/build/assets/{server-client-C3mC8Hl3.js → server-client-DyAQ3NZ_.js} +1 -1
- package/build/assets/{settings-D7E2U5tK.js → settings-BYkVX7vW.js} +1 -1
- package/build/assets/{settings-client-CwjfwoiB.js → settings-client-C73C7IgV.js} +1 -1
- package/build/assets/{settings-dropdown-input-VwAXNrOb.js → settings-dropdown-input-BJYvGdg-.js} +1 -1
- package/build/assets/{settings-gear-BJwWR1ej.js → settings-gear-C77PgE_O.js} +1 -1
- package/build/assets/{settings-index-J-3BNR0W.js → settings-index-Dz0BmdJD.js} +1 -1
- package/build/assets/{settings-input-DBywAnA7.js → settings-input-Bn7F5C75.js} +1 -1
- package/build/assets/{settings-list-classes-BOS092DR.js → settings-list-classes-Bf80tWtc.js} +1 -1
- package/build/assets/{settings-modal-B8vgWDTe.js → settings-modal-Brzgh5Yw.js} +1 -1
- package/build/assets/{settings-section-header-context-32x6WTyL.js → settings-section-header-context-BgZe5YkE.js} +1 -1
- package/build/assets/{settings-service.api-FvJGK45W.js → settings-service.api-CZ3uWx4v.js} +1 -1
- package/build/assets/{settings-switch-DTKmHC8F.js → settings-switch-BeIKrWms.js} +1 -1
- package/build/assets/{shared-conversation-EZV0FRIf.js → shared-conversation-DChOdb0t.js} +1 -1
- package/build/assets/{sidebar-mobile-menu-toggle-BnbzzpQl.js → sidebar-mobile-menu-toggle-BWuf4PRH.js} +1 -1
- package/build/assets/{sidebar-nav-link-CnWoZcwc.js → sidebar-nav-link-BGjiJq-4.js} +1 -1
- package/build/assets/{skill-card-pill-row-tZ599jli.js → skill-card-pill-row-DF1axQCG.js} +1 -1
- package/build/assets/{skills-ZyAO5dyK.js → skills-ChIKZPK4.js} +1 -1
- package/build/assets/{skills-plugins-BSRz041I.js → skills-plugins-CcI_19lM.js} +1 -1
- package/build/assets/{skills-settings-CG2hu34D.js → skills-settings-DlA5hlXw.js} +1 -1
- package/build/assets/{status-CsatcFbK.js → status-hp6M6E7E.js} +1 -1
- package/build/assets/{styled-tooltip-CS3mB_1X.js → styled-tooltip-CBzrri6o.js} +1 -1
- package/build/assets/{switch-skeleton-C-CfhYYV.js → switch-skeleton-DnC9wLp7.js} +1 -1
- package/build/assets/{task-list-tab-465DDju0.js → task-list-tab-DUJn1sgz.js} +1 -1
- package/build/assets/{terminal-CcgBEVnC.js → terminal-CRf9S0Z2.js} +1 -1
- package/build/assets/{terminal-LNa-iU5c.js → terminal-RmuaSdhJ.js} +1 -1
- package/build/assets/{toggle-switch-k-IZCDbt.js → toggle-switch-Pvyp2RAN.js} +1 -1
- package/build/assets/{typography-vVUMoNUg.js → typography-gpuWmrQO.js} +1 -1
- package/build/assets/{u-check-circle-DplbarS5.js → u-check-circle-IUIfACQQ.js} +1 -1
- package/build/assets/{u-check-circle-half-yDuiSZHC.js → u-check-circle-half-C1YxB6py.js} +1 -1
- package/build/assets/{u-circuit-C9tYkpeK.js → u-circuit-BmVikJHu.js} +1 -1
- package/build/assets/{u-edit-KAUlufD8.js → u-edit-CFvXHqZk.js} +1 -1
- package/build/assets/use-active-conversation-Db3IWSPK.js +1 -0
- package/build/assets/{use-agent-settings-schema-Bvp5UzV8.js → use-agent-settings-schema-33Un7UF2.js} +1 -1
- package/build/assets/{use-agent-state-D2C9SeGw.js → use-agent-state-Bn8vS5sY.js} +1 -1
- package/build/assets/{use-cloud-current-user-id-DWVar4st.js → use-cloud-current-user-id-CvkXFnTT.js} +1 -1
- package/build/assets/use-config-Co1O8-Ey.js +1 -0
- package/build/assets/{use-create-conversation-BEZg__Vv.js → use-create-conversation-CKS3EAHu.js} +1 -1
- package/build/assets/use-get-secrets-DuhdIA59.js +1 -0
- package/build/assets/{use-handle-plan-click-uOpew2LO.js → use-handle-plan-click-C9zJpK8A.js} +1 -1
- package/build/assets/use-is-authed-BggE5wPj.js +1 -0
- package/build/assets/{use-is-creating-conversation-DhDeeWfA.js → use-is-creating-conversation-BZ5hB_Bg.js} +1 -1
- package/build/assets/{use-launch-skill-in-chat-DVGPFrbI.js → use-launch-skill-in-chat-fNN_xGZG.js} +1 -1
- package/build/assets/{use-llm-profiles-O4a9V6RC.js → use-llm-profiles-DDOol3gK.js} +1 -1
- package/build/assets/use-runtime-is-ready-CQCE3xZC.js +1 -0
- package/build/assets/{use-save-settings-CEEKSTWG.js → use-save-settings-VUrj_QNG.js} +1 -1
- package/build/assets/{use-settings-DQ7Oo1Hj.js → use-settings-DQIZmIov.js} +1 -1
- package/build/assets/{use-settings-nav-items-YmrXrjn9.js → use-settings-nav-items-1ZvovKSr.js} +1 -1
- package/build/assets/{use-skills-BIvlWblA.js → use-skills-DAMLFjKU.js} +1 -1
- package/build/assets/use-unified-vscode-url-sZt29HrC.js +1 -0
- package/build/assets/use-user-conversation-DfgEB6RW.js +1 -0
- package/build/assets/{useMutation-B4OUESdw.js → useMutation-DqrumCWD.js} +1 -1
- package/build/assets/{useTranslation-CpIcQBq6.js → useTranslation-DCOdSSMl.js} +1 -1
- package/build/assets/{utils-D-HX7JCe.js → utils-i18rdUj2.js} +1 -1
- package/build/assets/v4-CNn21NXa.js +1 -0
- package/build/assets/{vendor~browser-Dr71AdrG.js → vendor~browser-BNjNhjFU.js} +1 -1
- package/build/assets/{vendor~browser-tab-BiVxfjJo.js → vendor~browser-tab-BgwV1mxF.js} +1 -1
- package/build/assets/{vendor~conversation-panel~conversation-BlCIz9XQ.js → vendor~conversation-panel~conversation-a9SyrrhV.js} +1 -1
- package/build/assets/{vendor~files-tab-DtLR-QD9.js → vendor~files-tab-BGKayPiK.js} +1 -1
- package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-Ds9quNZ9.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-smY2r837.js} +1 -1
- package/build/assets/{vendor~home~mcp~automations-list-C5PoHCy6.js → vendor~home~mcp~automations-list-Ccy2I0KU.js} +1 -1
- package/build/assets/{vendor~home~mcp~automations-list-BUBGGGYz.js → vendor~home~mcp~automations-list-DoPfwaXj.js} +1 -1
- package/build/assets/{vendor~home~mcp~llm-settings~agent-settings~condenser-settings~verification-settings~app-se~ocm3mykx-CGlZoBKa.js → vendor~home~mcp~llm-settings~agent-settings~condenser-settings~verification-settings~app-se~ocm3mykx-DbfELDJu.js} +2 -2
- package/build/assets/{vendor~home~mcp~llm-settings~agent-settings~condenser-settings~verification-settings~app-se~ocm3mykx-DE11mPxp.js → vendor~home~mcp~llm-settings~agent-settings~condenser-settings~verification-settings~app-se~ocm3mykx-Z3nsiNNq.js} +1 -1
- package/build/assets/{vendor~launch-Dg--Ssk6.js → vendor~launch-vdeRTWFu.js} +1 -1
- package/build/assets/{vendor~root-layout~conversation-panel~conversation~shared-conversation-DrXgiSCq.js → vendor~root-layout~conversation-panel~conversation~shared-conversation-DW31UyBp.js} +1 -1
- package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-8b8V5bfO.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-BkQGKpye.js} +1 -1
- package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-Dy7L6fMG.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-DzIXV3Ui.js} +1 -1
- package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~k776hupu-D40EXhZx.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~k776hupu-Bbs7UJ5U.js} +2 -2
- package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~dp08i1qy-CHrEOFl6.js → vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~dp08i1qy-DTwbEEcX.js} +1 -1
- package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~shared-conversation~alert-banner~pl~rqjteh0a-BP1SKG0F.js → vendor~root-layout~home~conversation-panel~conversation~shared-conversation~alert-banner~pl~rqjteh0a-d2oallMa.js} +1 -1
- package/build/assets/{vendor~root~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-s~kyz9p27j-CyUbhpbm.js → vendor~root~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-s~f2l2lr17-CDXvdvb2.js} +1 -1
- package/build/assets/{verification-settings-BtlTiHP8.js → verification-settings-CsbvQcYS.js} +1 -1
- package/build/assets/{vscode-tab-B0vdh9gU.js → vscode-tab-Zb-QbTuV.js} +1 -1
- package/build/assets/{waiting-for-runtime-message-DWPl_Yby.js → waiting-for-runtime-message-CntjExbU.js} +1 -1
- package/build/assets/{x-mark-CWI0f9yI.js → x-mark-CrpjscNc.js} +1 -1
- package/build/index.html +4 -4
- package/build/locales/ar/openhands.json +7 -0
- package/build/locales/ca/openhands.json +7 -0
- package/build/locales/de/openhands.json +7 -0
- package/build/locales/en/openhands.json +7 -0
- package/build/locales/es/openhands.json +7 -0
- package/build/locales/fr/openhands.json +7 -0
- package/build/locales/it/openhands.json +7 -0
- package/build/locales/ja/openhands.json +7 -0
- package/build/locales/ko-KR/openhands.json +7 -0
- package/build/locales/no/openhands.json +7 -0
- package/build/locales/pt/openhands.json +7 -0
- package/build/locales/tr/openhands.json +7 -0
- package/build/locales/uk/openhands.json +7 -0
- package/build/locales/zh-CN/openhands.json +7 -0
- package/build/locales/zh-TW/openhands.json +7 -0
- package/config/defaults.json +0 -4
- package/dist/api/agent-server-adapter.cjs +1 -1
- package/dist/api/agent-server-adapter.cjs.map +1 -1
- package/dist/api/agent-server-adapter.js +1 -1
- package/dist/api/agent-server-adapter.js.map +1 -1
- package/dist/api/agent-server-compatibility.cjs +1 -1
- package/dist/api/agent-server-compatibility.cjs.map +1 -1
- package/dist/api/agent-server-compatibility.d.ts +16 -0
- package/dist/api/agent-server-compatibility.js +31 -20
- package/dist/api/agent-server-compatibility.js.map +1 -1
- package/dist/api/agent-server-config.cjs +1 -1
- package/dist/api/agent-server-config.cjs.map +1 -1
- package/dist/api/agent-server-config.d.ts +45 -0
- package/dist/api/agent-server-config.js +49 -21
- package/dist/api/agent-server-config.js.map +1 -1
- package/dist/api/backend-registry/storage.cjs +1 -1
- package/dist/api/backend-registry/storage.cjs.map +1 -1
- package/dist/api/backend-registry/storage.js +34 -32
- package/dist/api/backend-registry/storage.js.map +1 -1
- package/dist/api/conversation-service/agent-server-conversation-service.api.cjs +1 -1
- package/dist/api/conversation-service/agent-server-conversation-service.api.cjs.map +1 -1
- package/dist/api/conversation-service/agent-server-conversation-service.api.d.ts +5 -4
- package/dist/api/conversation-service/agent-server-conversation-service.api.js +70 -76
- package/dist/api/conversation-service/agent-server-conversation-service.api.js.map +1 -1
- package/dist/components/features/backends/api-key-entry-screen.d.ts +10 -0
- package/dist/components/features/backends/backend-form-modal.cjs +1 -1
- package/dist/components/features/backends/backend-form-modal.cjs.map +1 -1
- package/dist/components/features/backends/backend-form-modal.d.ts +23 -2
- package/dist/components/features/backends/backend-form-modal.js +43 -38
- package/dist/components/features/backends/backend-form-modal.js.map +1 -1
- package/dist/components/features/browser/browser.cjs +1 -1
- package/dist/components/features/browser/browser.cjs.map +1 -1
- package/dist/components/features/browser/browser.js +10 -16
- package/dist/components/features/browser/browser.js.map +1 -1
- package/dist/components/features/mcp-page/install-server-modal.cjs +1 -1
- package/dist/components/features/mcp-page/install-server-modal.cjs.map +1 -1
- package/dist/components/features/mcp-page/install-server-modal.js +123 -116
- package/dist/components/features/mcp-page/install-server-modal.js.map +1 -1
- package/dist/components/features/mcp-page/installed-server-card.cjs +1 -1
- package/dist/components/features/mcp-page/installed-server-card.cjs.map +1 -1
- package/dist/components/features/mcp-page/installed-server-card.js +40 -40
- package/dist/components/features/mcp-page/installed-server-card.js.map +1 -1
- package/dist/components/features/mcp-page/marketplace-card.cjs +1 -1
- package/dist/components/features/mcp-page/marketplace-card.cjs.map +1 -1
- package/dist/components/features/mcp-page/marketplace-card.js +2 -3
- package/dist/components/features/mcp-page/marketplace-card.js.map +1 -1
- package/dist/components/features/mcp-page/marketplace-section.cjs +1 -1
- package/dist/components/features/mcp-page/marketplace-section.cjs.map +1 -1
- package/dist/components/features/mcp-page/marketplace-section.js +21 -21
- package/dist/components/features/mcp-page/marketplace-section.js.map +1 -1
- package/dist/components/features/onboarding/steps/setup-acp-secrets-step.d.ts +27 -0
- package/dist/components/features/settings/llm-profiles/llm-settings-local-view.cjs +1 -1
- package/dist/components/features/settings/llm-profiles/llm-settings-local-view.js +2 -0
- package/dist/components/features/settings/sdk-settings/sdk-section-page.cjs +1 -1
- package/dist/components/features/settings/sdk-settings/sdk-section-page.cjs.map +1 -1
- package/dist/components/features/settings/sdk-settings/sdk-section-page.d.ts +10 -1
- package/dist/components/features/settings/sdk-settings/sdk-section-page.js +87 -84
- package/dist/components/features/settings/sdk-settings/sdk-section-page.js.map +1 -1
- package/dist/constants/acp-providers.cjs +1 -1
- package/dist/constants/acp-providers.cjs.map +1 -1
- package/dist/constants/acp-providers.d.ts +25 -0
- package/dist/constants/acp-providers.js +1 -0
- package/dist/constants/acp-providers.js.map +1 -1
- package/dist/contexts/conversation-websocket-context.cjs +3 -3
- package/dist/contexts/conversation-websocket-context.cjs.map +1 -1
- package/dist/contexts/conversation-websocket-context.js +136 -132
- package/dist/contexts/conversation-websocket-context.js.map +1 -1
- package/dist/hooks/chat/use-model-interceptor.cjs.map +1 -1
- package/dist/hooks/chat/use-model-interceptor.js.map +1 -1
- package/dist/hooks/mutation/use-switch-llm-profile.cjs.map +1 -1
- package/dist/hooks/mutation/use-switch-llm-profile.d.ts +1 -1
- package/dist/hooks/mutation/use-switch-llm-profile.js.map +1 -1
- package/dist/hooks/query/use-config.cjs +1 -1
- package/dist/hooks/query/use-config.cjs.map +1 -1
- package/dist/hooks/query/use-config.js +10 -10
- package/dist/hooks/query/use-config.js.map +1 -1
- package/dist/hooks/query/use-local-git-info.cjs +3 -3
- package/dist/hooks/query/use-local-git-info.cjs.map +1 -1
- package/dist/hooks/query/use-local-git-info.js +24 -25
- package/dist/hooks/query/use-local-git-info.js.map +1 -1
- package/dist/i18n/declaration.cjs +1 -1
- package/dist/i18n/declaration.cjs.map +1 -1
- package/dist/i18n/declaration.d.ts +7 -0
- package/dist/i18n/declaration.js +1 -1
- package/dist/i18n/declaration.js.map +1 -1
- package/dist/i18n/translation.cjs +2 -2
- package/dist/i18n/translation.cjs.map +1 -1
- package/dist/i18n/translation.js +119 -0
- package/dist/i18n/translation.js.map +1 -1
- package/dist/locales/ar/openhands.json +7 -0
- package/dist/locales/ca/openhands.json +7 -0
- package/dist/locales/de/openhands.json +7 -0
- package/dist/locales/en/openhands.json +7 -0
- package/dist/locales/es/openhands.json +7 -0
- package/dist/locales/fr/openhands.json +7 -0
- package/dist/locales/it/openhands.json +7 -0
- package/dist/locales/ja/openhands.json +7 -0
- package/dist/locales/ko-KR/openhands.json +7 -0
- package/dist/locales/no/openhands.json +7 -0
- package/dist/locales/pt/openhands.json +7 -0
- package/dist/locales/tr/openhands.json +7 -0
- package/dist/locales/uk/openhands.json +7 -0
- package/dist/locales/zh-CN/openhands.json +7 -0
- package/dist/locales/zh-TW/openhands.json +7 -0
- package/dist/package.cjs +1 -1
- package/dist/package.cjs.map +1 -1
- package/dist/package.js +1 -1
- package/dist/package.js.map +1 -1
- package/dist/routes/mcp.cjs +1 -1
- package/dist/routes/mcp.cjs.map +1 -1
- package/dist/routes/mcp.js +64 -64
- package/dist/routes/mcp.js.map +1 -1
- package/dist/stores/browser-store.cjs +1 -1
- package/dist/stores/browser-store.cjs.map +1 -1
- package/dist/stores/browser-store.js +1 -1
- package/dist/stores/browser-store.js.map +1 -1
- package/dist/utils/mcp-marketplace-utils.cjs +1 -1
- package/dist/utils/mcp-marketplace-utils.cjs.map +1 -1
- package/dist/utils/mcp-marketplace-utils.d.ts +13 -22
- package/dist/utils/mcp-marketplace-utils.js +46 -28
- package/dist/utils/mcp-marketplace-utils.js.map +1 -1
- package/dist/utils/sdk-settings-schema.cjs +1 -1
- package/dist/utils/sdk-settings-schema.cjs.map +1 -1
- package/dist/utils/sdk-settings-schema.d.ts +1 -0
- package/dist/utils/sdk-settings-schema.js +1 -1
- package/dist/utils/sdk-settings-schema.js.map +1 -1
- package/package.json +1 -1
- package/scripts/dev-safe.mjs +59 -40
- package/scripts/dev-static.mjs +2 -3
- package/scripts/dev-with-automation.mjs +75 -19
- package/scripts/static-server.mjs +77 -35
- package/tools/canvas_ui_tool.py +4 -0
- package/build/assets/acp-providers-DauuOsW9.js +0 -1
- package/build/assets/add-backend-modal-FsnpTTgO.js +0 -1
- package/build/assets/agent-server-client-options-DT2GP6VJ.js +0 -1
- package/build/assets/agent-server-compatibility-2aOx5iWd.js +0 -1
- package/build/assets/agent-server-conversation-service.api-BZmUqtiO.js +0 -5
- package/build/assets/browser-store-C3AqxAO7.js +0 -1
- package/build/assets/browser-tab-B_BuTvrO.js +0 -1
- package/build/assets/conversation--ldUK72N.js +0 -19
- package/build/assets/conversation-eNrhH94O.js +0 -1
- package/build/assets/conversation-panel-B49Jpqpb.js +0 -1
- package/build/assets/conversation-websocket-context-BW68-J8o.js +0 -3
- package/build/assets/declaration-D378OjpZ.js +0 -1
- package/build/assets/files-tab-CQHdWpQt.js +0 -1
- package/build/assets/home-DD0GroCu.js +0 -1
- package/build/assets/install-server-modal-z5VaHeXd.js +0 -1
- package/build/assets/llm-settings-BEyqixPI.js +0 -1
- package/build/assets/llm-settings-BdiaGFbg.js +0 -1
- package/build/assets/manifest-9d1c34fb.js +0 -1
- package/build/assets/mcp-C06YssEI.js +0 -9
- package/build/assets/root-3t9rxEpE.js +0 -2
- package/build/assets/sdk-section-page-CJW0G04-.js +0 -1
- package/build/assets/secrets-settings-MLXqOtX2.js +0 -1
- package/build/assets/use-active-conversation-DS5j9R4q.js +0 -1
- package/build/assets/use-config-BSu_53GL.js +0 -1
- package/build/assets/use-conversation-id-DajhCn2A.js +0 -1
- package/build/assets/use-is-authed-hXC8vxgT.js +0 -1
- package/build/assets/use-runtime-is-ready-pGSbPddC.js +0 -1
- package/build/assets/use-unified-vscode-url-wAMzv8Sn.js +0 -1
- package/build/assets/use-user-conversation-B_zDoSeh.js +0 -1
- /package/build/assets/{automation-XLxhq3I8.js → automation-IdgZq6ZK.js} +0 -0
- /package/build/assets/{common-SMkEaBSr.js → common-DR1t-EeP.js} +0 -0
- /package/build/assets/{conversation-state-store-Bc0slAjL.js → conversation-state-store-u5jepov0.js} +0 -0
- /package/build/assets/{dist-yMQV8IUk.js → dist-BxBP7tFD.js} +0 -0
- /package/build/assets/{git-status-mapper-BI8FyUVp.js → git-status-mapper-DnL9OC8_.js} +0 -0
- /package/build/assets/{handle-capture-consent-BfZATzpI.js → handle-capture-consent-3XrjZ8wi.js} +0 -0
- /package/build/assets/{iconBase-C7N9pPOs.js → iconBase-DE30Zj_-.js} +0 -0
- /package/build/assets/{settings-D5am1n6X.js → settings-D_H-qsRm.js} +0 -0
- /package/build/assets/{settings-like-page-layout-classes-Bn-M9oOa.js → settings-like-page-layout-classes-I0BDBEoq.js} +0 -0
- /package/build/assets/{settings-utils-BsvSU3OM.js → settings-utils-B6Nl07io.js} +0 -0
- /package/build/assets/{sidebar-store-cOeaKmIm.js → sidebar-store-Uy3v0AOV.js} +0 -0
- /package/build/assets/{use-breakpoint-B86yKT9n.js → use-breakpoint-DbJ6FkQ-.js} +0 -0
- /package/build/assets/{use-click-outside-element-835W9pC6.js → use-click-outside-element-DffgWWoZ.js} +0 -0
- /package/build/assets/{use-task-list-DDeNHprj.js → use-task-list-CLJbuJgM.js} +0 -0
- /package/build/assets/{vendor~browser-BpdPBhgZ.js → vendor~browser-DDiZgqD3.js} +0 -0
- /package/build/assets/{vendor~conversation-panel~conversation~alert-banner-Df7_G0zR.js → vendor~conversation-panel~conversation~alert-banner-DbvX3OcM.js} +0 -0
- /package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~b4cctr4k-B7YVdv1X.js → vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~g56ukk6u-DsSvIDZQ.js} +0 -0
- /package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~i9dbt75i-CI82Did1.js → vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~hkqzh1hb-BZ0HXuHD.js} +0 -0
- /package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~pfbaerbd-zhv9fooy.js → vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~ninslayh-D9P8e98a.js} +0 -0
- /package/build/assets/{vendor~terminal-BUxzHKcC.js → vendor~terminal-DUrOWGFE.js} +0 -0
- /package/build/assets/{vscode-url-helper-jesbpos5.js → vscode-url-helper-Cwy1A62q.js} +0 -0
package/dist/routes/mcp.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp.cjs","names":[],"sources":["../../src/routes/mcp.tsx"],"sourcesContent":["import React from \"react\";\nimport { AxiosError } from \"axios\";\nimport { ExtensionsNavigation } from \"#/components/features/skills/extensions-navigation\";\nimport { useTranslation } from \"react-i18next\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { BrandButton } from \"#/components/features/settings/brand-button\";\nimport { ConfirmationModal } from \"#/components/shared/modals/confirmation-modal\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { useDeleteMcpServer } from \"#/hooks/mutation/use-delete-mcp-server\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport { parseMcpConfig } from \"#/utils/mcp-config\";\nimport { redirectIfAcpActive } from \"#/utils/acp-route-guard\";\nimport {\n displayErrorToast,\n displaySuccessToast,\n} from \"#/utils/custom-toast-handlers\";\nimport { retrieveAxiosErrorMessage } from \"#/utils/retrieve-axios-error-message\";\nimport { settingsLikeMainScrollClassName } from \"#/utils/settings-like-page-layout-classes\";\nimport {\n findCatalogEntryForServer,\n installedServerMatchesQuery,\n} from \"#/utils/mcp-marketplace-utils\";\nimport {\n INTEGRATION_CATALOG as INTEGRATION_MARKETPLACE,\n type IntegrationCatalogEntry as MarketplaceEntry,\n} from \"@openhands/extensions/integrations\";\nimport { MCPServerConfig } from \"#/types/mcp-server\";\nimport { flattenMcpConfig } from \"#/utils/mcp-installed-servers\";\nimport {\n InstalledServersSection,\n McpToolbar,\n MarketplaceSection,\n InstallServerModal,\n CustomServerEditor,\n type McpSectionFilter,\n} from \"#/components/features/mcp-page\";\n\n// ACP guard: the ACP sub-agent owns its own MCP server configuration —\n// the SDK explicitly rejects `mcp_config` on ACPAgent init, and\n// `agent-server-adapter` already strips it from start payloads. The\n// Settings → Agent page is where the user configures the ACP server, so\n// bouncing there is consistent with how `/settings` and\n// `/settings/condenser` already behave under ACP.\n//\n// Declared with no parameters (rather than typed as Route.ClientLoaderArgs)\n// so the lib build doesn't pull generated React Router types out of rootDir.\nexport const clientLoader = async () => redirectIfAcpActive();\n\nexport default function MCPPage() {\n const { t } = useTranslation(\"openhands\");\n const { data: settings, isLoading } = useSettings();\n const { mutate: deleteMcpServer, isPending: isDeleting } =\n useDeleteMcpServer();\n const activeBackend = useActiveBackend();\n const backendKind = activeBackend.backend.kind;\n\n const [installEntry, setInstallEntry] =\n React.useState<MarketplaceEntry | null>(null);\n const [editingServer, setEditingServer] =\n React.useState<MCPServerConfig | null>(null);\n const [serverToDelete, setServerToDelete] =\n React.useState<MCPServerConfig | null>(null);\n const [searchQuery, setSearchQuery] = React.useState(\"\");\n const [sectionFilter, setSectionFilter] =\n React.useState<McpSectionFilter>(\"all\");\n\n const mcpConfig = parseMcpConfig(settings?.agent_settings?.mcp_config);\n const allServers = flattenMcpConfig(mcpConfig);\n\n // Filter installed servers by the search query. We pair each server\n // with its catalog entry (if any) so the search can match friendly\n // names like \"Slack\" against a stdio server whose own `.name` is\n // just \"slack\".\n const filteredInstalledServers = allServers.filter((server) =>\n installedServerMatchesQuery(\n server,\n findCatalogEntryForServer(server, INTEGRATION_MARKETPLACE),\n searchQuery,\n ),\n );\n\n const handleMarketplaceInstall = (entry: MarketplaceEntry) => {\n setInstallEntry(entry);\n };\n\n const handleEdit = (server: MCPServerConfig) => {\n setEditingServer(server);\n };\n\n const handleDeleteClick = (serverId: string) => {\n const target = allServers.find((s) => s.id === serverId);\n if (target) setServerToDelete(target);\n };\n\n const handleConfirmDelete = () => {\n if (!serverToDelete) return;\n // Pass the full server config — useDeleteMcpServer re-resolves its\n // position against the fresh settings at mutation time, so a\n // background refresh between this click and confirm cannot point\n // us at the wrong index.\n deleteMcpServer(serverToDelete, {\n onSuccess: () => {\n displaySuccessToast(t(I18nKey.MCP$REMOVE_SUCCESS));\n setServerToDelete(null);\n },\n onError: (err) => {\n const message = retrieveAxiosErrorMessage(err as AxiosError);\n displayErrorToast(message || t(I18nKey.ERROR$GENERIC));\n setServerToDelete(null);\n },\n });\n };\n\n if (isLoading || !settings) {\n return (\n <div\n data-testid=\"mcp-page\"\n className=\"flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10\"\n >\n <ExtensionsNavigation />\n <div className=\"flex h-full flex-1 items-center justify-center px-4 md:px-0\">\n <div className=\"h-8 w-8 rounded-full border-2 border-[var(--oh-border)] border-t-white animate-spin\" />\n </div>\n </div>\n );\n }\n\n return (\n <div\n data-testid=\"mcp-page\"\n className=\"flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10\"\n >\n <ExtensionsNavigation />\n <main className={settingsLikeMainScrollClassName}>\n <div className=\"mx-auto flex w-full min-w-0 max-w-[800px] flex-col gap-6\">\n <div className=\"min-w-0\">\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"space-y-1\">\n <h2 className=\"text-xl font-medium leading-6 text-foreground\">\n {t(I18nKey.SETTINGS$MCP_TITLE)}\n </h2>\n <div className=\"max-w-2xl text-sm text-tertiary-light\">\n {t(I18nKey.MCP$PAGE_DESCRIPTION)}\n </div>\n </div>\n <BrandButton\n type=\"button\"\n variant=\"secondary\"\n testId=\"mcp-add-custom-server\"\n className=\"flex-shrink-0 whitespace-nowrap\"\n onClick={() => setEditingServer({ id: \"\", type: \"sse\" })}\n >\n {t(I18nKey.MCP$ADD_CUSTOM)}\n </BrandButton>\n </div>\n </div>\n\n <McpToolbar\n search={searchQuery}\n onSearchChange={setSearchQuery}\n sectionFilter={sectionFilter}\n onSectionFilterChange={setSectionFilter}\n />\n\n {sectionFilter !== \"library\" ? (\n <section className=\"flex flex-col gap-3\">\n <h2 className=\"text-base font-semibold text-foreground\">\n {t(I18nKey.MCP$INSTALLED_TITLE)}\n </h2>\n <InstalledServersSection\n servers={filteredInstalledServers}\n hasAnyInstalled={allServers.length > 0}\n query={searchQuery}\n onEdit={handleEdit}\n onDelete={handleDeleteClick}\n />\n </section>\n ) : null}\n\n {sectionFilter !== \"installed\" ? (\n <MarketplaceSection\n backendKind={backendKind}\n onSelect={handleMarketplaceInstall}\n onAdd={handleMarketplaceInstall}\n query={searchQuery}\n />\n ) : null}\n </div>\n\n {installEntry && (\n <InstallServerModal\n entry={installEntry}\n onClose={() => setInstallEntry(null)}\n />\n )}\n\n {/* Custom (or non-marketplace) server editor. The empty-id\n sentinel (`{ id: \"\", type: \"sse\" }`) means \"add new\". */}\n {editingServer && (\n <CustomServerEditor\n server={editingServer}\n existingServers={allServers}\n onClose={() => setEditingServer(null)}\n />\n )}\n\n {serverToDelete && (\n <ConfirmationModal\n text={t(I18nKey.SETTINGS$MCP_CONFIRM_DELETE)}\n onCancel={() => setServerToDelete(null)}\n onConfirm={handleConfirmDelete}\n isConfirming={isDeleting}\n />\n )}\n </main>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mcp.cjs","names":[],"sources":["../../src/routes/mcp.tsx"],"sourcesContent":["import React from \"react\";\nimport { AxiosError } from \"axios\";\nimport { ExtensionsNavigation } from \"#/components/features/skills/extensions-navigation\";\nimport { useTranslation } from \"react-i18next\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { BrandButton } from \"#/components/features/settings/brand-button\";\nimport { ConfirmationModal } from \"#/components/shared/modals/confirmation-modal\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { useDeleteMcpServer } from \"#/hooks/mutation/use-delete-mcp-server\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport { parseMcpConfig } from \"#/utils/mcp-config\";\nimport { redirectIfAcpActive } from \"#/utils/acp-route-guard\";\nimport {\n displayErrorToast,\n displaySuccessToast,\n} from \"#/utils/custom-toast-handlers\";\nimport { retrieveAxiosErrorMessage } from \"#/utils/retrieve-axios-error-message\";\nimport { settingsLikeMainScrollClassName } from \"#/utils/settings-like-page-layout-classes\";\nimport {\n findCatalogEntryForServer,\n getMcpMarketplaceCatalog,\n installedServerMatchesQuery,\n} from \"#/utils/mcp-marketplace-utils\";\nimport {\n INTEGRATION_CATALOG as MCP_MARKETPLACE,\n type IntegrationCatalogEntry as MarketplaceEntry,\n} from \"@openhands/extensions/integrations\";\nimport { MCPServerConfig } from \"#/types/mcp-server\";\nimport { flattenMcpConfig } from \"#/utils/mcp-installed-servers\";\nimport {\n InstalledServersSection,\n McpToolbar,\n MarketplaceSection,\n InstallServerModal,\n CustomServerEditor,\n type McpSectionFilter,\n} from \"#/components/features/mcp-page\";\n\n// ACP guard: the ACP sub-agent owns its own MCP server configuration —\n// the SDK explicitly rejects `mcp_config` on ACPAgent init, and\n// `agent-server-adapter` already strips it from start payloads. The\n// Settings → Agent page is where the user configures the ACP server, so\n// bouncing there is consistent with how `/settings` and\n// `/settings/condenser` already behave under ACP.\n//\n// Declared with no parameters (rather than typed as Route.ClientLoaderArgs)\n// so the lib build doesn't pull generated React Router types out of rootDir.\nexport const clientLoader = async () => redirectIfAcpActive();\n\nexport default function MCPPage() {\n const { t } = useTranslation(\"openhands\");\n const { data: settings, isLoading } = useSettings();\n const { mutate: deleteMcpServer, isPending: isDeleting } =\n useDeleteMcpServer();\n const activeBackend = useActiveBackend();\n const backendKind = activeBackend.backend.kind;\n\n const [installEntry, setInstallEntry] =\n React.useState<MarketplaceEntry | null>(null);\n const [editingServer, setEditingServer] =\n React.useState<MCPServerConfig | null>(null);\n const [serverToDelete, setServerToDelete] =\n React.useState<MCPServerConfig | null>(null);\n const [searchQuery, setSearchQuery] = React.useState(\"\");\n const [sectionFilter, setSectionFilter] =\n React.useState<McpSectionFilter>(\"all\");\n\n const mcpConfig = parseMcpConfig(settings?.agent_settings?.mcp_config);\n const allServers = flattenMcpConfig(mcpConfig);\n const mcpMarketplace = getMcpMarketplaceCatalog(MCP_MARKETPLACE);\n\n // Filter installed servers by the search query. We pair each server\n // with its catalog entry (if any) so the search can match friendly\n // names like \"Slack\" against a stdio server whose own `.name` is\n // just \"slack\".\n const filteredInstalledServers = allServers.filter((server) =>\n installedServerMatchesQuery(\n server,\n findCatalogEntryForServer(server, mcpMarketplace),\n searchQuery,\n ),\n );\n\n const handleMarketplaceInstall = (entry: MarketplaceEntry) => {\n setInstallEntry(entry);\n };\n\n const handleEdit = (server: MCPServerConfig) => {\n setEditingServer(server);\n };\n\n const handleDeleteClick = (serverId: string) => {\n const target = allServers.find((s) => s.id === serverId);\n if (target) setServerToDelete(target);\n };\n\n const handleConfirmDelete = () => {\n if (!serverToDelete) return;\n // Pass the full server config — useDeleteMcpServer re-resolves its\n // position against the fresh settings at mutation time, so a\n // background refresh between this click and confirm cannot point\n // us at the wrong index.\n deleteMcpServer(serverToDelete, {\n onSuccess: () => {\n displaySuccessToast(t(I18nKey.MCP$REMOVE_SUCCESS));\n setServerToDelete(null);\n },\n onError: (err) => {\n const message = retrieveAxiosErrorMessage(err as AxiosError);\n displayErrorToast(message || t(I18nKey.ERROR$GENERIC));\n setServerToDelete(null);\n },\n });\n };\n\n if (isLoading || !settings) {\n return (\n <div\n data-testid=\"mcp-page\"\n className=\"flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10\"\n >\n <ExtensionsNavigation />\n <div className=\"flex h-full flex-1 items-center justify-center px-4 md:px-0\">\n <div className=\"h-8 w-8 rounded-full border-2 border-[var(--oh-border)] border-t-white animate-spin\" />\n </div>\n </div>\n );\n }\n\n return (\n <div\n data-testid=\"mcp-page\"\n className=\"flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10\"\n >\n <ExtensionsNavigation />\n <main className={settingsLikeMainScrollClassName}>\n <div className=\"mx-auto flex w-full min-w-0 max-w-[800px] flex-col gap-6\">\n <div className=\"min-w-0\">\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"space-y-1\">\n <h2 className=\"text-xl font-medium leading-6 text-foreground\">\n {t(I18nKey.SETTINGS$MCP_TITLE)}\n </h2>\n <div className=\"max-w-2xl text-sm text-tertiary-light\">\n {t(I18nKey.MCP$PAGE_DESCRIPTION)}\n </div>\n </div>\n <BrandButton\n type=\"button\"\n variant=\"secondary\"\n testId=\"mcp-add-custom-server\"\n className=\"flex-shrink-0 whitespace-nowrap\"\n onClick={() => setEditingServer({ id: \"\", type: \"sse\" })}\n >\n {t(I18nKey.MCP$ADD_CUSTOM)}\n </BrandButton>\n </div>\n </div>\n\n <McpToolbar\n search={searchQuery}\n onSearchChange={setSearchQuery}\n sectionFilter={sectionFilter}\n onSectionFilterChange={setSectionFilter}\n />\n\n {sectionFilter !== \"library\" ? (\n <section className=\"flex flex-col gap-3\">\n <h2 className=\"text-base font-semibold text-foreground\">\n {t(I18nKey.MCP$INSTALLED_TITLE)}\n </h2>\n <InstalledServersSection\n servers={filteredInstalledServers}\n hasAnyInstalled={allServers.length > 0}\n query={searchQuery}\n onEdit={handleEdit}\n onDelete={handleDeleteClick}\n />\n </section>\n ) : null}\n\n {sectionFilter !== \"installed\" ? (\n <MarketplaceSection\n backendKind={backendKind}\n onSelect={handleMarketplaceInstall}\n onAdd={handleMarketplaceInstall}\n query={searchQuery}\n />\n ) : null}\n </div>\n\n {installEntry && (\n <InstallServerModal\n entry={installEntry}\n onClose={() => setInstallEntry(null)}\n />\n )}\n\n {/* Custom (or non-marketplace) server editor. The empty-id\n sentinel (`{ id: \"\", type: \"sse\" }`) means \"add new\". */}\n {editingServer && (\n <CustomServerEditor\n server={editingServer}\n existingServers={allServers}\n onClose={() => setEditingServer(null)}\n />\n )}\n\n {serverToDelete && (\n <ConfirmationModal\n text={t(I18nKey.SETTINGS$MCP_CONFIRM_DELETE)}\n onCancel={() => setServerToDelete(null)}\n onConfirm={handleConfirmDelete}\n isConfirming={isDeleting}\n />\n )}\n </main>\n </div>\n );\n}\n"],"mappings":"s3CAiDA,SAAwB,GAAU,CAChC,GAAM,CAAE,KAAM,EAAA,eAAe,YAAY,CACnC,CAAE,KAAM,EAAU,aAAc,EAAA,aAAa,CAC7C,CAAE,OAAQ,EAAiB,UAAW,GAC1C,EAAA,oBAAoB,CAEhB,EADgB,EAAA,kBACF,CAAc,QAAQ,KAEpC,CAAC,EAAc,GACnB,EAAA,QAAM,SAAkC,KAAK,CACzC,CAAC,EAAe,GACpB,EAAA,QAAM,SAAiC,KAAK,CACxC,CAAC,EAAgB,GACrB,EAAA,QAAM,SAAiC,KAAK,CACxC,CAAC,EAAa,GAAkB,EAAA,QAAM,SAAS,GAAG,CAClD,CAAC,EAAe,GACpB,EAAA,QAAM,SAA2B,MAAM,CAGnC,EAAa,EAAA,iBADD,EAAA,eAAe,GAAU,gBAAgB,WACvB,CAAU,CACxC,EAAiB,EAAA,yBAAyB,EAAA,QAAgB,CAM1D,EAA2B,EAAW,OAAQ,GAClD,EAAA,4BACE,EACA,EAAA,0BAA0B,EAAQ,EAAe,CACjD,EACD,CACF,CAEK,EAA4B,GAA4B,CAC5D,EAAgB,EAAM,EA6CxB,OAdI,GAAa,CAAC,GAEd,EAAA,EAAA,MAAC,MAAD,CACE,cAAY,WACZ,UAAU,iEAFZ,EAIE,EAAA,EAAA,KAAC,EAAA,qBAAD,EAAwB,CAAA,EACxB,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,wEACb,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,sFAAwF,CAAA,CACnG,CAAA,CACF,IAKR,EAAA,EAAA,MAAC,MAAD,CACE,cAAY,WACZ,UAAU,iEAFZ,EAIE,EAAA,EAAA,KAAC,EAAA,qBAAD,EAAwB,CAAA,EACxB,EAAA,EAAA,MAAC,OAAD,CAAM,UAAW,EAAA,yCAAjB,EACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,oEAAf,EACE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,oBACb,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,kDAAf,EACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,qBAAf,EACE,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,yDACX,EAAE,EAAA,QAAQ,mBAAmB,CAC3B,CAAA,EACL,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,iDACZ,EAAE,EAAA,QAAQ,qBAAqB,CAC5B,CAAA,CACF,IACN,EAAA,EAAA,KAAC,EAAA,YAAD,CACE,KAAK,SACL,QAAQ,YACR,OAAO,wBACP,UAAU,kCACV,YAAe,EAAiB,CAAE,GAAI,GAAI,KAAM,MAAO,CAAC,UAEvD,EAAE,EAAA,QAAQ,eAAe,CACd,CAAA,CACV,GACF,CAAA,EAEN,EAAA,EAAA,KAAC,EAAA,WAAD,CACE,OAAQ,EACR,eAAgB,EACD,gBACf,sBAAuB,EACvB,CAAA,CAED,IAAkB,UAaf,MAZF,EAAA,EAAA,MAAC,UAAD,CAAS,UAAU,+BAAnB,EACE,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,mDACX,EAAE,EAAA,QAAQ,oBAAoB,CAC5B,CAAA,EACL,EAAA,EAAA,KAAC,EAAA,wBAAD,CACE,QAAS,EACT,gBAAiB,EAAW,OAAS,EACrC,MAAO,EACP,OAxFM,GAA4B,CAC9C,EAAiB,EAAO,EAwFZ,SArFa,GAAqB,CAC9C,IAAM,EAAS,EAAW,KAAM,GAAM,EAAE,KAAO,EAAS,CACpD,GAAQ,EAAkB,EAAO,EAoFzB,CAAA,CACM,GAGX,IAAkB,YAOf,MANF,EAAA,EAAA,KAAC,EAAA,mBAAD,CACe,cACb,SAAU,EACV,MAAO,EACP,MAAO,EACP,CAAA,CAEA,GAEL,IACC,EAAA,EAAA,KAAC,EAAA,mBAAD,CACE,MAAO,EACP,YAAe,EAAgB,KAAK,CACpC,CAAA,CAKH,IACC,EAAA,EAAA,KAAC,EAAA,mBAAD,CACE,OAAQ,EACR,gBAAiB,EACjB,YAAe,EAAiB,KAAK,CACrC,CAAA,CAGH,IACC,EAAA,EAAA,KAAC,EAAA,kBAAD,CACE,KAAM,EAAE,EAAA,QAAQ,4BAA4B,CAC5C,aAAgB,EAAkB,KAAK,CACvC,cApHwB,CAC3B,GAKL,EAAgB,EAAgB,CAC9B,cAAiB,CACf,EAAA,oBAAoB,EAAE,EAAA,QAAQ,mBAAmB,CAAC,CAClD,EAAkB,KAAK,EAEzB,QAAU,GAAQ,CAEhB,EAAA,kBADgB,EAAA,0BAA0B,EACxB,EAAW,EAAE,EAAA,QAAQ,cAAc,CAAC,CACtD,EAAkB,KAAK,EAE1B,CAAC,EAqGM,aAAc,EACd,CAAA,CAEC,GACH"}
|
package/dist/routes/mcp.js
CHANGED
|
@@ -11,125 +11,125 @@ import { ExtensionsNavigation as u } from "../components/features/skills/extensi
|
|
|
11
11
|
import { ConfirmationModal as d } from "../components/shared/modals/confirmation-modal.js";
|
|
12
12
|
import { useDeleteMcpServer as f } from "../hooks/mutation/use-delete-mcp-server.js";
|
|
13
13
|
import "../utils/acp-route-guard.js";
|
|
14
|
-
import { findCatalogEntryForServer as p,
|
|
15
|
-
import
|
|
16
|
-
import { flattenMcpConfig as
|
|
17
|
-
import { InstalledServersSection as
|
|
18
|
-
import { MarketplaceSection as
|
|
19
|
-
import { InstallServerModal as
|
|
20
|
-
import { CustomServerEditor as
|
|
21
|
-
import { McpToolbar as
|
|
14
|
+
import { findCatalogEntryForServer as p, getMcpMarketplaceCatalog as m, installedServerMatchesQuery as h } from "../utils/mcp-marketplace-utils.js";
|
|
15
|
+
import g from "../node_modules/@openhands/extensions/integrations/index.js";
|
|
16
|
+
import { flattenMcpConfig as _ } from "../utils/mcp-installed-servers.js";
|
|
17
|
+
import { InstalledServersSection as v } from "../components/features/mcp-page/installed-servers-section.js";
|
|
18
|
+
import { MarketplaceSection as y } from "../components/features/mcp-page/marketplace-section.js";
|
|
19
|
+
import { InstallServerModal as b } from "../components/features/mcp-page/install-server-modal.js";
|
|
20
|
+
import { CustomServerEditor as x } from "../components/features/mcp-page/custom-server-editor.js";
|
|
21
|
+
import { McpToolbar as S } from "../components/features/mcp-page/mcp-toolbar.js";
|
|
22
22
|
import "../components/features/mcp-page/index.js";
|
|
23
|
-
import
|
|
24
|
-
import { jsx as
|
|
23
|
+
import C from "react";
|
|
24
|
+
import { jsx as w, jsxs as T } from "react/jsx-runtime";
|
|
25
25
|
//#region src/routes/mcp.tsx
|
|
26
|
-
function
|
|
27
|
-
let { t:
|
|
28
|
-
|
|
26
|
+
function E() {
|
|
27
|
+
let { t: E } = e("openhands"), { data: D, isLoading: O } = o(), { mutate: k, isPending: A } = f(), j = n().backend.kind, [M, N] = C.useState(null), [P, F] = C.useState(null), [I, L] = C.useState(null), [R, z] = C.useState(""), [B, V] = C.useState("all"), H = _(a(D?.agent_settings?.mcp_config)), U = m(g), W = H.filter((e) => h(e, p(e, U), R)), G = (e) => {
|
|
28
|
+
N(e);
|
|
29
29
|
};
|
|
30
|
-
return
|
|
30
|
+
return O || !D ? /* @__PURE__ */ T("div", {
|
|
31
31
|
"data-testid": "mcp-page",
|
|
32
32
|
className: "flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10",
|
|
33
|
-
children: [/* @__PURE__ */
|
|
33
|
+
children: [/* @__PURE__ */ w(u, {}), /* @__PURE__ */ w("div", {
|
|
34
34
|
className: "flex h-full flex-1 items-center justify-center px-4 md:px-0",
|
|
35
|
-
children: /* @__PURE__ */
|
|
35
|
+
children: /* @__PURE__ */ w("div", { className: "h-8 w-8 rounded-full border-2 border-[var(--oh-border)] border-t-white animate-spin" })
|
|
36
36
|
})]
|
|
37
|
-
}) : /* @__PURE__ */
|
|
37
|
+
}) : /* @__PURE__ */ T("div", {
|
|
38
38
|
"data-testid": "mcp-page",
|
|
39
39
|
className: "flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10",
|
|
40
|
-
children: [/* @__PURE__ */
|
|
40
|
+
children: [/* @__PURE__ */ w(u, {}), /* @__PURE__ */ T("main", {
|
|
41
41
|
className: c,
|
|
42
42
|
children: [
|
|
43
|
-
/* @__PURE__ */
|
|
43
|
+
/* @__PURE__ */ T("div", {
|
|
44
44
|
className: "mx-auto flex w-full min-w-0 max-w-[800px] flex-col gap-6",
|
|
45
45
|
children: [
|
|
46
|
-
/* @__PURE__ */
|
|
46
|
+
/* @__PURE__ */ w("div", {
|
|
47
47
|
className: "min-w-0",
|
|
48
|
-
children: /* @__PURE__ */
|
|
48
|
+
children: /* @__PURE__ */ T("div", {
|
|
49
49
|
className: "flex items-start justify-between gap-4",
|
|
50
|
-
children: [/* @__PURE__ */
|
|
50
|
+
children: [/* @__PURE__ */ T("div", {
|
|
51
51
|
className: "space-y-1",
|
|
52
|
-
children: [/* @__PURE__ */
|
|
52
|
+
children: [/* @__PURE__ */ w("h2", {
|
|
53
53
|
className: "text-xl font-medium leading-6 text-foreground",
|
|
54
|
-
children:
|
|
55
|
-
}), /* @__PURE__ */
|
|
54
|
+
children: E(t.SETTINGS$MCP_TITLE)
|
|
55
|
+
}), /* @__PURE__ */ w("div", {
|
|
56
56
|
className: "max-w-2xl text-sm text-tertiary-light",
|
|
57
|
-
children:
|
|
57
|
+
children: E(t.MCP$PAGE_DESCRIPTION)
|
|
58
58
|
})]
|
|
59
|
-
}), /* @__PURE__ */
|
|
59
|
+
}), /* @__PURE__ */ w(s, {
|
|
60
60
|
type: "button",
|
|
61
61
|
variant: "secondary",
|
|
62
62
|
testId: "mcp-add-custom-server",
|
|
63
63
|
className: "flex-shrink-0 whitespace-nowrap",
|
|
64
|
-
onClick: () =>
|
|
64
|
+
onClick: () => F({
|
|
65
65
|
id: "",
|
|
66
66
|
type: "sse"
|
|
67
67
|
}),
|
|
68
|
-
children:
|
|
68
|
+
children: E(t.MCP$ADD_CUSTOM)
|
|
69
69
|
})]
|
|
70
70
|
})
|
|
71
71
|
}),
|
|
72
|
-
/* @__PURE__ */
|
|
73
|
-
search:
|
|
74
|
-
onSearchChange:
|
|
75
|
-
sectionFilter:
|
|
76
|
-
onSectionFilterChange:
|
|
72
|
+
/* @__PURE__ */ w(S, {
|
|
73
|
+
search: R,
|
|
74
|
+
onSearchChange: z,
|
|
75
|
+
sectionFilter: B,
|
|
76
|
+
onSectionFilterChange: V
|
|
77
77
|
}),
|
|
78
|
-
|
|
78
|
+
B === "library" ? null : /* @__PURE__ */ T("section", {
|
|
79
79
|
className: "flex flex-col gap-3",
|
|
80
|
-
children: [/* @__PURE__ */
|
|
80
|
+
children: [/* @__PURE__ */ w("h2", {
|
|
81
81
|
className: "text-base font-semibold text-foreground",
|
|
82
|
-
children:
|
|
83
|
-
}), /* @__PURE__ */
|
|
84
|
-
servers:
|
|
85
|
-
hasAnyInstalled:
|
|
86
|
-
query:
|
|
82
|
+
children: E(t.MCP$INSTALLED_TITLE)
|
|
83
|
+
}), /* @__PURE__ */ w(v, {
|
|
84
|
+
servers: W,
|
|
85
|
+
hasAnyInstalled: H.length > 0,
|
|
86
|
+
query: R,
|
|
87
87
|
onEdit: (e) => {
|
|
88
|
-
|
|
88
|
+
F(e);
|
|
89
89
|
},
|
|
90
90
|
onDelete: (e) => {
|
|
91
|
-
let t =
|
|
92
|
-
t &&
|
|
91
|
+
let t = H.find((t) => t.id === e);
|
|
92
|
+
t && L(t);
|
|
93
93
|
}
|
|
94
94
|
})]
|
|
95
95
|
}),
|
|
96
|
-
|
|
97
|
-
backendKind:
|
|
98
|
-
onSelect:
|
|
99
|
-
onAdd:
|
|
100
|
-
query:
|
|
96
|
+
B === "installed" ? null : /* @__PURE__ */ w(y, {
|
|
97
|
+
backendKind: j,
|
|
98
|
+
onSelect: G,
|
|
99
|
+
onAdd: G,
|
|
100
|
+
query: R
|
|
101
101
|
})
|
|
102
102
|
]
|
|
103
103
|
}),
|
|
104
|
-
|
|
105
|
-
entry:
|
|
106
|
-
onClose: () =>
|
|
104
|
+
M && /* @__PURE__ */ w(b, {
|
|
105
|
+
entry: M,
|
|
106
|
+
onClose: () => N(null)
|
|
107
107
|
}),
|
|
108
|
-
|
|
109
|
-
server:
|
|
110
|
-
existingServers:
|
|
111
|
-
onClose: () =>
|
|
108
|
+
P && /* @__PURE__ */ w(x, {
|
|
109
|
+
server: P,
|
|
110
|
+
existingServers: H,
|
|
111
|
+
onClose: () => F(null)
|
|
112
112
|
}),
|
|
113
|
-
|
|
114
|
-
text:
|
|
115
|
-
onCancel: () =>
|
|
113
|
+
I && /* @__PURE__ */ w(d, {
|
|
114
|
+
text: E(t.SETTINGS$MCP_CONFIRM_DELETE),
|
|
115
|
+
onCancel: () => L(null),
|
|
116
116
|
onConfirm: () => {
|
|
117
|
-
|
|
117
|
+
I && k(I, {
|
|
118
118
|
onSuccess: () => {
|
|
119
|
-
i(
|
|
119
|
+
i(E(t.MCP$REMOVE_SUCCESS)), L(null);
|
|
120
120
|
},
|
|
121
121
|
onError: (e) => {
|
|
122
|
-
r(l(e) ||
|
|
122
|
+
r(l(e) || E(t.ERROR$GENERIC)), L(null);
|
|
123
123
|
}
|
|
124
124
|
});
|
|
125
125
|
},
|
|
126
|
-
isConfirming:
|
|
126
|
+
isConfirming: A
|
|
127
127
|
})
|
|
128
128
|
]
|
|
129
129
|
})]
|
|
130
130
|
});
|
|
131
131
|
}
|
|
132
132
|
//#endregion
|
|
133
|
-
export {
|
|
133
|
+
export { E as default };
|
|
134
134
|
|
|
135
135
|
//# sourceMappingURL=mcp.js.map
|
package/dist/routes/mcp.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp.js","names":[],"sources":["../../src/routes/mcp.tsx"],"sourcesContent":["import React from \"react\";\nimport { AxiosError } from \"axios\";\nimport { ExtensionsNavigation } from \"#/components/features/skills/extensions-navigation\";\nimport { useTranslation } from \"react-i18next\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { BrandButton } from \"#/components/features/settings/brand-button\";\nimport { ConfirmationModal } from \"#/components/shared/modals/confirmation-modal\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { useDeleteMcpServer } from \"#/hooks/mutation/use-delete-mcp-server\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport { parseMcpConfig } from \"#/utils/mcp-config\";\nimport { redirectIfAcpActive } from \"#/utils/acp-route-guard\";\nimport {\n displayErrorToast,\n displaySuccessToast,\n} from \"#/utils/custom-toast-handlers\";\nimport { retrieveAxiosErrorMessage } from \"#/utils/retrieve-axios-error-message\";\nimport { settingsLikeMainScrollClassName } from \"#/utils/settings-like-page-layout-classes\";\nimport {\n findCatalogEntryForServer,\n installedServerMatchesQuery,\n} from \"#/utils/mcp-marketplace-utils\";\nimport {\n INTEGRATION_CATALOG as INTEGRATION_MARKETPLACE,\n type IntegrationCatalogEntry as MarketplaceEntry,\n} from \"@openhands/extensions/integrations\";\nimport { MCPServerConfig } from \"#/types/mcp-server\";\nimport { flattenMcpConfig } from \"#/utils/mcp-installed-servers\";\nimport {\n InstalledServersSection,\n McpToolbar,\n MarketplaceSection,\n InstallServerModal,\n CustomServerEditor,\n type McpSectionFilter,\n} from \"#/components/features/mcp-page\";\n\n// ACP guard: the ACP sub-agent owns its own MCP server configuration —\n// the SDK explicitly rejects `mcp_config` on ACPAgent init, and\n// `agent-server-adapter` already strips it from start payloads. The\n// Settings → Agent page is where the user configures the ACP server, so\n// bouncing there is consistent with how `/settings` and\n// `/settings/condenser` already behave under ACP.\n//\n// Declared with no parameters (rather than typed as Route.ClientLoaderArgs)\n// so the lib build doesn't pull generated React Router types out of rootDir.\nexport const clientLoader = async () => redirectIfAcpActive();\n\nexport default function MCPPage() {\n const { t } = useTranslation(\"openhands\");\n const { data: settings, isLoading } = useSettings();\n const { mutate: deleteMcpServer, isPending: isDeleting } =\n useDeleteMcpServer();\n const activeBackend = useActiveBackend();\n const backendKind = activeBackend.backend.kind;\n\n const [installEntry, setInstallEntry] =\n React.useState<MarketplaceEntry | null>(null);\n const [editingServer, setEditingServer] =\n React.useState<MCPServerConfig | null>(null);\n const [serverToDelete, setServerToDelete] =\n React.useState<MCPServerConfig | null>(null);\n const [searchQuery, setSearchQuery] = React.useState(\"\");\n const [sectionFilter, setSectionFilter] =\n React.useState<McpSectionFilter>(\"all\");\n\n const mcpConfig = parseMcpConfig(settings?.agent_settings?.mcp_config);\n const allServers = flattenMcpConfig(mcpConfig);\n\n // Filter installed servers by the search query. We pair each server\n // with its catalog entry (if any) so the search can match friendly\n // names like \"Slack\" against a stdio server whose own `.name` is\n // just \"slack\".\n const filteredInstalledServers = allServers.filter((server) =>\n installedServerMatchesQuery(\n server,\n findCatalogEntryForServer(server, INTEGRATION_MARKETPLACE),\n searchQuery,\n ),\n );\n\n const handleMarketplaceInstall = (entry: MarketplaceEntry) => {\n setInstallEntry(entry);\n };\n\n const handleEdit = (server: MCPServerConfig) => {\n setEditingServer(server);\n };\n\n const handleDeleteClick = (serverId: string) => {\n const target = allServers.find((s) => s.id === serverId);\n if (target) setServerToDelete(target);\n };\n\n const handleConfirmDelete = () => {\n if (!serverToDelete) return;\n // Pass the full server config — useDeleteMcpServer re-resolves its\n // position against the fresh settings at mutation time, so a\n // background refresh between this click and confirm cannot point\n // us at the wrong index.\n deleteMcpServer(serverToDelete, {\n onSuccess: () => {\n displaySuccessToast(t(I18nKey.MCP$REMOVE_SUCCESS));\n setServerToDelete(null);\n },\n onError: (err) => {\n const message = retrieveAxiosErrorMessage(err as AxiosError);\n displayErrorToast(message || t(I18nKey.ERROR$GENERIC));\n setServerToDelete(null);\n },\n });\n };\n\n if (isLoading || !settings) {\n return (\n <div\n data-testid=\"mcp-page\"\n className=\"flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10\"\n >\n <ExtensionsNavigation />\n <div className=\"flex h-full flex-1 items-center justify-center px-4 md:px-0\">\n <div className=\"h-8 w-8 rounded-full border-2 border-[var(--oh-border)] border-t-white animate-spin\" />\n </div>\n </div>\n );\n }\n\n return (\n <div\n data-testid=\"mcp-page\"\n className=\"flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10\"\n >\n <ExtensionsNavigation />\n <main className={settingsLikeMainScrollClassName}>\n <div className=\"mx-auto flex w-full min-w-0 max-w-[800px] flex-col gap-6\">\n <div className=\"min-w-0\">\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"space-y-1\">\n <h2 className=\"text-xl font-medium leading-6 text-foreground\">\n {t(I18nKey.SETTINGS$MCP_TITLE)}\n </h2>\n <div className=\"max-w-2xl text-sm text-tertiary-light\">\n {t(I18nKey.MCP$PAGE_DESCRIPTION)}\n </div>\n </div>\n <BrandButton\n type=\"button\"\n variant=\"secondary\"\n testId=\"mcp-add-custom-server\"\n className=\"flex-shrink-0 whitespace-nowrap\"\n onClick={() => setEditingServer({ id: \"\", type: \"sse\" })}\n >\n {t(I18nKey.MCP$ADD_CUSTOM)}\n </BrandButton>\n </div>\n </div>\n\n <McpToolbar\n search={searchQuery}\n onSearchChange={setSearchQuery}\n sectionFilter={sectionFilter}\n onSectionFilterChange={setSectionFilter}\n />\n\n {sectionFilter !== \"library\" ? (\n <section className=\"flex flex-col gap-3\">\n <h2 className=\"text-base font-semibold text-foreground\">\n {t(I18nKey.MCP$INSTALLED_TITLE)}\n </h2>\n <InstalledServersSection\n servers={filteredInstalledServers}\n hasAnyInstalled={allServers.length > 0}\n query={searchQuery}\n onEdit={handleEdit}\n onDelete={handleDeleteClick}\n />\n </section>\n ) : null}\n\n {sectionFilter !== \"installed\" ? (\n <MarketplaceSection\n backendKind={backendKind}\n onSelect={handleMarketplaceInstall}\n onAdd={handleMarketplaceInstall}\n query={searchQuery}\n />\n ) : null}\n </div>\n\n {installEntry && (\n <InstallServerModal\n entry={installEntry}\n onClose={() => setInstallEntry(null)}\n />\n )}\n\n {/* Custom (or non-marketplace) server editor. The empty-id\n sentinel (`{ id: \"\", type: \"sse\" }`) means \"add new\". */}\n {editingServer && (\n <CustomServerEditor\n server={editingServer}\n existingServers={allServers}\n onClose={() => setEditingServer(null)}\n />\n )}\n\n {serverToDelete && (\n <ConfirmationModal\n text={t(I18nKey.SETTINGS$MCP_CONFIRM_DELETE)}\n onCancel={() => setServerToDelete(null)}\n onConfirm={handleConfirmDelete}\n isConfirming={isDeleting}\n />\n )}\n </main>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mcp.js","names":[],"sources":["../../src/routes/mcp.tsx"],"sourcesContent":["import React from \"react\";\nimport { AxiosError } from \"axios\";\nimport { ExtensionsNavigation } from \"#/components/features/skills/extensions-navigation\";\nimport { useTranslation } from \"react-i18next\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { BrandButton } from \"#/components/features/settings/brand-button\";\nimport { ConfirmationModal } from \"#/components/shared/modals/confirmation-modal\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { useDeleteMcpServer } from \"#/hooks/mutation/use-delete-mcp-server\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport { parseMcpConfig } from \"#/utils/mcp-config\";\nimport { redirectIfAcpActive } from \"#/utils/acp-route-guard\";\nimport {\n displayErrorToast,\n displaySuccessToast,\n} from \"#/utils/custom-toast-handlers\";\nimport { retrieveAxiosErrorMessage } from \"#/utils/retrieve-axios-error-message\";\nimport { settingsLikeMainScrollClassName } from \"#/utils/settings-like-page-layout-classes\";\nimport {\n findCatalogEntryForServer,\n getMcpMarketplaceCatalog,\n installedServerMatchesQuery,\n} from \"#/utils/mcp-marketplace-utils\";\nimport {\n INTEGRATION_CATALOG as MCP_MARKETPLACE,\n type IntegrationCatalogEntry as MarketplaceEntry,\n} from \"@openhands/extensions/integrations\";\nimport { MCPServerConfig } from \"#/types/mcp-server\";\nimport { flattenMcpConfig } from \"#/utils/mcp-installed-servers\";\nimport {\n InstalledServersSection,\n McpToolbar,\n MarketplaceSection,\n InstallServerModal,\n CustomServerEditor,\n type McpSectionFilter,\n} from \"#/components/features/mcp-page\";\n\n// ACP guard: the ACP sub-agent owns its own MCP server configuration —\n// the SDK explicitly rejects `mcp_config` on ACPAgent init, and\n// `agent-server-adapter` already strips it from start payloads. The\n// Settings → Agent page is where the user configures the ACP server, so\n// bouncing there is consistent with how `/settings` and\n// `/settings/condenser` already behave under ACP.\n//\n// Declared with no parameters (rather than typed as Route.ClientLoaderArgs)\n// so the lib build doesn't pull generated React Router types out of rootDir.\nexport const clientLoader = async () => redirectIfAcpActive();\n\nexport default function MCPPage() {\n const { t } = useTranslation(\"openhands\");\n const { data: settings, isLoading } = useSettings();\n const { mutate: deleteMcpServer, isPending: isDeleting } =\n useDeleteMcpServer();\n const activeBackend = useActiveBackend();\n const backendKind = activeBackend.backend.kind;\n\n const [installEntry, setInstallEntry] =\n React.useState<MarketplaceEntry | null>(null);\n const [editingServer, setEditingServer] =\n React.useState<MCPServerConfig | null>(null);\n const [serverToDelete, setServerToDelete] =\n React.useState<MCPServerConfig | null>(null);\n const [searchQuery, setSearchQuery] = React.useState(\"\");\n const [sectionFilter, setSectionFilter] =\n React.useState<McpSectionFilter>(\"all\");\n\n const mcpConfig = parseMcpConfig(settings?.agent_settings?.mcp_config);\n const allServers = flattenMcpConfig(mcpConfig);\n const mcpMarketplace = getMcpMarketplaceCatalog(MCP_MARKETPLACE);\n\n // Filter installed servers by the search query. We pair each server\n // with its catalog entry (if any) so the search can match friendly\n // names like \"Slack\" against a stdio server whose own `.name` is\n // just \"slack\".\n const filteredInstalledServers = allServers.filter((server) =>\n installedServerMatchesQuery(\n server,\n findCatalogEntryForServer(server, mcpMarketplace),\n searchQuery,\n ),\n );\n\n const handleMarketplaceInstall = (entry: MarketplaceEntry) => {\n setInstallEntry(entry);\n };\n\n const handleEdit = (server: MCPServerConfig) => {\n setEditingServer(server);\n };\n\n const handleDeleteClick = (serverId: string) => {\n const target = allServers.find((s) => s.id === serverId);\n if (target) setServerToDelete(target);\n };\n\n const handleConfirmDelete = () => {\n if (!serverToDelete) return;\n // Pass the full server config — useDeleteMcpServer re-resolves its\n // position against the fresh settings at mutation time, so a\n // background refresh between this click and confirm cannot point\n // us at the wrong index.\n deleteMcpServer(serverToDelete, {\n onSuccess: () => {\n displaySuccessToast(t(I18nKey.MCP$REMOVE_SUCCESS));\n setServerToDelete(null);\n },\n onError: (err) => {\n const message = retrieveAxiosErrorMessage(err as AxiosError);\n displayErrorToast(message || t(I18nKey.ERROR$GENERIC));\n setServerToDelete(null);\n },\n });\n };\n\n if (isLoading || !settings) {\n return (\n <div\n data-testid=\"mcp-page\"\n className=\"flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10\"\n >\n <ExtensionsNavigation />\n <div className=\"flex h-full flex-1 items-center justify-center px-4 md:px-0\">\n <div className=\"h-8 w-8 rounded-full border-2 border-[var(--oh-border)] border-t-white animate-spin\" />\n </div>\n </div>\n );\n }\n\n return (\n <div\n data-testid=\"mcp-page\"\n className=\"flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10\"\n >\n <ExtensionsNavigation />\n <main className={settingsLikeMainScrollClassName}>\n <div className=\"mx-auto flex w-full min-w-0 max-w-[800px] flex-col gap-6\">\n <div className=\"min-w-0\">\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"space-y-1\">\n <h2 className=\"text-xl font-medium leading-6 text-foreground\">\n {t(I18nKey.SETTINGS$MCP_TITLE)}\n </h2>\n <div className=\"max-w-2xl text-sm text-tertiary-light\">\n {t(I18nKey.MCP$PAGE_DESCRIPTION)}\n </div>\n </div>\n <BrandButton\n type=\"button\"\n variant=\"secondary\"\n testId=\"mcp-add-custom-server\"\n className=\"flex-shrink-0 whitespace-nowrap\"\n onClick={() => setEditingServer({ id: \"\", type: \"sse\" })}\n >\n {t(I18nKey.MCP$ADD_CUSTOM)}\n </BrandButton>\n </div>\n </div>\n\n <McpToolbar\n search={searchQuery}\n onSearchChange={setSearchQuery}\n sectionFilter={sectionFilter}\n onSectionFilterChange={setSectionFilter}\n />\n\n {sectionFilter !== \"library\" ? (\n <section className=\"flex flex-col gap-3\">\n <h2 className=\"text-base font-semibold text-foreground\">\n {t(I18nKey.MCP$INSTALLED_TITLE)}\n </h2>\n <InstalledServersSection\n servers={filteredInstalledServers}\n hasAnyInstalled={allServers.length > 0}\n query={searchQuery}\n onEdit={handleEdit}\n onDelete={handleDeleteClick}\n />\n </section>\n ) : null}\n\n {sectionFilter !== \"installed\" ? (\n <MarketplaceSection\n backendKind={backendKind}\n onSelect={handleMarketplaceInstall}\n onAdd={handleMarketplaceInstall}\n query={searchQuery}\n />\n ) : null}\n </div>\n\n {installEntry && (\n <InstallServerModal\n entry={installEntry}\n onClose={() => setInstallEntry(null)}\n />\n )}\n\n {/* Custom (or non-marketplace) server editor. The empty-id\n sentinel (`{ id: \"\", type: \"sse\" }`) means \"add new\". */}\n {editingServer && (\n <CustomServerEditor\n server={editingServer}\n existingServers={allServers}\n onClose={() => setEditingServer(null)}\n />\n )}\n\n {serverToDelete && (\n <ConfirmationModal\n text={t(I18nKey.SETTINGS$MCP_CONFIRM_DELETE)}\n onCancel={() => setServerToDelete(null)}\n onConfirm={handleConfirmDelete}\n isConfirming={isDeleting}\n />\n )}\n </main>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
require(`../_virtual/_rolldown/runtime.cjs`);const e=require(`../node_modules/zustand/esm/react.cjs`);var t={url
|
|
1
|
+
require(`../_virtual/_rolldown/runtime.cjs`);const e=require(`../node_modules/zustand/esm/react.cjs`);var t={url:``,screenshotSrc:``},n=e.create(e=>({...t,setUrl:t=>e({url:t}),setScreenshotSrc:t=>e({screenshotSrc:t}),reset:()=>e(t)}));exports.useBrowserStore=n;
|
|
2
2
|
//# sourceMappingURL=browser-store.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser-store.cjs","names":[],"sources":["../../src/stores/browser-store.ts"],"sourcesContent":["import { create } from \"zustand\";\n\ninterface BrowserState {\n // URL of
|
|
1
|
+
{"version":3,"file":"browser-store.cjs","names":[],"sources":["../../src/stores/browser-store.ts"],"sourcesContent":["import { create } from \"zustand\";\n\ninterface BrowserState {\n // URL of the last page the agent navigated to in the browser panel.\n url: string;\n // Base64-encoded screenshot of the browser window, when the tool provides one.\n screenshotSrc: string;\n}\n\ninterface BrowserStore extends BrowserState {\n setUrl: (url: string) => void;\n setScreenshotSrc: (screenshotSrc: string) => void;\n reset: () => void;\n}\n\nconst initialState: BrowserState = {\n url: \"\",\n screenshotSrc: \"\",\n};\n\nexport const useBrowserStore = create<BrowserStore>((set) => ({\n ...initialState,\n setUrl: (url: string) => set({ url }),\n setScreenshotSrc: (screenshotSrc: string) => set({ screenshotSrc }),\n reset: () => set(initialState),\n}));\n"],"mappings":"sGAeA,IAAM,EAA6B,CACjC,IAAK,GACL,cAAe,GAChB,CAEY,EAAkB,EAAA,OAAsB,IAAS,CAC5D,GAAG,EACH,OAAS,GAAgB,EAAI,CAAE,MAAK,CAAC,CACrC,iBAAmB,GAA0B,EAAI,CAAE,gBAAe,CAAC,CACnE,UAAa,EAAI,EAAa,CAC/B,EAAE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser-store.js","names":[],"sources":["../../src/stores/browser-store.ts"],"sourcesContent":["import { create } from \"zustand\";\n\ninterface BrowserState {\n // URL of
|
|
1
|
+
{"version":3,"file":"browser-store.js","names":[],"sources":["../../src/stores/browser-store.ts"],"sourcesContent":["import { create } from \"zustand\";\n\ninterface BrowserState {\n // URL of the last page the agent navigated to in the browser panel.\n url: string;\n // Base64-encoded screenshot of the browser window, when the tool provides one.\n screenshotSrc: string;\n}\n\ninterface BrowserStore extends BrowserState {\n setUrl: (url: string) => void;\n setScreenshotSrc: (screenshotSrc: string) => void;\n reset: () => void;\n}\n\nconst initialState: BrowserState = {\n url: \"\",\n screenshotSrc: \"\",\n};\n\nexport const useBrowserStore = create<BrowserStore>((set) => ({\n ...initialState,\n setUrl: (url: string) => set({ url }),\n setScreenshotSrc: (screenshotSrc: string) => set({ screenshotSrc }),\n reset: () => set(initialState),\n}));\n"],"mappings":";;AAeA,IAAM,IAA6B;CACjC,KAAK;CACL,eAAe;CAChB,EAEY,IAAkB,GAAsB,OAAS;CAC5D,GAAG;CACH,SAAS,MAAgB,EAAI,EAAE,QAAK,CAAC;CACrC,mBAAmB,MAA0B,EAAI,EAAE,kBAAe,CAAC;CACnE,aAAa,EAAI,EAAa;CAC/B,EAAE"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
require(`../_virtual/_rolldown/runtime.cjs`);
|
|
1
|
+
require(`../_virtual/_rolldown/runtime.cjs`);function e(e){return e.connectionOptions.filter(e=>e.provider===`mcp`&&!!e.transport)}function t(t){let n=e(t);return n.find(e=>e.id===t.defaultConnectionOptionId)??n[0]}function n(e){return e.auth.strategy!==`oauth2`}function r(t){let r=e(t),i=r.find(e=>e.id===t.defaultConnectionOptionId);return i&&n(i)?i:r.find(n)}function i(e){return t(e)?.transport}function a(e){return e.filter(e=>!!t(e))}var o=e=>{try{return new URL(e)}catch{return null}};function s(e,t){let n=typeof e==`string`?e:``,r=typeof t==`string`?t:``;if(!n||!r)return!1;let i=o(n),a=o(r);return!i||!a?n.replace(/\/+$/,``)===r.replace(/\/+$/,``):i.protocol===a.protocol&&i.host===a.host&&i.pathname.replace(/\/+$/,``)===a.pathname.replace(/\/+$/,``)}function c(e,t){if(e.kind===`shttp`){let n=e.url;return t.type===`shttp`&&!!t.url&&s(t.url,n)}if(e.kind===`sse`){let n=e.url;return t.type===`sse`&&!!t.url&&s(t.url,n)}return t.type===`stdio`&&t.name===e.serverName}function l(e,t){return!e.runtimeAvailability||e.runtimeAvailability===`all`?!0:e.runtimeAvailability===t}function u(e){return e.trim().toLowerCase()}function d(e){return e.map((e,t)=>({entry:e,index:t})).sort((e,t)=>(t.entry.popularityRank??0)-(e.entry.popularityRank??0)||e.index-t.index).map(({entry:e})=>e)}function f(e,t){let n=u(t);return n?[e.name,e.description,e.id,...e.keywords??[]].join(` `).toLowerCase().includes(n):!0}function p(e,t,n){let r=u(n);return r?[e.type,`name`in e?e.name:void 0,`command`in e?e.command:void 0,`args`in e?e.args?.join(` `):void 0,`url`in e?e.url:void 0,t?.name,t?.description,t?.id,...t?.keywords??[]].filter(Boolean).join(` `).toLowerCase().includes(r):!0}function m(t,n){return n.find(n=>e(n).some(e=>c(e.transport,t)))}exports.findCatalogEntryForServer=m,exports.getDefaultMcpTransport=i,exports.getInstallableMcpConnectionOption=r,exports.getMarketplaceEntriesByPopularity=d,exports.getMcpMarketplaceCatalog=a,exports.installedServerMatchesQuery=p,exports.isMarketplaceEntryAvailable=l,exports.marketplaceEntryMatchesQuery=f;
|
|
2
2
|
//# sourceMappingURL=mcp-marketplace-utils.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-marketplace-utils.cjs","names":[],"sources":["../../src/utils/mcp-marketplace-utils.ts"],"sourcesContent":["import { MCPServerConfig } from \"#/types/mcp-server\";\nimport type {\n IntegrationCatalogEntry as MarketplaceEntry,\n IntegrationTransport as MarketplaceTemplate,\n} from \"@openhands/extensions/integrations\";\n\nconst tryUrl = (raw: string): URL | null => {\n try {\n return new URL(raw);\n } catch {\n return null;\n }\n};\n\n/**\n * Loose URL match that ignores query strings, trailing slashes, and\n * default ports. We want clicking \"Linear\" to flag the entry as\n * installed even if the user pasted the URL with extra trailing slash\n * or a different port-equivalent variant.\n *\n * Defensive against runtime data that doesn't match the static type:\n * if either input is not a string (e.g. parsed from an older settings\n * blob), we fall through the URL parsing path and the safe trim\n * fallback below, never calling `.replace` on undefined.\n */\nexport function urlsMatch(a: unknown, b: unknown): boolean {\n const aStr = typeof a === \"string\" ? a : \"\";\n const bStr = typeof b === \"string\" ? b : \"\";\n if (!aStr || !bStr) return false;\n const left = tryUrl(aStr);\n const right = tryUrl(bStr);\n if (!left || !right) {\n return aStr.replace(/\\/+$/, \"\") === bStr.replace(/\\/+$/, \"\");\n }\n return (\n left.protocol === right.protocol &&\n left.host === right.host &&\n left.pathname.replace(/\\/+$/, \"\") === right.pathname.replace(/\\/+$/, \"\")\n );\n}\n\n/**\n * Get the default transport template from an integration catalog entry.\n * Integrations may have multiple connection options; we use the default\n * one (or the first if no default is specified). Only MCP-backed options\n * have a `transport` field.\n */\nexport function getDefaultTemplate(\n entry: MarketplaceEntry,\n): MarketplaceTemplate | undefined {\n const option =\n entry.connectionOptions.find(\n (o) => o.id === entry.defaultConnectionOptionId,\n ) ?? entry.connectionOptions[0];\n return option?.transport;\n}\n\n/**\n * Get the stdio (API key-based) transport template from an integration entry.\n * Many integrations have multiple connection options (e.g., OAuth + stdio).\n * Since OAuth isn't implemented in the UI yet, the install modal should use\n * this function to get the stdio-based option that can be configured with\n * API keys/tokens.\n *\n * Falls back to getDefaultTemplate if no stdio option exists.\n */\nexport function getInstallableTemplate(\n entry: MarketplaceEntry,\n): MarketplaceTemplate | undefined {\n // First, try to find a stdio option (API key-based, what we can actually install)\n const stdioOption = entry.connectionOptions.find(\n (o) => o.transport?.kind === \"stdio\",\n );\n if (stdioOption?.transport) return stdioOption.transport;\n\n // Fall back to the default template (could be shttp/sse with api_key)\n return getDefaultTemplate(entry);\n}\n\n/**\n * Decide whether a marketplace template is already represented by one\n * of the installed MCP servers. Used to render an \"Installed\" badge on\n * the marketplace tile. Returns the first matching server, or null.\n */\nexport function findInstalledMatch(\n template: MarketplaceTemplate,\n servers: MCPServerConfig[],\n): MCPServerConfig | null {\n if (template.kind === \"shttp\") {\n const tplUrl = template.url;\n if (!tplUrl) return null;\n return (\n servers.find(\n (s) => s.type === \"shttp\" && !!s.url && urlsMatch(s.url, tplUrl),\n ) ?? null\n );\n }\n\n if (template.kind === \"sse\") {\n const tplUrl = template.url;\n if (!tplUrl) return null;\n return (\n servers.find(\n (s) => s.type === \"sse\" && !!s.url && urlsMatch(s.url, tplUrl),\n ) ?? null\n );\n }\n\n // stdio: match on the registered server name.\n return (\n servers.find((s) => s.type === \"stdio\" && s.name === template.serverName) ??\n null\n );\n}\n\nexport function isMarketplaceEntryAvailable(\n entry: MarketplaceEntry,\n backendKind: \"local\" | \"cloud\",\n): boolean {\n if (!entry.runtimeAvailability || entry.runtimeAvailability === \"all\")\n return true;\n return entry.runtimeAvailability === backendKind;\n}\n\nfunction normalize(query: string): string {\n return query.trim().toLowerCase();\n}\n\n/**\n * Case-insensitive substring match against the catalog entry's\n * user-visible identity (name, description, id, keywords). Empty\n * queries always match.\n */\nexport function getMarketplaceEntriesByPopularity(\n catalog: MarketplaceEntry[],\n): MarketplaceEntry[] {\n return catalog\n .map((entry, index) => ({ entry, index }))\n .sort((a, b) => {\n const byPopularity =\n (b.entry.popularityRank ?? 0) - (a.entry.popularityRank ?? 0);\n return byPopularity || a.index - b.index;\n })\n .map(({ entry }) => entry);\n}\n\nexport function getMarketplaceEntryById(\n id: string,\n catalog: MarketplaceEntry[],\n): MarketplaceEntry | undefined {\n return catalog.find((entry) => entry.id === id);\n}\n\nexport function marketplaceEntryMatchesQuery(\n entry: MarketplaceEntry,\n rawQuery: string,\n): boolean {\n const q = normalize(rawQuery);\n if (!q) return true;\n const haystack = [\n entry.name,\n entry.description,\n entry.id,\n ...(entry.keywords ?? []),\n ]\n .join(\" \")\n .toLowerCase();\n return haystack.includes(q);\n}\n\n/**\n * Search match for an installed (already-configured) server. We\n * search the server's own identifying fields and — if it's a catalog\n * entry — its catalog name/keywords too, so typing \"Slack\" matches\n * the installed Slack tile even though the persisted server is just\n * `{ type: \"stdio\", name: \"slack\", ... }`.\n */\nexport function installedServerMatchesQuery(\n server: MCPServerConfig,\n catalogEntry: MarketplaceEntry | undefined,\n rawQuery: string,\n): boolean {\n const q = normalize(rawQuery);\n if (!q) return true;\n const haystack = [\n server.type,\n \"name\" in server ? server.name : undefined,\n \"command\" in server ? server.command : undefined,\n \"args\" in server ? server.args?.join(\" \") : undefined,\n \"url\" in server ? server.url : undefined,\n catalogEntry?.name,\n catalogEntry?.description,\n catalogEntry?.id,\n ...(catalogEntry?.keywords ?? []),\n ]\n .filter(Boolean)\n .join(\" \")\n .toLowerCase();\n return haystack.includes(q);\n}\n\n/**\n * Look up the catalog entry that best matches an installed server.\n * Mirrors the lookup used in `installed-server-card.tsx` for\n * rendering the friendly icon.\n *\n * Since an entry may have multiple connection options (e.g., OAuth + stdio),\n * we check ALL templates in the entry's connectionOptions, not just the default.\n */\nexport function findCatalogEntryForServer(\n server: MCPServerConfig,\n catalog: MarketplaceEntry[],\n): MarketplaceEntry | undefined {\n return catalog.find((entry) => {\n // Check all connection options, not just the default\n for (const option of entry.connectionOptions) {\n const tpl = option.transport;\n if (!tpl) continue;\n if (tpl.kind === \"stdio\") {\n if (server.type === \"stdio\" && server.name === tpl.serverName)\n return true;\n }\n // Reuse the same loose URL match as `findInstalledMatch` so a\n // server whose URL was normalized by the backend (trailing slash\n // stripped, query string dropped, etc.) still gets paired with\n // its catalog tile — otherwise the installed-servers list would\n // render the generic icon while the marketplace shows the\n // entry as installed, which is confusing.\n if (tpl.kind === \"shttp\") {\n if (server.type === \"shttp\" && urlsMatch(server.url, tpl.url))\n return true;\n }\n if (tpl.kind === \"sse\") {\n if (server.type === \"sse\" && urlsMatch(server.url, tpl.url))\n return true;\n }\n }\n return false;\n });\n}\n"],"mappings":"6CAMA,IAAM,EAAU,GAA4B,CAC1C,GAAI,CACF,OAAO,IAAI,IAAI,EAAI,MACb,CACN,OAAO,OAeX,SAAgB,EAAU,EAAY,EAAqB,CACzD,IAAM,EAAO,OAAO,GAAM,SAAW,EAAI,GACnC,EAAO,OAAO,GAAM,SAAW,EAAI,GACzC,GAAI,CAAC,GAAQ,CAAC,EAAM,MAAO,GAC3B,IAAM,EAAO,EAAO,EAAK,CACnB,EAAQ,EAAO,EAAK,CAI1B,MAHI,CAAC,GAAQ,CAAC,EACL,EAAK,QAAQ,OAAQ,GAAG,GAAK,EAAK,QAAQ,OAAQ,GAAG,CAG5D,EAAK,WAAa,EAAM,UACxB,EAAK,OAAS,EAAM,MACpB,EAAK,SAAS,QAAQ,OAAQ,GAAG,GAAK,EAAM,SAAS,QAAQ,OAAQ,GAAG,CAU5E,SAAgB,EACd,EACiC,CAKjC,OAHE,EAAM,kBAAkB,KACrB,GAAM,EAAE,KAAO,EAAM,0BACvB,EAAI,EAAM,kBAAkB,KAChB,UAYjB,SAAgB,EACd,EACiC,CAEjC,IAAM,EAAc,EAAM,kBAAkB,KACzC,GAAM,EAAE,WAAW,OAAS,QAC9B,CAID,OAHI,GAAa,UAAkB,EAAY,UAGxC,EAAmB,EAAM,CAuClC,SAAgB,EACd,EACA,EACS,CAGT,MAFI,CAAC,EAAM,qBAAuB,EAAM,sBAAwB,MACvD,GACF,EAAM,sBAAwB,EAGvC,SAAS,EAAU,EAAuB,CACxC,OAAO,EAAM,MAAM,CAAC,aAAa,CAQnC,SAAgB,EACd,EACoB,CACpB,OAAO,EACJ,KAAK,EAAO,KAAW,CAAE,QAAO,QAAO,EAAE,CACzC,MAAM,EAAG,KAEL,EAAE,MAAM,gBAAkB,IAAM,EAAE,MAAM,gBAAkB,IACtC,EAAE,MAAQ,EAAE,MACnC,CACD,KAAK,CAAE,WAAY,EAAM,CAU9B,SAAgB,EACd,EACA,EACS,CACT,IAAM,EAAI,EAAU,EAAS,CAU7B,OATK,EACY,CACf,EAAM,KACN,EAAM,YACN,EAAM,GACN,GAAI,EAAM,UAAY,EAAE,CACzB,CACE,KAAK,IAAI,CACT,aACI,CAAS,SAAS,EAAE,CATZ,GAmBjB,SAAgB,EACd,EACA,EACA,EACS,CACT,IAAM,EAAI,EAAU,EAAS,CAgB7B,OAfK,EACY,CACf,EAAO,KACP,SAAU,EAAS,EAAO,KAAO,IAAA,GACjC,YAAa,EAAS,EAAO,QAAU,IAAA,GACvC,SAAU,EAAS,EAAO,MAAM,KAAK,IAAI,CAAG,IAAA,GAC5C,QAAS,EAAS,EAAO,IAAM,IAAA,GAC/B,GAAc,KACd,GAAc,YACd,GAAc,GACd,GAAI,GAAc,UAAY,EAAE,CACjC,CACE,OAAO,QAAQ,CACf,KAAK,IAAI,CACT,aACI,CAAS,SAAS,EAAE,CAfZ,GA0BjB,SAAgB,EACd,EACA,EAC8B,CAC9B,OAAO,EAAQ,KAAM,GAAU,CAE7B,IAAK,IAAM,KAAU,EAAM,kBAAmB,CAC5C,IAAM,EAAM,EAAO,UACd,OACD,EAAI,OAAS,SACX,EAAO,OAAS,SAAW,EAAO,OAAS,EAAI,YASjD,EAAI,OAAS,SACX,EAAO,OAAS,SAAW,EAAU,EAAO,IAAK,EAAI,IAAI,EAG3D,EAAI,OAAS,OACX,EAAO,OAAS,OAAS,EAAU,EAAO,IAAK,EAAI,IAAI,EACzD,MAAO,GAGb,MAAO,IACP"}
|
|
1
|
+
{"version":3,"file":"mcp-marketplace-utils.cjs","names":[],"sources":["../../src/utils/mcp-marketplace-utils.ts"],"sourcesContent":["import { MCPServerConfig } from \"#/types/mcp-server\";\nimport type {\n IntegrationCatalogEntry as MarketplaceEntry,\n IntegrationConnectionOption,\n IntegrationTransport,\n} from \"@openhands/extensions/integrations\";\n\nexport type { MarketplaceEntry };\n\nexport type McpMarketplaceConnectionOption = IntegrationConnectionOption & {\n provider: \"mcp\";\n transport: IntegrationTransport;\n};\n\nexport function getMcpConnectionOptions(\n entry: MarketplaceEntry,\n): McpMarketplaceConnectionOption[] {\n return entry.connectionOptions.filter(\n (option): option is McpMarketplaceConnectionOption =>\n option.provider === \"mcp\" && !!option.transport,\n );\n}\n\nexport function getDefaultMcpConnectionOption(\n entry: MarketplaceEntry,\n): McpMarketplaceConnectionOption | undefined {\n const options = getMcpConnectionOptions(entry);\n return (\n options.find((option) => option.id === entry.defaultConnectionOptionId) ??\n options[0]\n );\n}\n\nfunction isLocallyInstallableMcpOption(\n option: McpMarketplaceConnectionOption,\n): boolean {\n // The local install modal writes static MCP server config. OAuth options\n // describe hosted redirect flows, so prefer an API/stdio fallback when one\n // exists and leave OAuth as the default connection for hosted integrations.\n return option.auth.strategy !== \"oauth2\";\n}\n\nexport function getInstallableMcpConnectionOption(\n entry: MarketplaceEntry,\n): McpMarketplaceConnectionOption | undefined {\n const options = getMcpConnectionOptions(entry);\n const defaultOption = options.find(\n (option) => option.id === entry.defaultConnectionOptionId,\n );\n if (defaultOption && isLocallyInstallableMcpOption(defaultOption)) {\n return defaultOption;\n }\n return options.find(isLocallyInstallableMcpOption);\n}\n\nexport function getDefaultMcpTransport(\n entry: MarketplaceEntry,\n): IntegrationTransport | undefined {\n return getDefaultMcpConnectionOption(entry)?.transport;\n}\n\nexport function getMcpMarketplaceCatalog(\n catalog: MarketplaceEntry[],\n): MarketplaceEntry[] {\n return catalog.filter((entry) => !!getDefaultMcpConnectionOption(entry));\n}\n\nconst tryUrl = (raw: string): URL | null => {\n try {\n return new URL(raw);\n } catch {\n return null;\n }\n};\n\n/**\n * Loose URL match that ignores query strings, trailing slashes, and\n * default ports. We want clicking \"Linear\" to flag the entry as\n * installed even if the user pasted the URL with extra trailing slash\n * or a different port-equivalent variant.\n *\n * Defensive against runtime data that doesn't match the static type:\n * if either input is not a string (e.g. parsed from an older settings\n * blob), we fall through the URL parsing path and the safe trim\n * fallback below, never calling `.replace` on undefined.\n */\nexport function urlsMatch(a: unknown, b: unknown): boolean {\n const aStr = typeof a === \"string\" ? a : \"\";\n const bStr = typeof b === \"string\" ? b : \"\";\n if (!aStr || !bStr) return false;\n const left = tryUrl(aStr);\n const right = tryUrl(bStr);\n if (!left || !right) {\n return aStr.replace(/\\/+$/, \"\") === bStr.replace(/\\/+$/, \"\");\n }\n return (\n left.protocol === right.protocol &&\n left.host === right.host &&\n left.pathname.replace(/\\/+$/, \"\") === right.pathname.replace(/\\/+$/, \"\")\n );\n}\n\n/**\n * Decide whether a marketplace template is already represented by one\n * of the installed MCP servers. Used to render an \"Installed\" badge on\n * the marketplace tile. Returns the first matching server, or null.\n */\nexport function findInstalledMatch(\n transport: IntegrationTransport,\n servers: MCPServerConfig[],\n): MCPServerConfig | null {\n return (\n servers.find((server) => transportMatchesServer(transport, server)) ?? null\n );\n}\n\nexport function findInstalledEntryMatch(\n entry: MarketplaceEntry,\n servers: MCPServerConfig[],\n): MCPServerConfig | null {\n for (const option of getMcpConnectionOptions(entry)) {\n const match = findInstalledMatch(option.transport, servers);\n if (match) return match;\n }\n return null;\n}\n\nfunction transportMatchesServer(\n transport: IntegrationTransport,\n server: MCPServerConfig,\n): boolean {\n if (transport.kind === \"shttp\") {\n const tplUrl = transport.url;\n return (\n server.type === \"shttp\" && !!server.url && urlsMatch(server.url, tplUrl)\n );\n }\n\n if (transport.kind === \"sse\") {\n const tplUrl = transport.url;\n return (\n server.type === \"sse\" && !!server.url && urlsMatch(server.url, tplUrl)\n );\n }\n\n // stdio: match on the registered server name.\n return server.type === \"stdio\" && server.name === transport.serverName;\n}\n\nexport function isMarketplaceEntryAvailable(\n entry: MarketplaceEntry,\n backendKind: \"local\" | \"cloud\",\n): boolean {\n if (!entry.runtimeAvailability || entry.runtimeAvailability === \"all\")\n return true;\n return entry.runtimeAvailability === backendKind;\n}\n\nfunction normalize(query: string): string {\n return query.trim().toLowerCase();\n}\n\n/**\n * Case-insensitive substring match against the catalog entry's\n * user-visible identity (name, description, id, keywords). Empty\n * queries always match.\n */\nexport function getMarketplaceEntriesByPopularity(\n catalog: MarketplaceEntry[],\n): MarketplaceEntry[] {\n return catalog\n .map((entry, index) => ({ entry, index }))\n .sort((a, b) => {\n const byPopularity =\n (b.entry.popularityRank ?? 0) - (a.entry.popularityRank ?? 0);\n return byPopularity || a.index - b.index;\n })\n .map(({ entry }) => entry);\n}\n\nexport function getMarketplaceEntryById(\n id: string,\n catalog: MarketplaceEntry[],\n): MarketplaceEntry | undefined {\n return catalog.find((entry) => entry.id === id);\n}\n\nexport function marketplaceEntryMatchesQuery(\n entry: MarketplaceEntry,\n rawQuery: string,\n): boolean {\n const q = normalize(rawQuery);\n if (!q) return true;\n const haystack = [\n entry.name,\n entry.description,\n entry.id,\n ...(entry.keywords ?? []),\n ]\n .join(\" \")\n .toLowerCase();\n return haystack.includes(q);\n}\n\n/**\n * Search match for an installed (already-configured) server. We\n * search the server's own identifying fields and — if it's a catalog\n * entry — its catalog name/keywords too, so typing \"Slack\" matches\n * the installed Slack tile even though the persisted server is just\n * `{ type: \"stdio\", name: \"slack\", ... }`.\n */\nexport function installedServerMatchesQuery(\n server: MCPServerConfig,\n catalogEntry: MarketplaceEntry | undefined,\n rawQuery: string,\n): boolean {\n const q = normalize(rawQuery);\n if (!q) return true;\n const haystack = [\n server.type,\n \"name\" in server ? server.name : undefined,\n \"command\" in server ? server.command : undefined,\n \"args\" in server ? server.args?.join(\" \") : undefined,\n \"url\" in server ? server.url : undefined,\n catalogEntry?.name,\n catalogEntry?.description,\n catalogEntry?.id,\n ...(catalogEntry?.keywords ?? []),\n ]\n .filter(Boolean)\n .join(\" \")\n .toLowerCase();\n return haystack.includes(q);\n}\n\n/**\n * Look up the catalog entry that best matches an installed server.\n * Mirrors the lookup used in `installed-server-card.tsx` for\n * rendering the friendly icon.\n */\nexport function findCatalogEntryForServer(\n server: MCPServerConfig,\n catalog: MarketplaceEntry[],\n): MarketplaceEntry | undefined {\n return catalog.find((entry) => {\n // Check every MCP option rather than only the default. Some unified\n // integration entries default to OAuth-hosted MCP while still exposing\n // an API/stdio option; existing installed servers should match either.\n return getMcpConnectionOptions(entry).some((option) =>\n transportMatchesServer(option.transport, server),\n );\n });\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
import { MCPServerConfig } from "#/types/mcp-server";
|
|
2
|
-
import type { IntegrationCatalogEntry as MarketplaceEntry, IntegrationTransport
|
|
2
|
+
import type { IntegrationCatalogEntry as MarketplaceEntry, IntegrationConnectionOption, IntegrationTransport } from "@openhands/extensions/integrations";
|
|
3
|
+
export type { MarketplaceEntry };
|
|
4
|
+
export type McpMarketplaceConnectionOption = IntegrationConnectionOption & {
|
|
5
|
+
provider: "mcp";
|
|
6
|
+
transport: IntegrationTransport;
|
|
7
|
+
};
|
|
8
|
+
export declare function getMcpConnectionOptions(entry: MarketplaceEntry): McpMarketplaceConnectionOption[];
|
|
9
|
+
export declare function getDefaultMcpConnectionOption(entry: MarketplaceEntry): McpMarketplaceConnectionOption | undefined;
|
|
10
|
+
export declare function getInstallableMcpConnectionOption(entry: MarketplaceEntry): McpMarketplaceConnectionOption | undefined;
|
|
11
|
+
export declare function getDefaultMcpTransport(entry: MarketplaceEntry): IntegrationTransport | undefined;
|
|
12
|
+
export declare function getMcpMarketplaceCatalog(catalog: MarketplaceEntry[]): MarketplaceEntry[];
|
|
3
13
|
/**
|
|
4
14
|
* Loose URL match that ignores query strings, trailing slashes, and
|
|
5
15
|
* default ports. We want clicking "Linear" to flag the entry as
|
|
@@ -12,29 +22,13 @@ import type { IntegrationCatalogEntry as MarketplaceEntry, IntegrationTransport
|
|
|
12
22
|
* fallback below, never calling `.replace` on undefined.
|
|
13
23
|
*/
|
|
14
24
|
export declare function urlsMatch(a: unknown, b: unknown): boolean;
|
|
15
|
-
/**
|
|
16
|
-
* Get the default transport template from an integration catalog entry.
|
|
17
|
-
* Integrations may have multiple connection options; we use the default
|
|
18
|
-
* one (or the first if no default is specified). Only MCP-backed options
|
|
19
|
-
* have a `transport` field.
|
|
20
|
-
*/
|
|
21
|
-
export declare function getDefaultTemplate(entry: MarketplaceEntry): MarketplaceTemplate | undefined;
|
|
22
|
-
/**
|
|
23
|
-
* Get the stdio (API key-based) transport template from an integration entry.
|
|
24
|
-
* Many integrations have multiple connection options (e.g., OAuth + stdio).
|
|
25
|
-
* Since OAuth isn't implemented in the UI yet, the install modal should use
|
|
26
|
-
* this function to get the stdio-based option that can be configured with
|
|
27
|
-
* API keys/tokens.
|
|
28
|
-
*
|
|
29
|
-
* Falls back to getDefaultTemplate if no stdio option exists.
|
|
30
|
-
*/
|
|
31
|
-
export declare function getInstallableTemplate(entry: MarketplaceEntry): MarketplaceTemplate | undefined;
|
|
32
25
|
/**
|
|
33
26
|
* Decide whether a marketplace template is already represented by one
|
|
34
27
|
* of the installed MCP servers. Used to render an "Installed" badge on
|
|
35
28
|
* the marketplace tile. Returns the first matching server, or null.
|
|
36
29
|
*/
|
|
37
|
-
export declare function findInstalledMatch(
|
|
30
|
+
export declare function findInstalledMatch(transport: IntegrationTransport, servers: MCPServerConfig[]): MCPServerConfig | null;
|
|
31
|
+
export declare function findInstalledEntryMatch(entry: MarketplaceEntry, servers: MCPServerConfig[]): MCPServerConfig | null;
|
|
38
32
|
export declare function isMarketplaceEntryAvailable(entry: MarketplaceEntry, backendKind: "local" | "cloud"): boolean;
|
|
39
33
|
/**
|
|
40
34
|
* Case-insensitive substring match against the catalog entry's
|
|
@@ -56,8 +50,5 @@ export declare function installedServerMatchesQuery(server: MCPServerConfig, cat
|
|
|
56
50
|
* Look up the catalog entry that best matches an installed server.
|
|
57
51
|
* Mirrors the lookup used in `installed-server-card.tsx` for
|
|
58
52
|
* rendering the friendly icon.
|
|
59
|
-
*
|
|
60
|
-
* Since an entry may have multiple connection options (e.g., OAuth + stdio),
|
|
61
|
-
* we check ALL templates in the entry's connectionOptions, not just the default.
|
|
62
53
|
*/
|
|
63
54
|
export declare function findCatalogEntryForServer(server: MCPServerConfig, catalog: MarketplaceEntry[]): MarketplaceEntry | undefined;
|
|
@@ -1,38 +1,62 @@
|
|
|
1
1
|
//#region src/utils/mcp-marketplace-utils.ts
|
|
2
|
-
|
|
2
|
+
function e(e) {
|
|
3
|
+
return e.connectionOptions.filter((e) => e.provider === "mcp" && !!e.transport);
|
|
4
|
+
}
|
|
5
|
+
function t(t) {
|
|
6
|
+
let n = e(t);
|
|
7
|
+
return n.find((e) => e.id === t.defaultConnectionOptionId) ?? n[0];
|
|
8
|
+
}
|
|
9
|
+
function n(e) {
|
|
10
|
+
return e.auth.strategy !== "oauth2";
|
|
11
|
+
}
|
|
12
|
+
function r(t) {
|
|
13
|
+
let r = e(t), i = r.find((e) => e.id === t.defaultConnectionOptionId);
|
|
14
|
+
return i && n(i) ? i : r.find(n);
|
|
15
|
+
}
|
|
16
|
+
function i(e) {
|
|
17
|
+
return t(e)?.transport;
|
|
18
|
+
}
|
|
19
|
+
function a(e) {
|
|
20
|
+
return e.filter((e) => !!t(e));
|
|
21
|
+
}
|
|
22
|
+
var o = (e) => {
|
|
3
23
|
try {
|
|
4
24
|
return new URL(e);
|
|
5
25
|
} catch {
|
|
6
26
|
return null;
|
|
7
27
|
}
|
|
8
28
|
};
|
|
9
|
-
function
|
|
10
|
-
let
|
|
11
|
-
if (!
|
|
12
|
-
let
|
|
13
|
-
return !
|
|
14
|
-
}
|
|
15
|
-
function n(e) {
|
|
16
|
-
return (e.connectionOptions.find((t) => t.id === e.defaultConnectionOptionId) ?? e.connectionOptions[0])?.transport;
|
|
29
|
+
function s(e, t) {
|
|
30
|
+
let n = typeof e == "string" ? e : "", r = typeof t == "string" ? t : "";
|
|
31
|
+
if (!n || !r) return !1;
|
|
32
|
+
let i = o(n), a = o(r);
|
|
33
|
+
return !i || !a ? n.replace(/\/+$/, "") === r.replace(/\/+$/, "") : i.protocol === a.protocol && i.host === a.host && i.pathname.replace(/\/+$/, "") === a.pathname.replace(/\/+$/, "");
|
|
17
34
|
}
|
|
18
|
-
function
|
|
19
|
-
|
|
20
|
-
|
|
35
|
+
function c(e, t) {
|
|
36
|
+
if (e.kind === "shttp") {
|
|
37
|
+
let n = e.url;
|
|
38
|
+
return t.type === "shttp" && !!t.url && s(t.url, n);
|
|
39
|
+
}
|
|
40
|
+
if (e.kind === "sse") {
|
|
41
|
+
let n = e.url;
|
|
42
|
+
return t.type === "sse" && !!t.url && s(t.url, n);
|
|
43
|
+
}
|
|
44
|
+
return t.type === "stdio" && t.name === e.serverName;
|
|
21
45
|
}
|
|
22
|
-
function
|
|
46
|
+
function l(e, t) {
|
|
23
47
|
return !e.runtimeAvailability || e.runtimeAvailability === "all" ? !0 : e.runtimeAvailability === t;
|
|
24
48
|
}
|
|
25
|
-
function
|
|
49
|
+
function u(e) {
|
|
26
50
|
return e.trim().toLowerCase();
|
|
27
51
|
}
|
|
28
|
-
function
|
|
52
|
+
function d(e) {
|
|
29
53
|
return e.map((e, t) => ({
|
|
30
54
|
entry: e,
|
|
31
55
|
index: t
|
|
32
56
|
})).sort((e, t) => (t.entry.popularityRank ?? 0) - (e.entry.popularityRank ?? 0) || e.index - t.index).map(({ entry: e }) => e);
|
|
33
57
|
}
|
|
34
|
-
function
|
|
35
|
-
let n =
|
|
58
|
+
function f(e, t) {
|
|
59
|
+
let n = u(t);
|
|
36
60
|
return n ? [
|
|
37
61
|
e.name,
|
|
38
62
|
e.description,
|
|
@@ -40,8 +64,8 @@ function s(e, t) {
|
|
|
40
64
|
...e.keywords ?? []
|
|
41
65
|
].join(" ").toLowerCase().includes(n) : !0;
|
|
42
66
|
}
|
|
43
|
-
function
|
|
44
|
-
let r =
|
|
67
|
+
function p(e, t, n) {
|
|
68
|
+
let r = u(n);
|
|
45
69
|
return r ? [
|
|
46
70
|
e.type,
|
|
47
71
|
"name" in e ? e.name : void 0,
|
|
@@ -54,16 +78,10 @@ function c(e, t, n) {
|
|
|
54
78
|
...t?.keywords ?? []
|
|
55
79
|
].filter(Boolean).join(" ").toLowerCase().includes(r) : !0;
|
|
56
80
|
}
|
|
57
|
-
function
|
|
58
|
-
return n.find((n) =>
|
|
59
|
-
for (let r of n.connectionOptions) {
|
|
60
|
-
let n = r.transport;
|
|
61
|
-
if (n && (n.kind === "stdio" && e.type === "stdio" && e.name === n.serverName || n.kind === "shttp" && e.type === "shttp" && t(e.url, n.url) || n.kind === "sse" && e.type === "sse" && t(e.url, n.url))) return !0;
|
|
62
|
-
}
|
|
63
|
-
return !1;
|
|
64
|
-
});
|
|
81
|
+
function m(t, n) {
|
|
82
|
+
return n.find((n) => e(n).some((e) => c(e.transport, t)));
|
|
65
83
|
}
|
|
66
84
|
//#endregion
|
|
67
|
-
export {
|
|
85
|
+
export { m as findCatalogEntryForServer, i as getDefaultMcpTransport, r as getInstallableMcpConnectionOption, d as getMarketplaceEntriesByPopularity, a as getMcpMarketplaceCatalog, p as installedServerMatchesQuery, l as isMarketplaceEntryAvailable, f as marketplaceEntryMatchesQuery };
|
|
68
86
|
|
|
69
87
|
//# sourceMappingURL=mcp-marketplace-utils.js.map
|