Aller au contenu principal

ADR-032: Response Transformation β€” Pluggable Adapter Pattern

Metadata​

FieldValue
StatusAccepted
Date2026-02-06
LinearN/A

Context​

API responses from backends are often:

  • Too verbose for LLM context windows
  • Structured for machines, not AI agents
  • Inconsistent across different API providers

MCP Gateway needs to transform responses into LLM-friendly formats while respecting token budgets.

The Problem​

"How do we make arbitrary API responses AI-consumable without hardcoding transformations per API?"

Decision​

Implement a Response Transformation Engine with pluggable adapters for different response formats.

Architecture​

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ TransformEngine β”‚
β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Field β”‚ β”‚ Truncation β”‚ β”‚ Pagination β”‚ β”‚
β”‚ β”‚ Selection β”‚ β”‚ β”‚ β”‚ β”‚ β”‚
β”‚ β”‚ β”‚ β”‚ - Max chars β”‚ β”‚ - Page size β”‚ β”‚
β”‚ β”‚ - Include β”‚ β”‚ - Ellipsis β”‚ β”‚ - Cursor β”‚ β”‚
β”‚ β”‚ - Exclude β”‚ β”‚ β”‚ β”‚ β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚
β”‚ Adapters: β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Notion β”‚ β”‚ Linear β”‚ β”‚ Capper β”‚ β”‚
β”‚ β”‚ Adapter β”‚ β”‚ Adapter β”‚ β”‚ Adapter β”‚ β”‚
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚
β”‚ β”‚ Blocks β†’ β”‚ β”‚ Issues β†’ β”‚ β”‚ Token β”‚ β”‚
β”‚ β”‚ Markdown β”‚ β”‚ Summary β”‚ β”‚ Budget β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Transform Operations​

Field Selection​

Extract only relevant fields:

config = TransformConfig(
include_fields=["id", "title", "status", "created_at"],
exclude_fields=["internal_id", "raw_data"],
)

Truncation​

Limit response size:

config = TransformConfig(
max_chars=4000,
truncation_marker="... [truncated]",
)

Capper (Token Budget)​

Enforce token limits for LLM context:

class CapperAdapter:
def transform(self, response: dict, max_tokens: int) -> dict:
"""Cap response to fit token budget."""
current_tokens = count_tokens(response)
if current_tokens <= max_tokens:
return response

# Progressive summarization
return self._summarize_to_budget(response, max_tokens)

Adapters​

Notion Adapter​

Transforms Notion block responses:

class NotionAdapter:
def transform(self, blocks: list[dict]) -> str:
"""Convert Notion blocks to Markdown."""
markdown = []
for block in blocks:
if block["type"] == "paragraph":
markdown.append(block["paragraph"]["rich_text"][0]["plain_text"])
elif block["type"] == "heading_1":
markdown.append(f"# {block['heading_1']['rich_text'][0]['plain_text']}")
return "\n\n".join(markdown)

Linear Adapter​

Transforms Linear issue responses:

class LinearAdapter:
def transform(self, issue: dict) -> dict:
"""Extract key issue fields."""
return {
"id": issue["identifier"],
"title": issue["title"],
"status": issue["state"]["name"],
"assignee": issue.get("assignee", {}).get("name"),
"priority": issue["priority"],
}

Configuration Schema​

transform:
enabled: true
default_max_tokens: 4000
adapters:
notion:
enabled: true
output_format: markdown
linear:
enabled: true
include_comments: false
capper:
enabled: true
model: gpt-4 # For token counting

Consequences​

Positive​

  • LLM-Friendly β€” Responses fit context windows
  • Extensible β€” New adapters without engine changes
  • Configurable β€” Per-tool transformation rules
  • Consistent β€” Uniform output format

Negative​

  • Information Loss β€” Truncation removes data
  • Adapter Maintenance β€” Each API needs an adapter
  • Token Counting β€” Requires model-specific logic

References​


Standard Marchemalo: A 40-year veteran architect understands in 30 seconds