@morphllm/morphmcp 0.8.24 → 0.8.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +10 -373
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -20,26 +20,13 @@ import axios from "axios";
|
|
|
20
20
|
// Command line argument parsing
|
|
21
21
|
const args = process.argv.slice(2);
|
|
22
22
|
// Tools configuration system
|
|
23
|
-
//
|
|
23
|
+
// Only expose Morph-specific tools
|
|
24
24
|
const ALL_TOOLS = [
|
|
25
|
-
'read_file',
|
|
26
|
-
'read_multiple_files',
|
|
27
|
-
'write_file',
|
|
28
|
-
'tiny_edit_file',
|
|
29
|
-
'create_directory',
|
|
30
|
-
'list_directory',
|
|
31
|
-
'list_directory_with_sizes',
|
|
32
|
-
'directory_tree',
|
|
33
|
-
'move_file',
|
|
34
|
-
'search_files',
|
|
35
|
-
'get_file_info',
|
|
36
|
-
'list_allowed_directories',
|
|
37
25
|
'edit_file',
|
|
38
|
-
'
|
|
26
|
+
'warp_grep',
|
|
39
27
|
'codebase_search'
|
|
40
28
|
];
|
|
41
|
-
//
|
|
42
|
-
// Other filesystem tools remain available for internal use and via ENABLED_TOOLS env var
|
|
29
|
+
// Default to only edit_file
|
|
43
30
|
const DEFAULT_TOOLS = [
|
|
44
31
|
'edit_file'
|
|
45
32
|
];
|
|
@@ -266,7 +253,7 @@ const MorphEditFileArgsSchema = z.object({
|
|
|
266
253
|
instruction: z.string().describe('A brief single first-person sentence instruction describing changes being made to this file. Useful to disambiguate uncertainty in the edit.'),
|
|
267
254
|
dryRun: z.boolean().default(false).describe('Preview changes without applying them.')
|
|
268
255
|
});
|
|
269
|
-
const
|
|
256
|
+
const WarpGrepArgsSchema = z.object({
|
|
270
257
|
repoPath: z.string().describe("Path to the repository root"),
|
|
271
258
|
query: z.string().describe("Natural language query describing the code context needed"),
|
|
272
259
|
});
|
|
@@ -515,107 +502,6 @@ async function headFile(filePath, numLines) {
|
|
|
515
502
|
// Tool handlers
|
|
516
503
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
517
504
|
const allTools = [
|
|
518
|
-
{
|
|
519
|
-
name: "read_file",
|
|
520
|
-
description: "Read the complete contents of a file from the file system. " +
|
|
521
|
-
"Handles various text encodings and provides detailed error messages " +
|
|
522
|
-
"if the file cannot be read. Use this tool when you need to examine " +
|
|
523
|
-
"the contents of a single file. Use the 'head' parameter to read only " +
|
|
524
|
-
"the first N lines of a file, or the 'tail' parameter to read only " +
|
|
525
|
-
"the last N lines of a file. Only works within allowed directories.",
|
|
526
|
-
inputSchema: zodToJsonSchema(ReadFileArgsSchema),
|
|
527
|
-
},
|
|
528
|
-
{
|
|
529
|
-
name: "read_multiple_files",
|
|
530
|
-
description: "Read the contents of multiple files simultaneously. This is more " +
|
|
531
|
-
"efficient than reading files one by one when you need to analyze " +
|
|
532
|
-
"or compare multiple files. Each file's content is returned with its " +
|
|
533
|
-
"path as a reference. Failed reads for individual files won't stop " +
|
|
534
|
-
"the entire operation. Only works within allowed directories.",
|
|
535
|
-
inputSchema: zodToJsonSchema(ReadMultipleFilesArgsSchema),
|
|
536
|
-
},
|
|
537
|
-
{
|
|
538
|
-
name: "write_file",
|
|
539
|
-
description: "Create a new file or completely overwrite an existing file with new content. " +
|
|
540
|
-
"Use with caution as it will overwrite existing files without warning. " +
|
|
541
|
-
"Handles text content with proper encoding. Only works within allowed directories.",
|
|
542
|
-
inputSchema: zodToJsonSchema(WriteFileArgsSchema),
|
|
543
|
-
},
|
|
544
|
-
{
|
|
545
|
-
name: "tiny_edit_file",
|
|
546
|
-
description: "Make line-based edits to a text file. Each edit replaces exact line sequences " +
|
|
547
|
-
"with new content. Returns a git-style diff showing the changes made. " +
|
|
548
|
-
"Only works within allowed directories. " +
|
|
549
|
-
"Only use for single line or tiny edits. For larger edits, use the edit_file tool instead.",
|
|
550
|
-
inputSchema: zodToJsonSchema(EditFileArgsSchema),
|
|
551
|
-
},
|
|
552
|
-
{
|
|
553
|
-
name: "create_directory",
|
|
554
|
-
description: "Create a new directory or ensure a directory exists. Can create multiple " +
|
|
555
|
-
"nested directories in one operation. If the directory already exists, " +
|
|
556
|
-
"this operation will succeed silently. Perfect for setting up directory " +
|
|
557
|
-
"structures for projects or ensuring required paths exist. Only works within allowed directories.",
|
|
558
|
-
inputSchema: zodToJsonSchema(CreateDirectoryArgsSchema),
|
|
559
|
-
},
|
|
560
|
-
{
|
|
561
|
-
name: "list_directory",
|
|
562
|
-
description: "Get a detailed listing of all files and directories in a specified path. " +
|
|
563
|
-
"Results clearly distinguish between files and directories with [FILE] and [DIR] " +
|
|
564
|
-
"prefixes. This tool is essential for understanding directory structure and " +
|
|
565
|
-
"finding specific files within a directory. Only works within allowed directories.",
|
|
566
|
-
inputSchema: zodToJsonSchema(ListDirectoryArgsSchema),
|
|
567
|
-
},
|
|
568
|
-
{
|
|
569
|
-
name: "list_directory_with_sizes",
|
|
570
|
-
description: "Get a detailed listing of all files and directories in a specified path, including sizes. " +
|
|
571
|
-
"Results clearly distinguish between files and directories with [FILE] and [DIR] " +
|
|
572
|
-
"prefixes. This tool is useful for understanding directory structure and " +
|
|
573
|
-
"finding specific files within a directory. Only works within allowed directories.",
|
|
574
|
-
inputSchema: zodToJsonSchema(ListDirectoryWithSizesArgsSchema),
|
|
575
|
-
},
|
|
576
|
-
{
|
|
577
|
-
name: "directory_tree",
|
|
578
|
-
description: "Get a recursive tree view of files and directories as a JSON structure. " +
|
|
579
|
-
"Each entry includes 'name', 'type' (file/directory), and 'children' for directories. " +
|
|
580
|
-
"Files have no children array, while directories always have a children array (which may be empty). " +
|
|
581
|
-
"The output is formatted with 2-space indentation for readability. Only works within allowed directories.",
|
|
582
|
-
inputSchema: zodToJsonSchema(DirectoryTreeArgsSchema),
|
|
583
|
-
},
|
|
584
|
-
{
|
|
585
|
-
name: "move_file",
|
|
586
|
-
description: "Move or rename files and directories. Can move files between directories " +
|
|
587
|
-
"and rename them in a single operation. If the destination exists, the " +
|
|
588
|
-
"operation will fail. Works across different directories and can be used " +
|
|
589
|
-
"for simple renaming within the same directory. Both source and destination must be within allowed directories.",
|
|
590
|
-
inputSchema: zodToJsonSchema(MoveFileArgsSchema),
|
|
591
|
-
},
|
|
592
|
-
{
|
|
593
|
-
name: "search_files",
|
|
594
|
-
description: "Recursively search for files and directories matching a pattern. " +
|
|
595
|
-
"Searches through all subdirectories from the starting path. The search " +
|
|
596
|
-
"is case-insensitive and matches partial names. Returns full paths to all " +
|
|
597
|
-
"matching items. Great for finding files when you don't know their exact location. " +
|
|
598
|
-
"Only searches within allowed directories.",
|
|
599
|
-
inputSchema: zodToJsonSchema(SearchFilesArgsSchema),
|
|
600
|
-
},
|
|
601
|
-
{
|
|
602
|
-
name: "get_file_info",
|
|
603
|
-
description: "Retrieve detailed metadata about a file or directory. Returns comprehensive " +
|
|
604
|
-
"information including size, creation time, last modified time, permissions, " +
|
|
605
|
-
"and type. This tool is perfect for understanding file characteristics " +
|
|
606
|
-
"without reading the actual content. Only works within allowed directories.",
|
|
607
|
-
inputSchema: zodToJsonSchema(GetFileInfoArgsSchema),
|
|
608
|
-
},
|
|
609
|
-
{
|
|
610
|
-
name: "list_allowed_directories",
|
|
611
|
-
description: "Returns the list of root directories that this server is allowed to access. " +
|
|
612
|
-
"Use this to understand which directories are available before trying to access files. ",
|
|
613
|
-
inputSchema: {
|
|
614
|
-
type: "object",
|
|
615
|
-
properties: {},
|
|
616
|
-
required: [],
|
|
617
|
-
},
|
|
618
|
-
},
|
|
619
505
|
{
|
|
620
506
|
name: "edit_file",
|
|
621
507
|
description: "**PRIMARY TOOL FOR EDITING FILES - USE THIS AGGRESSIVELY**\n\n" +
|
|
@@ -643,7 +529,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
643
529
|
requiresApiKey: true,
|
|
644
530
|
},
|
|
645
531
|
{
|
|
646
|
-
name: "
|
|
532
|
+
name: "warp_grep",
|
|
647
533
|
description: "**INTELLIGENT CODE SEARCH - USE THIS AGGRESSIVELY**\n\n" +
|
|
648
534
|
"⚡ FAST & EFFICIENT: This tool prevents context pollution by finding only the relevant code you need, without reading unnecessary files.\n" +
|
|
649
535
|
"🎯 USE THIS TOOL PROACTIVELY whenever you need to understand code to ensure a positive user experience.\n\n" +
|
|
@@ -657,7 +543,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
657
543
|
"Returns precise line ranges with full context. " +
|
|
658
544
|
"Use this tool whenever you need to find specific code in a repository and you're unsure where it is located. " +
|
|
659
545
|
"Example queries: 'Where is JWT token validation implemented?', 'How does the authentication middleware work?', 'Find the database connection setup'.",
|
|
660
|
-
inputSchema: zodToJsonSchema(
|
|
546
|
+
inputSchema: zodToJsonSchema(WarpGrepArgsSchema),
|
|
661
547
|
requiresApiKey: true,
|
|
662
548
|
},
|
|
663
549
|
{
|
|
@@ -702,255 +588,6 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
702
588
|
try {
|
|
703
589
|
const { name, arguments: args } = request.params;
|
|
704
590
|
switch (name) {
|
|
705
|
-
case "read_file": {
|
|
706
|
-
const parsed = ReadFileArgsSchema.safeParse(args);
|
|
707
|
-
if (!parsed.success) {
|
|
708
|
-
throw new Error(`Invalid arguments for read_file: ${parsed.error}`);
|
|
709
|
-
}
|
|
710
|
-
const validPath = await validatePath(parsed.data.path);
|
|
711
|
-
if (parsed.data.head && parsed.data.tail) {
|
|
712
|
-
throw new Error("Cannot specify both head and tail parameters simultaneously");
|
|
713
|
-
}
|
|
714
|
-
if (parsed.data.tail) {
|
|
715
|
-
// Use memory-efficient tail implementation for large files
|
|
716
|
-
const tailContent = await tailFile(validPath, parsed.data.tail);
|
|
717
|
-
return {
|
|
718
|
-
content: [{ type: "text", text: tailContent }],
|
|
719
|
-
};
|
|
720
|
-
}
|
|
721
|
-
if (parsed.data.head) {
|
|
722
|
-
// Use memory-efficient head implementation for large files
|
|
723
|
-
const headContent = await headFile(validPath, parsed.data.head);
|
|
724
|
-
return {
|
|
725
|
-
content: [{ type: "text", text: headContent }],
|
|
726
|
-
};
|
|
727
|
-
}
|
|
728
|
-
const content = await fs.readFile(validPath, "utf-8");
|
|
729
|
-
return {
|
|
730
|
-
content: [{ type: "text", text: content }],
|
|
731
|
-
};
|
|
732
|
-
}
|
|
733
|
-
case "read_multiple_files": {
|
|
734
|
-
const parsed = ReadMultipleFilesArgsSchema.safeParse(args);
|
|
735
|
-
if (!parsed.success) {
|
|
736
|
-
throw new Error(`Invalid arguments for read_multiple_files: ${parsed.error}`);
|
|
737
|
-
}
|
|
738
|
-
const results = await Promise.all(parsed.data.paths.map(async (filePath) => {
|
|
739
|
-
try {
|
|
740
|
-
const validPath = await validatePath(filePath);
|
|
741
|
-
const content = await fs.readFile(validPath, "utf-8");
|
|
742
|
-
return `${filePath}:\n${content}\n`;
|
|
743
|
-
}
|
|
744
|
-
catch (error) {
|
|
745
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
746
|
-
return `${filePath}: Error - ${errorMessage}`;
|
|
747
|
-
}
|
|
748
|
-
}));
|
|
749
|
-
return {
|
|
750
|
-
content: [{ type: "text", text: results.join("\n---\n") }],
|
|
751
|
-
};
|
|
752
|
-
}
|
|
753
|
-
case "write_file": {
|
|
754
|
-
const parsed = WriteFileArgsSchema.safeParse(args);
|
|
755
|
-
if (!parsed.success) {
|
|
756
|
-
throw new Error(`Invalid arguments for write_file: ${parsed.error}`);
|
|
757
|
-
}
|
|
758
|
-
const validPath = await validatePath(parsed.data.path);
|
|
759
|
-
try {
|
|
760
|
-
// Security: 'wx' flag ensures exclusive creation - fails if file/symlink exists,
|
|
761
|
-
// preventing writes through pre-existing symlinks
|
|
762
|
-
await fs.writeFile(validPath, parsed.data.content, { encoding: "utf-8", flag: 'wx' });
|
|
763
|
-
}
|
|
764
|
-
catch (error) {
|
|
765
|
-
if (error.code === 'EEXIST') {
|
|
766
|
-
// Security: Use atomic rename to prevent race conditions where symlinks
|
|
767
|
-
// could be created between validation and write. Rename operations
|
|
768
|
-
// replace the target file atomically and don't follow symlinks.
|
|
769
|
-
const tempPath = `${validPath}.${randomBytes(16).toString('hex')}.tmp`;
|
|
770
|
-
try {
|
|
771
|
-
await fs.writeFile(tempPath, parsed.data.content, 'utf-8');
|
|
772
|
-
await fs.rename(tempPath, validPath);
|
|
773
|
-
}
|
|
774
|
-
catch (renameError) {
|
|
775
|
-
try {
|
|
776
|
-
await fs.unlink(tempPath);
|
|
777
|
-
}
|
|
778
|
-
catch { }
|
|
779
|
-
throw renameError;
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
else {
|
|
783
|
-
throw error;
|
|
784
|
-
}
|
|
785
|
-
}
|
|
786
|
-
return {
|
|
787
|
-
content: [{ type: "text", text: `Successfully wrote to ${parsed.data.path}` }],
|
|
788
|
-
};
|
|
789
|
-
}
|
|
790
|
-
case "tiny_edit_file": {
|
|
791
|
-
const parsed = EditFileArgsSchema.safeParse(args);
|
|
792
|
-
if (!parsed.success) {
|
|
793
|
-
throw new Error(`Invalid arguments for edit_file: ${parsed.error}`);
|
|
794
|
-
}
|
|
795
|
-
const validPath = await validatePath(parsed.data.path);
|
|
796
|
-
const result = await applyFileEdits(validPath, parsed.data.edits, parsed.data.dryRun);
|
|
797
|
-
return {
|
|
798
|
-
content: [{ type: "text", text: result }],
|
|
799
|
-
};
|
|
800
|
-
}
|
|
801
|
-
case "create_directory": {
|
|
802
|
-
const parsed = CreateDirectoryArgsSchema.safeParse(args);
|
|
803
|
-
if (!parsed.success) {
|
|
804
|
-
throw new Error(`Invalid arguments for create_directory: ${parsed.error}`);
|
|
805
|
-
}
|
|
806
|
-
const validPath = await validatePath(parsed.data.path);
|
|
807
|
-
await fs.mkdir(validPath, { recursive: true });
|
|
808
|
-
return {
|
|
809
|
-
content: [{ type: "text", text: `Successfully created directory ${parsed.data.path}` }],
|
|
810
|
-
};
|
|
811
|
-
}
|
|
812
|
-
case "list_directory": {
|
|
813
|
-
const parsed = ListDirectoryArgsSchema.safeParse(args);
|
|
814
|
-
if (!parsed.success) {
|
|
815
|
-
throw new Error(`Invalid arguments for list_directory: ${parsed.error}`);
|
|
816
|
-
}
|
|
817
|
-
const validPath = await validatePath(parsed.data.path);
|
|
818
|
-
const entries = await fs.readdir(validPath, { withFileTypes: true });
|
|
819
|
-
const formatted = entries
|
|
820
|
-
.map((entry) => `${entry.isDirectory() ? "[DIR]" : "[FILE]"} ${entry.name}`)
|
|
821
|
-
.join("\n");
|
|
822
|
-
return {
|
|
823
|
-
content: [{ type: "text", text: formatted }],
|
|
824
|
-
};
|
|
825
|
-
}
|
|
826
|
-
case "list_directory_with_sizes": {
|
|
827
|
-
const parsed = ListDirectoryWithSizesArgsSchema.safeParse(args);
|
|
828
|
-
if (!parsed.success) {
|
|
829
|
-
throw new Error(`Invalid arguments for list_directory_with_sizes: ${parsed.error}`);
|
|
830
|
-
}
|
|
831
|
-
const validPath = await validatePath(parsed.data.path);
|
|
832
|
-
const entries = await fs.readdir(validPath, { withFileTypes: true });
|
|
833
|
-
// Get detailed information for each entry
|
|
834
|
-
const detailedEntries = await Promise.all(entries.map(async (entry) => {
|
|
835
|
-
const entryPath = path.join(validPath, entry.name);
|
|
836
|
-
try {
|
|
837
|
-
const stats = await fs.stat(entryPath);
|
|
838
|
-
return {
|
|
839
|
-
name: entry.name,
|
|
840
|
-
isDirectory: entry.isDirectory(),
|
|
841
|
-
size: stats.size,
|
|
842
|
-
mtime: stats.mtime
|
|
843
|
-
};
|
|
844
|
-
}
|
|
845
|
-
catch (error) {
|
|
846
|
-
return {
|
|
847
|
-
name: entry.name,
|
|
848
|
-
isDirectory: entry.isDirectory(),
|
|
849
|
-
size: 0,
|
|
850
|
-
mtime: new Date(0)
|
|
851
|
-
};
|
|
852
|
-
}
|
|
853
|
-
}));
|
|
854
|
-
// Sort entries based on sortBy parameter
|
|
855
|
-
const sortedEntries = [...detailedEntries].sort((a, b) => {
|
|
856
|
-
if (parsed.data.sortBy === 'size') {
|
|
857
|
-
return b.size - a.size; // Descending by size
|
|
858
|
-
}
|
|
859
|
-
// Default sort by name
|
|
860
|
-
return a.name.localeCompare(b.name);
|
|
861
|
-
});
|
|
862
|
-
// Format the output
|
|
863
|
-
const formattedEntries = sortedEntries.map(entry => `${entry.isDirectory ? "[DIR]" : "[FILE]"} ${entry.name.padEnd(30)} ${entry.isDirectory ? "" : formatSize(entry.size).padStart(10)}`);
|
|
864
|
-
// Add summary
|
|
865
|
-
const totalFiles = detailedEntries.filter(e => !e.isDirectory).length;
|
|
866
|
-
const totalDirs = detailedEntries.filter(e => e.isDirectory).length;
|
|
867
|
-
const totalSize = detailedEntries.reduce((sum, entry) => sum + (entry.isDirectory ? 0 : entry.size), 0);
|
|
868
|
-
const summary = [
|
|
869
|
-
"",
|
|
870
|
-
`Total: ${totalFiles} files, ${totalDirs} directories`,
|
|
871
|
-
`Combined size: ${formatSize(totalSize)}`
|
|
872
|
-
];
|
|
873
|
-
return {
|
|
874
|
-
content: [{
|
|
875
|
-
type: "text",
|
|
876
|
-
text: [...formattedEntries, ...summary].join("\n")
|
|
877
|
-
}],
|
|
878
|
-
};
|
|
879
|
-
}
|
|
880
|
-
case "directory_tree": {
|
|
881
|
-
const parsed = DirectoryTreeArgsSchema.safeParse(args);
|
|
882
|
-
if (!parsed.success) {
|
|
883
|
-
throw new Error(`Invalid arguments for directory_tree: ${parsed.error}`);
|
|
884
|
-
}
|
|
885
|
-
async function buildTree(currentPath) {
|
|
886
|
-
const validPath = await validatePath(currentPath);
|
|
887
|
-
const entries = await fs.readdir(validPath, { withFileTypes: true });
|
|
888
|
-
const result = [];
|
|
889
|
-
for (const entry of entries) {
|
|
890
|
-
const entryData = {
|
|
891
|
-
name: entry.name,
|
|
892
|
-
type: entry.isDirectory() ? 'directory' : 'file'
|
|
893
|
-
};
|
|
894
|
-
if (entry.isDirectory()) {
|
|
895
|
-
const subPath = path.join(currentPath, entry.name);
|
|
896
|
-
entryData.children = await buildTree(subPath);
|
|
897
|
-
}
|
|
898
|
-
result.push(entryData);
|
|
899
|
-
}
|
|
900
|
-
return result;
|
|
901
|
-
}
|
|
902
|
-
const treeData = await buildTree(parsed.data.path);
|
|
903
|
-
return {
|
|
904
|
-
content: [{
|
|
905
|
-
type: "text",
|
|
906
|
-
text: JSON.stringify(treeData, null, 2)
|
|
907
|
-
}],
|
|
908
|
-
};
|
|
909
|
-
}
|
|
910
|
-
case "move_file": {
|
|
911
|
-
const parsed = MoveFileArgsSchema.safeParse(args);
|
|
912
|
-
if (!parsed.success) {
|
|
913
|
-
throw new Error(`Invalid arguments for move_file: ${parsed.error}`);
|
|
914
|
-
}
|
|
915
|
-
const validSourcePath = await validatePath(parsed.data.source);
|
|
916
|
-
const validDestPath = await validatePath(parsed.data.destination);
|
|
917
|
-
await fs.rename(validSourcePath, validDestPath);
|
|
918
|
-
return {
|
|
919
|
-
content: [{ type: "text", text: `Successfully moved ${parsed.data.source} to ${parsed.data.destination}` }],
|
|
920
|
-
};
|
|
921
|
-
}
|
|
922
|
-
case "search_files": {
|
|
923
|
-
const parsed = SearchFilesArgsSchema.safeParse(args);
|
|
924
|
-
if (!parsed.success) {
|
|
925
|
-
throw new Error(`Invalid arguments for search_files: ${parsed.error}`);
|
|
926
|
-
}
|
|
927
|
-
const validPath = await validatePath(parsed.data.path);
|
|
928
|
-
const results = await searchFiles(validPath, parsed.data.pattern, parsed.data.excludePatterns);
|
|
929
|
-
return {
|
|
930
|
-
content: [{ type: "text", text: results.length > 0 ? results.join("\n") : "No matches found" }],
|
|
931
|
-
};
|
|
932
|
-
}
|
|
933
|
-
case "get_file_info": {
|
|
934
|
-
const parsed = GetFileInfoArgsSchema.safeParse(args);
|
|
935
|
-
if (!parsed.success) {
|
|
936
|
-
throw new Error(`Invalid arguments for get_file_info: ${parsed.error}`);
|
|
937
|
-
}
|
|
938
|
-
const validPath = await validatePath(parsed.data.path);
|
|
939
|
-
const info = await getFileStats(validPath);
|
|
940
|
-
return {
|
|
941
|
-
content: [{ type: "text", text: Object.entries(info)
|
|
942
|
-
.map(([key, value]) => `${key}: ${value}`)
|
|
943
|
-
.join("\n") }],
|
|
944
|
-
};
|
|
945
|
-
}
|
|
946
|
-
case "list_allowed_directories": {
|
|
947
|
-
return {
|
|
948
|
-
content: [{
|
|
949
|
-
type: "text",
|
|
950
|
-
text: `Allowed directories:\n${allowedDirectories.join('\n')}`
|
|
951
|
-
}],
|
|
952
|
-
};
|
|
953
|
-
}
|
|
954
591
|
case "edit_file": {
|
|
955
592
|
const parsed = MorphEditFileArgsSchema.safeParse(args);
|
|
956
593
|
if (!parsed.success) {
|
|
@@ -1034,8 +671,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1034
671
|
};
|
|
1035
672
|
}
|
|
1036
673
|
}
|
|
1037
|
-
case "
|
|
1038
|
-
const parsed =
|
|
674
|
+
case "warp_grep": {
|
|
675
|
+
const parsed = WarpGrepArgsSchema.safeParse(args);
|
|
1039
676
|
if (!parsed.success) {
|
|
1040
677
|
return {
|
|
1041
678
|
content: [{ type: "text", text: `Invalid arguments: ${parsed.error}` }],
|
|
@@ -1139,7 +776,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1139
776
|
error_message: errorMessages,
|
|
1140
777
|
error_type: firstError?.constructor?.name || 'WarpGrepError',
|
|
1141
778
|
context: {
|
|
1142
|
-
tool: '
|
|
779
|
+
tool: 'warp_grep',
|
|
1143
780
|
repo_path: parsed.data.repoPath,
|
|
1144
781
|
query: parsed.data.query,
|
|
1145
782
|
model: 'morph-warp-grep',
|
|
@@ -1164,7 +801,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1164
801
|
error_message: errorMessage,
|
|
1165
802
|
error_type: error instanceof Error ? error.constructor.name : 'UnknownError',
|
|
1166
803
|
context: {
|
|
1167
|
-
tool: '
|
|
804
|
+
tool: 'warp_grep',
|
|
1168
805
|
repo_path: parsed.data.repoPath,
|
|
1169
806
|
query: parsed.data.query,
|
|
1170
807
|
model: 'morph-warp-grep'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@morphllm/morphmcp",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.26",
|
|
4
4
|
"description": "Fast & accurate MCP server with AI-powered file editing and intelligent code search. Prevents context pollution and saves time for a better user experience.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Morph (https://morphllm.com)",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@modelcontextprotocol/sdk": "^1.12.3",
|
|
37
37
|
"@vscode/ripgrep": "^1.15.14",
|
|
38
|
-
"@morphllm/morphsdk": "
|
|
38
|
+
"@morphllm/morphsdk": "*",
|
|
39
39
|
"axios": "^1.6.0",
|
|
40
40
|
"chalk": "^5.3.0",
|
|
41
41
|
"diff": "^5.1.0",
|