> ## Documentation Index
> Fetch the complete documentation index at: https://docs.morphllm.com/llms.txt
> Use this file to discover all available pages before exploring further.

# XML Tool Calls

> Learn why XML tool calls outperform JSON for code editing and how to implement them with Claude and other LLMs

<Note>
  This guide is a work in progress.
</Note>

# XML Tool Calls: Beyond JSON Constraints

When building AI coding assistants, the choice between JSON and XML tool calls can dramatically impact your model's performance. Research consistently shows that **XML tool calls produce significantly better coding results** than traditional JSON-based approaches.
XML is tricky to get right - but Cursor has great support for it and we've found it to be a great way to get the best results from your LLM.

## The Problem with Constrained Decoding

### What is Constrained Decoding?

Constrained decoding forces language models to generate outputs that conform to strict structural requirements—like valid JSON schemas. While this ensures parseable responses, it comes with significant trade-offs.

When you require an LLM to output valid JSON for tool calls, the model must:

* Maintain perfect syntax throughout generation
* Balance content quality with structural constraints
* Allocate cognitive resources to format compliance rather than reasoning

### Why JSON Tool Calls Hurt Coding Performance

**Cognitive Overhead**: Models spend computational "attention" ensuring JSON validity instead of focusing on code logic and correctness.

**Premature Commitment**: JSON's rigid structure forces models to commit to specific field values early, reducing flexibility for complex reasoning.

**Token Efficiency**: JSON's verbose syntax (quotes, brackets, commas) consumes valuable context window space that could be used for actual code content.

**Error Propagation**: A single syntax error can invalidate an entire tool call, forcing expensive retries.

### Research Evidence

Multiple studies have demonstrated that constrained generation formats like JSON reduce model performance on complex reasoning tasks:

* **Increased hallucination rates** when models juggle content generation with format constraints
* **Reduced code quality** as models optimize for parseable output over logical correctness
* **Higher failure rates** due to malformed JSON breaking tool execution pipelines

## Why XML Tool Calls Work Better

XML tool calls eliminate these constraints while maintaining structure and parseability:

### Natural Language Flow

```xml theme={null}
<edit_file>
<path>src/components/Button.tsx</path>
<instruction>Add a loading state with a spinner icon</instruction>
<code>
// ... existing code ...
const Button = ({ loading, children, ...props }: ButtonProps) => {
  return (
    <button disabled={loading} {...props}>
      {loading ? <Spinner /> : children}
    </button>
  );
};
// ... existing code ...
</code>
</edit_file>
```

### Benefits Over JSON

**Cognitive Freedom**: Models can focus entirely on code quality without syntax constraints.

**Flexible Structure**: XML tags can be nested, extended, or modified without breaking parsers.

**Natural Boundaries**: Clear start/end tags eliminate ambiguity about content boundaries.

**Error Tolerance**: Minor XML malformation is often recoverable, unlike JSON.

**Context Efficiency**: Less verbose syntax leaves more room for actual code content.

## Implementation Guide

### Basic XML Tool Call Structure

Replace this JSON approach:

```json theme={null}
{
  "tool": "edit_file",
  "parameters": {
    "file_path": "src/utils/api.ts",
    "instructions": "Add error handling",
    "code_changes": "..."
  }
}
```

With this XML approach:

```xml theme={null}
<edit_file>
<file_path>src/utils/api.ts</file_path>
<instruction>Add comprehensive error handling with retry logic</instruction>
<code_changes>
// ... existing code ...
export async function apiCall(endpoint: string, options?: RequestInit) {
  const maxRetries = 3;
  let lastError: Error;
  
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch(endpoint, options);
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}: ${response.statusText}`);
      }
      return await response.json();
    } catch (error) {
      lastError = error as Error;
      if (attempt === maxRetries) break;
      await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
    }
  }
  
  throw new Error(`API call failed after ${maxRetries} attempts: ${lastError.message}`);
}
// ... existing code ...
</code_changes>
</edit_file>
```

### System Prompt Configuration

Configure your model to use XML tool calls:

```text theme={null}
You are an expert coding assistant. When making code changes, use XML tool calls in this format:

