Skip to content

feat: support using official MCP SDK types#332

Merged
hallvictoria merged 3 commits intodevfrom
hallvictoria/official-mcp-types
Apr 21, 2026
Merged

feat: support using official MCP SDK types#332
hallvictoria merged 3 commits intodevfrom
hallvictoria/official-mcp-types

Conversation

@hallvictoria
Copy link
Copy Markdown
Contributor

@hallvictoria hallvictoria commented Apr 21, 2026

Instead of maintaining azure-functions MCP types, instead support users returning mcp SDK types directly.

Example functions:

from mcp.types import TextContent, CallToolResult, ResourceLink, ContentBlock, ImageContent

# ============================================================================
# Scenario 1: Single ResourceLinkBlock return
# ============================================================================
@app.mcp_tool(metadata="""{"version": 1.0, "author": "Jane Doe"}""")
def get_functions_logo() -> ResourceLink:
    """Returns the Azure Functions logo as a resource link."""
    return ResourceLink(
        type="resource_link",
        uri="file://logo.png",
        name="Azure Functions Logo",
        mimeType="image/png"
    )

# ============================================================================
# Scenario 2: Multiple content blocks (List[ContentBlock])
# ============================================================================
@app.mcp_tool()
def multi_content_type_function(
    data: str,
    mime_type: Optional[str] = None
) -> List[ContentBlock]:
    """Responds to user with multiple content blocks."""
    return [
        TextContent(text="Here is an image for you!"),
        ResourceLink(
            type="resource_link",
            name="example",
            uri="https://www.google.com/",
            description="Image Information"
        ),
        ImageContent(
            type="image",
            data=data,
            mimeType=mime_type or "image/jpeg"
        )
    ]

# ============================================================================
# Scenario 3: Single ImageContentBlock return
# ============================================================================
@app.mcp_tool()
def render_image(
    data: str,
    mime_type: Optional[str] = None
) -> ImageContent:
    """Responds to user with an image."""
    return ImageContent(
        type="image",
        data=data,
        mimeType=mime_type or "image/jpeg"
    )

# ============================================================================
# Scenario 4: @mcp_content decorated dataclass
# ============================================================================
@func.mcp_content
class Snippet:
    """Snippet class that will be serialized as structured content."""
    def __init__(self, name: str, content: Optional[str] = None):
        self.name = name
        self.content = content


# In-memory snippet cache
snippets_cache: Dict[str, str] = {
    "hello": "print('Hello, World!')",
    "loop": "for i in range(10):\n    print(i)"
}


@app.mcp_tool()
def get_snippet(name: str) -> Optional[Snippet]:
    """Gets a code snippet by name."""
    if name in snippets_cache:
        return Snippet(name=name, content=snippets_cache[name])
    return None

# ============================================================================
# Scenario 5: CallToolResult with explicit content and structured content
# ============================================================================
@app.mcp_tool(use_result_schema=True)
def get_image_with_metadata() -> CallToolResult:
    """Returns an image with metadata as structured content."""
    # Metadata object
    metadata = {
        "ImageId": "logo",
        "Format": "png",
        "CreatedAt": datetime.utcnow().isoformat(),
        "Tags": ["functions", "azure", "serverless"]
    }
    
    # For demo, using a 10x10 red pixel PNG (larger version of the 1x1)
    import zlib
    import struct
    
    # PNG signature
    png_data = b'\x89PNG\r\n\x1a\n'
    
    def make_chunk(chunk_type, data):
        """Create a PNG chunk with proper CRC."""
        chunk_data = chunk_type + data
        crc = zlib.crc32(chunk_data) & 0xffffffff
        return struct.pack('>I', len(data)) + chunk_data + struct.pack('>I', crc)
    
    # IHDR: 10x10, 8-bit RGB
    width, height = 10, 10
    ihdr_data = struct.pack('>IIBBBBB', width, height, 8, 2, 0, 0, 0)
    png_data += make_chunk(b'IHDR', ihdr_data)
    
    # IDAT: image data (10x10 red pixels)
    raw_data = b''
    for y in range(height):
        raw_data += b'\x00'  # Filter type: None
        for x in range(width):
            raw_data += b'\xff\x00\x00'  # RGB: Red
    
    compressed = zlib.compress(raw_data, 9)
    png_data += make_chunk(b'IDAT', compressed)
    
    # IEND
    png_data += make_chunk(b'IEND', b'')
    
    base64_image = base64.b64encode(png_data).decode('utf-8')
    
    # Construct CallToolResult with both content blocks and structured content
    return CallToolResult(
        content=[
            TextContent(type="text", text=json.dumps(metadata)),  # Text representation
            ImageContent(
                type="image",
                data=base64_image,
                mimeType="image/png"
            )
        ],
        structuredContent=metadata  # Structured data for parsing
    )


# ============================================================================
# Scenario 6: use_result_schema parameter
# ============================================================================
@app.mcp_tool(use_result_schema=True)
def get_structured_data(query: str) -> Snippet:
    """Returns structured data using @mcp_content decorated class."""
    return Snippet(
        name="result",
        content=f"Query result for: {query}"
    )

# ============================================================================
# Previous scenarios (not using structured content) are still supported
# ============================================================================
@app.mcp_tool()
def happy_function() -> str:
    """Responds to the user with a hello message."""
   return "Hello!"

@hallvictoria hallvictoria marked this pull request as ready for review April 21, 2026 17:02
@hallvictoria hallvictoria merged commit 599cd42 into dev Apr 21, 2026
16 checks passed
@hallvictoria hallvictoria deleted the hallvictoria/official-mcp-types branch April 21, 2026 17:41
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.

2 participants