Skip to main content
Glama

create_text_file

Create or overwrite text files by specifying a relative path and content. This tool writes files and returns success or failure messages.

Instructions

Write a new file or overwrite an existing file. Returns a message indicating success or failure.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
relative_pathYesThe relative path to the file to create.
contentYesThe (appropriately encoded) content to write to the file.

Implementation Reference

  • The handler implementation of the 'create_text_file' tool. The 'apply' method validates the relative path, creates necessary directories, writes the content to the file, and returns a success message indicating if it was a new file or overwrite.
    class CreateTextFileTool(Tool, ToolMarkerCanEdit):
        """
        Creates/overwrites a file in the project directory.
        """
    
        def apply(self, relative_path: str, content: str) -> str:
            """
            Write a new file or overwrite an existing file.
    
            :param relative_path: the relative path to the file to create
            :param content: the (appropriately encoded) content to write to the file
            :return: a message indicating success or failure
            """
            project_root = self.get_project_root()
            abs_path = (Path(project_root) / relative_path).resolve()
            will_overwrite_existing = abs_path.exists()
    
            if will_overwrite_existing:
                self.project.validate_relative_path(relative_path, require_not_ignored=True)
            else:
                assert abs_path.is_relative_to(
                    self.get_project_root()
                ), f"Cannot create file outside of the project directory, got {relative_path=}"
    
            abs_path.parent.mkdir(parents=True, exist_ok=True)
            abs_path.write_text(content, encoding=self.project.project_config.encoding)
            answer = f"File created: {relative_path}."
            if will_overwrite_existing:
                answer += " Overwrote existing file."
            return answer
  • The ToolRegistry automatically discovers all subclasses of Tool in serena.tools modules (including CreateTextFileTool) and registers them with snake_case names derived from the class name (e.g., 'create_text_file').
    self._tool_dict: dict[str, RegisteredTool] = {}
    for cls in iter_subclasses(Tool):
        if not any(cls.__module__.startswith(pkg) for pkg in tool_packages):
            continue
        is_optional = issubclass(cls, ToolMarkerOptional)
        name = cls.get_name_from_cls()
        if name in self._tool_dict:
            raise ValueError(f"Duplicate tool name found: {name}. Tool classes must have unique names.")
        self._tool_dict[name] = RegisteredTool(tool_class=cls, is_optional=is_optional, tool_name=name)
  • Extracts function metadata (including JSON schema from type hints and docstring) from the tool's 'apply' method for use in MCP tool definitions.
    def get_apply_fn_metadata_from_cls(cls) -> FuncMetadata:
        """Get the metadata for the apply method from the class (static metadata).
        Needed for creating MCP tools in a separate process without running into serialization issues.
        """
        # First try to get from __dict__ to handle dynamic docstring changes
        if "apply" in cls.__dict__:
            apply_fn = cls.__dict__["apply"]
        else:
            # Fall back to getattr for inherited methods
            apply_fn = getattr(cls, "apply", None)
            if apply_fn is None:
                raise AttributeError(f"apply method not defined in {cls}. Did you forget to implement it?")
    
        return func_metadata(apply_fn, skip_names=["self", "cls"])
  • Derives the tool name 'create_text_file' from the class name 'CreateTextFileTool' by removing 'Tool' suffix and converting CamelCase to snake_case.
    def get_name_from_cls(cls) -> str:
        name = cls.__name__
        if name.endswith("Tool"):
            name = name[:-4]
        # convert to snake_case
        name = "".join(["_" + c.lower() if c.isupper() else c for c in name]).lstrip("_")
        return name

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/oraios/serena'

If you have feedback or need assistance with the MCP directory API, please join our Discord server