Skip to content

Fix case-insensitive handling of text MIME types for FileResource #3131

Description

@dchou1618

Initial Checks

Description

Summary

On current main (v2, tested at 3a6f299), FileResource treats MIME types as text only when the value starts with text/ using a case-sensitive comparison. As a result, mixed-case or uppercase text MIME types such as Text/Markdown or TEXT/plain are incorrectly classified as binary.

This is inconsistent with RFC 9110 §8.3.1, which states that media types are case-insensitive. In other words, application/json, Application/JSON, and APPLICATION/JSON are equivalent, and the same principle applies to text/* media types.

Root cause

The current logic checks whether the MIME type starts with text/ directly, without normalizing the value first. Because the comparison is case-sensitive, uppercase or mixed-case text media types do not match and are misclassified as binary.

Why it matters

This can cause text resources to be read and returned as bytes instead of text when the caller provides a non-lowercase text/* MIME type. That can break downstream consumers that expect text content to be handled as text.

Proposed fix

Normalize the MIME type to lowercase before checking whether it begins with text/, so text media types are detected case-insensitively.

This fix is already covered by this PR:

Example

from mcp.server.mcpserver.resources.types import FileResource

resource = FileResource(
    uri="file:///tmp/example.md",
    name="example",
    path="/tmp/example.md",
    mime_type="Text/Markdown",
)

assert resource.is_binary is False

Example Code

class DummyRequest:
    def __init__(self, headers):
        self.headers = headers


def _check_content_type(request):
    content_type = request.headers.get("content-type", "")

    media_types = [
        part.strip().lower()
        for part in content_type.split(";", 1)[0].split(",")
    ]

    return "application/json" in media_types


def test(ct):
    req = DummyRequest({"content-type": ct})
    result = _check_content_type(req)
    print(f'"{ct}" -> {result}')


if __name__ == '__main__':
    cases = [
        'application/json',
        'Application/JSON',
        'application/json; charset=utf-8',
        'APPLICATION/JSON; CHARSET=UTF-8',
        'text/plain',
    ]
    for c in cases:
        test(c)

Result:

"application/json" -> True
"Application/JSON" -> True
"application/json; charset=utf-8" -> True
"APPLICATION/JSON; CHARSET=UTF-8" -> True
"text/plain" -> False

Python & MCP Python SDK

Python 3.12.13
MCP Python SDK 1.28.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions