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
Install:
pip install drf-react-by-schema-mcpAdd 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 ]Mount the MCP endpoint (see Mounting /mcp).
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, results} envelope.
Tool |
What it does |
|---|---|
knowledge(modelo?) |
The project schema: a compact overview (endpoints, conventions, stamp) by default, or one model’s fields/interface/enums 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} 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 __.
# one page of 2026 entries
consultar("/api/movimento/",
{"field": "data", "operator": "entre",
"value": "2026-01-01,2026-12-31", "page": 1})
# count + sums for the whole filter, without the list
resumo("/api/movimento/", ["valor", "valor_bruto"],
{"field": "data", "operator": "entre",
"value": "2026-01-01,2026-12-31"})
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 endpoint (modelo/caminho/tipo/verbose names/parent/related), the API conventions (pagination, ordering/search/sum_rows, grid-filter operators) and the schema stamp.
knowledge(modelo="municipio") — that model’s field schema (types, choices, required, read_only…), its TypeScript interface and the referenced enums. The name is matched in any case/style, as a model name or an /api/... path.
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. "valor: 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.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| drf_react_by_schema_mcp-0.2.0.tar.gz | 610.2 kB | Details |
Release files / drf_react_by_schema_mcp-0.2.0.tar.gz
| Download URL | drf_react_by_schema_mcp-0.2.0.tar.gz |
|---|---|
| Size | 610.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e7bca40a2a8dd79615b72851afbef1739b54bdf3435b4c58d26b26ba364a9564
|
|
BLAKE2b-256 checksum How to use checksums |
fd5274d4f3102e35afcbd153fbe27d8171243245e1ae3e08b78ba055cb855079
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/5.0.0 CPython/3.12.3
|