返回提交历史
Modified
g4f/mcp/server.py
+2
-0
Modified
g4f/mcp/tools.py
+73
-0
XFEstudio/gpt4free
Add replace_string_in_file tool
de03716d
代码差异
2 个文件
+75
-0
@@ -38,6 +38,7 @@ from .tools import (
38
38
ApplyPatchTool,
39
39
CreateFileTool,
40
40
FileWriteTool,
41
ReplaceStringInFileTool,
41
42
FetchWebpageTool,
42
43
FileSearchGlobTool,
43
44
GrepSearchTool,
@@ -96,6 +97,7 @@ class MCPServer:
96
97
"file_delete": FileDeleteTool(),
97
98
"create_file": CreateFileTool(),
98
99
"file_write": FileWriteTool(),
100
"replace_string_in_file": ReplaceStringInFileTool(),
99
101
"fetch_webpage": FetchWebpageTool(),
100
102
"file_search_glob": FileSearchGlobTool(),
101
103
"grep_search": GrepSearchTool(),
@@ -881,6 +881,79 @@ class FileWriteTool(MCPTool):
881
881
return {"error": f"Write failed: {exc}"}
882
882
883
883
884
class ReplaceStringInFileTool(MCPTool):
885
"""Replace an exact string in a file inside the ``~/.g4f/workspace`` directory."""
886
887
@property
888
def description(self) -> str:
889
return (
890
"Replace an exact string in a file inside the ~/.g4f/workspace directory. "
891
"Provide the relative file path, the exact old string, and the new string. "
892
"Only the first occurrence is replaced. Returns whether a replacement was made."
893
)
894
895
@property
896
def input_schema(self) -> Dict[str, Any]:
897
return {
898
"type": "object",
899
"properties": {
900
"filePath": {
901
"type": "string",
902
"description": "Relative path to the file inside the workspace",
903
},
904
"oldString": {
905
"type": "string",
906
"description": "The exact text to replace. Must uniquely identify one location.",
907
},
908
"newString": {
909
"type": "string",
910
"description": "The text to replace oldString with.",
911
},
912
},
913
"required": ["filePath", "oldString", "newString"],
914
}
915
916
async def execute(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
917
from .pa_provider import get_workspace_dir
918
919
rel_path = arguments.get("filePath", "")
920
old_string = arguments.get("oldString")
921
new_string = arguments.get("newString")
922
923
if not rel_path:
924
return {"error": "filePath parameter is required"}
925
if old_string is None:
926
return {"error": "oldString parameter is required"}
927
if new_string is None:
928
return {"error": "newString parameter is required"}
929
930
workspace = get_workspace_dir().resolve()
931
try:
932
target = (workspace / rel_path).resolve()
933
if not str(target).startswith(str(workspace)):
934
return {"error": "Access outside the workspace is not allowed"}
935
if not target.exists():
936
return {"error": f"File not found: {rel_path}"}
937
if not target.is_file():
938
return {"error": f"Path is not a file: {rel_path}"}
939
940
content = target.read_text(encoding="utf-8")
941
if old_string not in content:
942
return {
943
"error": "oldString not found in file. Include more surrounding context to uniquely identify the location."
944
}
945
946
new_content = content.replace(old_string, new_string, 1)
947
target.write_text(new_content, encoding="utf-8")
948
return {
949
"filePath": rel_path,
950
"replaced": True,
951
"size": len(new_content),
952
}
953
except Exception as exc:
954
return {"error": f"Replace failed: {exc}"}
955
956
884
957
class FetchWebpageTool(MCPTool):
885
958
"""Fetch and return the main content from one or more web pages."""
886
959