Skip to content

Conversation

@tonxxd
Copy link
Contributor

@tonxxd tonxxd commented Dec 1, 2025

Pull Request Description

Changes

This PR implements SEP-973 by adding icons and websiteUrl as optional metadata fields to various MCP entities. This allows clients to display visual cues and links to documentation for implementations, tools, resources, and prompts.

Specifically, this PR:

  • Introduces the Icon interface.
  • Adds an optional icons field to ToolDefinition, ResourceDefinition, ResourceTemplateDefinition, and PromptDefinition.
  • Adds optional icons and websiteUrl fields to ServerConfig (representing Implementation metadata).
  • Updates the McpServer constructor and registration methods (tool, resource, resourceTemplate, prompt) to accept and pass these new metadata fields.

Implementation Details

  1. Icon Interface: Defined in libraries/typescript/packages/mcp-use/src/server/types/common.ts with src, mimeType?, and sizes? properties.
  2. Schema Extensions:
    • ServerConfig (for Implementation metadata) in src/server/types/common.ts now includes icons?: Icon[] and websiteUrl?: string.
    • ToolDefinition in src/server/types/tool.ts now includes icons?: Icon[].
    • ResourceDefinition and ResourceTemplateDefinition in src/server/types/resource.ts now include icons?: Icon[].
    • PromptDefinition in src/server/types/prompt.ts now includes icons?: Icon[].
  3. Server Logic Updates: The McpServer class in src/server/mcp-server.ts has been updated to:
    • Pass config.icons and config.websiteUrl to the OfficialMcpServer constructor.
    • Pass toolDefinition.icons to this.server.registerTool.
    • Pass resourceDefinition.icons to this.server.registerResource.
    • Pass resourceTemplateDefinition.icons within the metadata to this.server.registerResource.
    • Pass promptDefinition.icons to this.server.registerPrompt.
  4. Dependencies: No new external dependencies were added. Type assertions (as any) were used in mcp-server.ts to temporarily bypass type mismatches with @modelcontextprotocol/sdk as its types have not yet been updated to reflect SEP-973. These assertions can be removed once the SDK is updated.
  5. Exports: The Icon type is now exported from libraries/typescript/packages/mcp-use/src/server/types/index.ts and libraries/typescript/packages/mcp-use/src/server/index.ts.

Example Usage (Before)

import { McpServer } from "@modelcontextprotocol/mcp-use";

const server = new McpServer({
  name: "My Legacy Server",
  version: "1.0.0",
  description: "A server without visual metadata.",
});

server.tool({
  name: "legacy-tool",
  description: "A tool with only basic metadata.",
  inputSchema: { type: "object", properties: {} },
  cb: async () => ({}),
});

server.resource({
  name: "legacy-resource",
  title: "Legacy Data",
  mimeType: "text/plain",
  readCallback: async () => "Hello from legacy resource!",
});

Example Usage (After)

import { McpServer } from "@modelcontextprotocol/mcp-use";

const server = new McpServer({
  name: "My Enhanced Server",
  version: "1.0.0",
  description: "A server with visual metadata.",
  icons: [
    { src: "https://example.com/server-icon-48.png", sizes: "48x48" },
    { src: "data:image/svg+xml;base64,PHN2ZyB...", mimeType: "image/svg+xml", sizes: "any" },
  ],
  websiteUrl: "https://example.com/docs/server",
});

server.tool({
  name: "enhanced-tool",
  description: "A tool with an icon.",
  inputSchema: { type: "object", properties: {} },
  icons: [
    { src: "https://example.com/tool-icon.png", sizes: "96x96" },
  ],
  cb: async () => ({}),
});

server.resource({
  name: "enhanced-resource",
  title: "Enhanced Data",
  mimeType: "text/plain",
  icons: [
    { src: "https://example.com/resource-icon.svg", sizes: "any" },
  ],
  readCallback: async () => "Hello from enhanced resource!",
});

server.prompt({
  name: "enhanced-prompt",
  title: "Enhanced Prompt",
  description: "A prompt with an icon.",
  icons: [
    { src: "https://example.com/prompt-icon.png", sizes: "32x32" },
  ],
  cb: async () => ({ type: "text", content: "Generated text" }),
});

Documentation Updates

No separate documentation files were updated in this PR. The changes align with the SEP-973 specification.

Testing

  • Unit tests added/modified: No new unit tests were added as this PR focuses on schema and integration with the SDK.
  • Manual testing performed:
    • npm install
    • npm run build
    • npm run typecheck
      All commands executed successfully, confirming that the codebase compiles without TypeScript errors after the changes.
  • Edge cases considered: The SEP specifies that icons and websiteUrl are optional, which is reflected in the implementation. The Icon interface supports both URL and base64 data URIs, and flexible sizes strings.

Backwards Compatibility

These changes are fully backwards compatible. Both icons and websiteUrl are optional fields. Existing clients and servers that do not provide or consume these fields will continue to function as before, falling back to existing behavior.

Related Issues

Closes #MCP-814


Linear Issue: MCP-814

Open in Cursor Open in Web

@cursor
Copy link

cursor bot commented Dec 1, 2025

Cursor Agent can help with this pull request. Just @cursor in comments and I'll start working on changes in this branch.
Learn more about Cursor Agents

@tonxxd
Copy link
Contributor Author

tonxxd commented Dec 1, 2025

@claude review the pr

@claude
Copy link
Contributor

claude bot commented Dec 1, 2025

Claude finished @tonxxd's task —— View job


Code Review Complete ✅

PR #587: Add icon and website url metadata

I've reviewed the implementation of SEP-973 support for icons and website URLs. Overall, the implementation is solid and well-structured. Here's my detailed feedback:


Strengths

  1. Well-documented types: The Icon interface in common.ts:18-35 has excellent documentation, including security warnings about URL validation and SVG precautions.

  2. Backwards compatible: All new fields (icons, websiteUrl) are optional, ensuring existing code continues to work without changes.

  3. Consistent implementation: Icons are added uniformly across all entity types (tools, resources, prompts, server config) with identical patterns.

  4. Good UI integration: The IconRenderer component (IconRenderer.tsx:22-68) handles data URIs, URL loading, and error states gracefully with fallback support.

  5. Clean type exports: The new Icon type is properly exported through the module hierarchy.


🔍 Issues & Recommendations

1. Type Safety Concerns (High Priority)

Location: mcp-server.ts:179-185, 425-427, 499-502, 616-617, 820

The use of as any type assertions bypasses TypeScript's type checking, which could hide real type mismatches:

// Current approach
this.server = new OfficialMcpServer({
  name: config.name,
  version: config.version,
  icons: config.icons,
  websiteUrl: config.websiteUrl,
} as any);

Recommendation:

  • Consider creating temporary interface extensions until the SDK is updated:
interface TemporaryServerConfig extends ServerCapabilities {
  icons?: Icon[];
  websiteUrl?: string;
}

this.server = new OfficialMcpServer({
  name: config.name,
  version: config.version,
  icons: config.icons,
  websiteUrl: config.websiteUrl,
} as TemporaryServerConfig);
  • Add a TODO comment with the SDK version to track when these can be removed
  • The PR description mentions this is temporary, which is good, but tracking via comments would help

2. Security: Missing URL Validation (High Priority)

Locations:

  • common.ts:30 (Icon.src field)
  • common.ts:58 (ServerConfig.websiteUrl field)
  • IconRenderer.tsx:40-66

The documentation warns that consumers "MUST take steps to ensure URLs are from the same domain or a trusted domain," but there's no validation implemented. This could lead to:

  • SSRF attacks if URLs are fetched server-side
  • XSS attacks via SVG with embedded JavaScript
  • Phishing via malicious websiteUrl links

Recommendations:

  1. Add URL validation helper functions:
export function validateIconUrl(url: string, trustedDomains?: string[]): boolean {
  // Validate URL format, check against trusted domains
  // Reject javascript: and data: URIs with scripts
}
  1. In IconRenderer.tsx, add CSP-like protections:
// For external URLs, validate domain
// For data URIs, validate MIME type is image/*
// Consider adding sandbox attributes for SVG rendering
  1. For websiteUrl in ServerCapabilitiesModal.tsx:137-148, add rel="noopener noreferrer" (✅ already done) and consider warning users about external links.

3. IconRenderer Performance Issue (Medium Priority)

Location: IconRenderer.tsx:34-37

The comment says "For now, just use the first icon" but the sizes field exists specifically to select the best icon:

// Current: always uses first icon
const icon = icons[0];

Recommendation: Implement size-based selection:

function selectBestIcon(icons: Icon[], targetSize: number): Icon {
  // Parse sizes field (e.g., "48x48", "any")
  // Select closest match to targetSize
  // Fall back to first icon if no sizes specified
  return bestMatch || icons[0];
}

This would provide better visual quality and potentially reduce bandwidth for retina displays.

4. Type Casting Inconsistency (Low Priority)

Locations:

  • ToolsList.tsx:32 - const toolIcons = (tool as any).icons;
  • PromptsList.tsx:32 - const promptIcons = (prompt as any).icons;
  • ResourcesList.tsx:65 - const resourceIcons = (resource as any).icons;

These cast to any because the SDK types don't include icons yet, but this pattern is repeated 3 times.

Recommendation: Create a shared helper or type guard:

// In shared/utils.ts
export function getEntityIcons(entity: any): Icon[] | undefined {
  return entity.icons;
}

This centralizes the type assertion and makes it easier to remove once SDK types are updated.

5. Missing Error Handling in IconRenderer (Medium Priority)

Location: IconRenderer.tsx:28-68

The component tracks error state but only shows fallback. If an icon fails to load, there's no logging or debugging info.

Recommendation: Add optional error logging:

onError={(e) => {
  if (process.env.NODE_ENV === 'development') {
    console.warn('Failed to load icon:', icon.src, e);
  }
  setError(true);
}}

6. Documentation: No Migration Guide (Low Priority)

The PR description shows "before/after" examples, but there's no migration guide for users who want to add icons to existing servers.

Recommendation: Consider adding a brief migration guide in CHANGELOG or documentation about:

  • How to choose appropriate icon sizes
  • Best practices for icon hosting (CDN, data URIs, etc.)
  • Security considerations for icon URLs

🧪 Testing Suggestions

The PR mentions no new unit tests were added. While the schema changes are straightforward, consider adding:

  1. Type validation tests: Ensure icons array structure is validated
  2. IconRenderer tests:
    • Test data URI rendering
    • Test error handling and fallback
    • Test with missing/invalid icons
  3. Security tests: Validate URL schemes are restricted if validation is added
  4. Integration test: Verify icons appear in inspector UI

📋 Minor Observations

  1. Consistent comments: The icon documentation is copy-pasted across 4 files (tool.ts, resource.ts, prompt.ts, common.ts). Consider using JSDoc @see references to a single source of truth.

  2. Type definition location: The Icon interface in IconRenderer.tsx:5-9 duplicates the one in common.ts. The component should import from the shared types instead.

  3. ServerCapabilitiesModal complexity: The websiteUrl link logic at lines 137-148 is well-implemented with proper security attributes.


🎯 Summary

Overall Assessment: This is a solid implementation of SEP-973 with good structure and backwards compatibility. The main concerns are:

  1. Security: Add URL validation to prevent potential attacks
  2. Type Safety: Use more specific type assertions instead of as any
  3. Icon Selection: Implement size-based icon selection as per the spec
  4. Testing: Add tests for the new functionality

Recommendation: ✅ Approve with suggested improvements

The implementation is functional and safe to merge, but I strongly recommend addressing the security concerns (URL validation) before deploying to production. The type safety issues can be addressed when the SDK is updated.


📝 Action Items

If you'd like me to implement any of these suggestions, let me know! I can:

  • Add URL validation helpers
  • Implement size-based icon selection
  • Add unit tests for IconRenderer
  • Create a migration guide
  • Add type guards for entity icons

Todo List

  • Read repository guidelines (CLAUDE.md)
  • Review type definitions and interfaces
  • Review server implementation changes
  • Review UI component changes
  • Analyze type safety and error handling
  • Check backwards compatibility
  • Provide comprehensive feedback

@tonxxd
Copy link
Contributor Author

tonxxd commented Dec 1, 2025

needs to wait for the official sdk support

@aryasoni98
Copy link
Contributor

@tonxxd Would it be okay if I jump in and review this PR? I noticed a few areas where I can help with improvements.

@tonxxd
Copy link
Contributor Author

tonxxd commented Dec 4, 2025

@aryasoni98 the feature is not yet in the official sdk so for now it does not make sense to go forward, will reopen it once released

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants