thin-mcp
thin-mcp is a small, typed framework for implementing the tool-serving
surface of the Model Context Protocol.
It connects strict Pydantic models to an explicit tool registry and a
transport-independent protocol dispatcher.
The package deliberately does not own authentication, application permissions,
throttling, auditing, Django models, or business logic. A Django application
should provide a small integration package—typically named mcp_server/—that
registers tools from its application domains and connects the framework to its
HTTP and security layers.
Why Django Ninja?
Django API projects are often built with Django REST Framework (DRF). For this project, I wanted Pydantic models to define and validate the MCP-facing data, so I chose Django Ninja for the optional Django HTTP adapter. The protocol dispatcher and typed tool registry remain framework-neutral; applications can also connect them to another framework, such as FastAPI, with a small route adapter.
Installation
Install the core package:
pip install thin-mcp
Install the optional Django Ninja adapter:
pip install "thin-mcp[django]"
Python 3.12 or newer and Pydantic 2.12 or newer are required.
Recommended Django integration
Keep the MCP integration in the host application, separate from both
thin_mcp and the domain applications it exposes:
my_project/
├── accounts/
│ └── services.py
├── projects/
│ └── services.py
└── mcp_server/
├── api.py
├── core.py
├── permissions.py
├── schemas.py
├── tools_registry.py
└── tools/
├── __init__.py
├── accounts.py
└── projects.py
The recommended pattern is registration-driven:
tools_registry.pyowns oneToolRegistryand, when needed, a host-specificregister_toolwrapper that requires every tool to declare application policy such as token access.- Each
tools/<domain>.pymodule defines typed adapters for one Django domain. tools/__init__.pyexplicitly imports every domain module in stable order. Importing this package populates the shared registry.core.pyconstructs oneMcpServerwith that populated registry.api.pyhandles HTTP, authentication, throttling, and auditing, then delegates the validated request tocore.py.
This makes tools/list deterministic and ensures the schema advertised for a
tool is the schema enforced when that tool runs. Avoid filesystem auto-discovery
or registration hidden in Django app startup hooks.
See GUIDE.md for a complete generic Django example, permission patterns, tests, and migration steps.
Minimal framework example
from pydantic import BaseModel, ConfigDict
from thin_mcp import McpRequest, McpServer, ToolContext, ToolRegistry
class EchoArguments(BaseModel):
model_config = ConfigDict(extra="forbid")
text: str
class EchoResult(BaseModel):
text: str
registry = ToolRegistry()
@registry.register(
name="echo",
description="Echo typed text.",
arguments_model=EchoArguments,
result_model=EchoResult,
)
def echo(context: ToolContext, arguments: EchoArguments) -> EchoResult:
return EchoResult(text=arguments.text)
server = McpServer(
name="example",
version="1.0.0",
protocol_versions=("2025-11-25",),
tools=registry,
)
request = McpRequest.model_validate(
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {"name": "echo", "arguments": {"text": "hello"}},
}
)
response = server.dispatch_request(user=None, request=request)
The host validates transport input into McpRequest, supplies its authenticated
user and request-scoped resources, and serializes the returned McpHttpResult.
Django Ninja hosts can use thin_mcp.django_ninja.McpAPI and
render_mcp_result for exception mapping and HTTP serialization.
Supported MCP surface
The dispatcher currently supports:
initializeserver/discoverfor the modern protocol flowpingtools/listtools/call- notifications that require no response body
Legacy handshake protocol versions and the modern 2026-07-28 request metadata
flow are supported. For modern Streamable HTTP requests, the host builds
McpRequestHeaders from the incoming headers, calls
server.validate_http_request(request, headers), returns any validation result,
and otherwise dispatches the request. Modern responses include protocol result
metadata and disable caching for discovery and tool listings.
Resources, prompts, sampling, elicitation, tasks, sessions, server-initiated notifications, and streaming are not implemented.
Development
uv sync --extra django --group dev
uv run ruff check .
uv run mypy
uv run pytest
uv build
Repository contributors should also read AGENTS.md. Maintainers can follow Publishing to PyPI to configure Trusted Publishing and release from GitHub Actions.
Versioning and license
thin-mcp follows Semantic Versioning. Before 1.0.0, incompatible public API
changes may be released in a new minor version. After 1.0.0, incompatible
changes require a major version.
The package is distributed under the MIT License.
Metadata
Release files for thin-mcp 0.1.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 | Provenance | |
|---|---|---|---|---|
| thin_mcp-0.1.0.tar.gz | 70.7 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| thin_mcp-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 85.6 kB
Release files / thin_mcp-0.1.0.tar.gz
| Download URL | thin_mcp-0.1.0.tar.gz |
|---|---|
| Size | 70.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c164c5f263ce091301cadb591c18b5617a7bddd6935f29e7233982689a6d40c7
|
|
BLAKE2b-256 checksum How to use checksums |
b058e70ca125765f66b16d3ebf21185713be67c3ab609706323ee03360334f70
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 27, 2026.
Transparency logRelease files / thin_mcp-0.1.0-py3-none-any.whl
| Download URL | thin_mcp-0.1.0-py3-none-any.whl |
|---|---|
| Size | 14.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
032b14b6d9c1c40666eb44db4cc76e00c148e21accd71592edb8ed488e71c924
|
|
BLAKE2b-256 checksum How to use checksums |
d19f7ad1dbb21c642b16eafa977494e3c203a2ef3829922cf42c6ccd7820d55e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 27, 2026.
Transparency logSecurity for thin-mcp 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for thin_mcp-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 27, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.