Fix DRF Integration Body Processing and API Failure Issues#40
Fix DRF Integration Body Processing and API Failure Issues#40zacharypodbela wants to merge 2 commits intogts360:mainfrom
Conversation
|
@Artui this PR proposes a clean way as it seems to manage the request, but removes part of the logic you coded. Can you please confirm that it does not break your use case ? |
Yeah it will |
But I can keep using the older version for now |
|
@Artui what use case would this break? If you share more info I can try and figure out a solution that continues to support it, while fixing the 2 issues. |
|
Well to give you an opinion on the topic :
I don't have enough expertise on DRF internal to judge but I noticed that many issues are solved by giving somehow access to the original request, so maybe we should go this way. I appreciate about this MR that it uses
|
I was attempting to fix the issue of having some arbitrary metadata fields on a django |
|
Ah that makes sense. In your diagram you said "without data from middleware" -- Can you share more details on what data the middleware adds when an API call comes in that is missing when the Request is passed in via the Tool flow? |
|
Please i will like to ask, i get an error saying that viewset does not have attribute 'action' when i publishish and try the viewsets endpoint with my agent, again what is the fix for the missing have not been able to see that here. Is it part of a new release? |
|
@Artui if we keep the |
Yeah |
omarbenhamid
left a comment
There was a problem hiding this comment.
@zacharypodbela very important PR as it solves in a nicer way a longering issue with the request object.
Would you please apply the suggested changes for backward compatiblity if you still have time on the topic ? If you can't I can do.
| request.user = mcp_request.user | ||
| if mcp_request.session: | ||
| request.session = mcp_request.session | ||
|
|
There was a problem hiding this comment.
for compatibility of specific use cases that need for example communication between middleware and tools please add :
request.mcp_request = mcp_request
request.original_request = mcp_request # For backward compatiblity
| @@ -460,39 +461,35 @@ def init(): | |||
|
|
|||
There was a problem hiding this comment.
Add here :
warnings.warn("request.original_request is deprecated, and will be removed in future releases")
|
PR confirmed working |
|
An alternative approach that does not involve using import functools
import json
from io import BytesIO
import mcp_server.djangomcp as djangomcp
from django.http import HttpRequest
class CustomDRFRequestWrapper(HttpRequest):
def __init__(self, mcp_server, mcp_request, method, body_json=None, id=None):
super().__init__()
self._original_django_http_request = original_django_http_request = mcp_request._request
self.method = method
self.content_type = 'application/json'
serialized_body = b'' if body_json is None else json.dumps(body_json).encode('utf-8')
self.META = getattr(original_django_http_request, 'META', {})| {
'CONTENT_TYPE': 'application/json',
'HTTP_ACCEPT': 'application/json',
'CONTENT_LENGTH': len(serialized_body),
}
self._stream = BytesIO(serialized_body)
self._read_started = False
self.user = mcp_request.user
self.session = mcp_request.session
self.path = f'/_djangomcpserver/{mcp_server.name}'
if id is not None:
self.path = f'{self.path}/{id}'
def __getattr__(self, name):
return getattr(self._original_django_http_request, name)
def base_api_view_caller_tool_init(self, view_class, **kwargs):
self.view = view_class.as_view(**kwargs)
djangomcp._DRFRequestWrapper = CustomDRFRequestWrapper
djangomcp.BaseAPIViewCallerTool.__init__ = functools.update_wrapper(
base_api_view_caller_tool_init, djangomcp.BaseAPIViewCallerTool.__init__
) |


Summary
This PR fixes critical bugs in the Django REST Framework integration and adopts a cleaner architectural approach using composition over method patching.
Bugs Fixed
1. Body Parameter Mapping Issue
{"body": {"title": "...", "content": "..."}}) were not being properly extracted for DRF serializers2. Global ViewSet Patching Breaking Normal HTTP Requests
initialize_requestmethod was being globally patched on ViewSet classes, affecting ALL requests to those ViewSets, including normal API requestscurl localhost:8000/posts/) failed withAttributeError: 'WSGIRequest' object has no attribute 'original_request'Technical Strategy
Instead of trying to bypass or hack DRF's request creation, we pre-process the MCP request into exactly what DRF expects (a simple Django HttpRequest) and then let DRF run its full lifecycle using its intended mechanisms.
The benefits of this approach are:
The potential drawbacks are:
Demo / Testing
Here are screenshots of my really simple Blog Post app (see code here) working with Claude Desktop:





Here's my really simple Blog Post app normal API calls working:

All tests in the bird_counter example app pass: