Public Tool Base Class
The base class of the MCPServer’s public tools, the scope that they work on, and the limits of their results.
Each tool is a PublicTool: a name, a description, a Pydantic model of its
arguments, from which its MCP inputSchema is generated, and PublicTool.run(),
which returns its result as Markdown text for the LLM. PublicTool.call()
validates the arguments, and caches a read-only tool’s result.
A tool works on the repositories of its RepositoryScope. The endpoint of
one repository serves the tools without a repository argument, and the endpoint of
all of the repositories adds one, whose values are the repositories’ names.
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.
- smarter.apps.mcpserver.protocol.tools.public.DEFAULT_SEARCH_LIMIT = 8
The number of results that a search tool returns when the LLM does not give a
limit.
- smarter.apps.mcpserver.protocol.tools.public.MAX_SEARCH_LIMIT = 20
The most results that a search tool returns, which keeps a result within the LLM’s context.
- class smarter.apps.mcpserver.protocol.tools.public.PublicTool(scope, github_token=None)[source]
Bases:
MCPToolBaseA public tool of the MCPServer.
A subclass sets
name,title,descriptionandarguments_model, the class attributes that say which endpoints serve it and how it takes a repository, and implementsrun().call()validates the arguments and caches a read-only tool’s result, sorun()only does the work.- Parameters:
scope (
RepositoryScope) – The repositories of the endpoint.github_token (
SecretStr|None) – The caller’s GitHub token, from the request’sAuthorization: Bearerheader, or None. Only a tool thatrequires_github_tokenuses it.
- __init__(scope, github_token=None)[source]
Keep the endpoint’s scope, and the caller’s GitHub token.
- Parameters:
scope (
RepositoryScope) – The repositories of the endpoint.github_token (
SecretStr|None) – The caller’s GitHub token, or None.
- arguments_model
The Pydantic model of the tool’s arguments, a subclass of
PublicToolArguments.alias of
PublicToolArguments
- cache_ttl: ClassVar[int | None] = None
Seconds that a read-only tool’s result is cached, or None for
TOOL_RESULT_CACHE_TTL.
- call(arguments)[source]
Validate a tool call’s arguments, and run the tool.
The endpoint of one repository, and a tool that does not
uses_repository, drop arepositoryargument, which their schema does not offer, rather than refuse it.A read-only tool’s result is cached for an hour, or its
cache_ttl, until an index changes. Seesmarter.apps.mcpserver.protocol.caching. The cache key is the platform’s version, the index generation, the endpoint’s repository (*for all of them), the tool’s name and its validated arguments, so a new release or a new index never serves a stale result. An error is not cached. A tool that writes runs on every call.Side effects: reads, and on a miss writes, the Django cache, with
cached_tool_call().
- description: ClassVar[str]
What the tool does, and when to call it.
The LLM reads it to decide which tool to call.
- project_wide: ClassVar[bool] = False
Whether only the public endpoint of every repository serves the tool.
- requires_github_token: ClassVar[bool] = False
Whether the tool is served only to a request that carries the caller’s GitHub token.
- requires_repository: ClassVar[bool] = False
Whether a call to the public endpoint of every repository must name one.
- abstractmethod run(arguments)[source]
Run the tool.
call()has already validated the arguments, and checked the cache.- Parameters:
arguments (
PublicToolArguments) – The validated arguments, an instance ofarguments_model.- Return type:
- Returns:
The result, as Markdown.
- Raises:
SmarterMCPServerToolError – If the tool fails in a way that the LLM should be told about, e.g. a file that does not exist.
- run_service(arguments)[source]
Run the tool, and turn a service’s error into a tool error.
- Parameters:
arguments (
PublicToolArguments) – The validated arguments.- Return type:
- Returns:
The result, as Markdown.
- Raises:
SmarterMCPServerToolError – If the tool, or a service that it calls, fails.
- classmethod serves(scope, has_github_token=False)[source]
Whether the endpoint of a scope serves the tool.
A tool that
requires_github_tokenis served only to a request that carries one, and aproject_widetool only by the public endpoint of every repository.- Parameters:
scope (
RepositoryScope) – The endpoint’s repositories.has_github_token (
bool) – Whether the request carries the caller’s GitHub token.
- Return type:
- Returns:
True if the endpoint lists the tool, and lets the LLM call it.
- class smarter.apps.mcpserver.protocol.tools.public.PublicToolArguments(**data)[source]
Bases:
BaseModelThe arguments of every tool:
repository, which only the public endpoint of every repository offers.A tool’s own arguments model subclasses it. Arguments that the model does not define are refused (
extra="forbid"), so that a misspelled argument is reported to the LLM rather than ignored.- model_config = {'extra': 'forbid'}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- repository: str | None
The name of the repository to work on, e.g.
smarter-cli.PublicTool.input_schema()replaces its schema with anenumof the scope’s repositories, or removes it from the endpoint of one repository.
- class smarter.apps.mcpserver.protocol.tools.public.RepositoryScope(**data)[source]
Bases:
BaseModelThe repositories that one public endpoint serves.
The endpoint creates its scope once, and gives it to each of its tools, which call
resolve()to turn a call’srepositoryargument into a repository. It is frozen, because the tools share it.- Parameters:
repository – The one repository of the endpoint, or None for all of them.
repositories – The repositories that the endpoint serves:
(repository,), or every repository of The Smarter Project.
- model_config = {'frozen': True}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- repositories: tuple[ProjectRepository, ...]
The repositories that the endpoint serves, in their configured order.
- repository: ProjectRepository | None
The one repository of the endpoint, or None for the endpoint of every repository.
- resolve(name, required)[source]
Return the repository that a tool call names.
- Parameters:
- Return type:
- Returns:
The endpoint’s one repository, the named repository, or None for all of them.
- Raises:
SmarterMCPServerToolError – If the name is not one of the scope’s repositories, or a required name is missing.
- smarter.apps.mcpserver.protocol.tools.public.simplify_schema(schema)[source]
Simplify a Pydantic JSON schema for an LLM.
Pydantic’s schema carries what helps a form, not an LLM: a title for the model and for each field, the model’s docstring as its description, and
"default": nullfor each optional field. They cost tokens in everytools/listresult, and the docstring is written for developers, so they are removed. An optional field’sanyOf: [<type>, {"type": "null"}]becomes its type, which every MCP client understands.