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

# Output Schemas

> Type annotations that power Gumloop integrations

Gumloop uses your tool's return type to generate an output schema. This schema tells Gumloop what data your tool produces, enabling it to connect your tool's output to other nodes in workflows. Without proper type annotations, these connections break.

## Schema Mapping

Here's how different return types translate to schemas:

| Return type             | Generated schema                       |
| ----------------------- | -------------------------------------- |
| `BaseModel`             | Schema from model fields (recommended) |
| `TypedDict`             | Schema from typed keys                 |
| `dict[str, T]`          | Root-level dict schema                 |
| `list[T]`, `int`, `str` | Wrapped as `{"result": value}`         |
| No annotation           | **No schema — breaks Gumloop**         |

## Examples

See how different return types generate schemas that Gumloop can use.

### BaseModel (recommended)

```python theme={"dark"}
from pydantic import BaseModel, Field

class Issue(BaseModel):
    id: str
    title: str
    status: str = Field(description="Current status: open, closed, or in_progress")

@mcp.tool()
def get_issue(issue_id: str) -> Issue:
    """Fetch an issue by ID."""
    return Issue(id=issue_id, title="Bug report", status="open")
```

Generated schema:

```json theme={"dark"}
{
  "type": "object",
  "properties": {
    "id": { "type": "string" },
    "title": { "type": "string" },
    "status": {
      "type": "string",
      "description": "Current status: open, closed, or in_progress"
    }
  },
  "required": ["id", "title", "status"]
}
```

### Lists

```python theme={"dark"}
@mcp.tool()
def list_issues() -> list[Issue]:
    """List all issues."""
    return [Issue(...), Issue(...)]
```

### Typed dicts

```python theme={"dark"}
@mcp.tool()
def get_stats() -> dict[str, int]:
    """Get issue statistics."""
    return {"open": 5, "closed": 12}
```

### Primitives

Primitives are wrapped in a `result` key:

```python theme={"dark"}
@mcp.tool()
def count_issues() -> int:
    """Count total issues."""
    return 17
```

Output: `{"result": 17}`

## What to Avoid

These patterns will cause problems in Gumloop because they don't generate usable schemas:

```python theme={"dark"}
# No return type — no schema generated
@mcp.tool()
def bad_tool():
    return {"data": "value"}

# Untyped dict — schema too generic
@mcp.tool()
def also_bad() -> dict:
    return {"data": "value"}
```

These tools work for direct MCP calls but break Gumloop workflows because there's no schema for node connections.

## Field Descriptions

Make your output easier to understand by adding descriptions to fields. These show up in Gumloop's UI and help users know what each field contains:

```python theme={"dark"}
class SearchResult(BaseModel):
    url: str = Field(description="Full URL to the document")
    title: str = Field(description="Document title")
    score: float = Field(description="Relevance score from 0 to 1")
```
