Skip to content

Comments

feat: add IconTheme type for light/dark mode icon support#3163

Open
gfortaine wants to merge 1 commit intoPrefectHQ:mainfrom
gfortaine:feat/icon-theme-support
Open

feat: add IconTheme type for light/dark mode icon support#3163
gfortaine wants to merge 1 commit intoPrefectHQ:mainfrom
gfortaine:feat/icon-theme-support

Conversation

@gfortaine
Copy link
Contributor

Description

Add IconTheme type alias and document the theme field on Icon for parity with the MCP Python SDK and Go SDK. This allows servers to specify whether an icon is designed for a light or dark background, enabling clients to select the appropriate icon based on their UI theme.

This complements the existing icon support (added in v2.13.0), adding theme-aware icon variants that MCP clients like VS Code and GitHub Desktop can use to match their UI appearance.

Changes

  1. src/fastmcp/utilities/types.py: Add IconTheme = Literal["light", "dark"] with a forward-compatible import from mcp.types (for when MCP SDK v2+ is available)
  2. src/fastmcp/__init__.py: Export IconTheme from the fastmcp package
  3. docs/servers/icons.mdx & docs/v2/servers/icons.mdx: Document the theme field and add a "Theme Variants" section with usage examples
  4. tests/utilities/test_inspect.py: Add 4 tests for icon theme support

MCP Python SDK Reference

The MCP Python SDK added this in modelcontextprotocol/python-sdk#1978:

IconTheme = Literal["light", "dark"]

class Icon(MCPModel):
    src: str
    mimeType: str | None = None
    sizes: list[str] | None = None
    theme: IconTheme | None = None

Go SDK Reference

type IconTheme string
const (
    IconThemeLight IconTheme = "light"
    IconThemeDark  IconTheme = "dark"
)

Use Case

MCP servers like GitHub MCP Server provide both light and dark variants of their icons. The IconTheme type enables type-safe theme specification:

from fastmcp import FastMCP, IconTheme
from mcp.types import Icon

mcp = FastMCP(
    name="MyServer",
    icons=[
        Icon(src="https://example.com/icon-dark.svg", theme="dark"),
        Icon(src="https://example.com/icon-light.svg", theme="light"),
    ]
)

Implementation Note

Since FastMCP currently pins to mcp>=1.24.0,<2.0 and the theme field was added to the MCP SDK's main (v2 development), this PR defines IconTheme locally with a forward-compatible try/except import. When MCP SDK v2 is available, FastMCP will automatically use the upstream type. The Icon model already accepts extra fields via extra='allow', so the theme field works at runtime today.

Generated using GitHub Copilot.

Contributors Checklist

Review Checklist

  • I have self-reviewed my changes
  • My Pull Request is ready for review

@marvin-context-protocol marvin-context-protocol bot added enhancement Improvement to existing functionality. For issues and smaller PR improvements. server Related to FastMCP server implementation or server-side functionality. labels Feb 12, 2026
@marvin-context-protocol
Copy link
Contributor

Test Failure Analysis

Summary: Type checker () errors because from (v1.x) doesn't support the theme parameter yet.

Root Cause: The PR adds IconTheme type and documentation showing theme="light" and theme="dark" usage, but the tests in tests/utilities/test_inspect.py attempt to pass the theme parameter to Icon objects. The current MCP SDK version used by FastMCP is mcp>=1.24.0,<2.0, and the v1.x Icon class only has these fields: ['src', 'mimeType', 'sizes'] — no theme field.

The type checker correctly identifies 4 instances where theme is passed to Icon():

  • Line 862: theme="dark"
  • Line 867: theme="light"
  • Line 890: theme="dark"
  • Line 895: theme="light"

Suggested Solution:

The IconTheme type was added with forward-compatible imports (falling back to a local definition for MCP SDK v1.x), but the tests need to be adjusted to match what the current MCP SDK version supports.

Option 1: Remove theme from test cases (simplest, works now)

  • Remove the theme parameter from all Icon() calls in the new tests
  • Keep the IconTheme type definition for when MCP SDK v2+ is released
  • Update documentation examples to show IconTheme type usage but note that theme support requires MCP SDK v2+

Option 2: Mark tests as xfail/skip until MCP SDK v2+

  • Use pytest.mark.skipif to skip these tests until mcp>=2.0 is available
  • Keep the test code as-is for when the SDK is upgraded
Detailed Analysis

Type Checker Errors

All 4 errors are from the ty type checker:

error[unknown-argument]: Argument `theme` does not match any known parameter
   --> tests/utilities/test_inspect.py:862:21
   --> tests/utilities/test_inspect.py:867:21
   --> tests/utilities/test_inspect.py:890:21
   --> tests/utilities/test_inspect.py:895:21

Verification

# Check Icon model fields
$ uv run python -c "from mcp.types import Icon; print(Icon.model_fields.keys())"
dict_keys(['src', 'mimeType', 'sizes'])

