Skip to content

fix(site): bundle Notion/Linear/Figma icons and unify tool icon rendering#26228

Draft
tracyjohnsonux wants to merge 6 commits into
mainfrom
fix-mcp-icon-rendering
Draft

fix(site): bundle Notion/Linear/Figma icons and unify tool icon rendering#26228
tracyjohnsonux wants to merge 6 commits into
mainfrom
fix-mcp-icon-rendering

Conversation

@tracyjohnsonux

@tracyjohnsonux tracyjohnsonux commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Tool-call icons rendered inconsistently across MCP servers: Linear and Notion came out as flat silhouettes, GitHub washed out near-white in dark mode, and Notion's block logo collapsed into a featureless square. Root cause was two CSS filter systems fighting on the same <img>, with the winner decided per-URL.

Diagnosis

The ToolIcon component applied a class-based brightness-0 dark:invert opacity-* silhouette filter to every external MCP icon. Separately, ExternalImage runs every src through getExternalImageStylesFromUrl in site/src/theme/externalImages.ts; if the URL is same-origin and listed in defaultParametersForBuiltinIcons, it sets an inline style.filter (for example grayscale(100%) contrast(0%) brightness(250%) for the monochrome mode).

Inline style wins over class for the same CSS property. So:

Icon URL source Effective filter
Linear cdn.jsdelivr.net/.../linear-dark.webp class silhouette (brightness(0) invert(1))
Notion cdn.brandfetch.io/.../symbol.svg class silhouette
GitHub /icon/github.svg inline monochrome (class silhouette silently dropped)

The sourcing inconsistency itself came from administrators manually pasting different CDN URLs into the MCP server admin form's free-text icon field. Nothing in our code chose those.

Notion's notion-logo-block-main.svg layers fill="white" (rounded square) under fill="black" (the "N"). Any single-channel silhouette filter crushes both fills to one shade, producing a featureless block in the chat row.