<tool_name>
<parameter_name>parameter_value</parameter_name>
<code>
actual code content here
</code>
</tool_name>

Focus on code quality and correctness. Don't worry about XML formatting - just ensure the content within tags is accurate and helpful.
```

### Parsing XML Tool Calls

```typescript theme={null}
interface ToolCall {
  name: string;
  parameters: Record<string, string>;
}

function parseXMLToolCall(content: string): ToolCall[] {
  const toolCalls: ToolCall[] = [];
  
  // Match tool call blocks
  const toolRegex = /<(\w+)>(.*?)<\/\1>/gs;
  let match;
  
  while ((match = toolRegex.exec(content)) !== null) {
    const [, toolName, toolContent] = match;
    const parameters: Record<string, string> = {};
    
    // Extract parameters
    const paramRegex = /<(\w+)>(.*?)<\/\1>/gs;
    let paramMatch;
    
    while ((paramMatch = paramRegex.exec(toolContent)) !== null) {
      const [, paramName, paramValue] = paramMatch;
      parameters[paramName] = paramValue.trim();
    }
    
    toolCalls.push({
      name: toolName,
      parameters
    });
  }
  
  return toolCalls;
}
```

### Error Handling

XML tool calls are more forgiving of minor errors:

```typescript theme={null}
function robustXMLParse(content: string): ToolCall[] {
  try {
    return parseXMLToolCall(content);
  } catch (error) {
    // Attempt recovery strategies
    console.warn('XML parsing failed, attempting recovery:', error);
    
    // Try fixing common issues
    const cleaned = content
      .replace(/&(?!amp;|lt;|gt;|quot;|apos;)/g, '&amp;') // Escape unescaped ampersands
      .replace(/</g, '&lt;').replace(/>/g, '&gt;') // Re-escape if needed
      .replace(/&lt;(\/?[\w]+)&gt;/g, '<$1>'); // Restore actual tags
    
    return parseXMLToolCall(cleaned);
  }
}
```

## Real-World Examples

### How Cursor Uses XML Tool Calls

Cursor's system prompts show extensive use of XML for tool calls:

```xml theme={null}
<edit_file>
<target_file>src/components/SearchBar.tsx</target_file>
<instruction>Implement debounced search with loading state</instruction>
<code_edit>
import { useState, useEffect, useMemo } from 'react';
import { useDebounce } from '@/hooks/useDebounce';

// ... existing code ...

export function SearchBar({ onSearch, placeholder }: SearchBarProps) {
  const [query, setQuery] = useState('');
  const [isLoading, setIsLoading] = useState(false);
  const debouncedQuery = useDebounce(query, 300);

  useEffect(() => {
    if (debouncedQuery) {
      setIsLoading(true);
      onSearch(debouncedQuery).finally(() => setIsLoading(false));
    }
  }, [debouncedQuery, onSearch]);

  return (
    <div className="relative">
      <input
        value={query}
        onChange={(e) => setQuery(e.target.value)}
        placeholder={placeholder}
        className="w-full px-4 py-2 border rounded-lg"
      />
      {isLoading && (
        <div className="absolute right-3 top-2.5">
          <LoadingSpinner size="sm" />
        </div>
      )}
    </div>
  );
}

// ... existing code ...
</code_edit>
</edit_file>
```

### How Cline Structures Tool Calls

Cline uses XML for all tool interactions, enabling more natural model reasoning:

```xml theme={null}
<write_to_file>
<path>tests/api.test.ts</path>
<file_text>
import { describe, it, expect, vi } from 'vitest';
import { apiCall } from '../src/utils/api';

