count_substring
Count how many times a specific pattern appears in text, with options for case sensitivity and overlapping matches. Returns the total count and positions of each occurrence.
Instructions
Count occurrences of a substring or pattern in text.
Can count overlapping or non-overlapping matches.
Args:
text (string): The text to search in
substring (string): The pattern to find
case_sensitive (boolean): Match case exactly (default: false)
overlapping (boolean): Count overlapping matches (default: false)
Returns: count and positions of each match.
Example: count_substring("banana", "ana", overlapping=true) → count: 2, positions: [1, 3]
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| text | Yes | The text to search in | |
| substring | Yes | The pattern to find | |
| case_sensitive | No | Match case exactly | |
| overlapping | No | Count overlapping matches |
Implementation Reference
- src/tools/counting.ts:131-167 (handler)Core implementation of the count_substring tool logic: counts occurrences of a substring in text, handling case sensitivity and optional overlapping matches using indexOf in a loop.export function countSubstring(input: CountSubstringInput): CountSubstringOutput { const { text, substring, case_sensitive, overlapping } = input; if (substring.length === 0) { return { text, substring, count: 0, case_sensitive, overlapping, positions: [], }; } const searchText = case_sensitive ? text : text.toLowerCase(); const searchSubstring = case_sensitive ? substring : substring.toLowerCase(); const positions: number[] = []; let startIndex = 0; while (startIndex < searchText.length) { const foundIndex = searchText.indexOf(searchSubstring, startIndex); if (foundIndex === -1) break; positions.push(foundIndex); startIndex = overlapping ? foundIndex + 1 : foundIndex + searchSubstring.length; } return { text, substring, count: positions.length, case_sensitive, overlapping, positions, }; }
- src/tools/counting.ts:115-129 (schema)TypeScript interfaces defining the input and output structure for the countSubstring function.export interface CountSubstringInput { text: string; substring: string; case_sensitive: boolean; overlapping: boolean; } export interface CountSubstringOutput { text: string; substring: string; count: number; case_sensitive: boolean; overlapping: boolean; positions: number[]; }
- src/index.ts:128-164 (registration)MCP server registration for the 'count_substring' tool, including description, Zod input schema validation, and wrapper handler that invokes the core countSubstring function and formats the response.server.registerTool( "count_substring", { title: "Count Substring", description: `Count occurrences of a substring or pattern in text. Can count overlapping or non-overlapping matches. Args: - text (string): The text to search in - substring (string): The pattern to find - case_sensitive (boolean): Match case exactly (default: false) - overlapping (boolean): Count overlapping matches (default: false) Returns: count and positions of each match. Example: count_substring("banana", "ana", overlapping=true) → count: 2, positions: [1, 3]`, inputSchema: z.object({ text: z.string().min(1).describe("The text to search in"), substring: z.string().min(1).describe("The pattern to find"), case_sensitive: z.boolean().default(false).describe("Match case exactly"), overlapping: z.boolean().default(false).describe("Count overlapping matches"), }).strict(), annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }, }, async (params) => { const result = countSubstring({ text: params.text, substring: params.substring, case_sensitive: params.case_sensitive, overlapping: params.overlapping, }); return { content: [{ type: "text" as const, text: `Found "${result.substring}" ${result.count} time(s) in "${result.text}" at positions: [${result.positions.join(', ')}]` }], }; } );
- src/index.ts:145-150 (schema)Zod schema for input validation used in the tool registration.inputSchema: z.object({ text: z.string().min(1).describe("The text to search in"), substring: z.string().min(1).describe("The pattern to find"), case_sensitive: z.boolean().default(false).describe("Match case exactly"), overlapping: z.boolean().default(false).describe("Count overlapping matches"), }).strict(),