django-mcp-server

repository·main·Indexed 18 days ago

https://github.com/gts360/django-mcp-server

A Django extension that implements the Model Context Protocol (MCP), enabling AI agents to interact with Django models and logic via a standardized interface. It supports both WSGI and ASGI, providing tools like ModelQueryToolset for querying models, MCPToolset for custom logic, and integration with Django Rest Framework (DRF) to publish APIs as MCP tools. Includes management commands such as mcp_inspect for verification and stdio_server for local transport.

Tokens
3.9K
Snippets
17
Records
17
Agent score
13%

What's inside django-mcp-server

  1. Create a secondary MCP endpoint

    main

    You can host multiple independent MCP servers by creating new DjangoMCP instances and mounting them to different URL paths.

    Security Warning: When mounting a secondary MCP server via MCPServerStreamableHttpView.as_view(mcp_server=second_mcp), the DJANGO_MCP_AUTHENTICATION_CLASSES setting is ignored. You MUST manually provide permission_classes and authentication_classes to the view to secure the endpoint.

    # In mcp.py
    from mcp_server.djangomcp import DjangoMCP
    second_mcp = DjangoMCP(name="altserver")
    
    @second_mcp.tool()
    async def my_tool():
        ...
    
    # In urls.py
    from rest_framework.permissions import IsAuthenticated
    from rest_framework.authentication import TokenAuthentication
    from mcp_server.djangomcp import MCPServerStreamableHttpView
    from yourapp.mcp import second_mcp
    
    urlpatterns = [
        path(
            "altmcp", 
            MCPServerStreamableHttpView.as_view(
                mcp_server=second_mcp, 
                permission_classes=[IsAuthenticated], 
                authentication_classes=[TokenAuthentication]
            )
        ),
    ]
  2. Configure Django for MCP

    main

    To enable the MCP server in your Django project, follow these two steps:

    1. Add mcp_server to your INSTALLED_APPS in settings.py.
    2. Include the mcp_server.urls in your project's urls.py.

    By default, the MCP endpoint will be available at /mcp.

    # settings.py
    INSTALLED_APPS = [
        # your apps...
        'mcp_server',
    ]
    
    # urls.py
    from django.urls import path, include
    
    urlpatterns = [
        # your urls...
        path("", include('mcp_server.urls')),
    ]
  3. Configure Claude Desktop for local MCP testing

    main

    To test your Django MCP server in Claude Desktop, you must use the stdio_server transport. Since Claude Desktop currently only supports local MCP servers, your Django application must be running on the same machine.

    Update your claude_desktop_config.json with the following structure:

    {
     "mcpServers": {
         "test_django_mcp": {
             "command": "/path/to/interpreter/python",
             "args": [
                 "/path/to/your/project/manage.py",
                 "stdio_server"
             ]
         }
     }
    }

    Note:

    • /path/to/interpreter/ should be the path to your Python interpreter (e.g., inside your virtual environment).
    • /path/to/your/project/ is the absolute path to your Django project directory.
  4. Customize output format and resource attachment in ModelQueryToolset

    main

    You can customize how ModelQueryToolset produces output by:

    1. Defining DRF renderer classes in DJANGO_MCP_OUTPUT_RENDERER_CLASSES in settings.py.
    2. Specifying output_format (e.g., "csv") in the toolset declaration.
    3. Using output_as_resource=True to attach the result as an [MCP Embedded Resource] instead of a direct return value.

    Note: Some renderers like drf-excel may not work as they require a full DRF View context.

    # In settings.py
    DJANGO_MCP_OUTPUT_RENDERER_CLASSES = [
        "rest_framework.renderers.JSONRenderer",
        "rest_framework_csv.renderers.CSVRenderer"
    ]
    
    # In your toolset
    class MyToolset(ModelQueryToolset):
        # ...
        output_format="csv"
        output_as_resource=True
  5. Publish Django Rest Framework APIs as MCP Tools

    main

    You can seamlessly register DRF Mixin-based views (CreateModelMixin, UpdateModelMixin, DestroyModelMixin, ListModelMixin) as MCP tools using specific registration annotations. The server will automatically generate the necessary schemas for MCP Clients.

    Important Considerations:

    • Authentication/Permissions: Built-in authentication classes, filter_backends, permission_classes, and pagination_class are disabled by default because MCP-specific authentication is used instead.
    • Pagination: Since pagination_class is disabled, self.paginator will be None in existing paginated views.
    • Instructions: The docstring of the view is used as instructions for the model. You can also explicitly provide instructions via the annotation to tune the model's behavior.
    from mcp_server import drf_publish_create_mcp_tool
    
    @drf_publish_create_mcp_tool(instructions="Use this view to create instances of MyModel")
    class MyModelView(CreateAPIView):
        """
        A view to create MyModel instances
        """
        serializer_class=MySerializer
  6. Configure global MCP server settings

    main

    Initialize global server settings in your Django settings.py using the DJANGO_MCP_GLOBAL_SERVER_CONFIG dictionary. These settings are passed to the MCPServer during initialization.

    DJANGO_MCP_GLOBAL_SERVER_CONFIG = {
        "name": "mymcp",
        "instructions": "Some instructions to use this server",
        "stateless": False
    }
  7. Configure MCP Authentication and Authorization

    main

    The MCP endpoint supports Django Rest Framework (DRF) authentication classes. You can specify them in settings.py using DJANGO_MCP_AUTHENTICATION_CLASSES.

    Recommendation: For compliance with the MCP Specification (2025-03-26), it is advised to use an OAuth2 workflow by integrating django-oauth-toolkit and using 'oauth2_provider.contrib.rest_framework.OAuth2Authentication'.

    DJANGO_MCP_AUTHENTICATION_CLASSES = ["rest_framework.authentication.TokenAuthentication"]
  8. Test the MCP server with the MCP Python SDK

    main

    You can test your integration using the mcp Python SDK by connecting to the streamable HTTP endpoint (default /mcp).

    from mcp.client.streamable_http import streamablehttp_client
    from mcp import ClientSession
    
    
    async def main():
        # Connect to a streamable HTTP server
        async with streamablehttp_client("http://localhost:8000/mcp") as (read_stream, write_stream, _):
            # Create a session using the client streams
            async with ClientSession(read_stream, write_stream) as session:
                # Initialize the connection
                await session.initialize()
                # Call a tool
                tool_result = await session.call_tool("get_alerts", {"state": "NY"})
                print(tool_result)
    
    
    if __name__ == "__main__":
        import asyncio
        asyncio.run(main())
  9. Use low-level FastMCP annotations for tools and resources

    main

    You can bypass the high-level toolset abstractions and use the mcp_server instance directly with FastMCP-style annotations (@mcp.tool()).

    Critical Requirements for Async Tools:

    1. Always use Django's async ORM API (e.g., .afirst(), .asave(), .acreate()) when defining async tools.
    2. Do not return a QuerySet. Returning a QuerySet will cause errors because it will be evaluated asynchronously outside the expected context.
    from mcp_server import mcp_server as mcp
    from .models import Bird
    
    @mcp.tool()
    async def get_species_count(name: str) -> int:
        '''Find the ID of a bird species by name (partial match). Returns the count.'''
        ret = await Bird.objects.filter(species__icontains=name).afirst()
        if ret is None:
            ret = await Bird.objects.acreate(species=name)
        return ret.count
  10. Define generic MCP tools using MCPToolset

    main

    To publish custom logic or service methods as MCP tools, create a subclass of MCPToolset. Only public methods (those without a leading underscore _) will be published as tools available to the MCP client.

    from mcp_server import MCPToolset
    from django.core.mail import send_mail
    
    class MyAITools(MCPToolset):
        def add(self, a: int, b: int) -> list[dict]:
            """A service to add two numbers together"""
            return a + b
    
        def send_email(self, to_email: str, subject: str, body: str):
            """ A tool to send emails"""
            send_mail(
                 subject=subject,
                 message=body,
                 from_email='your_email@example.com',
                 recipient_list=[to_email],
                 fail_silently=False,
             )
  11. Expose Django models as MCP tools using ModelQueryToolset

    main

    To allow AI agents to query your Django models, create a subclass of ModelQueryToolset and define the model attribute. You can override get_queryset() to apply custom filtering logic. Note that self.request is available within the toolset to facilitate request-based filtering.

    from mcp_server import ModelQueryToolset
    from .models import Bird, Location, City
    
    class BirdQueryTool(ModelQueryToolset):
        model = Bird
    
        def get_queryset(self):
            """self.request can be used to filter the queryset"""
            return super().get_queryset().filter(location__isnull=False)
    
    class LocationTool(ModelQueryToolset):
        model = Location
    
    class CityTool(ModelQueryToolset):
        model = City