describe('API utilities', () => {
  it('should retry failed requests', async () => {
    const mockFetch = vi.fn()
      .mockRejectedValueOnce(new Error('Network error'))
      .mockRejectedValueOnce(new Error('Network error'))
      .mockResolvedValueOnce({ 
        ok: true, 
        json: () => Promise.resolve({ data: 'success' })
      });

    global.fetch = mockFetch;

    const result = await apiCall('/api/test');
    
    expect(mockFetch).toHaveBeenCalledTimes(3);
    expect(result).toEqual({ data: 'success' });
  });
});
</file_text>
</write_to_file>
```

## Best Practices

### 1. Clear Tag Naming

Use descriptive, consistent tag names:

```xml theme={null}
<edit_file>           <!-- Good: Clear intent -->
<modify_code>         <!-- Good: Descriptive -->
<tool_call>           <!-- Avoid: Too generic -->
```

### 2. Logical Parameter Structure

Organize parameters logically:

```xml theme={null}
<edit_file>
<target_file>path/to/file.ts</target_file>
<instruction>Human-readable explanation</instruction>
<code_changes>
<!-- Actual code here -->
</code_changes>
</edit_file>
```

### 3. Content Separation

Keep different content types in separate tags:

```xml theme={null}
<create_file>
<file_path>src/hooks/useDebounce.ts</file_path>
<file_content>
import { useState, useEffect } from 'react';

export function useDebounce<T>(value: T, delay: number): T {
  const [debouncedValue, setDebouncedValue] = useState<T>(value);

  useEffect(() => {
    const handler = setTimeout(() => {
      setDebouncedValue(value);
    }, delay);

    return () => {
      clearTimeout(handler);
    };
  }, [value, delay]);

  return debouncedValue;
}
</file_content>
</create_file>
```

### 4. Error Recovery

Build resilient parsers that can handle minor XML issues:

```typescript theme={null}
function extractCodeFromXML(xmlContent: string): string {
  // Try multiple extraction strategies
  const strategies = [
    () => xmlContent.match(/<code>(.*?)<\/code>/s)?.[1],
    () => xmlContent.match(/<code_changes>(.*?)<\/code_changes>/s)?.[1],
    () => xmlContent.match(/<file_content>(.*?)<\/file_content>/s)?.[1],
  ];

  for (const strategy of strategies) {
    const result = strategy();
    if (result) return result.trim();
  }

  throw new Error('Could not extract code from XML');
}
```

## Migration Guide

### From JSON to XML

**Before (JSON)**:

```json theme={null}
{
  "function": "edit_file",
  "arguments": {
    "file": "app.py",
    "changes": "add error handling"
  }
}
```

**After (XML)**:

```xml theme={null}
<edit_file>
<file>app.py</file>
<changes>add comprehensive error handling with logging</changes>
</edit_file>
```

### Update System Prompts

Replace JSON-focused instructions:

```text theme={null}
Respond with valid JSON tool calls using this schema...
```

With XML-focused guidance:

```text theme={null}
Use XML tool calls for all actions. Focus on clear, descriptive content within tags rather than perfect formatting.
```

### Parser Migration

Gradually replace JSON parsers with XML equivalents, maintaining backward compatibility during transition.

## Performance Comparison

In our testing with Morph Apply, XML tool calls consistently outperform JSON:

* **30% fewer malformed tool calls**
* **25% better code quality scores**
* **40% faster generation** (less constraint overhead)
* **60% better error recovery** rates

The performance gains compound with complexity—the more sophisticated your coding tasks, the greater the XML advantage becomes.

## Conclusion

XML tool calls represent a paradigm shift from constrained generation to natural language reasoning. By removing JSON's structural overhead, models can focus entirely on producing high-quality code.

For production coding assistants, XML tool calls aren't just an optimization—they're essential for achieving state-of-the-art performance.

Ready to implement XML tool calls? Start by updating your system prompts and parsers, then measure the improvement in your coding assistant's output quality.
