MCP Protocol

The Smarter Project MCP server: the Model Context Protocol, over Streamable HTTP, in Django.

SmarterProjectMCPServer answers the JSON-RPC messages of one POST request, and SmarterProjectMCPServerView serves it. It speaks the initialize handshake of every protocol version that the MCP Python SDK negotiates (mcp_types.version.HANDSHAKE_PROTOCOL_VERSIONS), and implements these methods:

  • initialize: the server’s identity, its tools capability and its instructions.

  • notifications/initialized and every other notification: accepted, and ignored.

  • ping: an empty result.

  • tools/list: the tools of smarter.apps.mcpserver.tools.

  • tools/call: runs a tool. A tool’s own errors, e.g. a file that does not exist, are returned as a result with isError set, so that the LLM can correct its call.

Why not the MCP SDK’s server. The SDK’s server runs as an ASGI application, with an anyio task group for its lifetime, and calls its tools as coroutines. Smarter’s views and ORM are synchronous, and the platform runs under both the Django development server and uvicorn. Every message of this server is answered from the database, with no state between requests, so the server is a plain Django view that uses the SDK’s own Pydantic models, mcp_types, to validate the requests and to build the responses.

Stateless. The server answers every POST with application/json, and does not issue an Mcp-Session-Id. Clients therefore open no GET stream, and send no DELETE, and any of the platform’s pods can answer any request.

Note

Experimental. The MCPServer was designed and coded by Claude Code (Anthropic’s Claude Opus 5.5), with Lawrence McDaniel as co-author. It is experimental, and will be documented.

class smarter.apps.mcpserver.server.SmarterProjectMCPServer(repository=None)[source]

Bases: object

The MCP server of one repository of The Smarter Project, or of all of them.

Parameters:

repository (ProjectRepository | None) – The repository, or None for all of them.

Example usage:

server = SmarterProjectMCPServer(get_repository("smarter-cli"))
response = server.handle({"jsonrpc": "2.0", "id": 1, "method": "tools/list"})
__init__(repository=None)[source]
call_tool(params)[source]

Run a tool.

Parameters:

params (CallToolRequestParams) – The tool’s name and arguments.

Return type:

CallToolResult

Returns:

The tool’s result, as text. A tool error is a result with is_error set.

Raises:

LookupError – If there is no such tool.

dispatch(method, params)[source]

Run one JSON-RPC method.

Parameters:
  • method (str) – The method.

  • params (dict[str, Any]) – Its params.

Return type:

Result

Returns:

Its result.

Raises:
  • LookupError – If the server does not implement the method, or the tool does not exist.

  • ValidationError – If the params are not valid.

static dump(response)[source]

Return a response as JSON.

An error keeps its id, which JSON-RPC requires, even when it is null.

Return type:

TypeAliasType

static error(request_id, code, message)[source]

Return a JSON-RPC error response.

Return type:

JSONRPCError

property formatted_class_name: str

The class name, for logging.

handle(payload)[source]

Answer the JSON-RPC message, or batch of messages, of one POST request.

Parameters:

payload (TypeAliasType) – The request body, parsed.

Return type:

TypeAliasType | None

Returns:

The response body, or None if no message needs a response, e.g. a notification.

handle_message(message)[source]

Answer one JSON-RPC message.

Parameters:

message (TypeAliasType) – The message.

Return type:

JSONRPCResponse | JSONRPCError | None

Returns:

The response, or None for a notification, or for a response from the client.

initialize(params)[source]

Answer the initialize handshake.

Parameters:

params (InitializeRequestParams) – The client’s offer.

Return type:

InitializeResult

Returns:

The client’s protocol version, if this server speaks it, and otherwise the latest that it speaks, which the client may refuse.

instructions()[source]

Return the server’s instructions, which MCP clients add to the LLM’s system prompt.

Return type:

str

property name: str

The server’s name, e.g. smarter-project or smarter-project-smarter-cli.

server_info()[source]

Return the server’s identity, for the initialize result.

Return type:

Implementation