feat(mcp): the server gives hosts its title and icon (#3095)

`initialize` now answers with serverInfo.title "CodeGraph" and one
embedded SVG in serverInfo.icons, on the direct path and from the
daemon proxy, which share SERVER_INFO. A host that shows them can list
CodeGraph by name and logo instead of a plain `codegraph`.

The icon is the site's favicon (site/public/favicon.svg) on a light
tile. The bare mark is dark ink on nothing, and on a dark background
only its two white dots show (checked in a browser at 16 to 64 px). It
is spelled out in the source instead of as a base64 blob, so a reader
can see it is three lines and three circles.

`sizes` is left off the icon on purpose. It's optional and says nothing
about an SVG, and @modelcontextprotocol/sdk 1.18.0 typed it as a string
where the spec settled on an array, so a host on that SDK would fail the
whole handshake on the array form.

Left out from PR #879, on purpose: `_meta.icons` and icons on every
tool. Those add about 1 KB per tool to each tools/list for no host we
could find that needs them; Codex reads serverInfo.icons.

What each host shows, read from its source or binary on 2026-10-30:
- Codex: keeps serverInfo.title and .icons and sends them to its app
  (McpServerStatus.serverInfo); the terminal UI's /mcp doesn't read them.
- opencode: reads serverInfo.title into the server list; its dialogs
  still print the config name, and it doesn't read icons.
- Claude Code 2.1.296: connects fine with these fields (checked with
  `claude mcp list` in a sandbox home), and no read of title or icons
  turns up in its binary, so it keeps showing the config name.
- Cursor: closed source and not on this machine. Its docs mention no
  server title or icon, so this is unverified.

Validation: 3 tests in mcp-initialize fail on main's session and pass
here; mcp-daemon now pins the proxy's serverInfo to the same object.

Reimplements PR #879 by @fedosov.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Colby Mchenry
2026-10-30 18:38:45 +00:00
committed by GitHub
co-authored by Claude Opus 5.5
parent 22cf7d3aa1
commit f4c4dae91c
4 changed files with 58 additions and 1 deletions
+25
View File
@@ -23,15 +23,40 @@ import { getTelemetry, ClientInfo } from '../telemetry';
import { getUpdateNotice } from '../upgrade/update-check';
import { ExploreSessionState } from './explore-session-state';
/**
* The site's favicon on a light tile: the bare mark is dark ink on nothing,
* which a dark UI loses. Written out rather than as base64 so a reader can see
* it is two lines of shapes and nothing else.
*/
const SERVER_ICON_SVG =
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="none" stroke="#16150f" stroke-width="2">' +
'<rect width="32" height="32" rx="6" fill="#f7f6f2" stroke="none"/>' +
'<line x1="16" y1="8" x2="8" y2="23"/><line x1="16" y1="8" x2="24" y2="23"/><line x1="8" y1="23" x2="24" y2="23"/>' +
'<circle cx="16" cy="8" r="3.4" fill="#16150f"/><circle cx="8" cy="23" r="3.4" fill="#f7f6f2"/><circle cx="24" cy="23" r="3.4" fill="#f7f6f2"/>' +
'</svg>';
/**
* MCP Server Info — kept on the session because some clients log it. The
* version tracks the real package version (was a hard-coded '0.1.0').
*
* `title` and `icons` are what a host may show in place of `name`. They are
* newer than the protocol version this server claims, so a host that doesn't
* know them passes over them. The icon has no `sizes`: it is optional and says
* nothing about an SVG, and a host on an SDK that typed it as a string, as 1.18
* did, would fail the whole handshake on the array the spec settled on.
*/
// Exported so the proxy can answer `initialize` locally with the IDENTICAL
// payload the daemon would send — no drift between the two handshake paths.
export const SERVER_INFO = {
name: 'codegraph',
title: 'CodeGraph',
version: CodeGraphPackageVersion,
icons: [
{
src: `data:image/svg+xml;base64,${Buffer.from(SERVER_ICON_SVG).toString('base64')}`,
mimeType: 'image/svg+xml',
},
],
};
/**