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

# Progress Reporting

> Update clients on the progress of long-running operations through the MCP context.

export const VersionBadge = ({version}) => {
  return <Badge stroke size="lg" icon="gift" iconType="regular" className="version-badge">
            New in version <code>{version}</code>
        </Badge>;
};

Progress reporting allows MCP tools to notify clients about the progress of long-running operations. This enables clients to display progress indicators and provide better user experience during time-consuming tasks.

## Why Use Progress Reporting?

Progress reporting is valuable for:

* **User experience**: Keep users informed about long-running operations
* **Progress indicators**: Enable clients to show progress bars or percentages
* **Timeout prevention**: Demonstrate that operations are actively progressing
* **Debugging**: Track execution progress for performance analysis

### Basic Usage

Use `ctx.report_progress()` to send progress updates to the client:

```python {14, 21} theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
from fastmcp import FastMCP, Context
import asyncio

mcp = FastMCP("ProgressDemo")

@mcp.tool
async def process_items(items: list[str], ctx: Context) -> dict:
    """Process a list of items with progress updates."""
    total = len(items)
    results = []
    
    for i, item in enumerate(items):
        # Report progress as we process each item
        await ctx.report_progress(progress=i, total=total)
        
        # Simulate processing time
        await asyncio.sleep(0.1)
        results.append(item.upper())
    
    # Report 100% completion
    await ctx.report_progress(progress=total, total=total)
    
    return {"processed": len(results), "results": results}
```

## Method Signature

<Card icon="code" title="Context Progress Method">
  <ResponseField name="ctx.report_progress" type="async method">
    Report progress to the client for long-running operations

    <Expandable title="Parameters">
      <ResponseField name="progress" type="float">
        Current progress value (e.g., 24, 0.75, 1500)
      </ResponseField>

      <ResponseField name="total" type="float | None" default="None">
        Optional total value (e.g., 100, 1.0, 2000). When provided, clients may interpret this as enabling percentage calculation.
      </ResponseField>
    </Expandable>
  </ResponseField>
</Card>

## Progress Patterns

### Percentage-Based Progress

Report progress as a percentage (0-100):

```python {13-14} theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
@mcp.tool
async def download_file(url: str, ctx: Context) -> str:
    """Download a file with percentage progress."""
    total_size = 1000  # KB
    downloaded = 0
    
    while downloaded < total_size:
        # Download chunk
        chunk_size = min(50, total_size - downloaded)
        downloaded += chunk_size
        
        # Report percentage progress
        percentage = (downloaded / total_size) * 100
        await ctx.report_progress(progress=percentage, total=100)
        
        await asyncio.sleep(0.1)  # Simulate download time
    
    return f"Downloaded file from {url}"
```

### Absolute Progress

Report progress with absolute values:

```python {10} theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
@mcp.tool
async def backup_database(ctx: Context) -> str:
    """Backup database tables with absolute progress."""
    tables = ["users", "orders", "products", "inventory", "logs"]
    
    for i, table in enumerate(tables):
        await ctx.info(f"Backing up table: {table}")
        
        # Report absolute progress
        await ctx.report_progress(progress=i + 1, total=len(tables))
        
        # Simulate backup time
        await asyncio.sleep(0.5)
    
    return "Database backup completed"
```

### Indeterminate Progress

Report progress without a known total for operations where the endpoint is unknown:

```python {11} theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
@mcp.tool
async def scan_directory(directory: str, ctx: Context) -> dict:
    """Scan directory with indeterminate progress."""
    files_found = 0
    
    # Simulate directory scanning
    for i in range(10):  # Unknown number of files
        files_found += 1
        
        # Report progress without total for indeterminate operations
        await ctx.report_progress(progress=files_found)
        
        await asyncio.sleep(0.2)
    
    return {"files_found": files_found, "directory": directory}
```

### Multi-Stage Operations

Break complex operations into stages with progress for each:

```python theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
@mcp.tool
async def data_migration(source: str, destination: str, ctx: Context) -> str:
    """Migrate data with multi-stage progress reporting."""
    
    # Stage 1: Validation (0-25%)
    await ctx.info("Validating source data")
    for i in range(5):
        await ctx.report_progress(progress=i * 5, total=100)
        await asyncio.sleep(0.1)
    
    # Stage 2: Export (25-60%)
    await ctx.info("Exporting data from source")
    for i in range(7):
        progress = 25 + (i * 5)
        await ctx.report_progress(progress=progress, total=100)
        await asyncio.sleep(0.1)
    
    # Stage 3: Transform (60-80%)
    await ctx.info("Transforming data format")
    for i in range(4):
        progress = 60 + (i * 5)
        await ctx.report_progress(progress=progress, total=100)
        await asyncio.sleep(0.1)
    
    # Stage 4: Import (80-100%)
    await ctx.info("Importing to destination")
    for i in range(4):
        progress = 80 + (i * 5)
        await ctx.report_progress(progress=progress, total=100)
        await asyncio.sleep(0.1)
    
    # Final completion
    await ctx.report_progress(progress=100, total=100)
    
    return f"Migration from {source} to {destination} completed"
```

## Client Requirements

Progress reporting requires clients to support progress handling:

* Clients must send a `progressToken` in the initial request to receive progress updates
* If no progress token is provided, progress calls will have no effect (they won't error)
* See [Client Progress](/v2/clients/progress) for details on implementing client-side progress handling
