Claude Code Plugins

Community-maintained marketplace

Feedback

mcp-response-optimization

@sellersessions/Sub-Agents
0
0

Prevent massive MCP responses from WordPress, Playwright, Notion, and other MCPs that can kill conversations on first call. Sophisticated token management for all MCP tool usage.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name mcp-response-optimization
description Prevent massive MCP responses from WordPress, Playwright, Notion, and other MCPs that can kill conversations on first call. Sophisticated token management for all MCP tool usage.

MCP Response Optimization

Core Principle

REQUEST MINIMAL, DISPLAY NOTHING, SAVE EVERYTHING

Single MCP calls can kill entire conversations. This skill ensures every MCP call is filtered, limited, silent, extracted, and saved for maximum token efficiency.

When to Activate

ALWAYS activate before ANY MCP tool call, especially:

  • WordPress MCP operations (list posts, get pages, media queries)
  • Playwright browser automation (DOM queries, screenshots)
  • Notion API queries (search, database queries)
  • Any search or list operations across MCPs
  • Large data retrievals from any source

This skill is MANDATORY for all MCP usage in Claude Desktop.

The Critical Problem

One MCP call = conversation dead:

  • WordPress query returns 50 full pages → 100,000+ tokens
  • Playwright DOM query returns entire page HTML → 80,000+ tokens
  • Notion search returns 100 full pages → 120,000+ tokens
  • Result: Conversation ends on first message

MCP Integration

This skill optimizes these MCPs:

  • wordpress-mcp: WordPress content management
  • playwright: Browser automation and testing
  • notion / notionApi: Notion workspace integration
  • filesystem: File system operations (for saving large responses)
  • gmail: Email management
  • supabase: Database queries
  • firecrawl-mcp: Web scraping

WordPress MCP - The Worst Offender

The Problem

WordPress returns EVERYTHING by default:

  • Full post content (50KB per post)
  • All metadata, revisions, images (base64)
  • Author details, comments, categories
  • One query = conversation killer

The Solution: Aggressive Filtering

Rule 1: Always Use Field Filters

// ❌ NEVER:
wordpress.list_posts({ per_page: 100 })
// Returns: 5MB of data, 1,250,000 tokens

// ✅ ALWAYS:
wordpress.list_posts({
  per_page: 10,
  fields: 'id,title,date,status',
  context: 'view'
})
// Returns: 5KB of data, 1,250 tokens

Rule 2: Limit Results Aggressively

// Default limits:
per_page: 10  // NEVER use 100
page: 1       // Paginate if needed

Rule 3: Request Specific Fields Only

For Posts:

// Minimal (when listing):
fields: 'id,title,status,date'

// Add only when needed:
fields: 'id,title,status,date,excerpt'  // For preview
fields: 'id,title,content'  // Only when editing

For Pages:

fields: 'id,title,status,parent'

For Media:

// NEVER load full images
fields: 'id,title,source_url'  // URL only, not base64

Rule 4: Use Targeted Queries

// ❌ BAD:
wordpress.list_posts({ search: 'conference' })

// ✅ GOOD:
wordpress.list_posts({
  search: 'conference',
  per_page: 5,
  fields: 'id,title,date',
  status: 'publish',
  orderby: 'date',
  order: 'desc'
})

Rule 5: Never Display Full Responses

// ❌ DON'T:
console.log(response)

// ✅ DO:
const ids = response.map(post => ({ id: post.id, title: post.title }))
console.log(`Found ${ids.length} posts`)

WordPress Response Patterns

Pattern: List Posts

const posts = wordpress.list_posts({
  per_page: 10,
  fields: 'id,title,status,date',
  status: 'publish'
})

const post_ids = posts.map(p => p.id)
`Found ${posts.length} posts: ${post_ids.join(', ')}`

Pattern: Get Single Post

const post = wordpress.get_post({
  id: 123,
  fields: 'id,title,content,status'
})

`Retrieved post: ${post.title} (${post.id})`
// Save full content to file if needed

Pattern: Search and Filter

const results = wordpress.list_posts({
  search: 'keyword',
  per_page: 5,
  fields: 'id,title,date'
})

const filtered = results.filter(/* criteria */)
`Found ${filtered.length} matches: [${filtered.map(p => p.id)}]`

Playwright MCP - DOM and Screenshot Killer

The Problem

  • Full page HTML (200KB)
  • Complete DOM tree with attributes
  • Base64 screenshots (500KB-2MB)
  • One screenshot = conversation over

The Solution: Selective Queries

Rule 1: Use CSS Selectors, Not Full DOM

// ❌ NEVER:
playwright.evaluate("document.documentElement.outerHTML")
// Returns: 50,000+ tokens

// ✅ ALWAYS:
playwright.locator('.product-title').textContent()
// Returns: 10 tokens

Rule 2: Target Specific Elements

const data = {
  title: await page.locator('h1').textContent(),
  price: await page.locator('.price').textContent(),
  available: await page.locator('.stock-status').textContent()
}
// DON'T extract full page content

Rule 3: Screenshots - Save, Never Display

// ❌ NEVER include in response:
const screenshot = await page.screenshot()
// 500KB-2MB base64 = 125,000+ tokens

// ✅ SAVE screenshot:
await page.screenshot({ path: '/outputs/screenshot.png' })
`Screenshot saved: /outputs/screenshot.png`
// 20 tokens vs 125,000 tokens

