Skip to main content
DRF And React By Schema - MCP

DRF And React By Schema - MCP

A generic, schema-driven MCP server for projects built with DRF And React By Schema (DRBS).

It exposes any DRBS project’s DRF API (/api/...) to MCP clients such as opencode through a small set of generic tools — consultar, resumo, criar, editar, minha_conta — plus the schema-aware knowledge tool and optional per-project shortcuts, so an assistant can understand the project (models, fields, endpoints, conventions) and then read (and, when opted in, write) its data with no per-model tool explosion.

The server is a stateless proxy: it takes the caller’s OAuth 2.1 Bearer token (issued by drf-react-by-schema-oauth), forwards it to the project’s /api/... and lets the project’s own DRF permissions scope the data. It stores no credentials.

About the suite

drf-react-by-schema is a suite that builds headless Django + React applications directly from your models:

  • drf-react-by-schema-django (PyPI) — generates the DRF API (serializers, viewsets, filters, schemas) from your models;

  • drf-react-by-schema-react (npm) — consumes those schemas to build the React forms, grids and CRUD interfaces;

  • drf-react-by-schema-oauth — OAuth 2.1 authorization/resource server that issues the tokens both the API and this MCP server accept;

  • drf-react-by-schema-mcp (this package) — the generic MCP server that exposes the same API to MCP clients.

About this package

A DRBS project already exposes a rich DRF API generated from its models. This package mounts a FastMCP server that proxies that API to MCP clients, so an assistant can:

  • understand the system before acting (knowledge) — the project’s endpoints, conventions and per-model field schemas, fetched from the base package’s GET /drbs/schema/;

  • read any /api/... endpoint (consultar), count and sum filtered sets without downloading them (resumo) and identify the logged-in account (minha_conta);

  • write — opt-in per project — with criar (POST) and editar (PATCH); DELETE is never exposed.

It is deliberately generic: the tool surface is bounded by a fixed set of generic tools plus any project shortcuts, not one tool per model. The same OAuth token authenticates /mcp and /api/..., and the project’s DRF permissions and OAuth scopes (read/write) remain the authority.

Compatibility

The base DRBS package supports Django ≥ 3.2, and some deployments are still on Django 3.2. This package therefore supports Django 3.2 through 5.x (and the 2.x django-oauth-toolkit line pulled in by drf-react-by-schema-oauth). It requires Python ≥ 3.10 (the mcp SDK).

Pre-requisites

  • Django ≥ 3.2

  • djangorestframework

  • drf-react-by-schema-oauth (installed automatically) — provides the OAuth server and the DRF authentication/scopes

  • mcp (installed automatically)

Quick start

  1. Install:

    pip install drf-react-by-schema-mcp
  2. Add the app (after the OAuth package) and include the URLs:

    INSTALLED_APPS = [
        ...
        'oauth2_provider',
        'drf_react_by_schema_oauth',
        'drf_react_by_schema_mcp',
    ]
    
    urlpatterns = [
        ...
        path('', include('drf_react_by_schema_oauth.urls')),
        path('', include('drf_react_by_schema_mcp.urls')),  # Protected Resource Metadata
    ]
  3. Mount the MCP endpoint (see Mounting /mcp).

  4. Configure (all keys optional):

    DRBS_MCP = {
        'WRITE': False,       # read-only by default
        'KNOWLEDGE': True,    # schema-aware knowledge() + write validation
        'RESOURCE_URL': '/mcp',
        'SHORTCUTS': [],      # dotted paths to project-specific tools
    }

Mounting /mcp

/mcp speaks the MCP streamable-http transport, a long-lived ASGI application (it cannot be served from a synchronous WSGI URLconf). There are two supported deployments:

  • Combined — one ASGI process serves both Django and /mcp:

    # asgi.py
    from drf_react_by_schema_mcp.server import get_mcp_asgi_application
    
    application = get_mcp_asgi_application()
  • Standalone — a second ASGI process serves only /mcp (point DRBS_MCP['API_URL'] at the Django host) and the reverse proxy routes /mcp to it:

    python -m drf_react_by_schema_mcp.server
    # or: uvicorn drf_react_by_schema_mcp.server:get_mcp_asgi_application --factory

In both cases the endpoint is protected: an unauthenticated request answers 401 with WWW-Authenticate: Bearer resource_metadata="…", so an MCP client can discover the OAuth server (RFC 9728) and start the flow automatically.

