Jake Shore f3c4cd817b Add all MCP servers + factory infra to MCPEngine — 2026-02-06
=== NEW SERVERS ADDED (7) ===
- servers/closebot — 119 tools, 14 modules, 4,656 lines TS (Stage 7)
- servers/google-console — Google Search Console MCP (Stage 7)
- servers/meta-ads — Meta/Facebook Ads MCP (Stage 8)
- servers/twilio — Twilio communications MCP (Stage 8)
- servers/competitor-research — Competitive intel MCP (Stage 6)
- servers/n8n-apps — n8n workflow MCP apps (Stage 6)
- servers/reonomy — Commercial real estate MCP (Stage 1)

=== FACTORY INFRASTRUCTURE ADDED ===
- infra/factory-tools — mcp-jest, mcp-validator, mcp-add, MCP Inspector
  - 60 test configs, 702 auto-generated test cases
  - All 30 servers score 100/100 protocol compliance
- infra/command-center — Pipeline state, operator playbook, dashboard config
- infra/factory-reviews — Automated eval reports

=== DOCS ADDED ===
- docs/MCP-FACTORY.md — Factory overview
- docs/reports/ — 5 pipeline evaluation reports
- docs/research/ — Browser MCP research

=== RULES ESTABLISHED ===
- CONTRIBUTING.md — All MCP work MUST go in this repo
- README.md — Full inventory of 37 servers + infra docs
- .gitignore — Updated for Python venvs

TOTAL: 37 MCP servers + full factory pipeline in one repo.
This is now the single source of truth for all MCP work.
2026-02-06 06:32:29 -05:00
..

MCP Apps for Google Search Console

This directory contains 5 interactive HTML applications that render as rich UIs in Claude Desktop via the MCP Apps protocol.

Apps Overview

1. Performance Dashboard (dashboard.ts)

  • Tool: performance_dashboard
  • Shows: KPI cards, sparkline charts, top queries/pages with sortable tables
  • Data needs: { siteUrl, startDate, endDate, kpis, trends, timeseries, topQueries, topPages }

2. Quick Wins Board (quick-wins.ts)

  • Tool: quick_wins_board
  • Shows: Card grid of optimization opportunities with impact scores
  • Data needs: { opportunities: [{ keyword, page, position, impressions, currentCtr, estimatedClickGain, impactScore }] }
  • Interactive: Position and impressions filters

3. URL Health Inspector (url-health.ts)

  • Tool: url_health_inspector
  • Shows: Traffic-light status cards with expandable inspection details
  • Data needs: { results: [{ url, verdict, coverageState, lastCrawlTime, mobileUsability, richResults, ... }] }
  • Interactive: Click to expand full inspection details

4. Cannibalization Map (cannibalization.ts)

  • Tool: cannibalization_map
  • Shows: Expandable table rows with competing pages and impression distribution
  • Data needs: { keywords: [{ keyword, pages: [...], totalImpressions, severity }] }
  • Interactive: Click to expand competing pages, sort by severity/impressions/pages

5. Content Decay Tracker (content-decay.ts)

  • Tool: content_decay_tracker
  • Shows: Declining pages with sparkline trends and actionable recommendations
  • Data needs: { pages: [{ url, trend: [], peakClicks, recentClicks, percentDrop, daysSincePeak, severity, peakDate, absoluteLoss }] }
  • Interactive: Click to expand timeline details and recommendations, sort by multiple metrics

How to Integrate

Step 1: Register Apps as Resources

In your server.ts:

```typescript import { allApps } from './apps/index.js';

// Register each app's HTML as a resource allApps.forEach(app => { server.setRequestHandler(ListResourcesRequestSchema, async () => { return { resources: [{ uri: app.resourceUri, name: app.toolName, description: app.description, mimeType: 'text/html', }] }; });

server.setRequestHandler(ReadResourceRequestSchema, async (request) => { if (request.params.uri === app.resourceUri) { return { contents: [{ uri: app.resourceUri, mimeType: 'text/html', text: app.getHtml(), }] }; } }); }); ```

Step 2: Register Tools with UI Metadata

```typescript // Register tools that trigger apps allApps.forEach(app => { server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [{ name: app.toolName, description: app.description, inputSchema: app.inputSchema, annotations: app.annotations, _meta: { ui: { resourceUri: app.resourceUri, } } }] }; }); }); ```

Step 3: Return Data via structuredContent

In your tool handler:

```typescript async function handlePerformanceDashboard(args: any) { // Fetch data from Google Search Console API const data = await fetchDashboardData(args.siteUrl, args.startDate, args.endDate);

// Replace {{DATA}} placeholder with actual JSON const html = dashboardApp.getHtml().replace('{{DATA}}', JSON.stringify(data));

return { content: [{ type: 'resource', resource: { uri: dashboardApp.resourceUri, mimeType: 'text/html', text: html, } }], structuredContent: data, // Also send as structured data }; } ```

Design System

All apps use a consistent Google-inspired design:

  • Colors:

    • Primary: #1a73e8 (Google blue)
    • Success: #34a853 (green)
    • Warning: #fbbc04 (yellow)
    • Error: #ea4335 (red)
    • Background: #f8f9fa (light) / #1e1e1e (dark)
    • Text: #202124 (light) / #e8eaed (dark)
  • Typography:

    • Font: system-ui, -apple-system, sans-serif
  • Spacing:

    • Base unit: 8px
    • Card padding: 16px
    • Gap between elements: 12px/16px/24px
  • Components:

    • Border radius: 8px (cards), 4px (badges)
    • Box shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.08)

Key Implementation Notes

  1. No External Dependencies: All apps are self-contained HTML strings with inline CSS and JS. No CDN links, no external libraries.

  2. Dark Mode: Every app supports dark mode via @media (prefers-color-scheme: dark).

  3. Responsive: All apps work on narrow panels (mobile-friendly).

  4. Data Injection: The {{DATA}} placeholder gets replaced with actual JSON data at serve time.

  5. Interactive Elements: All interactivity (sorting, filtering, expanding) is handled by vanilla JavaScript in the HTML.

  6. SVG Sparklines: Dashboard and content decay apps use inline SVG for sparkline charts (no chart libraries needed).

Testing

To test an app in isolation, create a standalone HTML file:

```typescript import { dashboardApp } from './dashboard.js';

const testData = { siteUrl: 'https://example.com', startDate: '2026-01-01', endDate: '2026-01-28', kpis: { totalClicks: 1234, totalImpressions: 56789, avgCtr: 0.0217, avgPosition: 12.3 }, trends: { clicks: 5.2, impressions: 3.1, ctr: 1.8, position: -2.1 }, timeseries: { clicks: [100, 120, 115, 130, 140, 135, 145] }, topQueries: [...], topPages: [...], };

const html = dashboardApp.getHtml().replace('{{DATA}}', JSON.stringify(testData)); fs.writeFileSync('test-dashboard.html', html); ```

Then open test-dashboard.html in a browser to verify it works correctly.