Skip to content

Commit 40da17d

Browse files
committed
added search, rename, replace tools to MCP server
1 parent 64dbdda commit 40da17d

File tree

6 files changed

+318
-3
lines changed

6 files changed

+318
-3
lines changed

docs/src/content/docs/mcp/overview.mdx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,18 @@ Every renaming operation includes multiple safety layers:
8181

8282
## Available Tools
8383

84-
The MCP Server provides 7 specialized tools:
84+
The MCP Server provides 10 specialized tools:
8585

86+
- [**renamify_search**](/renamify/mcp/tools#renamify_search) - Search for identifiers across your codebase
8687
- [**renamify_plan**](/renamify/mcp/tools#renamify_plan) - Create a renaming plan with case-aware transformations
8788
- [**renamify_apply**](/renamify/mcp/tools#renamify_apply) - Execute a plan to make the actual changes
8889
- [**renamify_undo**](/renamify/mcp/tools#renamify_undo) - Revert a previously applied renaming
8990
- [**renamify_redo**](/renamify/mcp/tools#renamify_redo) - Re-apply an undone renaming
9091
- [**renamify_history**](/renamify/mcp/tools#renamify_history) - View past renaming operations
9192
- [**renamify_status**](/renamify/mcp/tools#renamify_status) - Check current state and pending plans
9293
- [**renamify_preview**](/renamify/mcp/tools#renamify_preview) - Review a plan in different formats
94+
- [**renamify_rename**](/renamify/mcp/tools#renamify_rename) - Case-aware rename (plan + apply in one step)
95+
- [**renamify_replace**](/renamify/mcp/tools#renamify_replace) - Simple regex/literal replacement without case transformations
9396

9497
## Installation Steps
9598

docs/src/content/docs/mcp/tools.mdx

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ description: Complete reference for all Renamify MCP Server tools
55

66
import { Card, CardGrid, Code } from '@astrojs/starlight/components';
77

8-
The Renamify MCP Server provides 7 specialized tools for AI agents to perform intelligent renaming operations.
8+
The Renamify MCP Server provides 10 specialized tools for AI agents to perform intelligent renaming operations.
99

1010
## renamify_plan
1111

@@ -312,6 +312,85 @@ Arguments: {
312312
+export function CustomerAccountComponent({ account }: CustomerAccountProps) {
313313
```
314314

315+
## renamify_rename
316+
317+
Perform case-aware renaming in a single step (combines plan + apply).
318+
319+
### Parameters
320+
321+
| Parameter | Type | Required | Default | Description |
322+
|-----------|------|----------|---------|-------------|
323+
| `old` | string | ✅ Yes | - | The identifier to replace |
324+
| `new` | string | ✅ Yes | - | The new identifier |
325+
| `paths` | string[] | No | Current dir | Paths to search |
326+
| `dryRun` | boolean | No | `false` | Preview without applying |
327+
| `preview` | string | No | `summary` | Preview format |
328+
| `excludeStyles` | string[] | No | None | Case styles to exclude |
329+
| `includeStyles` | string[] | No | None | Additional case styles |
330+
| `onlyStyles` | string[] | No | None | Use only these styles |
331+
332+
### Example Usage
333+
334+
```
335+
Tool: renamify_rename
336+
Arguments: {
337+
"old": "getUserInfo",
338+
"new": "fetchUserProfile",
339+
"paths": ["src"],
340+
"dryRun": true
341+
}
342+
```
343+
344+
### When to Use
345+
346+
- Quick renames without saving a plan
347+
- Simple refactorings with immediate apply
348+
- When you don't need to review changes beforehand
349+
350+
## renamify_replace
351+
352+
Perform simple regex or literal string replacement without case transformations.
353+
354+
### Parameters
355+
356+
| Parameter | Type | Required | Default | Description |
357+
|-----------|------|----------|---------|-------------|
358+
| `pattern` | string | ✅ Yes | - | Search pattern (regex or literal) |
359+
| `replacement` | string | ✅ Yes | - | Replacement string |
360+
| `paths` | string[] | No | Current dir | Paths to search |
361+
| `noRegex` | boolean | No | `false` | Treat pattern as literal |
362+
| `preview` | string | No | `summary` | Preview format |
363+
| `dryRun` | boolean | No | `false` | Preview without applying |
364+
365+
### Example Usage
366+
367+
**Regex replacement:**
368+
```
369+
Tool: renamify_replace
370+
Arguments: {
371+
"pattern": "console\\.log\\((.*?)\\)",
372+
"replacement": "logger.debug($1)",
373+
"paths": ["src"]
374+
}
375+
```
376+
377+
**Literal replacement:**
378+
```
379+
Tool: renamify_replace
380+
Arguments: {
381+
"pattern": "http://localhost:3000",
382+
"replacement": "https://api.example.com",
383+
"noRegex": true
384+
}
385+
```
386+
387+
### When to Use
388+
389+
- URL or endpoint replacements
390+
- Regex-based transformations
391+
- Literal string replacements without case variations
392+
- When you explicitly DON'T want case transformations
393+
315394
## Tool Interaction Patterns
316395

317396
### Safe Renaming Workflow

renamify-mcp/src/index.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ describe('MCP Server', () => {
186186

187187
const tools = responseObj.result.tools;
188188
expect(tools).toBeInstanceOf(Array);
189-
expect(tools.length).toBe(8);
189+
expect(tools.length).toBe(10);
190190

191191
const toolNames = tools.map((t: { name: string }) => t.name);
192192
expect(toolNames).toContain('renamify_search');
@@ -197,5 +197,7 @@ describe('MCP Server', () => {
197197
expect(toolNames).toContain('renamify_history');
198198
expect(toolNames).toContain('renamify_status');
199199
expect(toolNames).toContain('renamify_preview');
200+
expect(toolNames).toContain('renamify_rename');
201+
expect(toolNames).toContain('renamify_replace');
200202
});
201203
});

renamify-mcp/src/index.ts

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,93 @@ export function createServer(
271271
}
272272
);
273273

274+
server.registerTool(
275+
'renamify_rename',
276+
{
277+
title: 'Rename (Plan + Apply)',
278+
description:
279+
'Create and immediately apply a renaming plan (combines plan + apply)',
280+
inputSchema: {
281+
old: z.string().describe('The identifier to search for and replace'),
282+
new: z.string().describe('The replacement identifier'),
283+
paths: z
284+
.array(z.string())
285+
.optional()
286+
.describe('Paths to search (defaults to current directory)'),
287+
dryRun: z
288+
.boolean()
289+
.optional()
290+
.default(false)
291+
.describe('Preview changes without applying them'),
292+
preview: z
293+
.enum(['table', 'diff', 'summary', 'json'])
294+
.optional()
295+
.default('summary')
296+
.describe('Preview format for the results'),
297+
excludeStyles: z
298+
.array(z.string())
299+
.optional()
300+
.describe('Case styles to exclude from transformations'),
301+
includeStyles: z
302+
.array(z.string())
303+
.optional()
304+
.describe('Additional case styles to include'),
305+
onlyStyles: z
306+
.array(z.string())
307+
.optional()
308+
.describe('Only use these specific case styles'),
309+
},
310+
},
311+
async (params) => {
312+
const result = await toolsInstance.rename(params);
313+
return { content: [{ type: 'text', text: result }] };
314+
}
315+
);
316+
317+
server.registerTool(
318+
'renamify_replace',
319+
{
320+
title: 'Replace (Regex/Literal)',
321+
description:
322+
'Simple regex or literal string replacement without case transformations',
323+
inputSchema: {
324+
pattern: z
325+
.string()
326+
.describe(
327+
'Search pattern (regex by default, literal with noRegex=true)'
328+
),
329+
replacement: z
330+
.string()
331+
.describe(
332+
'Replacement string (supports $1, $2 capture groups in regex mode)'
333+
),
334+
paths: z
335+
.array(z.string())
336+
.optional()
337+
.describe('Paths to search (defaults to current directory)'),
338+
noRegex: z
339+
.boolean()
340+
.optional()
341+
.default(false)
342+
.describe('Treat pattern as literal string instead of regex'),
343+
preview: z
344+
.enum(['table', 'diff', 'summary', 'json'])
345+
.optional()
346+
.default('summary')
347+
.describe('Preview format for the results'),
348+
dryRun: z
349+
.boolean()
350+
.optional()
351+
.default(false)
352+
.describe('Preview changes without applying them'),
353+
},
354+
},
355+
async (params) => {
356+
const result = await toolsInstance.replace(params);
357+
return { content: [{ type: 'text', text: result }] };
358+
}
359+
);
360+
274361
return server;
275362
}
276363

renamify-mcp/src/renamify-service.ts

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,4 +425,90 @@ export class RenamifyService {
425425
}
426426
throw error;
427427
}
428+
429+
/**
430+
* Rename with case-aware transformations (plan + apply in one step)
431+
*/
432+
async rename(options: {
433+
old: string;
434+
new: string;
435+
paths?: string[];
436+
dryRun?: boolean;
437+
preview?: 'table' | 'diff' | 'summary' | 'json';
438+
excludeStyles?: string[];
439+
includeStyles?: string[];
440+
onlyStyles?: string[];
441+
}): Promise<string> {
442+
const args = ['rename', options.old, options.new];
443+
444+
// Add paths after old and new
445+
if (options.paths?.length) {
446+
args.push(...options.paths);
447+
}
448+
449+
// Add preview format
450+
if (options.preview) {
451+
args.push('--preview', options.preview);
452+
}
453+
454+
// Add style options
455+
if (options.excludeStyles?.length) {
456+
args.push('--exclude-styles', options.excludeStyles.join(','));
457+
}
458+
if (options.includeStyles?.length) {
459+
args.push('--include-styles', options.includeStyles.join(','));
460+
}
461+
if (options.onlyStyles?.length) {
462+
args.push('--only-styles', options.onlyStyles.join(','));
463+
}
464+
465+
// Add dry-run flag
466+
if (options.dryRun) {
467+
args.push('--dry-run');
468+
}
469+
470+
// Always skip confirmation for MCP usage
471+
args.push('--yes');
472+
473+
return await this.executeCommand(args, 'rename');
474+
}
475+
476+
/**
477+
* Simple regex or literal replacement without case transformations
478+
*/
479+
async replace(options: {
480+
pattern: string;
481+
replacement: string;
482+
paths?: string[];
483+
noRegex?: boolean;
484+
preview?: 'table' | 'diff' | 'summary' | 'json';
485+
dryRun?: boolean;
486+
}): Promise<string> {
487+
const args = ['replace', options.pattern, options.replacement];
488+
489+
// Add paths after pattern and replacement
490+
if (options.paths?.length) {
491+
args.push(...options.paths);
492+
}
493+
494+
// Add no-regex flag
495+
if (options.noRegex) {
496+
args.push('--no-regex');
497+
}
498+
499+
// Add preview format
500+
if (options.preview) {
501+
args.push('--preview', options.preview);
502+
}
503+
504+
// Add dry-run flag
505+
if (options.dryRun) {
506+
args.push('--dry-run');
507+
}
508+
509+
// Always skip confirmation for MCP usage
510+
args.push('--yes');
511+
512+
return await this.executeCommand(args, 'replace');
513+
}
428514
}

renamify-mcp/src/tools.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,4 +203,62 @@ This is a preview only. Use 'renamify_apply' to make these changes.`;
203203
return `Error previewing plan: ${error instanceof Error ? error.message : String(error)}`;
204204
}
205205
}
206+
207+
/**
208+
* Rename with case-aware transformations (plan + apply in one step)
209+
*/
210+
async rename(params: {
211+
old: string;
212+
new: string;
213+
paths?: string[];
214+
dryRun?: boolean;
215+
preview?: 'table' | 'diff' | 'summary' | 'json';
216+
excludeStyles?: string[];
217+
includeStyles?: string[];
218+
onlyStyles?: string[];
219+
}): Promise<string> {
220+
try {
221+
const result = await this.renamifyService.rename(params);
222+
223+
if (params.dryRun) {
224+
return `${result}
225+
226+
This was a dry run. Use without --dry-run to apply these changes.`;
227+
}
228+
229+
return `${result}
230+
231+
Renaming completed successfully. Use 'renamify_undo' if you need to revert.`;
232+
} catch (error) {
233+
return `Error during rename: ${error instanceof Error ? error.message : String(error)}`;
234+
}
235+
}
236+
237+
/**
238+
* Simple regex or literal replacement without case transformations
239+
*/
240+
async replace(params: {
241+
pattern: string;
242+
replacement: string;
243+
paths?: string[];
244+
noRegex?: boolean;
245+
preview?: 'table' | 'diff' | 'summary' | 'json';
246+
dryRun?: boolean;
247+
}): Promise<string> {
248+
try {
249+
const result = await this.renamifyService.replace(params);
250+
251+
if (params.dryRun) {
252+
return `${result}
253+
254+
This was a dry run. Use without --dry-run to apply these changes.`;
255+
}
256+
257+
return `${result}
258+
259+
Replacement completed successfully. Use 'renamify_undo' if you need to revert.`;
260+
} catch (error) {
261+
return `Error during replace: ${error instanceof Error ? error.message : String(error)}`;
262+
}
263+
}
206264
}

0 commit comments

Comments
 (0)