Connecting an MCP client

Point a remote MCP client at https://<host>/mcp with OAuth (no secret file):

"example": {
  "type": "remote",
  "url": "https://<host>/mcp",
  "enabled": true,
  "oauth": {}
}

With opencode that is opencode mcp auth example, followed by opencode mcp debug example.

Tools

The generic tools mirror the DRF API. List endpoints return the results list; detail/object endpoints return the object; metadados=True returns the full {count, next, previous, sum_rows, facets, results} envelope.

Tool

What it does

knowledge(modelo?)

The project schema: a compact overview (endpoints, conventions, stamp, project about) by default, or one model’s field schema (with related_model), valid sum_rows measures/dimensions and docstring with modelo. Registered only when KNOWLEDGE is on.

minha_conta()

GET /api/my_account/ — the logged-in account.

consultar(caminho, parametros?, metadados?)

GET /api/... (list or object). parametros is the querystring.

resumo(caminho, campos?, parametros?)

{count, sum_rows, facets} for the whole filtered set, without the list.

criar(caminho, dados)

POST /api/... (registered only when WRITE is on).

editar(caminho, registro_id, dados)

PATCH /api/.../<id>/ (registered only when WRITE is on).

Accepted querystring parametros (combinable): page (100 rows/page), search (text), ordering (- for descending), sum_rows (comma-separated numeric fields), and the grid filter field / operator / value. The three filter keys may each be a list; items match positionally and combine with AND. Common operators: equals, contains, startsWith, endsWith, isAnyOf, is, not, after, before, onOrAfter, onOrBefore, entre ("start,end"), isEmpty, isNotEmpty. field accepts relation paths with __. Equality on a foreign key compares the related object’s label (__str__/nome/slug), not its id; to filter by id use field="<fk>__id" with operator="is".

sum_rows items may also carry facets: medida|dimensao[|dimensao...] [|limite] (|-separated). medida is a numeric field or count; each dimensao must be a foreign key, a field with choices or a boolean — and may be a nested forward relation with __ (e.g. categoria__regiao); a trailing all-digits part is the top-N limite (ordered by the measure). Each measure still reports its <medida>_total flat, and the grouped buckets come back under facets.

# one page of 2026 entries
consultar("/api/widget/",
          {"field": "publicado_em", "operator": "entre",
           "value": "2026-01-01,2026-12-31", "page": 1})

# count + sums for the whole filter, without the list
resumo("/api/widget/", ["preco", "peso"],
       {"field": "publicado_em", "operator": "entre",
        "value": "2026-01-01,2026-12-31"})

# nº de itens por categoria (e total de preço)
resumo("/api/widget/", ["preco", "count|categoria"])

# top-5 categorias por preço, tabela cruzada com tipo
resumo("/api/widget/", ["preco|categoria|5", "count|categoria|tipo"])

# nº de itens por região da categoria (relação aninhada)
resumo("/api/widget/", ["count|categoria__regiao"])

Schema awareness

Instead of guessing /api/<model>/ paths and field names, the assistant can ask the project what it looks like. knowledge reads the base package’s machine-readable schema endpoint, GET /drbs/schema/ (see drf-react-by-schema, the base package’s “Machine-readable schema” section), with the caller’s Bearer token:

  • knowledge() — a compact overview: every top-level endpoint (modelo/model/app_label/caminho/tipo/verbose names), the API conventions (pagination, ordering/search/sum_rows, grid-filter operators), the schema stamp and the project’s about (the project root’s ABOUT.md, when present).

  • knowledge(modelo="widget") — that model’s field schema (types, choices, required, read_only…, with related_model on each relation field), the valid sum_rows measures and dimensions (medidas/dimensoes) and the model class docstring. Field documentation travels inside the schema as each field’s description — distinct from help_text, which is the text the React UI shows the end user. Both are opt-in on the Django side (a model docstring, or description="..." passed to a schema field) and trimmed when served. The name is matched in any case/style, as the endpoint name, the underlying Django model name, or an /api/... path.

The bundle is schema-only: the React-only TypeScript artifacts (interface/enums) and the auto-generated nested *Related* viewsets are deliberately not shipped, so each relation field instead carries a related_model (query /api/<model>/ and constrain with the grid filter rather than navigating a nested route).