Code Added in PR

The PR correctly adds the IconTheme type with forward-compatible imports:

# src/fastmcp/utilities/types.py
try:
    from mcp.types import IconTheme
except ImportError:
    IconTheme: TypeAlias = Literal["light", "dark"]  # type: ignore[no-redef]

But the tests assume Icon accepts theme parameter, which it doesn't in v1.x.

Related Files
  • tests/utilities/test_inspect.py: Lines 852-932 contain the new tests with theme parameter usage
  • src/fastmcp/utilities/types.py: Lines 27-34 define the forward-compatible IconTheme type
  • pyproject.toml: Line 9 specifies mcp>=1.24.0,<2.0 dependency

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 12, 2026

Walkthrough

Adds an IconTheme type alias and exposes it from fastmcp; IconTheme is imported from mcp.types when available with a local fallback Literal["light", "dark"] for compatibility. The public API (src/fastmcp/__init__.py) now exports IconTheme. Documentation (docs/servers/icons.mdx and docs/v2/servers/icons.mdx) is updated to document an optional theme field on Icon and to show examples of light/dark icon variants.

🚥 Pre-merge checks | ✅ 6
✅ Passed checks (6 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the main change: adding an IconTheme type for light/dark mode icon support. It is specific, clear, and directly reflects the primary objective of the PR.
Description check ✅ Passed The description is comprehensive and well-structured, covering all required template sections: clear description of changes, complete contributors checklist, and review checklist. It includes implementation details, MCP SDK references, use cases, and a note about AI tool usage.
Linked Issues check ✅ Passed The PR successfully implements all requirements from issue #3162: IconTheme type is added with forward-compatible import, exported from fastmcp package, documentation is updated with theme field and Theme Variants section, and tests are added for icon theme support.
Out of Scope Changes check ✅ Passed All changes are directly related to the linked issue #3162 objectives: type definition, package exports, documentation updates, and test additions for icon theme support. No unrelated changes detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

No actionable comments were generated in the recent review. 🎉

🧹 Recent nitpick comments
src/fastmcp/__init__.py (1)

21-21: IconTheme may not warrant top-level re-export.

The existing top-level exports (FastMCP, Client, Context, settings) are all fundamental building blocks of the library. IconTheme is a narrow utility type alias (Literal["light", "dark"]) for a specific feature (icon theming) and feels more at home in fastmcp.utilities.types, where users who need it can import it directly.

Promoting every auxiliary type to fastmcp.* dilutes the top-level API surface over time. Consider keeping it importable via from fastmcp.utilities.types import IconTheme (or re-exporting from a mid-level module like fastmcp.server) instead.

Suggested diff
-from .utilities.types import IconTheme
 
 __all__ = [
     "Client",
     "Context",
     "FastMCP",
-    "IconTheme",
     "settings",
 ]

As per coding guidelines: "only re-export to fastmcp.* for the most fundamental types." Based on learnings: "Be intentional about module re-exports - only re-export core types that define a module's purpose to parent namespaces, with most fundamental types going to fastmcp.*."

Also applies to: 35-35


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/fastmcp/__init__.py (1)

21-21: Consider whether IconTheme warrants top-level export.

The existing top-level exports (FastMCP, Client, Context) are core abstractions. IconTheme is a narrow auxiliary type—users who need it could import from fastmcp.utilities.types directly. That said, the PR objective explicitly requests this, and the doc examples use from fastmcp import IconTheme, so this is a deliberate choice.

Just flagging for intentionality per the project's re-export guideline. If the maintainer is comfortable with it, no change needed. Based on learnings: "only re-export to fastmcp.* for the most fundamental types."

Also applies to: 35-35

docs/servers/icons.mdx (1)

67-89: Consider simplifying the example by passing string literals directly.

The intermediate variables light_theme and dark_theme exist only to showcase the type annotation but add verbosity. A simpler example that passes theme="light" directly (with a note about IconTheme for type checking) would be more idiomatic and easier to copy-paste.

Add IconTheme type alias and document the theme field on Icon for parity
with the MCP Python SDK and Go SDK. This allows servers to specify whether
an icon is designed for a light or dark background, enabling clients to
select the appropriate icon based on their UI theme.

Changes:
- Add IconTheme = Literal['light', 'dark'] to fastmcp.utilities.types
  with forward-compatible import from mcp.types when available (v2+)
- Export IconTheme from fastmcp package
- Document theme field and theme variants in icon docs
- Add tests for icon theme support

Closes jlowin#3162
@gfortaine gfortaine force-pushed the feat/icon-theme-support branch from 1e67eab to 7af0676 Compare February 13, 2026 15:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement Improvement to existing functionality. For issues and smaller PR improvements. server Related to FastMCP server implementation or server-side functionality.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: add IconTheme type for light/dark mode icon support

1 participant