/**
* Schema for local_fetch_content tool
*/
import { z } from 'zod';
import { BaseQuerySchema, createBulkQuerySchema } from './baseSchema.js';
import { TOOL_NAMES } from '../constants.js';
/**
* Tool description for MCP registration
*/
export const LOCAL_FETCH_CONTENT_DESCRIPTION = `FILE READER - Read file contents with smart extraction
PURPOSE: Read code after discovering location. Get file content in chunks/sections.
USE_WHEN: Have file path | After RIPGREP/FIND_FILES discovery
AVOID: Don't know location → RIPGREP/FIND_FILES first
DECISION_TREE:
4. GET CONTENT IN CHUNKS
└─► FETCH_CONTENT (matchString, charOffset, charLength)
├─► matchString="literal" → Extract sections [BEST: most efficient]
└─► fullContent + charLength → Full file (paginated)
WORKFLOW: Discovery (RIPGREP/FIND_FILES) → Read (FETCH_CONTENT) → Explore (RIPGREP)
LARGE FILES:
Use matchString to read chunks (functions, classes, patterns)
Understand flow: Extract chunks → Analyze patterns → RIPGREP for connections
Avoid: fullContent on large files - use targeted pattern extraction instead
MODES (2 options):
1. matchString + matchStringContextLines → BEST: most token efficient
2. fullContent + charLength → Full file (paginated, REQUIRED for large files)
KEY_PARAMS:
- matchString: Pattern to extract (most efficient)
- matchStringContextLines: Context around matches (default 5)
- fullContent: Entire file (needs charLength for large files)
- minified: true (default, removes whitespace)
- charOffset: Start position for pagination (default 0)
- charLength: Max chars to return (universal pagination)
OPTIMIZATION:
- matchString: Most token efficient
- minified=true: Removes whitespace (default)
- Bulk queries: queries=[{path:"a.ts",matchString:"fn"},{path:"b.ts",matchString:"fn"}] - faster
GOTCHAS:
- fullContent on large files without charLength → ERROR
- matchString with no matches → empty
- minified=true on JSON/YAML → breaks formatting, use false
NEXT_STEP:
hasResults → RIPGREP (find related)
empty → FIND_FILES name | VIEW_STRUCTURE
EXAMPLES:
matchString="validateUser", matchStringContextLines=20 # BEST
path="large.js", fullContent=true, charLength=10000 # Paginated
path="config.json", fullContent=true, minified=false # Config`;
/**
* Schema descriptions for fetch content parameters
*/
const FETCH_CONTENT_DESCRIPTIONS = {
path: 'File path (absolute or relative)',
fullContent:
'Return entire file (token expensive, use matchString for targeted extraction)',
matchString:
'Search pattern - returns matches with context (most token-efficient, RECOMMENDED for ripgrep integration)',
matchStringContextLines:
'Context lines around matches (1-50, default 5)',
minified:
'Minify content for token efficiency (default true)',
charOffset:
'Character offset for pagination (start position, default 0). NOTE: For ripgrep integration, prefer matchString over charOffset for reliability due to byte vs character offset differences in UTF-8.',
charLength:
'Max characters to return per request (max 10,000 recommended for large files)',
} as const;
/**
* Single query schema for fetching file content
*/
export const FetchContentQuerySchema = BaseQuerySchema.extend({
path: z.string().min(1).describe(FETCH_CONTENT_DESCRIPTIONS.path),
fullContent: z
.boolean()
.default(false)
.describe('Return entire file. For large files, MUST use with charLength parameter for pagination'),
matchString: z
.string()
.optional()
.describe(FETCH_CONTENT_DESCRIPTIONS.matchString),
matchStringContextLines: z
.number()
.int()
.min(1)
.max(50)
.default(5)
.describe(FETCH_CONTENT_DESCRIPTIONS.matchStringContextLines),
minified: z
.boolean()
.optional()
.default(true)
.describe(FETCH_CONTENT_DESCRIPTIONS.minified),
charOffset: z
.number()
.min(0)
.optional()
.describe(FETCH_CONTENT_DESCRIPTIONS.charOffset),
charLength: z
.number()
.min(1)
.max(10000)
.optional()
.describe(FETCH_CONTENT_DESCRIPTIONS.charLength),
});
/**
* Bulk query schema for fetching multiple file contents
*/
export const BulkFetchContentSchema = createBulkQuerySchema(
TOOL_NAMES.LOCAL_FETCH_CONTENT,
FetchContentQuerySchema
);
export type FetchContentQuery = z.infer<typeof FetchContentQuerySchema>;
export type BulkFetchContentRequest = z.infer<typeof BulkFetchContentSchema>;