Skip to main content
Glama
possible055

Relace MCP Server

by possible055

fast_apply

Edit existing files or create new ones in the Relace MCP Server by applying code changes with truncation placeholders for unchanged sections.

Instructions

PRIMARY TOOL FOR EDITING FILES - USE THIS AGGRESSIVELY

Use this tool to edit an existing file or create a new file.

Use truncation placeholders to represent unchanged code:

  • // ... existing code ... (C/JS/TS-style)

  • ... existing code ... (Python/shell-style)

For deletions:

  • ALWAYS include 1-2 context lines above/below, omit deleted code, OR

  • Mark explicitly: // remove BlockName (or # remove BlockName)

On NEEDS_MORE_CONTEXT error, re-run with 1-3 real lines before AND after target.

Rules:

  • Preserve exact indentation

  • Be length efficient

  • ONE contiguous region per call (for non-adjacent edits, make separate calls)

To create a new file, simply specify the content in edit_snippet.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
pathYes
edit_snippetYes
instructionNo

Implementation Reference

  • The primary handler for the 'fast_apply' tool. Decorated with @mcp.tool for automatic schema generation and registration. Handles path resolution and delegates core logic to apply_file_logic.
    @mcp.tool(
        annotations={
            "readOnlyHint": False,  # Modifies files
            "destructiveHint": True,  # Can overwrite content
            "idempotentHint": False,  # Same edit twice = different results
            "openWorldHint": False,  # Only local filesystem
        }
    )
    async def fast_apply(
        path: str,
        edit_snippet: str,
        instruction: str = "",
        ctx: Context | None = None,
    ) -> dict[str, Any]:
        """**PRIMARY TOOL FOR EDITING FILES - USE THIS AGGRESSIVELY**
    
        Use this tool to edit an existing file or create a new file.
    
        Use truncation placeholders to represent unchanged code:
        - // ... existing code ...   (C/JS/TS-style)
        - # ... existing code ...    (Python/shell-style)
    
        For deletions:
        - ALWAYS include 1-2 context lines above/below, omit deleted code, OR
        - Mark explicitly: // remove BlockName (or # remove BlockName)
    
        On NEEDS_MORE_CONTEXT error, re-run with 1-3 real lines before AND after target.
    
        Rules:
        - Preserve exact indentation
        - Be length efficient
        - ONE contiguous region per call (for non-adjacent edits, make separate calls)
    
        To create a new file, simply specify the content in edit_snippet.
        """
        # Resolve base_dir dynamically (aligns with other tools).
        # This allows relative paths when MCP_BASE_DIR is not set but MCP Roots are available,
        # and provides a consistent security boundary for absolute paths.
        base_dir, _ = await resolve_base_dir(config.base_dir, ctx)
        return await apply_file_logic(
            backend=apply_backend,
            file_path=path,
            edit_snippet=edit_snippet,
            instruction=instruction or None,  # Convert empty string to None internally
            base_dir=base_dir,
        )
  • Core helper function implementing the file resolution, validation, LLM apply call, diff generation, atomic write, and comprehensive error handling for fast_apply.
    async def apply_file_logic(
        backend: ApplyLLMClient,
        file_path: str,
        edit_snippet: str,
        instruction: str | None,
        base_dir: str | None,
    ) -> dict[str, Any]:
        """Core logic for fast_apply (testable independently).
    
        Args:
            backend: Apply backend instance.
            file_path: Target file path.
            edit_snippet: Code snippet to apply, using abbreviation comments.
            instruction: Optional natural language instruction forwarded to the apply backend for disambiguation.
            base_dir: Base directory restriction. If None, only absolute paths are accepted.
    
        Returns:
            A structured dict with status, path, trace_id, timing_ms, diff, and message.
        """
        ctx = ApplyContext(
            trace_id=str(uuid.uuid4())[:8],
            started_at=datetime.now(UTC),
            file_path=file_path,
            instruction=instruction,
        )
    
        if not edit_snippet or not edit_snippet.strip():
            return errors.recoverable_error(
                "INVALID_INPUT",
                "edit_snippet cannot be empty",
                file_path,
                instruction,
                ctx.trace_id,
                ctx.elapsed_ms(),
            )
    
        try:
            result = _resolve_path(file_path, base_dir, ctx)
            if isinstance(result, dict):
                return result
            resolved_path, file_exists, file_size = result
    
            if not file_exists:
                return _create_new_file(ctx, resolved_path, edit_snippet)
            return await _apply_to_existing_file(ctx, backend, resolved_path, edit_snippet, file_size)
        except Exception as exc:
            apply_logging.log_apply_error(
                ctx.trace_id, ctx.started_at, file_path, edit_snippet, instruction, exc
            )
    
            if isinstance(exc, openai.APIError):
                logger.warning(
                    "[%s] Apply API error for %s: %s",
                    ctx.trace_id,
                    file_path,
                    exc,
                )
                return errors.openai_error_to_recoverable(
                    exc, file_path, instruction, ctx.trace_id, ctx.elapsed_ms()
                )
    
            if isinstance(exc, ValueError):
                logger.warning(
                    "[%s] API response parsing error for %s: %s",
                    ctx.trace_id,
                    file_path,
                    exc,
                )
                return errors.recoverable_error(
                    "API_INVALID_RESPONSE",
                    str(exc),
                    file_path,
                    instruction,
                    ctx.trace_id,
                    ctx.elapsed_ms(),
                )
    
            if isinstance(exc, ApplyError):
                logger.warning(
                    "[%s] Apply error (%s) for %s: %s",
                    ctx.trace_id,
                    exc.error_code,
                    file_path,
                    exc.message,
                )
                return errors.recoverable_error(
                    exc.error_code, exc.message, file_path, instruction, ctx.trace_id, ctx.elapsed_ms()
                )
    
            if isinstance(exc, PermissionError):
                logger.warning("[%s] Permission error for %s: %s", ctx.trace_id, file_path, exc)
                return errors.recoverable_error(
                    "PERMISSION_ERROR",
                    f"Permission denied: {exc}",
                    file_path,
                    instruction,
                    ctx.trace_id,
                    ctx.elapsed_ms(),
                )
    
            if isinstance(exc, OSError):
                errno_info = f"errno={exc.errno}" if exc.errno else ""
                strerror = exc.strerror or str(exc)
                logger.warning("[%s] Filesystem error for %s: %s", ctx.trace_id, file_path, exc)
                return errors.recoverable_error(
                    "FS_ERROR",
                    f"Filesystem error ({type(exc).__name__}, {errno_info}): {strerror}",
                    file_path,
                    instruction,
                    ctx.trace_id,
                    ctx.elapsed_ms(),
                )
    
            logger.error("[%s] Apply failed for %s: %s", ctx.trace_id, file_path, exc)
            return errors.recoverable_error(
                "INTERNAL_ERROR",
                f"Unexpected error ({type(exc).__name__}): {exc}",
                file_path,
                instruction,
                ctx.trace_id,
                ctx.elapsed_ms(),
            )
  • In build_server(), calls register_tools(mcp, config) which internally registers the fast_apply handler via decorator.
    mcp = FastMCP("Relace Fast Apply MCP")
    
    # Register middleware to handle MCP notifications (e.g., roots/list_changed)
    mcp.add_middleware(RootsMiddleware())
    
    register_tools(mcp, config)
    return mcp
  • MCP resource providing tool list including schema-like metadata for fast_apply (id, name, description). The actual input schema is auto-derived from handler function signature.
    @mcp.resource("relace://tools_list", mime_type="application/json")
    def tools_list() -> list[dict[str, Any]]:
        """List all available tools with their status."""
        tools = [
            {
                "id": "fast_apply",
                "name": "Fast Apply",
                "description": "Edit or create files using fuzzy matching",
                "enabled": True,
            },
            {
                "id": "fast_search",
                "name": "Fast Search",
                "description": "Agentic search over local codebase",
                "enabled": True,
            },
        ]
        if RELACE_CLOUD_TOOLS:
            tools.extend(
                [
                    {
                        "id": "cloud_sync",
                        "name": "Cloud Sync",
                        "description": "Upload codebase for semantic indexing",
                        "enabled": True,
                    },
                    {
                        "id": "cloud_search",
                        "name": "Cloud Search",
                        "description": "Semantic code search using AI embeddings",
                        "enabled": True,
                    },
                    {
                        "id": "cloud_clear",
                        "name": "Cloud Clear",
                        "description": "Delete cloud repository and sync state",
                        "enabled": True,
                    },
                    {
                        "id": "cloud_list",
                        "name": "Cloud List",
                        "description": "List all repositories in Relace Cloud",
                        "enabled": True,
                    },
                    {
                        "id": "cloud_info",
                        "name": "Cloud Info",
                        "description": "Get sync status for current repository",
                        "enabled": True,
                    },
                ]
            )
        return tools
Install Server

Other Tools

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/possible055/relace-mcp'

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