How the Dify MCP Plugin Handles Text and Blob Content Types When Reading MCP Resources

The Dify MCP plugin normalizes text and binary blob content from Model Context Protocol servers by detecting the presence of text or blob keys in resource responses, wrapping payloads with URI and MIME type metadata, and dispatching them through Dify's messaging system as either plain text, decoded binary, or structured JSON objects.

The junjiem/dify-plugin-tools-mcp_sse repository enables seamless integration between Dify workflows and MCP servers, requiring robust handling of diverse resource formats. When reading MCP resources, the plugin must accommodate both human-readable text (JSON, markdown, plain text) and binary blobs (PDFs, images, videos) while providing a consistent interface for downstream processing.

Resource Content Type Detection in MCP

MCP servers return resource content as a list of dictionaries, where each dictionary represents a discrete piece of the resource. According to the protocol implementation in this plugin, each content item contains either a text key or a blob key, accompanied by metadata such as uri and mimeType. The plugin's responsibility is to normalize these heterogeneous formats into a uniform structure that Dify tools can consume predictably.

Normalizing Text and Blob Payloads in utils/mcp_client.py

The core normalization logic resides in utils/mcp_client.py, where the McpClient.read_resource() method processes raw server responses. When McpClients.execute_tool() forwards a RESOURCE or RESOURCE_TEMPLATE action, it invokes this method and iterates over the returned content list to construct standardized resource objects.

Text Content Handling

When the plugin encounters a dictionary containing a "text" key, it constructs a resource entry with explicit type labeling:

{
    "type": "resource",
    "resource": {
        "uri": "<uri>",
        "mimeType": "<mime type, default 'text/plain'>",
        "text": "<the textual payload>"
    }
}

This structure preserves the original URI and MIME type while ensuring the textual payload remains accessible as a string. The logic specifically checks for the existence of the text key before accessing it, preventing attribute errors on malformed responses.

Binary Blob Content Handling

For binary content, the plugin detects the "blob" key and constructs a similar wrapper, but stores the data as base64-encoded strings:

{
    "type": "resource",
    "resource": {
        "uri": "<uri>",
        "mimeType": "<mime type if provided>",
        "blob": "<base64-encoded binary data>"
    }
}

This approach allows binary data to traverse JSON serialization boundaries while maintaining the original byte integrity. If a content item lacks both text and blob keys, the plugin raises an exception immediately, preventing unsupported formats from propagating through the workflow.

Dispatching Content to Dify in tools/mcp_call_tool.py

After normalization, execute_tool() returns the tool_contents list to the calling tool. The McpTool._invoke() method in tools/mcp_call_tool.py (lines 42–57) implements the final dispatch logic, routing each content type to the appropriate Dify message abstraction:

  • Text resources are converted to plain-text ToolInvokeMessage objects for direct consumption by LLM prompts
  • Image and Video blobs undergo base64.b64decode conversion to produce binary blob messages with proper MIME metadata for rendering
  • Generic resources return as JSON messages containing either the text field or the raw blob field, allowing downstream consumers to handle specialized formats appropriately

This three-tier routing ensures that a PDF document receives different treatment than a JSON configuration file, while both originate from the same normalized resource structure.

Practical Implementation Examples

Invoking a Resource-Type Tool from a Dify Workflow

When configuring an MCP tool node in Dify, you specify the resource URI and server configuration:

import json

# Parameters passed to the MCP tool

params = {
    "servers_config": json.dumps([{
        "name": "demo",
        "url": "https://mcp.example.com",
        "authorization": {"type": "Bearer", "value": "YOUR_TOKEN"}
    }]),
    "tool_name": "read_resource",
    "arguments": json.dumps({
        "uri": "file://documents/report.pdf"
    })
}

When executed, McpClients.execute_tool() calls client.read_resource(uri). For a binary PDF file, the normalized response appears as:

{
    "uri": "file://documents/report.pdf",
    "mimeType": "application/pdf",
    "blob": "JVBERi0xLjQKJcTl8uXrp..."
}

Processing Mixed Content in Downstream Logic

After invocation, handle the returned resource messages based on their content type:

for msg in tool.invoke(params):
    if msg.type == "json":
        resource = msg.content
        if "text" in resource:
            # Process textual data (JSON, markdown, etc.)

            print("Text content:", resource["text"])
        elif "blob" in resource:
            # Decode and persist binary data

            import base64
            decoded_data = base64.b64decode(resource["blob"])
            with open("downloaded_file.pdf", "wb") as f:
                f.write(decoded_data)

This pattern mirrors the internal logic of tools/mcp_call_tool.py, where the plugin uses self.create_json_message(item["resource"]) to emit the final payload.

Summary

  • The plugin detects content type by inspecting for text or blob keys in utils/mcp_client.py, ensuring type-safe processing
  • Text payloads are wrapped with URI and MIME type metadata, defaulting to text/plain when unspecified
  • Binary blobs are base64-encoded for JSON transport and decoded when dispatched as image or video content in tools/mcp_call_tool.py
  • The McpTool._invoke() method routes each content type to the appropriate Dify message format (text, binary blob, or JSON resource)
  • Unsupported content formats trigger immediate exceptions, preventing workflow execution with malformed data

Frequently Asked Questions

What happens if an MCP resource returns content without text or blob keys?

The plugin raises an exception during the iteration over content items in utils/mcp_client.py. This validation prevents undefined behavior by rejecting any resource format that does not conform to the expected text-or-blob contract, ensuring workflow stability.

How does the plugin encode binary data for transmission through Dify?

Binary data remains base64-encoded when wrapped in the JSON resource message structure, allowing it to pass through JSON-serialized communication channels. When dispatched as image or video content, the plugin decodes the base64 string using base64.b64decode before creating the binary blob message.

Can a single MCP resource response contain multiple content items?

Yes, the read_resource method returns a list of content dictionaries, and the plugin iterates over every item to normalize each entry individually. This supports multi-part resources where a single URI might return both metadata text and binary attachments.

Where is the MIME type determined for returned resources?

The MIME type is extracted directly from the MCP server response metadata and preserved in the resource wrapper object. For text content without an explicit MIME type, the plugin defaults to text/plain, while binary content relies on the server's provided MIME type to ensure proper handling downstream.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →