@shipit-ai/cli 1.173.2 → 1.174.1-pr20.dba624c
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/dist/packages/core/src/infrastructure/services/mcp-server-browser/mcp-server-browser.service.js +46 -1
- package/dist/packages/core/src/infrastructure/services/tool-installer/tools/codex-cli.json +1 -1
- package/dist/src/presentation/web/components/features/mcp-servers/mcp-connect-instructions.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/mcp-servers/mcp-connect-instructions.js +1 -3
- package/dist/src/presentation/web/components/features/mcp-servers/mcp-server-card.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/mcp-servers/mcp-server-card.js +2 -8
- package/dist/src/presentation/web/components/features/mcp-servers/mcp-server-detail-drawer.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/mcp-servers/mcp-server-detail-drawer.js +5 -4
- package/dist/src/presentation/web/components/features/mcp-servers/mcp-server-icon.d.ts +45 -0
- package/dist/src/presentation/web/components/features/mcp-servers/mcp-server-icon.d.ts.map +1 -0
- package/dist/src/presentation/web/components/features/mcp-servers/mcp-server-icon.js +138 -0
- package/dist/src/presentation/web/components/features/mcp-servers/mcp-servers-page-client.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/mcp-servers/mcp-servers-page-client.js +7 -6
- package/dist/src/presentation/web/components/features/mcp-servers/vendor-brand-icons.d.ts +29 -0
- package/dist/src/presentation/web/components/features/mcp-servers/vendor-brand-icons.d.ts.map +1 -0
- package/dist/src/presentation/web/components/features/mcp-servers/vendor-brand-icons.js +25 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +6 -6
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/build-manifest.json +3 -3
- package/web/.next/fallback-build-manifest.json +3 -3
- package/web/.next/prerender-manifest.json +3 -3
- package/web/.next/required-server-files.js +3 -3
- package/web/.next/required-server-files.json +3 -3
- package/web/.next/server/app/(dashboard)/@drawer/adopt/page/server-reference-manifest.json +29 -29
- package/web/.next/server/app/(dashboard)/@drawer/adopt/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/adopt/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/chat/page/server-reference-manifest.json +27 -27
- package/web/.next/server/app/(dashboard)/@drawer/chat/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/chat/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +31 -31
- package/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page/server-reference-manifest.json +37 -37
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +37 -37
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/[tab]/page/server-reference-manifest.json +28 -28
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/[tab]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/[tab]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +28 -28
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/chat/page/server-reference-manifest.json +27 -27
- package/web/.next/server/app/(dashboard)/chat/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/chat/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +31 -31
- package/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page/server-reference-manifest.json +37 -37
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +37 -37
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +27 -27
- package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/[tab]/page/server-reference-manifest.json +28 -28
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/[tab]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/[tab]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +28 -28
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/_global-error.html +1 -1
- package/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/_not-found/page/server-reference-manifest.json +6 -6
- package/web/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/api/attachments/preview/route.js.nft.json +1 -1
- package/web/.next/server/app/api/dialog/pick-files/route.js.nft.json +1 -1
- package/web/.next/server/app/api/evidence/route.js.nft.json +1 -1
- package/web/.next/server/app/api/graph-data/route.js.nft.json +1 -1
- package/web/.next/server/app/api/interactive/chat/[featureId]/messages/route.js.nft.json +1 -1
- package/web/.next/server/app/mcp-servers/page/server-reference-manifest.json +13 -13
- package/web/.next/server/app/mcp-servers/page.js.nft.json +1 -1
- package/web/.next/server/app/mcp-servers/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/plugins/page/server-reference-manifest.json +15 -15
- package/web/.next/server/app/plugins/page.js.nft.json +1 -1
- package/web/.next/server/app/plugins/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/settings/page/server-reference-manifest.json +12 -12
- package/web/.next/server/app/settings/page.js.nft.json +1 -1
- package/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/skills/page/server-reference-manifest.json +11 -11
- package/web/.next/server/app/skills/page.js.nft.json +1 -1
- package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/tools/page/server-reference-manifest.json +11 -11
- package/web/.next/server/app/tools/page.js.nft.json +1 -1
- package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/version/page/server-reference-manifest.json +6 -6
- package/web/.next/server/app/version/page.js.nft.json +1 -1
- package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
- package/web/.next/server/chunks/[root-of-the-server]__0tb~wwk._.js +1 -1
- package/web/.next/server/chunks/ssr/0j.8_web_components_common_control-center-drawer_create-drawer-client_tsx_0g70fc5._.js +1 -1
- package/web/.next/server/chunks/ssr/0j.8_web_components_common_control-center-drawer_create-drawer-client_tsx_0g70fc5._.js.map +1 -1
- package/web/.next/server/chunks/ssr/0j.8_web_components_common_control-center-drawer_feature-drawer-client_tsx_104cna.._.js +2 -2
- package/web/.next/server/chunks/ssr/0j.8_web_components_common_control-center-drawer_feature-drawer-client_tsx_104cna.._.js.map +1 -1
- package/web/.next/server/chunks/ssr/0j.8_web_components_features_mcp-servers_mcp-servers-page-client_tsx_0dda8ih._.js +2 -2
- package/web/.next/server/chunks/ssr/0j.8_web_components_features_mcp-servers_mcp-servers-page-client_tsx_0dda8ih._.js.map +1 -1
- package/web/.next/server/chunks/ssr/0ukq_presentation_web_components_features_settings_settings-page-client_tsx_0j1uius._.js +1 -1
- package/web/.next/server/chunks/ssr/0ukq_presentation_web_components_features_settings_settings-page-client_tsx_0j1uius._.js.map +1 -1
- package/web/.next/server/chunks/ssr/11y9_components_common_control-center-drawer_repository-drawer-client_tsx_09z.znp._.js +1 -1
- package/web/.next/server/chunks/ssr/11y9_components_common_control-center-drawer_repository-drawer-client_tsx_09z.znp._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__0.5ojmt._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__0.5ojmt._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__05_qc0n._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__05_qc0n._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__0ge~xny._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__0ge~xny._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__0mwao26._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__0mwao26._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__0qda~yi._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__0qda~yi._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__0rv1gci._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__0tq2syh._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__0t~u8sd._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__0t~u8sd._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__10tll_l._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__10tll_l._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__12j29w-._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__12j29w-._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{_0~d-l61._.js → _01.73dm._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_0~d-l61._.js.map → _01.73dm._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/_01sesw0._.js +1 -1
- package/web/.next/server/chunks/ssr/_01sesw0._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_069y.js._.js +2 -2
- package/web/.next/server/chunks/ssr/_069y.js._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{_1031n_-._.js → _083k45~._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_1031n_-._.js.map → _083k45~._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/_0__4si~._.js +1 -1
- package/web/.next/server/chunks/ssr/_0__4si~._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_0_m17kl._.js +1 -1
- package/web/.next/server/chunks/ssr/_0_m17kl._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{_09b301s._.js → _0ajzmj-._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_09b301s._.js.map → _0ajzmj-._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/_0d4miu.._.js +1 -1
- package/web/.next/server/chunks/ssr/_0d4miu.._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_0e8ern9._.js +1 -1
- package/web/.next/server/chunks/ssr/_0e8ern9._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_0fswe4r._.js +1 -1
- package/web/.next/server/chunks/ssr/_0fswe4r._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{_0u09c2.._.js → _0mbb.7k._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_0u09c2.._.js.map → _0mbb.7k._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/_0p3~u8u._.js +2 -2
- package/web/.next/server/chunks/ssr/_0p3~u8u._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_0r.3n~3._.js +1 -1
- package/web/.next/server/chunks/ssr/_0r.3n~3._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_0t59q8r._.js +1 -1
- package/web/.next/server/chunks/ssr/_0t59q8r._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{_096x3u~._.js → _0vq0c0x._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_096x3u~._.js.map → _0vq0c0x._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/_0vyfc4b._.js +1 -1
- package/web/.next/server/chunks/ssr/_0vyfc4b._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_0w-_hww._.js +1 -1
- package/web/.next/server/chunks/ssr/_0w-_hww._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_0zk-h5w._.js +1 -1
- package/web/.next/server/chunks/ssr/_0zk-h5w._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_0~7lwu_._.js +1 -1
- package/web/.next/server/chunks/ssr/_0~7lwu_._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_0~g5-.e._.js +3 -0
- package/web/.next/server/chunks/ssr/_0~g5-.e._.js.map +1 -0
- package/web/.next/server/chunks/ssr/_1161g9x._.js +1 -1
- package/web/.next/server/chunks/ssr/_1161g9x._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_mcp-servers_page_actions_0d.r4q..js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_mcp-servers_page_actions_0d.r4q..js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_plugins_page_actions_0rdndum.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_plugins_page_actions_0rdndum.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_05m2q~u.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_05m2q~u.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_0.6zk.t.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_0.6zk.t.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_app_actions_approve-feature_ts_0pjb_re._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_app_actions_open-ide_ts_0w2wqvu._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_0l3oxx9._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_0l3oxx9._.js.map +1 -1
- package/web/.next/server/middleware-build-manifest.js +3 -3
- package/web/.next/server/pages/500.html +1 -1
- package/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/server/server-reference-manifest.json +57 -57
- package/web/.next/static/chunks/{0whqmoyf3zd67.js → 0-m4rnec155i1.js} +1 -1
- package/web/.next/static/chunks/02940.vqpqt~w.js +8 -0
- package/web/.next/static/chunks/{0t~1ohqb2m7ma.js → 094xbjw.1t41_.js} +1 -1
- package/web/.next/static/chunks/{0ul697ie_gsw9.js → 0_bfubsp9neaf.js} +1 -1
- package/web/.next/static/chunks/0a~-dbzk6tkpw.css +1 -0
- package/web/.next/static/chunks/{159n33nvplqug.js → 0g304jt8qhu-~.js} +1 -1
- package/web/.next/static/chunks/{0pb77veci.7gd.js → 0k4d8i58i.mo0.js} +1 -1
- package/web/.next/static/chunks/0lb_dekd7d4xu.js +1 -0
- package/web/.next/static/chunks/{08w-qt8wfe5u..js → 0lc14m5evyhuu.js} +1 -1
- package/web/.next/static/chunks/{07kpqi8hle98h.js → 0lt_ok~0hysqu.js} +1 -1
- package/web/.next/static/chunks/{06_a861w0tkp6.js → 0nct2gnbj84mf.js} +1 -1
- package/web/.next/static/chunks/{0xee.1sl6c~24.js → 0nm97zmm.ri8o.js} +1 -1
- package/web/.next/static/chunks/{10p0lo4adb2~5.js → 0y~7z3sw~k~a3.js} +1 -1
- package/web/.next/static/chunks/{0mekjif_lg0-r.js → 0~5w460yes32a.js} +2 -2
- package/web/.next/static/chunks/{10j-adknfho63.js → 10rtagfoabp3b.js} +1 -1
- package/web/.next/static/chunks/{0~9hrc9~63dvr.js → 13wohdlnw9eid.js} +1 -1
- package/web/.next/static/chunks/{050mn~oci41h6.js → 15qu-.zhd9f48.js} +3 -3
- package/web/public/icons/tools/openai.svg +1 -0
- package/web/.next/server/chunks/ssr/_0vm01xk._.js +0 -3
- package/web/.next/server/chunks/ssr/_0vm01xk._.js.map +0 -1
- package/web/.next/static/chunks/0h2nh2s2b3ma2.css +0 -1
- package/web/.next/static/chunks/14ixmk5pm1-rc.js +0 -8
- package/web/.next/static/chunks/167z9~gq-q~oy.js +0 -1
- /package/web/.next/static/{q4u94V1z_KGlqS1uxSgT2 → MgGhOZyXLY0dmh1EnLE2U}/_buildManifest.js +0 -0
- /package/web/.next/static/{q4u94V1z_KGlqS1uxSgT2 → MgGhOZyXLY0dmh1EnLE2U}/_clientMiddlewareManifest.js +0 -0
- /package/web/.next/static/{q4u94V1z_KGlqS1uxSgT2 → MgGhOZyXLY0dmh1EnLE2U}/_ssgManifest.js +0 -0
|
@@ -134,17 +134,62 @@ async function fetchJson(endpoint, options) {
|
|
|
134
134
|
});
|
|
135
135
|
if (!res.ok)
|
|
136
136
|
return null;
|
|
137
|
+
const contentType = res.headers.get('content-type')?.toLowerCase() ?? '';
|
|
137
138
|
const text = await res.text();
|
|
138
139
|
if (text.length > MAX_RESPONSE_SIZE)
|
|
139
140
|
return null;
|
|
141
|
+
// MCP Streamable HTTP transport may return either application/json
|
|
142
|
+
// or text/event-stream. SSE responses look like:
|
|
143
|
+
// event: message
|
|
144
|
+
// data: {"jsonrpc":"2.0","id":1,"result":{"tools":[...]}}
|
|
145
|
+
//
|
|
146
|
+
// We extract the first `data:` line's payload and parse that as JSON.
|
|
147
|
+
// If the content type is JSON, we parse directly.
|
|
148
|
+
if (contentType.includes('text/event-stream')) {
|
|
149
|
+
return parseSseFirstDataEvent(text);
|
|
150
|
+
}
|
|
140
151
|
try {
|
|
141
152
|
return JSON.parse(text);
|
|
142
153
|
}
|
|
143
154
|
catch {
|
|
144
|
-
return
|
|
155
|
+
// Some servers omit the content-type header but return SSE anyway.
|
|
156
|
+
// Try SSE parsing as a fallback before giving up.
|
|
157
|
+
return parseSseFirstDataEvent(text);
|
|
145
158
|
}
|
|
146
159
|
}
|
|
147
160
|
finally {
|
|
148
161
|
clearTimeout(timeout);
|
|
149
162
|
}
|
|
150
163
|
}
|
|
164
|
+
/**
|
|
165
|
+
* Extract the first `data: ...` payload from a Server-Sent Events response
|
|
166
|
+
* body and parse it as JSON. Returns null if no valid data line is found.
|
|
167
|
+
*
|
|
168
|
+
* Handles:
|
|
169
|
+
* event: message
|
|
170
|
+
* data: {"jsonrpc":"2.0",...}
|
|
171
|
+
*
|
|
172
|
+
* And multi-line data fields (per SSE spec — though rare for MCP).
|
|
173
|
+
*/
|
|
174
|
+
function parseSseFirstDataEvent(body) {
|
|
175
|
+
const lines = body.split(/\r?\n/);
|
|
176
|
+
const dataParts = [];
|
|
177
|
+
for (const line of lines) {
|
|
178
|
+
if (line.startsWith('data:')) {
|
|
179
|
+
// Strip the "data:" prefix and any single leading space.
|
|
180
|
+
dataParts.push(line.slice(5).replace(/^ /, ''));
|
|
181
|
+
}
|
|
182
|
+
else if (line === '' && dataParts.length > 0) {
|
|
183
|
+
// Empty line terminates the first SSE event — stop collecting.
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (dataParts.length === 0)
|
|
188
|
+
return null;
|
|
189
|
+
try {
|
|
190
|
+
return JSON.parse(dataParts.join('\n'));
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"author": "OpenAI",
|
|
7
7
|
"website": "https://github.com/openai/codex",
|
|
8
8
|
"platforms": ["linux", "darwin", "win32"],
|
|
9
|
-
"iconUrl": "
|
|
9
|
+
"iconUrl": "/icons/tools/openai.svg",
|
|
10
10
|
"binary": "codex",
|
|
11
11
|
"packageManager": "npm",
|
|
12
12
|
"commands": {
|
package/dist/src/presentation/web/components/features/mcp-servers/mcp-connect-instructions.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-connect-instructions.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/mcp-servers/mcp-connect-instructions.tsx"],"names":[],"mappings":"AAOA,UAAU,2BAA2B;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,KAAK,QAAQ,GAAG,aAAa,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC;AAgBlF;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAkFjG;AAED,wBAAgB,sBAAsB,CAAC,EAAE,YAAY,EAAE,UAAU,EAAE,EAAE,2BAA2B,
|
|
1
|
+
{"version":3,"file":"mcp-connect-instructions.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/mcp-servers/mcp-connect-instructions.tsx"],"names":[],"mappings":"AAOA,UAAU,2BAA2B;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,KAAK,QAAQ,GAAG,aAAa,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC;AAgBlF;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAkFjG;AAED,wBAAgB,sBAAsB,CAAC,EAAE,YAAY,EAAE,UAAU,EAAE,EAAE,2BAA2B,2CAkE/F"}
|
package/dist/src/presentation/web/components/features/mcp-servers/mcp-connect-instructions.js
CHANGED
|
@@ -102,7 +102,5 @@ export function McpConnectInstructions({ proxyBaseUrl, serverName }) {
|
|
|
102
102
|
// Clipboard not available (e.g., insecure context) — silently ignore.
|
|
103
103
|
}
|
|
104
104
|
};
|
|
105
|
-
return (_jsxs("div", { className: "space-y-3", children: [_jsx("div", { className: "flex flex-wrap gap-1", role: "tablist", children: CLIENTS.map((client) => (_jsx("button", { type: "button", role: "tab", "aria-selected": activeClient === client.id, onClick: () => setActiveClient(client.id),
|
|
106
|
-
? 'bg-primary text-primary-foreground rounded-md px-2.5 py-1 text-xs font-medium'
|
|
107
|
-
: 'border-border hover:bg-muted rounded-md border px-2.5 py-1 text-xs', children: client.label }, client.id))) }), _jsxs("div", { className: "relative", children: [_jsx("pre", { className: "bg-muted max-h-64 overflow-auto rounded-md p-3 pr-10 font-mono text-[11px] leading-relaxed", children: _jsx("code", { children: snippet }) }), _jsx(Button, { type: "button", variant: "ghost", size: "icon", className: "absolute top-1 right-1 h-7 w-7", onClick: handleCopy, "aria-label": t('mcpServers.connect.copy'), children: copied ? (_jsx(Check, { className: "text-primary h-3.5 w-3.5" })) : (_jsx(Copy, { className: "h-3.5 w-3.5" })) })] }), _jsx("p", { className: "text-muted-foreground text-xs", children: t('mcpServers.connect.replaceKey') })] }));
|
|
105
|
+
return (_jsxs("div", { className: "space-y-3", children: [_jsx("div", { className: "flex flex-wrap gap-1.5 rounded-lg border border-slate-200/60 bg-slate-50/50 p-1 dark:border-slate-700/50 dark:bg-slate-900/40", role: "tablist", "aria-label": t('mcpServers.connect.title'), children: CLIENTS.map((client) => (_jsx("button", { type: "button", role: "tab", "aria-selected": activeClient === client.id, onClick: () => setActiveClient(client.id), "data-state": activeClient === client.id ? 'active' : 'inactive', className: "data-[state=active]:bg-card data-[state=active]:text-primary text-muted-foreground hover:text-foreground rounded-md px-2.5 py-1 text-xs font-medium transition-all data-[state=active]:shadow-sm data-[state=active]:ring-1 data-[state=active]:ring-slate-200/70 dark:data-[state=active]:ring-slate-700/50", children: client.label }, client.id))) }), _jsxs("div", { className: "editorial-shadow group relative overflow-hidden rounded-xl border border-slate-200/60 bg-slate-50/60 dark:border-slate-700/50 dark:bg-slate-900/60", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-slate-200/60 bg-slate-100/40 px-3 py-2 dark:border-slate-700/50 dark:bg-slate-900/40", children: [_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: "size-2 rounded-full bg-slate-300 dark:bg-slate-600", "aria-hidden": true }), _jsx("span", { className: "size-2 rounded-full bg-slate-300 dark:bg-slate-600", "aria-hidden": true }), _jsx("span", { className: "size-2 rounded-full bg-slate-300 dark:bg-slate-600", "aria-hidden": true })] }), _jsx(Button, { type: "button", variant: "ghost", size: "icon", className: "size-6 shrink-0", onClick: handleCopy, "aria-label": t('mcpServers.connect.copy'), children: copied ? _jsx(Check, { className: "text-primary size-3" }) : _jsx(Copy, { className: "size-3" }) })] }), _jsx("pre", { className: "max-h-64 overflow-auto p-3 font-mono text-[11px] leading-relaxed", children: _jsx("code", { children: snippet }) })] }), _jsx("p", { className: "text-muted-foreground text-xs", children: t('mcpServers.connect.replaceKey') })] }));
|
|
108
106
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-server-card.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/mcp-servers/mcp-server-card.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gFAAgF,CAAC;AAEpH,UAAU,kBAAkB;IAC1B,MAAM,EAAE,aAAa,CAAC;IACtB,QAAQ,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAC;CAC3C;
|
|
1
|
+
{"version":3,"file":"mcp-server-card.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/mcp-servers/mcp-server-card.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gFAAgF,CAAC;AAEpH,UAAU,kBAAkB;IAC1B,MAAM,EAAE,aAAa,CAAC;IACtB,QAAQ,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAC;CAC3C;AAED,wBAAgB,aAAa,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,kBAAkB,2CAkDrE"}
|
|
@@ -3,20 +3,14 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { useTranslation } from 'react-i18next';
|
|
4
4
|
import { Card } from '../../ui/card.js';
|
|
5
5
|
import { Badge } from '../../ui/badge.js';
|
|
6
|
-
import {
|
|
7
|
-
const TRANSPORT_ICONS = {
|
|
8
|
-
http: Server,
|
|
9
|
-
sse: Wifi,
|
|
10
|
-
stdio: Terminal,
|
|
11
|
-
};
|
|
6
|
+
import { McpServerIcon } from './mcp-server-icon.js';
|
|
12
7
|
export function McpServerCard({ server, onSelect }) {
|
|
13
8
|
const { t } = useTranslation('web');
|
|
14
|
-
const TransportIcon = TRANSPORT_ICONS[server.transport] ?? Server;
|
|
15
9
|
const description = server.mcp_info?.description ?? '';
|
|
16
10
|
return (_jsxs(Card, { className: "cursor-pointer p-5 transition-all duration-300 hover:scale-[1.02] hover:shadow-md hover:ring-slate-300 dark:hover:ring-slate-600", role: "button", tabIndex: 0, onClick: () => onSelect(server), onKeyDown: (e) => {
|
|
17
11
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
18
12
|
e.preventDefault();
|
|
19
13
|
onSelect(server);
|
|
20
14
|
}
|
|
21
|
-
}, children: [_jsxs("div", { className: "flex items-start
|
|
15
|
+
}, "data-testid": `mcp-server-card-${server.server_name}`, children: [_jsxs("div", { className: "flex items-start gap-3", children: [_jsx("div", { className: "flex size-11 shrink-0 items-center justify-center rounded-lg bg-slate-100 ring-1 ring-slate-200/50 dark:bg-slate-800 dark:ring-slate-700/50", children: _jsx(McpServerIcon, { serverName: server.server_name, url: server.url, transport: server.transport, size: "md" }) }), _jsx("h3", { className: "text-foreground mt-2 min-w-0 flex-1 truncate text-sm leading-tight font-bold tracking-tight", children: server.name })] }), description ? (_jsx("p", { className: "text-muted-foreground mt-3 line-clamp-2 text-xs leading-relaxed", children: description })) : null, _jsxs("div", { className: "mt-4 flex flex-wrap items-center gap-1.5", children: [_jsx(Badge, { variant: "outline", children: t(`mcpServers.transport.${server.transport}`, server.transport.toUpperCase()) }), server.auth_type && server.auth_type !== 'none' ? (_jsx(Badge, { variant: "secondary", children: t(`mcpServers.authType.${server.auth_type}`, server.auth_type) })) : null] })] }));
|
|
22
16
|
}
|
package/dist/src/presentation/web/components/features/mcp-servers/mcp-server-detail-drawer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-server-detail-drawer.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/mcp-servers/mcp-server-detail-drawer.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mcp-server-detail-drawer.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/mcp-servers/mcp-server-detail-drawer.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,EACV,aAAa,EAEd,MAAM,gFAAgF,CAAC;AAExF,UAAU,0BAA0B;IAClC,MAAM,EAAE,aAAa,GAAG,IAAI,CAAC;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAYD,wBAAgB,qBAAqB,CAAC,EACpC,MAAM,EACN,YAAY,EACZ,IAAI,EACJ,OAAO,GACR,EAAE,0BAA0B,kDA2J5B"}
|
package/dist/src/presentation/web/components/features/mcp-servers/mcp-server-detail-drawer.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import {
|
|
2
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import { useEffect, useState, useCallback } from 'react';
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
5
|
import { BaseDrawer } from '../../common/base-drawer/index.js';
|
|
@@ -10,6 +10,7 @@ import { Button } from '../../ui/button.js';
|
|
|
10
10
|
import { RefreshCw } from 'lucide-react';
|
|
11
11
|
import { McpToolList } from './mcp-tool-list.js';
|
|
12
12
|
import { McpConnectInstructions } from './mcp-connect-instructions.js';
|
|
13
|
+
import { McpServerIcon } from './mcp-server-icon.js';
|
|
13
14
|
import { fetchMcpServerToolsAction } from '../../../app/actions/fetch-mcp-server-tools.js';
|
|
14
15
|
function isValidDisplayUrl(url) {
|
|
15
16
|
if (!url)
|
|
@@ -56,13 +57,13 @@ export function McpServerDetailDrawer({ server, proxyBaseUrl, open, onClose, })
|
|
|
56
57
|
const handleRefresh = useCallback(() => {
|
|
57
58
|
if (!server)
|
|
58
59
|
return;
|
|
59
|
-
// Clear the cached server name to force a re-fetch
|
|
60
|
-
//
|
|
60
|
+
// Clear the cached server name to force a re-fetch and call loadTools
|
|
61
|
+
// directly for immediate feedback.
|
|
61
62
|
setLoadedServerName(null);
|
|
62
63
|
loadTools(server.server_name);
|
|
63
64
|
}, [server, loadTools]);
|
|
64
65
|
if (!server)
|
|
65
66
|
return null;
|
|
66
67
|
const description = server.mcp_info?.description ?? '';
|
|
67
|
-
return (
|
|
68
|
+
return (_jsx(BaseDrawer, { open: open, onClose: onClose, "data-testid": "mcp-server-detail-drawer", children: _jsxs("div", { className: "flex flex-col gap-6 overflow-y-auto p-6", children: [_jsxs("div", { className: "space-y-2", children: [_jsxs("span", { className: "text-[10px] font-bold tracking-[0.2em] text-slate-400 uppercase", children: [t(`mcpServers.transport.${server.transport}`, server.transport.toUpperCase()), " \u00B7 MCP Server"] }), _jsxs("div", { className: "flex items-start gap-3", children: [_jsx("div", { className: "flex size-12 shrink-0 items-center justify-center rounded-lg bg-slate-100 ring-1 ring-slate-200/50 dark:bg-slate-800 dark:ring-slate-700/50", children: _jsx(McpServerIcon, { serverName: server.server_name, url: server.url, transport: server.transport, size: "lg" }) }), _jsx(DrawerTitle, { className: "text-foreground mt-2 text-lg font-bold tracking-tight", children: server.name })] }), description ? (_jsx(DrawerDescription, { className: "text-muted-foreground text-sm leading-relaxed", children: description })) : null] }), _jsx(Separator, {}), _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-muted-foreground text-xs font-medium", children: t('mcpServers.detail.serverName') }), _jsx("span", { className: "font-mono text-xs", children: server.server_name })] }), isValidDisplayUrl(server.url) ? (_jsxs("div", { className: "flex items-center justify-between gap-4", children: [_jsx("span", { className: "text-muted-foreground shrink-0 text-xs font-medium", children: t('mcpServers.detail.url') }), _jsx("span", { className: "truncate font-mono text-xs", title: server.url, children: server.url })] })) : null, _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-muted-foreground text-xs font-medium", children: t('mcpServers.detail.transport') }), _jsx(Badge, { variant: "outline", children: t(`mcpServers.transport.${server.transport}`, server.transport.toUpperCase()) })] }), server.auth_type && server.auth_type !== 'none' ? (_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-muted-foreground text-xs font-medium", children: t('mcpServers.detail.authType') }), _jsx(Badge, { variant: "secondary", children: t(`mcpServers.authType.${server.auth_type}`, server.auth_type) })] })) : null] }), _jsx(Separator, {}), _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("h3", { className: "text-foreground text-sm font-bold tracking-tight", children: t('mcpServers.tools.title') }), _jsx(Button, { type: "button", variant: "ghost", size: "icon", className: "size-7", onClick: handleRefresh, disabled: loadingTools, "aria-label": t('mcpServers.tools.refresh'), "data-testid": "mcp-tools-refresh", children: _jsx(RefreshCw, { className: `size-3.5 ${loadingTools ? 'animate-spin' : ''}` }) })] }), loadingTools ? (_jsxs("p", { className: "text-muted-foreground text-sm", children: [t('accessibility.loading'), "..."] })) : toolError ? (_jsx("p", { className: "text-destructive text-sm", children: toolError })) : (_jsx(McpToolList, { tools: tools, serverName: server.server_name }))] }), _jsx(Separator, {}), _jsxs("div", { className: "space-y-3", children: [_jsx("h3", { className: "text-foreground text-sm font-bold tracking-tight", children: t('mcpServers.connect.title') }), _jsx(McpConnectInstructions, { proxyBaseUrl: proxyBaseUrl, serverName: server.server_name })] })] }) }));
|
|
68
69
|
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { type ComponentType } from 'react';
|
|
2
|
+
interface McpServerIconProps {
|
|
3
|
+
serverName: string;
|
|
4
|
+
url?: string;
|
|
5
|
+
transport: string;
|
|
6
|
+
className?: string;
|
|
7
|
+
size?: 'sm' | 'md' | 'lg';
|
|
8
|
+
}
|
|
9
|
+
type BrandIconComponent = ComponentType<{
|
|
10
|
+
className?: string;
|
|
11
|
+
size?: number;
|
|
12
|
+
}>;
|
|
13
|
+
export type VendorResolution = {
|
|
14
|
+
kind: 'inline';
|
|
15
|
+
component: BrandIconComponent;
|
|
16
|
+
} | {
|
|
17
|
+
kind: 'simpleicons';
|
|
18
|
+
slug: string;
|
|
19
|
+
} | {
|
|
20
|
+
kind: 'none';
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Resolve a vendor icon for an MCP server by matching name and URL against
|
|
24
|
+
* the VENDOR_MAP patterns. Returns an inline component, a SimpleIcons slug,
|
|
25
|
+
* or 'none' (caller falls back to transport icon).
|
|
26
|
+
*
|
|
27
|
+
* Exported for unit testing.
|
|
28
|
+
*/
|
|
29
|
+
export declare function resolveVendorMapping(serverName: string, url?: string): VendorResolution;
|
|
30
|
+
/**
|
|
31
|
+
* Renders an MCP server's brand icon when recognizable, falling back to the
|
|
32
|
+
* transport-type icon otherwise.
|
|
33
|
+
*
|
|
34
|
+
* Resolution order:
|
|
35
|
+
* 1. Inline brand SVG (Microsoft, Azure, DeepWiki, Firecrawl, AWS)
|
|
36
|
+
* 2. SimpleIcons CDN image (GitHub, Stripe, Postgres, etc.)
|
|
37
|
+
* 3. Transport fallback (Server/Wifi/Terminal from lucide-react)
|
|
38
|
+
*
|
|
39
|
+
* For SimpleIcons images, we handle `onError` by swapping to the transport
|
|
40
|
+
* fallback — this protects against SimpleIcons slug changes without breaking
|
|
41
|
+
* the UI.
|
|
42
|
+
*/
|
|
43
|
+
export declare function McpServerIcon({ serverName, url, transport, className, size, }: McpServerIconProps): import("react/jsx-runtime").JSX.Element;
|
|
44
|
+
export {};
|
|
45
|
+
//# sourceMappingURL=mcp-server-icon.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-server-icon.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/mcp-servers/mcp-server-icon.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAY,KAAK,aAAa,EAAE,MAAM,OAAO,CAAC;AAYrD,UAAU,kBAAkB;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;CAC3B;AAED,KAAK,kBAAkB,GAAG,aAAa,CAAC;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AA4F/E,MAAM,MAAM,gBAAgB,GACxB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,kBAAkB,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACrC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAErB;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,gBAAgB,CASvF;AAoBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,EAC5B,UAAU,EACV,GAAG,EACH,SAAS,EACT,SAAS,EACT,IAAW,GACZ,EAAE,kBAAkB,2CA6BpB"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { Server, Wifi, Terminal } from 'lucide-react';
|
|
5
|
+
import { MicrosoftIcon, MicrosoftLearnIcon, AzureIcon, FirecrawlIcon, DeepWikiIcon, AwsIcon, } from './vendor-brand-icons.js';
|
|
6
|
+
/**
|
|
7
|
+
* Vendor icon resolution map.
|
|
8
|
+
*
|
|
9
|
+
* Priority rules:
|
|
10
|
+
* 1. More-specific patterns FIRST (e.g. `microsoft_learn` before `microsoft`,
|
|
11
|
+
* `github_copilot` before plain `github`).
|
|
12
|
+
* 2. Inline SVG brand icons take priority over SimpleIcons when both are
|
|
13
|
+
* available — inline icons are guaranteed to render and have no CDN
|
|
14
|
+
* dependency.
|
|
15
|
+
* 3. Verified slugs only. Every SimpleIcons slug in this file must return
|
|
16
|
+
* HTTP 200 from https://cdn.simpleicons.org/{slug} as of the last audit.
|
|
17
|
+
*
|
|
18
|
+
* When no vendor matches, the `McpServerIcon` component falls back to the
|
|
19
|
+
* transport-type Lucide icon (Server/Wifi/Terminal).
|
|
20
|
+
*
|
|
21
|
+
* Exported `resolveVendorMapping` is the source of truth for tests.
|
|
22
|
+
*/
|
|
23
|
+
const VENDOR_MAP = [
|
|
24
|
+
// Microsoft (SimpleIcons removed all MS icons for legal reasons — use inline)
|
|
25
|
+
{ match: /microsoft[_-]?learn|learn\.microsoft/, inlineIcon: MicrosoftLearnIcon },
|
|
26
|
+
{ match: /foundry|ai\.azure|azure[_-]?foundry|bedrock[_-]?agentcore/, inlineIcon: AzureIcon },
|
|
27
|
+
{ match: /\bazure\b/, inlineIcon: AzureIcon },
|
|
28
|
+
{ match: /microsoft|\.microsoft\./, inlineIcon: MicrosoftIcon },
|
|
29
|
+
// GitHub / Copilot (SimpleIcons has these)
|
|
30
|
+
{ match: /github[_-]?copilot|\bcopilot\b/, simpleIconSlug: 'githubcopilot' },
|
|
31
|
+
{ match: /github|api\.github/, simpleIconSlug: 'github' },
|
|
32
|
+
{ match: /gitlab/, simpleIconSlug: 'gitlab' },
|
|
33
|
+
{ match: /bitbucket/, simpleIconSlug: 'bitbucket' },
|
|
34
|
+
// AI / LLM vendors
|
|
35
|
+
{ match: /anthropic|\bclaude\b/, simpleIconSlug: 'anthropic' },
|
|
36
|
+
{ match: /gemini|google[_-]?ai/, simpleIconSlug: 'googlegemini' },
|
|
37
|
+
{ match: /perplexity/, simpleIconSlug: 'perplexity' },
|
|
38
|
+
// Documentation / knowledge (DeepWiki gets its own distinct mark)
|
|
39
|
+
{ match: /deepwiki|deep[_-]?wiki/, inlineIcon: DeepWikiIcon },
|
|
40
|
+
{ match: /notion/, simpleIconSlug: 'notion' },
|
|
41
|
+
{ match: /confluence/, simpleIconSlug: 'confluence' },
|
|
42
|
+
{ match: /readthedocs/, simpleIconSlug: 'readthedocs' },
|
|
43
|
+
{ match: /mintlify/, simpleIconSlug: 'mintlify' },
|
|
44
|
+
// Web scraping / crawling (inline for Firecrawl — no SimpleIcons)
|
|
45
|
+
{ match: /firecrawl/, inlineIcon: FirecrawlIcon },
|
|
46
|
+
// Cloud / infra
|
|
47
|
+
{ match: /\baws\b|amazon[_-]?web|bedrock/, inlineIcon: AwsIcon },
|
|
48
|
+
{ match: /cloudflare/, simpleIconSlug: 'cloudflare' },
|
|
49
|
+
{ match: /vercel/, simpleIconSlug: 'vercel' },
|
|
50
|
+
{ match: /netlify/, simpleIconSlug: 'netlify' },
|
|
51
|
+
{ match: /digitalocean/, simpleIconSlug: 'digitalocean' },
|
|
52
|
+
{ match: /railway/, simpleIconSlug: 'railway' },
|
|
53
|
+
// Databases
|
|
54
|
+
{ match: /postgres/, simpleIconSlug: 'postgresql' },
|
|
55
|
+
{ match: /mongodb/, simpleIconSlug: 'mongodb' },
|
|
56
|
+
{ match: /\bredis\b/, simpleIconSlug: 'redis' },
|
|
57
|
+
{ match: /mysql/, simpleIconSlug: 'mysql' },
|
|
58
|
+
{ match: /sqlite/, simpleIconSlug: 'sqlite' },
|
|
59
|
+
{ match: /supabase/, simpleIconSlug: 'supabase' },
|
|
60
|
+
{ match: /planetscale/, simpleIconSlug: 'planetscale' },
|
|
61
|
+
// Productivity / collaboration
|
|
62
|
+
{ match: /slack/, simpleIconSlug: 'slack' },
|
|
63
|
+
{ match: /discord/, simpleIconSlug: 'discord' },
|
|
64
|
+
{ match: /linear/, simpleIconSlug: 'linear' },
|
|
65
|
+
{ match: /jira|atlassian/, simpleIconSlug: 'jira' },
|
|
66
|
+
{ match: /asana/, simpleIconSlug: 'asana' },
|
|
67
|
+
{ match: /zapier/, simpleIconSlug: 'zapier' },
|
|
68
|
+
// Observability
|
|
69
|
+
{ match: /datadog/, simpleIconSlug: 'datadog' },
|
|
70
|
+
{ match: /sentry/, simpleIconSlug: 'sentry' },
|
|
71
|
+
{ match: /grafana/, simpleIconSlug: 'grafana' },
|
|
72
|
+
{ match: /newrelic/, simpleIconSlug: 'newrelic' },
|
|
73
|
+
// Payments / commerce
|
|
74
|
+
{ match: /stripe/, simpleIconSlug: 'stripe' },
|
|
75
|
+
{ match: /shopify/, simpleIconSlug: 'shopify' },
|
|
76
|
+
];
|
|
77
|
+
/**
|
|
78
|
+
* Resolve a vendor icon for an MCP server by matching name and URL against
|
|
79
|
+
* the VENDOR_MAP patterns. Returns an inline component, a SimpleIcons slug,
|
|
80
|
+
* or 'none' (caller falls back to transport icon).
|
|
81
|
+
*
|
|
82
|
+
* Exported for unit testing.
|
|
83
|
+
*/
|
|
84
|
+
export function resolveVendorMapping(serverName, url) {
|
|
85
|
+
const haystack = `${serverName} ${url ?? ''}`.toLowerCase();
|
|
86
|
+
for (const entry of VENDOR_MAP) {
|
|
87
|
+
if (entry.match.test(haystack)) {
|
|
88
|
+
if (entry.inlineIcon)
|
|
89
|
+
return { kind: 'inline', component: entry.inlineIcon };
|
|
90
|
+
if (entry.simpleIconSlug)
|
|
91
|
+
return { kind: 'simpleicons', slug: entry.simpleIconSlug };
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return { kind: 'none' };
|
|
95
|
+
}
|
|
96
|
+
const TRANSPORT_FALLBACKS = {
|
|
97
|
+
http: Server,
|
|
98
|
+
sse: Wifi,
|
|
99
|
+
stdio: Terminal,
|
|
100
|
+
};
|
|
101
|
+
const SIZE_CLASSES = {
|
|
102
|
+
sm: 'size-4',
|
|
103
|
+
md: 'size-5',
|
|
104
|
+
lg: 'size-6',
|
|
105
|
+
};
|
|
106
|
+
const SIZE_PIXELS = {
|
|
107
|
+
sm: 16,
|
|
108
|
+
md: 20,
|
|
109
|
+
lg: 24,
|
|
110
|
+
};
|
|
111
|
+
/**
|
|
112
|
+
* Renders an MCP server's brand icon when recognizable, falling back to the
|
|
113
|
+
* transport-type icon otherwise.
|
|
114
|
+
*
|
|
115
|
+
* Resolution order:
|
|
116
|
+
* 1. Inline brand SVG (Microsoft, Azure, DeepWiki, Firecrawl, AWS)
|
|
117
|
+
* 2. SimpleIcons CDN image (GitHub, Stripe, Postgres, etc.)
|
|
118
|
+
* 3. Transport fallback (Server/Wifi/Terminal from lucide-react)
|
|
119
|
+
*
|
|
120
|
+
* For SimpleIcons images, we handle `onError` by swapping to the transport
|
|
121
|
+
* fallback — this protects against SimpleIcons slug changes without breaking
|
|
122
|
+
* the UI.
|
|
123
|
+
*/
|
|
124
|
+
export function McpServerIcon({ serverName, url, transport, className, size = 'sm', }) {
|
|
125
|
+
const [imageFailed, setImageFailed] = useState(false);
|
|
126
|
+
const resolution = resolveVendorMapping(serverName, url);
|
|
127
|
+
const FallbackIcon = TRANSPORT_FALLBACKS[transport] ?? Server;
|
|
128
|
+
const sizeClass = SIZE_CLASSES[size];
|
|
129
|
+
const sizePx = SIZE_PIXELS[size];
|
|
130
|
+
if (resolution.kind === 'inline') {
|
|
131
|
+
const Brand = resolution.component;
|
|
132
|
+
return _jsx(Brand, { className: `${sizeClass} shrink-0 ${className ?? ''}`, size: sizePx });
|
|
133
|
+
}
|
|
134
|
+
if (resolution.kind === 'simpleicons' && !imageFailed) {
|
|
135
|
+
return (_jsx("img", { src: `https://cdn.simpleicons.org/${resolution.slug}`, alt: "", width: sizePx, height: sizePx, className: `${sizeClass} shrink-0 ${className ?? ''}`, onError: () => setImageFailed(true) }));
|
|
136
|
+
}
|
|
137
|
+
return (_jsx(FallbackIcon, { className: `text-muted-foreground ${sizeClass} shrink-0 ${className ?? ''}` }));
|
|
138
|
+
}
|
package/dist/src/presentation/web/components/features/mcp-servers/mcp-servers-page-client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-servers-page-client.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/mcp-servers/mcp-servers-page-client.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mcp-servers-page-client.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/mcp-servers/mcp-servers-page-client.tsx"],"names":[],"mappings":"AAcA,UAAU,yBAAyB;IACjC,eAAe,EAAE,OAAO,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;CACtB;AAID,wBAAgB,oBAAoB,CAAC,EAAE,eAAe,EAAE,YAAY,EAAE,EAAE,yBAAyB,2CA2IhG"}
|
package/dist/src/presentation/web/components/features/mcp-servers/mcp-servers-page-client.js
CHANGED
|
@@ -4,8 +4,9 @@ import { useState, useEffect, useMemo } from 'react';
|
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
5
|
import { AlertCircle, Search, Server } from 'lucide-react';
|
|
6
6
|
import { Input } from '../../ui/input.js';
|
|
7
|
-
import {
|
|
7
|
+
import { Button } from '../../ui/button.js';
|
|
8
8
|
import { EmptyState } from '../../common/empty-state/index.js';
|
|
9
|
+
import { PageHeader } from '../../common/page-header/index.js';
|
|
9
10
|
import { McpServerCard } from './mcp-server-card.js';
|
|
10
11
|
import { McpServerDetailDrawer } from './mcp-server-detail-drawer.js';
|
|
11
12
|
import { fetchMcpServersAction } from '../../../app/actions/fetch-mcp-servers.js';
|
|
@@ -47,12 +48,12 @@ export function McpServersPageClient({ proxyConfigured, proxyBaseUrl }) {
|
|
|
47
48
|
});
|
|
48
49
|
}, [servers, searchQuery, transportFilter]);
|
|
49
50
|
if (!proxyConfigured) {
|
|
50
|
-
return (
|
|
51
|
+
return (_jsxs("div", { className: "flex flex-col gap-8 p-8", children: [_jsx(PageHeader, { eyebrow: "Developer Portal", title: t('mcpServers.title'), description: t('mcpServers.subtitle') }), _jsx(EmptyState, { icon: _jsx(AlertCircle, { className: "size-10" }), title: t('mcpServers.noProxy') })] }));
|
|
51
52
|
}
|
|
52
53
|
if (loading) {
|
|
53
|
-
return (
|
|
54
|
+
return (_jsxs("div", { className: "flex flex-col gap-8 p-8", children: [_jsx(PageHeader, { eyebrow: "Developer Portal", title: t('mcpServers.title'), description: t('mcpServers.subtitle') }), _jsxs("div", { className: "text-muted-foreground text-center text-sm", children: [t('accessibility.loading'), "..."] })] }));
|
|
54
55
|
}
|
|
55
|
-
return (_jsxs("div", { className: "
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
return (_jsxs("div", { className: "flex flex-col gap-8 p-8", children: [_jsx(PageHeader, { eyebrow: "Developer Portal", title: t('mcpServers.title'), description: t('mcpServers.subtitle') }), error ? (_jsxs("div", { role: "alert", className: "border-destructive/40 bg-destructive/10 editorial-shadow flex items-center gap-2 rounded-xl border px-4 py-3", children: [_jsx(AlertCircle, { className: "text-destructive size-4 shrink-0" }), _jsx("p", { className: "text-destructive text-sm font-medium", children: error })] })) : null, _jsxs("div", { className: "relative", children: [_jsx(Search, { className: "text-muted-foreground absolute top-1/2 left-3 size-4 -translate-y-1/2" }), _jsx(Input, { placeholder: t('mcpServers.searchPlaceholder'), value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), className: "ps-9", "data-testid": "mcp-servers-search" })] }), _jsx("div", { className: "flex flex-wrap gap-2", children: TRANSPORT_FILTERS.map((filter) => (_jsx(Button, { variant: transportFilter === filter ? 'default' : 'outline', size: "sm", onClick: () => setTransportFilter(filter), "data-testid": `mcp-servers-filter-${filter}`, children: filter === 'all'
|
|
57
|
+
? t('mcpServers.filter.all')
|
|
58
|
+
: t(`mcpServers.transport.${filter}`, filter.toUpperCase()) }, filter))) }), filtered.length === 0 ? (_jsx(EmptyState, { icon: servers.length === 0 ? _jsx(Server, { className: "size-10" }) : _jsx(Search, { className: "size-10" }), title: servers.length === 0 ? t('mcpServers.noServers') : t('mcpServers.noResults') })) : (_jsx("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3", children: filtered.map((server) => (_jsx(McpServerCard, { server: server, onSelect: setSelectedServer }, server.server_id))) })), _jsx(McpServerDetailDrawer, { server: selectedServer, proxyBaseUrl: proxyBaseUrl, open: !!selectedServer, onClose: () => setSelectedServer(null) })] }));
|
|
58
59
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inline brand icons for MCP server vendors that SimpleIcons either doesn't
|
|
3
|
+
* serve (Microsoft — removed for legal reasons), hasn't added yet (Firecrawl,
|
|
4
|
+
* DeepWiki), or where we want a project-specific treatment.
|
|
5
|
+
*
|
|
6
|
+
* Using inline SVG instead of remote image URLs because:
|
|
7
|
+
* - No network request, no 404 risk, no CORS
|
|
8
|
+
* - Uses `currentColor` where possible so brand marks adapt to dark mode
|
|
9
|
+
* - All paths are public brand marks simplified to their geometric essentials
|
|
10
|
+
* to avoid trademark ambiguity
|
|
11
|
+
*/
|
|
12
|
+
interface BrandIconProps {
|
|
13
|
+
className?: string;
|
|
14
|
+
size?: number;
|
|
15
|
+
}
|
|
16
|
+
/** Microsoft four-square window mark (simplified from public brand guidelines). */
|
|
17
|
+
export declare function MicrosoftIcon({ className, size }: BrandIconProps): import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
/** Microsoft Learn — book + graduation cap motif. */
|
|
19
|
+
export declare function MicrosoftLearnIcon({ className, size }: BrandIconProps): import("react/jsx-runtime").JSX.Element;
|
|
20
|
+
/** Azure / Foundry — stylized mountain triangles mark. */
|
|
21
|
+
export declare function AzureIcon({ className, size }: BrandIconProps): import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
/** Firecrawl — flame mark. */
|
|
23
|
+
export declare function FirecrawlIcon({ className, size }: BrandIconProps): import("react/jsx-runtime").JSX.Element;
|
|
24
|
+
/** DeepWiki — stacked pages with magnifying lens motif. */
|
|
25
|
+
export declare function DeepWikiIcon({ className, size }: BrandIconProps): import("react/jsx-runtime").JSX.Element;
|
|
26
|
+
/** AWS — orange cube mark. */
|
|
27
|
+
export declare function AwsIcon({ className, size }: BrandIconProps): import("react/jsx-runtime").JSX.Element;
|
|
28
|
+
export {};
|
|
29
|
+
//# sourceMappingURL=vendor-brand-icons.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vendor-brand-icons.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/mcp-servers/vendor-brand-icons.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,UAAU,cAAc;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,mFAAmF;AACnF,wBAAgB,aAAa,CAAC,EAAE,SAAS,EAAE,IAAS,EAAE,EAAE,cAAc,2CAgBrE;AAED,qDAAqD;AACrD,wBAAgB,kBAAkB,CAAC,EAAE,SAAS,EAAE,IAAS,EAAE,EAAE,cAAc,2CAoB1E;AAED,0DAA0D;AAC1D,wBAAgB,SAAS,CAAC,EAAE,SAAS,EAAE,IAAS,EAAE,EAAE,cAAc,2CAcjE;AAED,8BAA8B;AAC9B,wBAAgB,aAAa,CAAC,EAAE,SAAS,EAAE,IAAS,EAAE,EAAE,cAAc,2CAiBrE;AAED,2DAA2D;AAC3D,wBAAgB,YAAY,CAAC,EAAE,SAAS,EAAE,IAAS,EAAE,EAAE,cAAc,2CA0BpE;AAED,8BAA8B;AAC9B,wBAAgB,OAAO,CAAC,EAAE,SAAS,EAAE,IAAS,EAAE,EAAE,cAAc,2CAiB/D"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/** Microsoft four-square window mark (simplified from public brand guidelines). */
|
|
3
|
+
export function MicrosoftIcon({ className, size = 20 }) {
|
|
4
|
+
return (_jsxs("svg", { className: className, width: size, height: size, viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: [_jsx("rect", { x: "2", y: "2", width: "9", height: "9", fill: "#F25022" }), _jsx("rect", { x: "13", y: "2", width: "9", height: "9", fill: "#7FBA00" }), _jsx("rect", { x: "2", y: "13", width: "9", height: "9", fill: "#00A4EF" }), _jsx("rect", { x: "13", y: "13", width: "9", height: "9", fill: "#FFB900" })] }));
|
|
5
|
+
}
|
|
6
|
+
/** Microsoft Learn — book + graduation cap motif. */
|
|
7
|
+
export function MicrosoftLearnIcon({ className, size = 20 }) {
|
|
8
|
+
return (_jsxs("svg", { className: className, width: size, height: size, viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: [_jsx("path", { d: "M3 6a1 1 0 0 1 1-1h6a2 2 0 0 1 2 2v13a1 1 0 0 1-1.447.894L6 18.618V7H4a1 1 0 0 1-1-1Z", fill: "#0078D4" }), _jsx("path", { d: "M21 6a1 1 0 0 0-1-1h-6a2 2 0 0 0-2 2v13a1 1 0 0 0 1.447.894L18 18.618V7h2a1 1 0 0 0 1-1Z", fill: "#50E6FF" })] }));
|
|
9
|
+
}
|
|
10
|
+
/** Azure / Foundry — stylized mountain triangles mark. */
|
|
11
|
+
export function AzureIcon({ className, size = 20 }) {
|
|
12
|
+
return (_jsxs("svg", { className: className, width: size, height: size, viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: [_jsx("path", { d: "M12 4L2 20h7l3-5 3 5h7L12 4Z", fill: "#0089D6" }), _jsx("path", { d: "M12 4l-3 5h6l-3-5Z", fill: "#54AEF0" })] }));
|
|
13
|
+
}
|
|
14
|
+
/** Firecrawl — flame mark. */
|
|
15
|
+
export function FirecrawlIcon({ className, size = 20 }) {
|
|
16
|
+
return (_jsxs("svg", { className: className, width: size, height: size, viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: [_jsx("path", { d: "M12 2C12 2 6 8 6 13a6 6 0 0 0 12 0c0-2-1-4-2-5 0 2-1 3-2 3 0-3-2-6-2-9Z", fill: "#F26B21" }), _jsx("path", { d: "M12 11c0 2-1.5 3-1.5 5a1.5 1.5 0 0 0 3 0c0-1.5-1.5-2.5-1.5-5Z", fill: "#FFD166" })] }));
|
|
17
|
+
}
|
|
18
|
+
/** DeepWiki — stacked pages with magnifying lens motif. */
|
|
19
|
+
export function DeepWikiIcon({ className, size = 20 }) {
|
|
20
|
+
return (_jsxs("svg", { className: className, width: size, height: size, viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: [_jsx("rect", { x: "4", y: "3", width: "13", height: "16", rx: "1.5", fill: "#6366F1" }), _jsx("rect", { x: "7", y: "6", width: "7", height: "1.5", rx: "0.5", fill: "#E0E7FF" }), _jsx("rect", { x: "7", y: "9", width: "7", height: "1.5", rx: "0.5", fill: "#E0E7FF" }), _jsx("rect", { x: "7", y: "12", width: "4", height: "1.5", rx: "0.5", fill: "#E0E7FF" }), _jsx("circle", { cx: "17", cy: "17", r: "4", fill: "none", stroke: "#F59E0B", strokeWidth: "2" }), _jsx("line", { x1: "20", y1: "20", x2: "22", y2: "22", stroke: "#F59E0B", strokeWidth: "2", strokeLinecap: "round" })] }));
|
|
21
|
+
}
|
|
22
|
+
/** AWS — orange cube mark. */
|
|
23
|
+
export function AwsIcon({ className, size = 20 }) {
|
|
24
|
+
return (_jsxs("svg", { className: className, width: size, height: size, viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: [_jsx("path", { d: "M6 14.5c0 1 .5 1.8 1.3 2.2L12 19l4.7-2.3c.8-.4 1.3-1.2 1.3-2.2v-5c0-1-.5-1.8-1.3-2.2L12 5 7.3 7.3C6.5 7.7 6 8.5 6 9.5v5Z", fill: "#FF9900" }), _jsx("path", { d: "M12 5v14M6 9.5l6 3 6-3", stroke: "#232F3E", strokeWidth: "1.2", fill: "none" })] }));
|
|
25
|
+
}
|