-
Notifications
You must be signed in to change notification settings - Fork 39
Description
When adding django-mcp-server to a project that uses drf-spectacular to generate an OpenAPI specification for the endpoints provided by DRF, the following fails:
python manage.py spectacular --validate --fail-on-warn --file /tmp/some.yaml
With the error message:
.../mcp_server/views.py:13: Error [MCPServerStreamableHttpView]: unable to guess serializer. This is graceful fallback handling for APIViews. Consider using GenericAPIView as view base class, if view is under your control. Either way you may want to add a serializer_class (or method). Ignoring view for now.
Workaround
- Remove the command line option
--fail-on-warn
. However, this is not ideal because then other warnings also slip through. - Remove the MCP server endpoint from the OpenAPI specification using a precprocessing hook. This seems fine enough because few will call the MCP server directly by using its REST endpoint.
The latter can be done with:
# settings.py
SPECTACULAR_SETTINGS = {
...
"PREPROCESSING_HOOKS": ["core.mcp.endpoints_without_mcp_server"],
...
}
# core/mcp.py
def endpoints_without_mcp_server(endpoints: list[tuple]) -> list[tuple]:
"""
Preprocessing hook for drf-spectacular that excludes mcp-server endpoints.
"""
return [
(path, path_regex, method, callback)
for path, path_regex, method, callback in endpoints
if path != "/mcp"
]
Permanent solution
While this workaround works for me, basically everybody else using drf-spectacular
would need to add it to their project, too. So I was wondering if a general solution could be added.
As far as I understand, all the MCP server endpoints just use JSON RPC 2.0. So basically adding a serializer that represents JSON 2.0 to the endpoints in MCPServerStreamableHttpView
should do the trick. Something along the line:
from rest_framework import serializers
class JsonRpcSerializer(serializers.Serializer):
id = serializers.IntegerField()
jsonrpc = serializers.CharField(read_only=True)
method = serializers.CharField()
params = serializers.ListField(child=serializers.DictField(), required=False)
error = serializers.DictField(required=False)
If you are interested, I can make a stab at it.
But maybe there is a better solution, so I'm putting this up for discussion first.
PS: Thank you for this library, in particular for the remarkably elegant and clean design that integrates so well with DRF.