Search
Search of the indexed files of The Smarter Project’s repositories, and of its blog.
search_documentation(), search_code() and search_blog() search the documentation,
the source code and the blog’s posts. The MCPServer’s public tools of the same names call them
(see smarter.apps.mcpserver.protocol.tools.search). They search only the indexes that are
ready, and queue the others for indexing. All three call search_files(), which ranks the
files that smarter.apps.mcpserver.services.indexing.github and
smarter.apps.mcpserver.services.indexing.blog stored, for a query, in the database, without embeddings:
The query is split into at most
MAX_TERMSterms. A quoted phrase is one term, and so is an identifier such assmarter_settings.environment_platform_domain. Common English words are dropped.A file is a candidate if its path or content contains any of the terms.
Each term is weighted by how rare it is among the files searched, its inverse document frequency, so that a rare identifier counts for more than a common word.
A file’s score adds up, for each term, a bonus for containing it, its number of occurrences, capped at
MAX_COUNTED_OCCURRENCESso that long files do not win by length alone, and bonuses for matching the file’s path and title.
Occurrences are counted in SQL, as (LENGTH(LOWER(content)) - LENGTH(REPLACE(LOWER(content), term, ''))) / LENGTH(term),
which every database that Django supports can evaluate. Only the best files are then read,
to extract their matching lines.
Nothing is cached here: the public tools cache their results. The only writes are those of queuing an index that is not ready.
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.services.search.SearchHit(**data)[source]
Bases:
BaseModelA file that matches a search, as
search_files()returns it.The search tools format it as Markdown: a heading, its links, and its lines in a code block.
- kind: RepositoryFileKind
- lines: list[SearchLine]
- model_config = {'extra': 'forbid', 'frozen': True}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.apps.mcpserver.services.search.SearchLine(**data)[source]
Bases:
BaseModelA line of a file, with its line number, which a
SearchHitshows.- model_config = {'extra': 'forbid', 'frozen': True}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.apps.mcpserver.services.search.SearchResults(**data)[source]
Bases:
BaseModelThe result of a search of the repositories: the hits, and the repositories that were not searched.
A repository that is not indexed yet is queued for indexing, and named in
not_indexed, so that the caller can say that it was left out, and when to try again.- model_config = {'extra': 'forbid', 'frozen': True}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- smarter.apps.mcpserver.services.search.query_terms(query)[source]
Split a search query into lowercase terms.
A word shorter than
MIN_TERM_LENGTH, or one ofSTOPWORDS, is dropped, unless it is quoted. Only the firstMAX_TERMSterms are kept.
- smarter.apps.mcpserver.services.search.search_blog(query, limit)[source]
Search the posts of The Smarter Project’s blog.
Side effects: database queries, and, if the blog is not indexed yet, a Celery task queued to index it.
- Parameters:
- Return type:
- Returns:
The passages of the posts, best first.
- Raises:
SmarterMCPServerServiceError – If the blog is not indexed yet.
- smarter.apps.mcpserver.services.search.search_code(repositories, query, limit, path=None)[source]
Search the source code and configuration of the repositories.
Side effects: see
search_repositories().- Parameters:
- Return type:
- Returns:
The files, best first, with their matching lines, and the repositories that were not searched.
- Raises:
SmarterMCPServerServiceError – If none of the repositories is indexed yet.
- smarter.apps.mcpserver.services.search.search_documentation(repositories, query, limit)[source]
Search the documentation of the repositories: the Sphinx documentation, READMEs and other prose.
Side effects: see
search_repositories().- Parameters:
repositories (
Sequence[ProjectRepository]) – The repositories to search.query (
str) – The query, e.g.custom domain verification.limit (
int) – The maximum number of hits.
- Return type:
- Returns:
The passages, best first, and the repositories that were not searched.
- Raises:
SmarterMCPServerServiceError – If none of the repositories is indexed yet.
Example usage:
results = search_documentation([get_repository("smarter")], "custom domain verification", limit=8) results.hits[0].documentation_url
- smarter.apps.mcpserver.services.search.search_files(repositories, query, kind=None, path=None, limit=10)[source]
Search the indexed files of one or more repositories.
Only indexes that are ready are searched. The files are ranked in the database, and only the best
limitfiles are then read, to extract their matching lines.Side effects: three database queries: the terms’ weights, the ranking, and the best files’ rows.
- Parameters:
repositories (
Sequence[ProjectRepository|ProjectBlog]) – The repositories to search, or the blog.query (
str) – The query.kind (
str|None) – Only documentation, or only code. Defaults to both.path (
str|None) – Only files under this folder, or with this path prefix, e.g.smarter/smarter/apps/llmclient.limit (
int) – The maximum number of hits.
- Return type:
- Returns:
The best hits, best first. Empty if the query has no terms, or nothing matches.
Example usage:
hits = search_files([get_repository("smarter")], "custom domain verification", kind="documentation") hits[0].documentation_url
- smarter.apps.mcpserver.services.search.search_repositories(repositories, query, kind, path, limit)[source]
Search the files of one kind in the repositories that are indexed, and name those that are not.
Side effects: database queries, and Celery tasks queued for the repositories that are not indexed yet (see
ready_indexes()).- Parameters:
repositories (
Sequence[ProjectRepository]) – The repositories to search.query (
str) – The query.kind (
str) – Documentation, or code: aRepositoryFileKind.path (
str|None) – Only files under this folder, or None to search them all.limit (
int) – The maximum number of hits.
- Return type:
- Returns:
The hits, best first, and the repositories that were not searched.
- Raises:
SmarterMCPServerServiceError – If none of the repositories is indexed yet.