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.

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: BaseModel

Lines of a file of a repository, as read_file() returns them, with where to find the file.

documentation_url: str | None
github_url: str
lines: ReadLines
model_config = {'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

path: str
repository: str
class smarter.apps.mcpserver.services.reading.FolderEntry(**data)[source]

Bases: BaseModel

A folder or a file directly in a folder of a repository.

files: int
is_folder: bool
model_config = {'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

name: str
size: int
class smarter.apps.mcpserver.services.reading.FolderListing(**data)[source]

Bases: BaseModel

The folders and files directly in a folder of a repository, as list_files() returns them.

entries: list[FolderEntry]
folder: str
github_url: str
hidden: int
model_config = {'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

repository: str
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: BaseModel

Lines of a post of the blog, as read_blog_post() returns them.

lines: ReadLines
model_config = {'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

path: str
url: str
class smarter.apps.mcpserver.services.reading.ReadLines(**data)[source]

Bases: BaseModel

The lines of a file that read_lines() selected.

end: int
property is_complete: bool

Whether the last line of the file was read.

model_config = {'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

start: int
text: str
total: int
class smarter.apps.mcpserver.services.reading.RepositoryOverview(**data)[source]

Bases: BaseModel

What a repository contains, as repository_overview() returns it.

code_files: int
commit_sha: str
documentation_files: int
file_count: int
indexed_at: datetime
model_config = {'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

readme: str
readme_path: str | None
readme_truncated: bool
repository: ProjectRepository
top_level: list[FolderEntry]
top_level_hidden: int
class smarter.apps.mcpserver.services.reading.RepositoryState(**data)[source]

Bases: BaseModel

Whether a repository is indexed, and at which commit, as repositories_state() returns it.

commit_sha: str
file_count: int
is_indexed: bool
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:

FolderListing

Returns:

The folder’s entries and GitHub url.

Raises:
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 as read_lines() allows.

Return type:

PostLines

Returns:

The lines, and the post’s url.

Raises:
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 as read_lines() allows.

Return type:

FileLines

Returns:

The lines, and the file’s GitHub url and documentation page.

Raises:
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_LINES and MAX_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 from end + 1.

Parameters:
  • content (str) – The file’s content.

  • 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 as allowed.

Return type:

ReadLines

Returns:

The lines.

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:

list[RepositoryState]

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:

RepositoryOverview

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_SUGGESTIONS paths 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. path or -path.

  • path_filter (str) – The lookup to filter the files by, e.g. path__icontains="tasks.py".

Return type:

list[str]

Returns:

The paths.