Rule 4: Limit Element Extraction

const products = await page.locator('.product-card').all()

const product_data = []
for (const product of products.slice(0, 10)) {
  product_data.push({
    name: await product.locator('.name').textContent(),
    price: await product.locator('.price').textContent()
  })
}

fs.writeFileSync('/outputs/products.json', JSON.stringify(product_data))
`Extracted ${product_data.length} products → /outputs/products.json`

Playwright Response Patterns

Pattern: Page Scraping

await page.goto(url)

const data = {
  title: await page.title(),
  h1: await page.locator('h1').first().textContent(),
  meta: await page.locator('meta[name="description"]').getAttribute('content')
}

fs.writeFileSync('/outputs/page_data.json', JSON.stringify(data))
`Page data saved: /outputs/page_data.json`

Pattern: Element Analysis

const count = await page.locator('.product-item').count()
`Found ${count} products`

const sample = await page.locator('.product-item').first().textContent()
`Sample product: ${sample}`

Pattern: Screenshots for User

await page.screenshot({
  path: '/mnt/user-data/outputs/page.png',
  fullPage: false  // Viewport only
})

`[View screenshot](computer:///mnt/user-data/outputs/page.png)`

Notion MCP - Large Page Objects

The Problem

Notion returns full page objects with all blocks - can be massive.

The Solution

// ❌ DON'T:
notion.search({ query: 'project' })  // 100 full pages

// ✅ DO:
notion.search({
  query: 'project',
  page_size: 10,
  filter: { property: 'Status', select: { equals: 'Active' } }
})

const page_ids = results.map(r => r.id)
`Found ${page_ids.length} pages: ${page_ids}`

Universal MCP Rules

Rule 1: Pre-Call Token Budget

Before EVERY MCP call:

  • What's minimum data I actually need?
  • Can I filter to specific fields?
  • Can I limit result count?
  • Will response fit in 2,000 tokens?

If answer to last question is NO → Adjust parameters

Rule 2: Pagination Over Bulk

// ❌ NEVER:
get_all_items({ limit: 1000 })

// ✅ ALWAYS:
get_items({ limit: 10, page: 1 })

Rule 3: Save Large Responses

// Any response >5KB → Save to file

// ❌ DON'T:
console.log(large_response)

// ✅ DO:
fs.writeFileSync('/outputs/response.json', JSON.stringify(large_response))
`Response saved: /outputs/response.json`

Rule 4: ID-Based Workflows

// Step 1: Get IDs only
const ids = get_minimal_list()

// Step 2: User picks which ID
`Found ${ids.length} items: ${ids}`

// Step 3: Fetch full details for THAT ONE
const full_item = get_item_by_id(selected_id)

Rule 5: Never Display Raw MCP Responses

// ❌ FATAL:
`Here's what I found: ${JSON.stringify(mcp_response)}`

// ✅ CORRECT:
const summary = {
  count: mcp_response.length,
  items: mcp_response.map(i => i.id)
}
`Found ${summary.count} items: ${summary.items.join(', ')}`

Token Estimation Guide

Operation Bad Approach Good Approach
List 100 WP posts 1,000,000 tokens 2,500 tokens
Get WP page content 50,000 tokens 200 tokens
Playwright full DOM 100,000 tokens 500 tokens
Playwright screenshot 125,000 tokens 50 tokens
Notion page search 80,000 tokens 1,000 tokens

Pre-Call Checklist

Before EVERY MCP tool call:

  1. ✅ Minimum fields requested?
  2. ✅ Result limit set to <20?
  3. ✅ Estimated response <2,000 tokens?
  4. ✅ Plan to save, not display?
  5. ✅ ID-based workflow possible?
  6. ✅ Pagination strategy ready?

If all YES → Proceed If any NO → Adjust parameters

Emergency Patterns

If MCP Response Already Too Large

// Response came back huge (>50,000 tokens)

// 1. Save full response to file
fs.writeFileSync('/outputs/large_response.json', JSON.stringify(response))

// 2. Extract minimal summary
const summary = {
  count: response.length,
  first_id: response[0]?.id,
  last_id: response[response.length - 1]?.id
}

// 3. Return summary only
`Response saved to /outputs/large_response.json`
`Summary: ${summary.count} items (${summary.first_id} to ${summary.last_id})`

Success Checklist

This skill is working correctly when:

  • ✅ No MCP call exceeds 2,000 tokens in response
  • ✅ WordPress queries use field filters 100% of time
  • ✅ Playwright saves screenshots, never displays
  • ✅ Raw MCP responses NEVER appear in conversation
  • ✅ ID-based workflows used consistently
  • ✅ Large datasets saved to files automatically

The Golden Rules

  1. Request minimal fields - Only what you need
  2. Limit results aggressively - 10 items max initially
  3. Save, don't display - Files, not conversation
  4. IDs, not content - Work with identifiers
  5. Paginate on demand - Never bulk load
  6. Estimate before call - Budget tokens first

Integration with Other Skills

Works with:

  • curv-design-system - On-brand outputs with token efficiency
  • dashboard-auto-generation - Data dashboards without token bloat

Deployment: Import .zip to Claude Desktop → Settings → Skills Impact: Prevents 50,000-100,000+ token MCP disasters Result: Full conversation capacity instead of 1-message death