如何在 Django 中集成 MCP Server

目录

    • 背景说明
    • [第一步:使用 ASGI](#第一步:使用 ASGI)
      • [第二步:修改 asgi.py 中的应用](#第二步:修改 asgi.py 中的应用)
      • [第三步:Django 数据的异步查询](#第三步:Django 数据的异步查询)

背景说明

有几个原因导致 Django 集成 MCP Server 比较麻烦

  • 目前支持的 MCP 服务是 SSE 协议的,需要长连接,但一般来讲 Django 是传统的连接方式
  • MCP 的 Python SDK 直接封装了 Starlette 作为 ASGI 服务的提供,和 Django 的框架并不兼容
  • 目前无法直接将 Starlette 的服务,作为 Django 某个子路由下的处理函数直接使用,我有看到一个插件项目,在处理这个事情,但目前我自己没有运行成功,欢迎交流

所以最简单的思路是 MCP 跑在另一个端口上,通过 Django ORM 来获取 Django 项目中的数据。

但如果希望集成到一个项目中使用,需要做一些调整:

  • 使用 ASGI 来处理服务请求
  • 修改 asgi.py 中的应用,指定部分路由由 Starlette 或其他 ASGI 服务处理
  • 针对 Django 数据库查询语句,进行异步环境下的使用调整

第一步:使用 ASGI

官方文档推荐了几个 ASGI 服务,可以用来替代原有的 uwsgi,包括 Daphne、Hypercorn、Uvicorn,这里以 Daphne 为例说明,因为 Daphne 提供了和 Django 更好的集成效果

  • 原有项目中 wsgi.py 下的相应调整,需要放到 asgy.py

  • 调整 settings.py 文件

    python 复制代码
    # settings.py
    INSTALLED_APPS = [
        'daphne', # 需要放在第一个
    	...
    ]
    ASGI_APPLICATION = '项目名称.asgi.application'
  • 使用 Daphne 来接受请求,需要运行

    shell 复制代码
    # 提供接口
    daphne -b 127.0.0.1 -p 8001 your_project_name.asgi:application
    # 通过 socket 文件
    daphne -u /path/to/your/project/daphne.sock your_project_name.asgi:application
    
    # 调试
    python manage.py runserver
  • 至于 Daphne 和 Nginx 或 Apache 的配置文件,和之前使用 uwsgi 没有太大差异

第二步:修改 asgi.py 中的应用

主要目的有几个

  • 引入 mcp 服务的 starlette app,对部分路径进行处理
  • 对于其他路径,仍由 Django 进行处理

这里作为一个参考

python 复制代码
import os

from django.core.asgi import get_asgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', '项目名称.settings')

# 原来的 application
django_asgi_app = get_asgi_application()

# ============
# 写一个 mcp 服务,内容也可以挪到其他位置,引入即可
from mcp.server.fastmcp import FastMCP
from asgiref.sync import sync_to_async

mcp1 = FastMCP("weather")

@mcp1.resource("greeting://{name}")
def get_greeting(name: str) -> str:
    """Get a personalized greeting"""
    return f"Hello, {name}!"# Add an addition tool

@mcp1.tool()
def add(a: int, b: int) -> int:
    """Add two numbers"""
    return a + b

mcp1.settings.mount_path = "/star" # 告诉 mcp server 将要处理 /star 路径下的内容
starlette_app = mcp1.sse_app()

# ============
# 对 application 进行引流
def application(scope, receive, send):
	
	# star 开头的服务全部交给 mcp1 处理
    if scope['path'].startwith('/star):
        scope['path'] = scope['path'].replace('/star', '', 1) # 记得把路径做个调整,不然会出错
        return starlette_app(scope, receive, send)
	# 其他交给 Django 处理
    return django_asgi_app(scope, receive, send)

第三步:Django 数据的异步查询

当我们定义一个 mcp 的工具,需要访问 Django 数据库时,初始化的部分需要注意:

  • 如果 mcp 的服务就在 Django 的工程目录下,和 Django 一起完成了初始化,基本不需要做数据库和配置的处理
  • 如果需要单独使用 Django 的数据库,可以参考之前的文章,完成配置。

由于 mcp 是 ASGI 服务,所以需要把所有的 Django 数据库查询调整为异步模式:

  • queryset 是惰性执行的,需要通过某些涉及数据库查询的函数才能触发执行
  • 数据库查询的函数是同步的需要调整成异步函数
python 复制代码
# 假设我们定义了一个 Model 叫 Entry
from xxx import Entry
# 引入 sync_to_async
from asgiref.sync import sync_to_async


@mcp1.tool()
# 工具函数,需要定义为 async 函数,和 mcp1 放在同一个文件里
async def get_entry(tile: str):
    """Get the Entries"""
	# 方法一:async 循环
	async for e in Entry.objects.filter(title=name):
    	results.append(e.body)
		break
    return results

	# 方法二:通过 sync_to_async 函数,把同步函数异步执行
	q = Entry.objects.all()
	lc = sync_to_async(len)(q) # sync_to_async 会把函数变成一个 coroutine
	l = await lc # 等待 lc 执行
	results = q[0].body
    return results

	# 方法三,使用同步函数的异步版本,通常在同步函数前会增加 a,例如 aget、afirst
	q = await Entry.objects.afirst()
	results = q.body
    return results
相关推荐
风象南22 分钟前
Claude Code这个隐藏技能,让我告别PPT焦虑
人工智能·后端
Mintopia1 小时前
OpenClaw 对软件行业产生的影响
人工智能
陈广亮2 小时前
构建具有长期记忆的 AI Agent:从设计模式到生产实践
人工智能
会写代码的柯基犬2 小时前
DeepSeek vs Kimi vs Qwen —— AI 生成俄罗斯方块代码效果横评
人工智能·llm
Mintopia2 小时前
OpenClaw 是什么?为什么节后热度如此之高?
人工智能
爱可生开源社区2 小时前
DBA 的未来?八位行业先锋的年度圆桌讨论
人工智能·dba
叁两5 小时前
用opencode打造全自动公众号写作流水线,AI 代笔太香了!
前端·人工智能·agent
前端付豪5 小时前
LangChain记忆:通过Memory记住上次的对话细节
人工智能·python·langchain
strayCat232555 小时前
Clawdbot 源码解读 7: 扩展机制
人工智能·开源