Reading
Reading the index of The Smarter Project’s repositories and blog: files, folders, posts and overviews.
The search service (search) finds what to read, and this
service reads it, from the copy that indexing keeps in the
database. GitHub is never asked.
read_file(): a file of a repository, or a range of its lines, with line numbers.read_blog_post(): a post of the blog, or a range of its lines.list_files(): the folders and files directly in a folder of a repository.repository_overview(): what a repository contains, its top-level folders and files, and its README.repositories_state(): whether each repository is indexed, and at which commit.
Each function returns a Pydantic model, which the MCPServer’s public tools
(smarter.apps.mcpserver.protocol.tools.reading) format as Markdown. A repository that is not
indexed yet is queued for indexing, and a file or post that does not exist raises
SmarterMCPServerNotFoundError, with the paths that the
caller may have meant.
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.reading.FileLines(**data)[source]
Bases:
BaseModelLines of a file of a repository, as
read_file()returns them, with where to find the file.- 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.reading.FolderEntry(**data)[source]
Bases:
BaseModelA folder or a file directly in a folder of a repository.
- 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.reading.FolderListing(**data)[source]
Bases:
BaseModelThe folders and files directly in a folder of a repository, as
list_files()returns them.- entries: list[FolderEntry]
- model_config = {'extra': 'forbid', 'frozen': True}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- smarter.apps.mcpserver.services.reading.MAX_LIST_ENTRIES = 300
The maximum number of folders and files that a listing returns.
The rest are counted.
- smarter.apps.mcpserver.services.reading.MAX_README_CHARACTERS = 6000
The most characters of a README that an overview shows.
The rest is read with
read_file().
- smarter.apps.mcpserver.services.reading.MAX_READ_CHARACTERS = 16000
The maximum length of what is read at once, below the MCPClient’s limit for a tool result.
The public tools also keep their results that read a schema or an issue within it.
- smarter.apps.mcpserver.services.reading.MAX_READ_LINES = 400
The maximum number of lines of a file or post that are read at once.
- class smarter.apps.mcpserver.services.reading.PostLines(**data)[source]
Bases:
BaseModelLines of a post of the blog, as
read_blog_post()returns them.- 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.reading.ReadLines(**data)[source]
Bases:
BaseModelThe lines of a file that
read_lines()selected.- 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.reading.RepositoryOverview(**data)[source]
Bases:
BaseModelWhat a repository contains, as
repository_overview()returns it.- model_config = {'extra': 'forbid', 'frozen': True}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- repository: ProjectRepository
- top_level: list[FolderEntry]
- class smarter.apps.mcpserver.services.reading.RepositoryState(**data)[source]
Bases:
BaseModelWhether a repository is indexed, and at which commit, as
repositories_state()returns it.- model_config = {'extra': 'forbid', 'frozen': True}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- repository: ProjectRepository
- smarter.apps.mcpserver.services.reading.folder_entries(index, folder)[source]
Return the folders and files directly in a folder of an index.
Only indexed files are listed, so a folder of only binaries or vendored files does not appear.
Side effects: one database query, of the paths and sizes of the files under the folder.
- Parameters:
index (
RepositoryIndex) – The repository’s index.folder (
str) – The folder, or an empty string for the top level.
- Return type:
tuple[list[FolderEntry],int]- Returns:
The folders, with the number of files under each, then the files, with their sizes, each sorted by name, at most
MAX_LIST_ENTRIES, and the number of entries left out.
- smarter.apps.mcpserver.services.reading.list_files(repository, folder=None)[source]
List the folders and indexed files directly in a folder of a repository.
Side effects: database queries, and, for a repository that is not indexed yet, a Celery task queued to index it.
- Parameters:
repository (
ProjectRepository) – The repository.folder (
str|None) – The folder, e.g.smarter/smarter/apps, or None for the top level.
- Return type:
- Returns:
The folder’s entries and GitHub url.
- Raises:
SmarterMCPServerServiceError – If the repository is not indexed yet.
SmarterMCPServerNotFoundError – If the folder has no indexed files.
- smarter.apps.mcpserver.services.reading.read_blog_post(path, start_line=1, end_line=None)[source]
Read a post of the blog, or a range of its lines, by its path or its url.
Side effects: database queries, and, if the blog is not indexed yet, a Celery task queued to index it.
- Parameters:
path (
str) – The post’s path, e.g.2026/10/26/release-smarter-api-v0-6, or its url.start_line (
int) – The first line to read, from 1.end_line (
int|None) – The last line to read, or None to read as many asread_lines()allows.
- Return type:
- Returns:
The lines, and the post’s url.
- Raises:
SmarterMCPServerServiceError – If the blog is not indexed yet.
SmarterMCPServerNotFoundError – If the blog has no such post. The error suggests the posts with the same slug.
- smarter.apps.mcpserver.services.reading.read_file(repository, path, start_line=1, end_line=None)[source]
Read a file of a repository, or a range of its lines.
Side effects: database queries, and, for a repository that is not indexed yet, a Celery task queued to index it.
- Parameters:
repository (
ProjectRepository) – The repository.path (
str) – The file’s path in the repository, e.g.README.md. A leading slash is ignored.start_line (
int) – The first line to read, from 1.end_line (
int|None) – The last line to read, or None to read as many asread_lines()allows.
- Return type:
- Returns:
The lines, and the file’s GitHub url and documentation page.
- Raises:
SmarterMCPServerServiceError – If the repository is not indexed yet.
SmarterMCPServerNotFoundError – If the repository has no such file.
- smarter.apps.mcpserver.services.reading.read_lines(content, start_line, end_line)[source]
Return a range of a file’s lines, with line numbers, within
MAX_READ_LINESandMAX_READ_CHARACTERS.A start after the last line reads the last line. The range ends early, but always has at least one line, when its text would exceed
MAX_READ_CHARACTERS, so that the result fits in a tool result: the caller then reads on fromend + 1.
- smarter.apps.mcpserver.services.reading.repositories_state(repositories)[source]
Return whether each repository is indexed, and queue those that are not for indexing.
Side effects: one database query, and a Celery task queued for each repository that is not indexed yet (see
queue_indexing()).- Parameters:
repositories (
Sequence[ProjectRepository]) – The repositories, in the order to return them.- Return type:
- Returns:
One state per repository, in the same order.
- smarter.apps.mcpserver.services.reading.repository_overview(repository)[source]
Describe a repository: its indexed commit, its numbers of files, its top-level folders and files, and its README.
Side effects: database queries, and, for a repository that is not indexed yet, a Celery task queued to index it.
- Parameters:
repository (
ProjectRepository) – The repository.- Return type:
- Returns:
The overview.
- Raises:
SmarterMCPServerServiceError – If the repository is not indexed yet.
- smarter.apps.mcpserver.services.reading.suggested_paths(index, order_by, **path_filter)[source]
Return up to
MAX_SUGGESTIONSpaths of an index’s files that match a filter.Side effects: one database query.
- Parameters:
index (
RepositoryIndex) – The index.order_by (
str) – The field to order the paths by, e.g.pathor-path.path_filter (
str) – The lookup to filter the files by, e.g.path__icontains="tasks.py".
- Return type:
- Returns:
The paths.