Views
The Django views of the MCPServer’s two endpoints, over MCP’s Streamable HTTP transport.
PublicEndpointView is the endpoint of the public tools,
PublicEndpoint. It is mounted at:
/api/v1/mcp/smarter-project/: every repository of The Smarter Project./api/v1/mcp/smarter-project/<repository>/: one repository, e.g.smarter-cli.
StaffEndpointView is the endpoint of the staff-only tools,
StaffEndpoint, at
/api/v1/mcp/smarter-operations/. It serves only the platform’s staff
(is_platform_staff(): the active staff users of the Smarter
account, not the admins of other accounts), in one of two ways:
a request whose
Authorization: Tokenheader carries a staff user’s api key (aSmarterAuthToken), e.g. from Claude Code, ora request that this platform signed, whose
X-Smarter-Acting-Userheader names the staff user who is chatting with an LLMClient, e.g.smarter_sysadmin: seeacting_user. One that the platform signed for nobody in particular, e.g. the background refresh of an MCPClient’s catalog, may list the tools, but every tool refuses to run.
Without a valid credential it answers 401 Unauthorized, and for a user who is not one of the
platform’s staff 403 Forbidden, before it reads the request’s JSON-RPC. The checks are in
smarter.apps.mcpserver.protocol.auth.
Only POST is served. A POST whose messages are all notifications is answered 202
Accepted, with no body, and every other POST with application/json. The server
issues no session, and offers no GET stream, so GET and DELETE are answered 405 Method
Not Allowed, which MCP clients expect of a stateless server.
The public endpoint requires no authentication: its read-only tools serve the public
repositories of The Smarter Project. A client may send the user’s GitHub classic personal
access token in an Authorization: Bearer header, and is then also served the tools
that write as that user: create_issue, comment_on_issue, close_issue and
create_pull_request. The token is passed to the tool as a
SecretStr, and is never logged. Each client IP address may send at most
smarter_settings.mcpserver_rate_limit requests a minute: see
smarter.apps.mcpserver.protocol.ratelimit.
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.protocol.views.PublicEndpointView(**kwargs)[source]
Bases:
SmarterViewThe view of the MCPServer’s public endpoint, over MCP’s Streamable HTTP transport.
It is public: no authentication, but a rate limit for each IP address. CSRF does not apply, because MCP clients are not browsers with a session, and responses are never cached, because each one answers a different JSON-RPC message.
- Parameters:
repository – From the url: the repository’s name, or None for every repository.
- dispatch(request, *args, **kwargs)
- property formatted_class_name: str
The module and class name, formatted for the start of a log message.
- http_method_names = ['post', 'options']
GET and DELETE are
405 Method Not Allowed, as MCP clients expect of a stateless server.- Type:
Only POST and OPTIONS
- post(request, repository=None)[source]
Answer the JSON-RPC message, or batch of messages, in the request body.
- Parameters:
request (
HttpRequest) – The request.repository (
str|None) – The repository’s name, or None for every repository.
- Return type:
- Returns:
The JSON-RPC response, or
202 Acceptedif no message needs one. An unknown repository is404 Not Found, a body that is not JSON is400 Bad Request, and a client over the rate limit is429 Too Many Requests.
- class smarter.apps.mcpserver.protocol.views.StaffEndpointView(**kwargs)[source]
Bases:
SmarterViewThe view of the MCPServer’s staff-only endpoint, over MCP’s Streamable HTTP transport, for staff only.
It checks the rate limit first, then the caller: the signed
X-Smarter-Acting-Userheader that the platform sends for the user who is chatting with an LLMClient, withacting_staff_user(), or else the api key of theAuthorization: Tokenheader, withstaff_user(). It reads the JSON-RPC only for one of the platform’s staff, or for a request that the platform signed itself, so that nobody else learns even which tools the server has. The server’s tools record each call in the audit trail,OperationsToolCall, under that user.- dispatch(request, *args, **kwargs)
- property formatted_class_name: str
The module and class name, formatted for the start of a log message.
- http_method_names = ['post', 'options']
GET and DELETE are
405 Method Not Allowed, as MCP clients expect of a stateless server.- Type:
Only POST and OPTIONS
- post(request)[source]
Answer the JSON-RPC message, or batch of messages, in the request body, for a staff user.
- Parameters:
request (
HttpRequest) – The request.- Return type:
- Returns:
The JSON-RPC response, or
202 Acceptedif no message needs one. A request without a valid api key or signed acting user is401 Unauthorized, one whose user is not one of the platform’s staff is403 Forbidden, a client over the rate limit is429 Too Many Requests, and a body that is not JSON is400 Bad Request.
- smarter.apps.mcpserver.protocol.views.answer(request, server)[source]
Answer the JSON-RPC message, or batch of messages, of a request’s body with a server.
Both views end with this, once they have checked the rate limit and, for the staff-only endpoint, the caller.
- Parameters:
request (
HttpRequest) – The request.server (
MCPEndpointBase) – The MCP server.
- Return type:
- Returns:
The JSON-RPC response,
202 Acceptedif no message needs one, or400 Bad Requestif the body is not JSON.
- smarter.apps.mcpserver.protocol.views.rate_limited(view, request)[source]
Return a
429 Too Many Requestsresponse if the request’s IP address is over the rate limit.Each call counts the request against its IP address’s limit, in the cache (Redis), which every pod shares: see
is_rate_limited(). A refused request is logged as a warning, and its response carries a JSON-RPC error and aRetry-Afterheader, in seconds.- Parameters:
view (
SmarterView) – The view, for logging.request (
HttpRequest) – The request.
- Return type:
- Returns:
The response, or None if the request may go on.