The bundle is fetched once per MCP process and cached in memory, keyed by its stamp: later calls send If-None-Match and a 304 Not Modified reuses the cache, while a changed schema (new stamp) transparently replaces it. Nothing is written to disk and the schema is never exposed as an MCP resource — it reaches the agent only as knowledge() output.

When the project exposes /drbs/schema/, criar/editar validate the payload against the same schema before sending it — required fields, read_only fields, value types and choice options — and return a field-level error without calling the API if it is invalid (e.g. "preco: campo obrigatório ausente."). A valid payload is forwarded unchanged.

If the project does not expose the endpoint (drf-react-by-schema < 0.27 or SCHEMA_ENDPOINT off), knowledge reports it as unavailable and writes are not validated — the server keeps working as a plain proxy.

Shortcuts

Register project-specific tools with dotted paths; each is a callable taking the MCP Context first (exactly like the generic tools) and is exposed under its own name:

DRBS_MCP = {
    "SHORTCUTS": ["myproject.mcp.saldo_ferias"],
    # optionally limit/rename the surface:
    "TOOLS": ["consultar", "resumo", {"ferias": "saldo_ferias"}],
}

Settings

DRBS_MCP is a single dict; every key is optional.

Key

Default

Meaning

WRITE

False

Register the write tools (criar/editar).

KNOWLEDGE

True

Register the schema-aware knowledge tool and validate write payloads against /drbs/schema/ when the project exposes it.

SCHEMA_PATH

"/drbs/schema/"

Path (or absolute URL) of the base package’s schema bundle endpoint.

TOOLS

None

Allowlist of tools to expose. None = all generic (minus writes when WRITE is off) plus every shortcut. A list limits and orders the surface; an entry may rename, e.g. {"buscar": "consultar"}.

SHORTCUTS

[]

Dotted paths to project-specific tool callables.

RESOURCE_URL

"/mcp"

Path (or absolute URL) of the protected resource.

API_URL

None

Base URL the proxy forwards to. None = this request’s origin (the right value when combined with Django); set it for a standalone process.

SERVER_NAME

"drf-react-by-schema"

Name advertised to MCP clients.

READ_SCOPE / WRITE_SCOPE

"read" / "write"

Scope names advertised in the Protected Resource Metadata.

VALIDATE_TOKEN

True

Validate the Bearer token against VALIDATE_PATH before handling a request (so an expired token yields 401).

VALIDATE_PATH

"/api/my_account/"

API path used for that check.

ALLOWED_HOSTS

[]

Transport Host allowlist (anti-DNS-rebinding); empty disables it.

HOST / PORT

"127.0.0.1" / 8000

Bind address for the standalone entrypoint.

TIMEOUT

60

Upstream request timeout, in seconds.

Security model

  • Stateless proxy — no credentials are stored server-side; the caller’s Bearer token is forwarded to /api/... on every call.

  • Read-only by default — writes require WRITE=True and a token carrying the write scope and the project’s DRF permissions.

  • No ``DELETE`` — only GET/POST/PATCH are exposed.

  • Schema is structure, not data — /drbs/schema/ carries the generated picture (models, fields, endpoints, static config) only: no row data and no secrets; it is fetched with the caller’s own token and the project’s existing auth.

  • Scope enforcement is the project’s: read for safe methods, write for unsafe ones, via drf_react_by_schema_oauth.permissions.HasScope.

License

GPLv3 — Cooperativa EITA.

Metadata

Release files for drf-react-by-schema-mcp 0.2.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for drf-react-by-schema-mcp 0.2.4
File Size Uploaded
drf_react_by_schema_mcp-0.2.4.tar.gz 614.3 kB Details

Release files / drf_react_by_schema_mcp-0.2.4.tar.gz

Download URL drf_react_by_schema_mcp-0.2.4.tar.gz
Size 614.3 kB
Tags Source
SHA-256 checksum
How to use checksums
9ab912f20af640008ce5de150267e031591add031c74c025de4f41612b97fe59
BLAKE2b-256 checksum
How to use checksums
32ca0441c4a27260b03af8398446c5d8c527321e92e6d4338f8d306cd03104f9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/5.0.0 CPython/3.12.3

Release history Release notifications | RSS feed

0.2.5

1 release file

This release

0.2.4 This release

1 release file

0.2.3

1 release file

0.2.2

1 release file

0.2.1

1 release file

0.2.0

1 release file

0.1.1

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page