What this PR does

  1. Bundles the three brand SVGs directly named in the bug: notion.svg, linear.svg, figma-black.svg (monochrome-safe variant), and figma-color.svg (full-colour reference variant). All normalised to the repo's 256x256 viewBox, registered in icons.json so they appear in the icon picker, and mapped to the existing monochrome mode in defaultParametersForBuiltinIcons.

  2. Adds site/src/pages/AgentsPage/data/knownMcpServers.ts, a small registry keyed on Server URL hostname patterns. The MCP server admin form watches the URL field and pre-fills any empty sibling fields (display name, slug, icon URL) when a known host is recognised. User input is never overwritten. When the icon URL is pre-filled, the form auto-expands the Details section so the suggested icon is visible before save. Clearing the icon field while a known URL is present re-suggests the bundled default so admins do not have to retype the URL to recover the suggestion.

    Registry starts with the brands this PR bundles (Notion, Linear, Figma) plus the popular brands we already shipped (GitHub, GitLab, Bitbucket, Slack, Discord). Additional brands land in the follow-up PR below.

  3. Drops the class-based silhouette filter and the Notion regex special case from ToolIcon. External MCP icons now route through the single ExternalImage + getExternalImageStylesFromUrl pipeline:

    • Bundled /icon/*.svg paths receive the theme-aware monochrome filter (grayscale(100%) contrast(0%) brightness(70%) in light, brightness(250%) in dark), producing a uniform muted silhouette that matches the surrounding lucide icons.
    • Cross-origin URLs not in the bundled map fall through unfiltered, matching the MCP server pill rendering.
    • There is no longer any code path where two filter systems fight on the same <img>.

Follow-up PR

A data-only follow-up will land the remaining 12 popular MCP brand bundles I had ready (Atlassian, Auth0, Cloudflare, Databricks, Datadog, Firecrawl, Grafana Labs, MongoDB, Netlify, PagerDuty, Sentry, Snowflake) plus their icons.json / externalImages.ts / knownMcpServers.ts entries. Keeping them out of this PR holds the surface area tight while the platform pieces (filter pipeline collapse, form prefill, clear-restore) get reviewed.

Migration

Existing MCP server entries whose icon_url was set by an administrator to a third-party CDN URL keep working: they render unfiltered through ExternalImage, the same way the MCP server pill renders them today. They'll start using the bundled icons when an administrator re-saves the server, either by accepting the URL-prefill suggestion or by selecting the bundled icon from the picker. No backend migration is required.

Testing

  • MCPToolNotionIconBundled story in Tool.stories.tsx exercises the bundled-icon path and asserts the inline monochrome filter is applied.
  • MCPToolNotionIcon story keeps regression coverage for the cross-origin Brandfetch URL.
  • CreateServerKnownUrlPrefill, CreateServerKnownUrlPrefillRespectsExistingValues, and CreateServerKnownUrlIconRestoresOnClear stories in MCPServerAdminPanel.stories.tsx exercise the URL-host-keyed prefill and the clear-restore behaviour on both empty and partially-filled forms.
  • Existing tool-rendering stories updated to drop assertions on the removed wrapper container and silhouette filter classes.
  • All affected story tests pass locally: Tool.stories.tsx (115/115), MCPServerAdminPanel.stories.tsx (19/19).

This PR was generated by Coder Agents.

The tool-call icon render path stacked two CSS filter systems: a
class-based `brightness-0 dark:invert` silhouette filter on the
`<img>`, plus the inline `filter` style that `ExternalImage` adds via
`getExternalImageStylesFromUrl` for any URL listed in
`defaultParametersForBuiltinIcons`. Inline style wins over class, so
bundled icons quietly used the older `monochrome` pipeline while
cross-origin URLs used the silhouette one. The result was visibly
random across MCP servers, and Notion's composite block logo (a
white-filled rounded square layered under a black "N") collapsed
into a featureless square under the silhouette filter.

- Bundle the popular MCP brand SVGs we did not yet ship (Atlassian,
  Auth0, Cloudflare, Databricks, Datadog, Figma plus a
  monochrome-safe Figma variant, Firecrawl, Grafana, Linear,
  MongoDB, Netlify, Notion, PagerDuty, Sentry, Snowflake). All
  normalised to the repo's 256x256 viewBox via a fit-and-centre
  transform around the upstream Brandfetch symbol art, matching the
  existing `github.svg`, `slack.svg`, `gitlab.svg` convention, and
  registered for the existing `monochrome` mode in
  `externalImages.ts`.
- Add `site/src/pages/AgentsPage/data/knownMcpServers.ts`, a small
  registry keyed on Server URL hostname patterns. The MCP server
  admin form watches the URL field and pre-fills any empty sibling
  fields (display name, slug, icon URL) when a known host is
  recognised. Existing user input is never overwritten. The
  Details section auto-expands so the suggested icon is visible
  before save.
- Drop the class-based silhouette filter and the Notion regex
  special case it required from `ToolIcon`. External MCP icons
  now route through the single `ExternalImage` pipeline: bundled
  paths receive the theme-aware `monochrome` filter, cross-origin
  URLs render unfiltered to match the MCP pill, and no two filter
  systems ever fight on the same `<img>`.

Notion's composite block logo no longer needs special handling:
admins (or the URL prefill) pick `/icon/notion.svg`, a flat
lowercase wordmark that filters cleanly to a muted silhouette in
both themes. Existing MCP servers pointing at third-party CDN URLs
continue to render unfiltered until an admin re-saves them with the
bundled icon.
@tracyjohnsonux tracyjohnsonux force-pushed the fix-mcp-icon-rendering branch from 74f0d0d to 8376c83 Compare June 10, 2026 20:55
@tracyjohnsonux tracyjohnsonux changed the title fix(site/src/pages/AgentsPage): render external MCP tool icons in natural colours fix(site): bundle popular MCP brand icons and unify tool icon rendering Jun 10, 2026
Adding MCP servier potential services for better tool call experience.
Adopt the SVGs uploaded directly to the branch and drop the
intermediate files I had committed.

- Use `figma-black.svg` (monochrome) and `figma-color.svg` (color)
  in place of `figma-monochrome.svg` / `figma.svg`.
- Use `grafana-labs.svg` in place of `grafana.svg`.
- Update `icons.json`, `defaultParametersForBuiltinIcons`, and the
  knownMcpServers registry to point at the new filenames.
…lears the icon field

When the admin clears the icon URL field and the current Server URL
still matches a known MCP server, immediately re-suggest the bundled
default. This keeps the registry suggestion one keystroke away
without forcing the admin to retype the Server URL just to get the
suggestion back.

Add `CreateServerKnownUrlIconRestoresOnClear` story to cover the
clear-then-restore flow.
Keep only the brands the original bug screenshots covered (Notion,
Linear, Figma). Drop the 12 speculative additions (Atlassian, Auth0,
Cloudflare, Databricks, Datadog, Firecrawl, Grafana, MongoDB,
Netlify, PagerDuty, Sentry, Snowflake) along with their
`icons.json`, `externalImages.ts`, and `knownMcpServers.ts`
entries. Adjust the `CreateServerKnownUrlIconRestoresOnClear`
storybook scenario to exercise Linear instead of Sentry.

Follow-up PR will land the deferred brands as a data-only change
once the platform pieces here are merged.
@tracyjohnsonux tracyjohnsonux changed the title fix(site): bundle popular MCP brand icons and unify tool icon rendering fix(site): bundle Notion/Linear/Figma icons and unify tool icon rendering Jun 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant