Skip to content

feat: support metadata in Python SDK#134

Merged
idosal merged 6 commits intomainfrom
copilot/fix-preferred-frame-size-metadata
Oct 25, 2025
Merged

feat: support metadata in Python SDK#134
idosal merged 6 commits intomainfrom
copilot/fix-preferred-frame-size-metadata

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Oct 22, 2025

Problem

The Python SDK was missing support for the uiMetadata field when creating UI resources, causing metadata like preferred-frame-size to be ignored and resulting in meta: null in the output. This prevented users from specifying important UI hints such as preferred dimensions or initial render data.

# This was being ignored, resulting in meta: null
resource = create_ui_resource({
    "uri": "ui://chart",
    "uiMetadata": {
        "preferred-frame-size": [800, 600],
    },
    "content": {"type": "rawHtml", "htmlString": "<div>...</div>"},
    "encoding": "text"
})

Solution

Implemented full metadata support in the Python SDK to match the TypeScript implementation:

  • Added uiMetadata and metadata optional fields to CreateUIResourceOptions
  • UI-specific metadata is automatically prefixed with mcpui.dev/ui- for client recognition
  • Custom metadata can be provided alongside UI metadata without prefixing
  • Metadata is properly included in the resource's _meta field for MCP protocol compliance

Usage

from mcp_ui_server import create_ui_resource

# Specify preferred frame size
resource = create_ui_resource({
    "uri": "ui://visualization",
    "content": {
        "type": "externalUrl",
        "iframeUrl": "https://charts.example.com"
    },
    "encoding": "text",
    "uiMetadata": {
        "preferred-frame-size": [800, 600]
    }
})

# Provide initial render data
resource = create_ui_resource({
    "uri": "ui://dashboard",
    "content": {
        "type": "remoteDom",
        "script": "function Dashboard({ theme }) { ... }",
        "framework": "react"
    },
    "encoding": "text",
    "uiMetadata": {
        "initial-render-data": {
            "theme": "dark",
            "userId": "123"
        }
    }
})

# Combine UI and custom metadata
resource = create_ui_resource({
    "uri": "ui://widget",
    "content": {"type": "rawHtml", "htmlString": "<div>Widget</div>"},
    "encoding": "text",
    "uiMetadata": {
        "preferred-frame-size": [640, 480]
    },
    "metadata": {
        "version": "1.0.0",
        "customKey": "value"
    }
})

Changes

  • types.py: Added uiMetadata and metadata fields, metadata constants
  • core.py: Implemented _get_additional_resource_props() helper for metadata processing
  • test_metadata.py: Added 11 comprehensive test cases covering all metadata scenarios
  • README.md: Added extensive documentation with examples
  • python_server_demo.py: Updated example to demonstrate metadata usage

Testing

  • All 32 tests pass (21 existing + 11 new metadata tests)
  • Covers all content types (rawHtml, externalUrl, remoteDom)
  • Covers both encodings (text, blob)
  • Tests metadata prefixing, override behavior, and serialization
  • Linting (Ruff) and type checking (Pyright) clean
  • Security scan (CodeQL) clean - 0 vulnerabilities

Compatibility

  • Matches TypeScript SDK implementation
  • No breaking changes - purely additive
  • Works with all existing code without modification
  • Compatible with MCP protocol specifications

Fixes #[issue_number]

Original prompt

This section details on the original issue you should resolve

<issue_title>python SDK and metadata</issue_title>
<issue_description>I tried passing in the preferred-frame-size as metadata from python sdk's create_ui_resource as shown below

@mcp.tool
def some_ui_resource():
    """plot a dataframe"""
    df = fetch_a_dataframe()
    axes = df.plot()
    #convert matplotlib plot to base64 string
    import io
    import base64
    buf = io.BytesIO()
    fig = axes.get_figure()
    fig.savefig(buf, format='png')
    buf.seek(0)
    plot_data = base64.b64encode(buf.read()).decode('utf-8')
    buf.close()
    return create_ui_resource({
        "uri": f"ui://some/ui/path",
        "uiMetadata": {
            "preferred-frame-size": [800, 600],
        },
        "content": {
            "type": "rawHtml",
            "htmlString": f"""
                <img src="data:image/jpeg;base64,{plot_data}" alt="plot"/>
            """
        },
        "encoding": "text"
    })

I tried a model_dump of the created resource object and seems like the metadata is null.

{
    "type": "resource",
    "resource": {
        "uri": "ui://some/uipath",
        "mimeType": "text/html",
        "meta": null,
        "text": "\n                <img src=\"data:image/jpeg;base64,some_data_here\" alt=\"plot\"/>\n            "
    },
    "annotations": null,
    "meta": null
}

is this a missing feature in python sdk?</issue_description>

Comments on the Issue (you are @copilot in this section)

Fixes #133


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Loading
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.

python SDK and metadata

3 participants