read_shelf_file
Retrieve a specific file from a Shelv shelf by providing the shelf identifier and file path to access its contents.
Instructions
Read a single file from a shelf
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| shelf_id | Yes | ||
| path | Yes |
Implementation Reference
- src/tools/read-shelf-file.ts:39-64 (handler)The main handler function that executes the read_shelf_file tool. It validates the path, creates a client, retrieves the file content, truncates if necessary, and returns the result with metadata including content type, bytes, and truncation status.
async (input, extra) => { try { const normalizedPath = ensureRelativePath(input.path); const apiKey = context.getApiKey(extra); const client = context.createShelvClient(apiKey); const raw = await client.getFile(input.shelf_id, normalizedPath); const truncated = truncateUtf8(raw, context.config.readMaxBytes); return successResult( truncated.truncated ? `Read ${normalizedPath} (truncated to ${truncated.bytes} bytes)` : `Read ${normalizedPath}`, { shelf_id: input.shelf_id, path: normalizedPath, content_type: inferContentType(normalizedPath), content: truncated.value, bytes: truncated.bytes, truncated: truncated.truncated, }, ); } catch (error) { return errorResult(error); } }, - src/tools/read-shelf-file.ts:12-24 (schema)Schema definitions for the read_shelf_file tool. Input schema requires shelf_id and path strings. Output schema defines the structure of the response including shelf_id, path, content_type, content, bytes, and truncated flag.
const inputSchema = { shelf_id: z.string().min(1), path: z.string().min(1), }; const outputSchema = { shelf_id: z.string(), path: z.string(), content_type: z.string(), content: z.string(), bytes: z.number(), truncated: z.boolean(), }; - src/tools/read-shelf-file.ts:26-66 (registration)The registerReadShelfFileTool function that registers the tool with the MCP server, defining its title, description, input/output schemas, and annotations (readOnlyHint). This function is exported and called from the tools index.
export function registerReadShelfFileTool( server: McpServer, context: ToolContext, ): void { server.registerTool( "read_shelf_file", { title: "Read Shelf File", description: "Read a single file from a shelf", inputSchema, outputSchema, annotations: { readOnlyHint: true }, }, async (input, extra) => { try { const normalizedPath = ensureRelativePath(input.path); const apiKey = context.getApiKey(extra); const client = context.createShelvClient(apiKey); const raw = await client.getFile(input.shelf_id, normalizedPath); const truncated = truncateUtf8(raw, context.config.readMaxBytes); return successResult( truncated.truncated ? `Read ${normalizedPath} (truncated to ${truncated.bytes} bytes)` : `Read ${normalizedPath}`, { shelf_id: input.shelf_id, path: normalizedPath, content_type: inferContentType(normalizedPath), content: truncated.value, bytes: truncated.bytes, truncated: truncated.truncated, }, ); } catch (error) { return errorResult(error); } }, ); } - src/tools/index.ts:7-16 (registration)Import and registration of the read_shelf_file tool in the main tools index. The registerReadShelfFileTool is imported and called within the registerShelvTools function to initialize the tool.
import { registerReadShelfFileTool } from "./read-shelf-file"; import { registerSearchShelfTool } from "./search-shelf"; export function registerShelvTools( server: McpServer, context: ToolContext, ): void { registerListShelvesTool(server, context); registerGetShelfTreeTool(server, context); registerReadShelfFileTool(server, context); - src/tools/common.ts:92-119 (helper)The truncateUtf8 helper function used by read_shelf_file to limit output size. It uses binary search to efficiently truncate UTF-8 content to a maximum byte size while preserving valid UTF-8 encoding.
export function truncateUtf8( content: string, maxBytes: number, ): { value: string; truncated: boolean; bytes: number } { const totalBytes = Buffer.byteLength(content, "utf8"); if (totalBytes <= maxBytes) { return { value: content, truncated: false, bytes: totalBytes }; } let low = 0; let high = content.length; while (low < high) { const mid = Math.ceil((low + high) / 2); const candidateBytes = Buffer.byteLength(content.slice(0, mid), "utf8"); if (candidateBytes <= maxBytes) { low = mid; } else { high = mid - 1; } } const value = content.slice(0, low); return { value, truncated: true, bytes: Buffer.byteLength(value, "utf8"), }; }