Skip to main content
Glama
joshuadavidthomas

Django Shell MCP Server

resources.py7.11 kB
from __future__ import annotations import inspect import os import sys import sysconfig from pathlib import Path from typing import Any from typing import Literal import django from django.apps import AppConfig from django.apps import apps from django.conf import settings from django.contrib.auth import get_user_model from django.db import models from pydantic import BaseModel from pydantic import field_serializer def get_source_file_path(obj: Any) -> Path: target = obj if inspect.isclass(obj) else obj.__class__ try: return Path(inspect.getfile(target)) except (TypeError, OSError): return Path("unknown") def is_first_party_app(app_config: AppConfig) -> bool: """Check if an app is first-party (project code) vs third-party (installed package). Uses Python's sysconfig to determine installation paths, which properly handles all installation scenarios (pip, conda, virtualenv, etc.) and is platform-independent. Args: app_config: Django AppConfig to check Returns: True if the app is first-party project code, False if third-party or stdlib """ try: # Defensive check for malformed app configs (should never happen in practice) if app_config.module is None: # pragma: no cover return False app_path = Path(inspect.getfile(app_config.module)).resolve() for lib_path in [ Path(sysconfig.get_path("purelib")), # site-packages (pure Python) Path(sysconfig.get_path("platlib")), # site-packages (platform-specific) Path(sysconfig.get_path("stdlib")), # standard library ]: try: if app_path.is_relative_to(lib_path): return False # Windows-specific: paths on different drives (e.g., C:\ vs D:\) except ValueError: # pragma: no cover pass return True # Defensive error handling for built-in modules or broken app configs except (TypeError, OSError): # pragma: no cover return False def filter_models( models: list[Any], include: list[str] | None = None, scope: Literal["project", "all"] = "project", ) -> list[Any]: """Filter Django models by app inclusion or scope. Args: models: List of Django model classes to filter include: Specific app labels to include (overrides scope) scope: "project" for project models, "all" for everything Returns: Filtered list of model classes """ filtered_models = [] for model in models: app_label = model._meta.app_label # If include is specified, only filter by include (ignore scope) if include is not None: if app_label in include: filtered_models.append(model) # Otherwise, filter by scope elif scope == "project" and is_first_party_app(apps.get_app_config(app_label)): filtered_models.append(model) elif scope == "all": filtered_models.append(model) return filtered_models class ProjectResource(BaseModel): python: PythonResource django: DjangoResource @classmethod def from_env(cls) -> ProjectResource: py = PythonResource.from_sys() dj = DjangoResource.from_django() return ProjectResource(python=py, django=dj) class PythonResource(BaseModel): base_prefix: Path executable: Path path: list[Path] platform: str prefix: Path version_info: tuple[ int, int, int, Literal["alpha", "beta", "candidate", "final"], int ] @classmethod def from_sys(cls) -> PythonResource: return cls( base_prefix=Path(sys.base_prefix), executable=Path(sys.executable), path=[Path(p) for p in sys.path], platform=sys.platform, prefix=Path(sys.prefix), version_info=sys.version_info, ) class DjangoResource(BaseModel): apps: list[str] auth_user_model: str | None base_dir: Path databases: dict[str, dict[str, str]] debug: bool settings_module: str version: tuple[int, int, int, Literal["alpha", "beta", "rc", "final"], int] @classmethod def from_django(cls) -> DjangoResource: app_names = [app_config.name for app_config in apps.get_app_configs()] databases = { db_alias: { "engine": db_config.get("ENGINE", ""), "name": str(db_config.get("NAME", "")), } for db_alias, db_config in settings.DATABASES.items() } if "django.contrib.auth" in app_names: user_model = get_user_model() auth_user_model = f"{user_model.__module__}.{user_model.__name__}" else: auth_user_model = None return cls( apps=app_names, auth_user_model=auth_user_model, base_dir=Path(getattr(settings, "BASE_DIR", Path.cwd())), databases=databases, debug=settings.DEBUG, settings_module=os.environ.get("DJANGO_SETTINGS_MODULE", ""), version=django.VERSION, ) class AppResource(BaseModel): name: str label: str path: Path models: list[ModelResource] @classmethod def from_app(cls, app: AppConfig) -> AppResource: appconfig = get_source_file_path(app) app_path = appconfig.parent if appconfig != Path("unknown") else Path("unknown") app_models = ( [ ModelResource.from_model(model) for model in app.models.values() if not model._meta.auto_created ] if app.models else [] ) return cls(name=app.name, label=app.label, path=app_path, models=app_models) @field_serializer("models") def serialize_models(self, models: list[ModelResource]) -> list[str]: return [model.model_dump()["model_class"] for model in models] class ModelResource(BaseModel): model_class: type[models.Model] import_path: str source_path: Path fields: dict[str, str] @classmethod def from_model(cls, model: type[models.Model]): field_types = { field.name: field.__class__.__name__ for field in model._meta.fields } return cls( model_class=model, import_path=f"{model.__module__}.{model.__name__}", source_path=get_source_file_path(model), fields=field_types, ) @field_serializer("model_class") def serialize_model_class(self, klass: type[models.Model]) -> str: return klass.__name__ class SettingResource(BaseModel): key: str value: Any value_type: str @field_serializer("value") def serialize_value(self, value: Any) -> Any: # Handle common Django types that need conversion if isinstance(value, Path): return str(value) if isinstance(value, type): # Class objects return f"{value.__module__}.{value.__name__}" return value

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/joshuadavidthomas/mcp-django-shell'

If you have feedback or need assistance with the MCP directory API, please join our Discord server