01//THE PROBLEM
Context Window Waste
MCP tools often return large JSON responses. When an agent only needs a few fields, the full response wastes precious context window tokens.
Without mcp-distill
1,157{
"id": "123",
"name": "Item",
"description": "...(2000 chars)...",
"metadata": {...},
"content": "...(10000 chars)..."
}
With mcp-distill
23{
"id": "123",
"name": "Item"
}
02//INSTALLATION
Get Started
❯pip install git+https://github.com/shoegazerstella/mcp-distill.git
Or with uv:
❯uv add git+https://github.com/shoegazerstella/mcp-distill.git
03//QUICK START
Basic Usage
Python
from fastmcp import FastMCP
from mcp_distill import projectable
mcp = FastMCP("my-server")
@mcp.tool
@projectable(fields=["id", "name", "metadata.created_by"])
def get_resource(resource_id: str) -> dict:
"""Fetch a resource by ID."""
return {
"id": resource_id,
"name": "Example Resource",
"description": "A" * 2000, # Large field - not advertised
"metadata": {
"created_by": "admin",
"huge_audit_log": [...], # Large field - not advertised
},
"content": "B" * 10000, # Large field - not advertised
}
04//HOW IT WORKS
Three Steps
1. Advertise available fields
The fields parameter tells the agent what fields it can request:
@projectable(fields=["id", "name", "metadata.created_by"])
2. Agent sees them in tool description
Tool: get_resource
Description: Fetch a resource by ID.
Projectable fields: id, name, metadata.created_by
Parameters:
- resource_id: string (required)
- _fields: array of strings (optional)
3. Agent requests only what it needs
# Agent needs just ID and name
get_resource(resource_id="123", _fields=["id", "name"])
# Returns: {"id": "123", "name": "Example Resource"}
# Agent needs everything (omits _fields)
get_resource(resource_id="123")
# Returns: full response
05//FIELD SYNTAX
Supported Patterns
| Pattern | Description | Example |
|---|---|---|
field |
Top-level field | "id", "name" |
a.b.c |
Nested field (dot notation) | "metadata.created_by" |
items.* |
All fields in object | "config.*" |
*.field |
Field from all top-level objects | "*.id" |
items.*.field |
Field from each item in array/dict | "results.*.name" |
06//ADVANCED USAGE
Additional APIs
Standalone function
from mcp_distill import project
data = {
"id": 1,
"name": "Item",
"nested": {"a": 1, "b": 2},
"large_blob": "x" * 10000,
}
result = project(data, ["id", "name", "nested.a"])
# {"id": 1, "name": "Item", "nested": {"a": 1}}
Reusable projector
from mcp_distill import Projector
slim = Projector(["id", "name", "status"])
for item in large_dataset:
yield slim.apply(item)
Decorator on any function
from mcp_distill import projectable
@projectable(fields=["id", "name", "email"])
def fetch_user(user_id: str) -> dict:
return db.get_user(user_id)
# With projection
fetch_user("123", _fields=["id", "name"])
# Without projection (full response)
fetch_user("123")
07//API REFERENCE
Core Functions
@projectable
@projectable(
fields=["id", "name", ...], # Available fields (shown to agent)
field_param="_fields", # Parameter name (default: "_fields")
field_description="...", # Custom parameter description
)
project(data, fields)
project(data: Any, fields: list[str] | None) -> Any
Projector
projector = Projector(["id", "name"])
result = projector.apply(data)