# MCP Servers - Usage Examples

Practical examples demonstrating how to use the workflow MCP servers.

## Table of Contents

1. [Dashboard API Integration](#dashboard-api-integration)
2. [React Components](#react-components)
3. [Direct Server Usage](#direct-server-usage)
4. [Token Comparison](#token-comparison)
5. [Error Handling](#error-handling)

---

## Dashboard API Integration

### Complete Dashboard Summary Endpoint

```typescript
// app/api/dashboard/workflow-summary/route.ts
import { NextRequest } from "next/server";
import { getWorkflowDashboardSummary } from "@/.claude/mcp/skills/workflow-dashboard-summary";
import { validateStaffSession } from "@/lib/staff-session";
import { getUserSubscription } from "@/lib/services/billing";

export async function GET(req: NextRequest) {
  try {
    // Validate session
    const session = await validateStaffSession(req);
    if (!session) {
      return Response.json({ error: "Unauthorized" }, { status: 401 });
    }

    // Get user's subscription tier
    const subscription = await getUserSubscription(session.userId);
    if (!subscription) {
      return Response.json({ error: "No subscription found" }, { status: 404 });
    }

    // Get comprehensive dashboard summary
    const summary = await getWorkflowDashboardSummary({
      userId: session.userId,
      packageTier: subscription.tierId,
      includeWeeklyTrend: true,
      includeTopWorkflows: true,
      conversationLimit: 10,
    });

    return Response.json({
      success: true,
      data: summary,
    });
  } catch (error) {
    console.error("Dashboard summary error:", error);
    return Response.json(
      { error: "Failed to fetch dashboard summary" },
      { status: 500 },
    );
  }
}
```

### Minimal Stats Endpoint (Fast)

```typescript
// app/api/dashboard/quick-stats/route.ts
import { NextRequest } from "next/server";
import { getMinimalDashboardSummary } from "@/.claude/mcp/skills/workflow-dashboard-summary";
import { validateStaffSession } from "@/lib/staff-session";
import { getUserSubscription } from "@/lib/services/billing";

export async function GET(req: NextRequest) {
  try {
    const session = await validateStaffSession(req);
    if (!session) {
      return Response.json({ error: "Unauthorized" }, { status: 401 });
    }

    const subscription = await getUserSubscription(session.userId);

    // Quick stats - minimal token usage
    const stats = await getMinimalDashboardSummary(
      session.userId,
      subscription?.tierId || "starter",
    );

    return Response.json({ success: true, data: stats });
  } catch (error) {
    console.error("Quick stats error:", error);
    return Response.json({ error: "Failed to fetch stats" }, { status: 500 });
  }
}
```

### Workflow Access Check Endpoint

```typescript
// app/api/workflows/check-access/route.ts
import { NextRequest } from "next/server";
import { checkWorkflowAccess } from "@/.claude/mcp/skills/workflow-dashboard-summary";
import { validateStaffSession } from "@/lib/staff-session";
import { getUserSubscription } from "@/lib/services/billing";

export async function POST(req: NextRequest) {
  try {
    const session = await validateStaffSession(req);
    if (!session) {
      return Response.json({ error: "Unauthorized" }, { status: 401 });
    }

    const { workflowType } = await req.json();
    const subscription = await getUserSubscription(session.userId);

    const access = await checkWorkflowAccess(
      session.userId,
      subscription?.tierId || "starter",
      workflowType,
    );

    return Response.json({ success: true, data: access });
  } catch (error) {
    console.error("Access check error:", error);
    return Response.json({ error: "Failed to check access" }, { status: 500 });
  }
}
```

---

## React Components

### Dashboard Overview Component

```tsx
// components/dashboard/WorkflowOverview.tsx
"use client";

import { useEffect, useState } from "react";
import { Card } from "@/components/ui/card";
import { Loader2 } from "lucide-react";

interface DashboardSummary {
  summary: {
    activeWorkflows: number;
    conversationsToday: number;
    messagesHandled: number;
    appointmentsBooked: number;
  };
  workflows: {
    total: number;
    active: number;
    inactive: number;
    error: number;
  };
  conversations: {
    weeklyTrend: Array<{ date: string; count: number }>;
  };
}

export function WorkflowOverview() {
  const [data, setData] = useState<DashboardSummary | null>(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    async function fetchSummary() {
      try {
        const res = await fetch("/api/dashboard/workflow-summary");
        const json = await res.json();
        setData(json.data);
      } catch (error) {
        console.error("Failed to fetch summary:", error);
      } finally {
        setLoading(false);
      }
    }

    fetchSummary();
    // Refresh every 30 seconds
    const interval = setInterval(fetchSummary, 30000);
    return () => clearInterval(interval);
  }, []);

  if (loading) {
    return (
      <div className="flex items-center justify-center p-8">
        <Loader2 className="h-8 w-8 animate-spin" />
      </div>
    );
  }

  if (!data) {
    return <div>Failed to load dashboard data</div>;
  }

  return (
    <div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
      <Card className="p-6">
        <h3 className="text-sm font-medium text-muted-foreground">
          Active Workflows
        </h3>
        <p className="text-3xl font-bold">{data.summary.activeWorkflows}</p>
        <p className="text-xs text-muted-foreground mt-1">
          {data.workflows.total} total configured
        </p>
      </Card>

      <Card className="p-6">
        <h3 className="text-sm font-medium text-muted-foreground">
          Conversations Today
        </h3>
        <p className="text-3xl font-bold">{data.summary.conversationsToday}</p>
        <p className="text-xs text-muted-foreground mt-1">
          {data.summary.messagesHandled} messages handled
        </p>
      </Card>

      <Card className="p-6">
        <h3 className="text-sm font-medium text-muted-foreground">
          Appointments Booked
        </h3>
        <p className="text-3xl font-bold">{data.summary.appointmentsBooked}</p>
        <p className="text-xs text-muted-foreground mt-1">Last 7 days</p>
      </Card>

      <Card className="p-6">
        <h3 className="text-sm font-medium text-muted-foreground">
          Weekly Trend
        </h3>
        <div className="flex items-end gap-1 h-12 mt-2">
          {data.conversations.weeklyTrend?.map((day, i) => (
            <div
              key={i}
              className="flex-1 bg-primary rounded-t"
              style={{
                height: `${(day.count / Math.max(...data.conversations.weeklyTrend.map((d) => d.count))) * 100}%`,
                minHeight: "4px",
              }}
              title={`${day.date}: ${day.count} conversations`}
            />
          ))}
        </div>
      </Card>
    </div>
  );
}
```

### Workflow Access Guard Component

```tsx
// components/workflows/WorkflowAccessGuard.tsx
"use client";

import { useEffect, useState } from "react";
import { Button } from "@/components/ui/button";
import { Lock } from "lucide-react";

interface WorkflowAccessGuardProps {
  workflowType: string;
  children: React.ReactNode;
  fallback?: React.ReactNode;
}

export function WorkflowAccessGuard({
  workflowType,
  children,
  fallback,
}: WorkflowAccessGuardProps) {
  const [hasAccess, setHasAccess] = useState<boolean | null>(null);
  const [requiredTier, setRequiredTier] = useState<string>("");

  useEffect(() => {
    async function checkAccess() {
      try {
        const res = await fetch("/api/workflows/check-access", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ workflowType }),
        });
        const json = await res.json();
        setHasAccess(json.data.hasAccess);
        setRequiredTier(json.data.requiredTier || "");
      } catch (error) {
        console.error("Access check failed:", error);
        setHasAccess(false);
      }
    }

    checkAccess();
  }, [workflowType]);

  if (hasAccess === null) {
    return <div>Checking access...</div>;
  }

  if (!hasAccess) {
    return (
      fallback || (
        <div className="text-center p-8 border rounded-lg bg-muted/20">
          <Lock className="h-12 w-12 mx-auto mb-4 text-muted-foreground" />
          <h3 className="text-lg font-semibold mb-2">Upgrade Required</h3>
          <p className="text-muted-foreground mb-4">
            This workflow requires a {requiredTier} plan or higher.
          </p>
          <Button>Upgrade Now</Button>
        </div>
      )
    );
  }

  return <>{children}</>;
}
```

---

## Direct Server Usage

### Custom Dashboard Logic

```typescript
// lib/services/custom-dashboard.service.ts
import * as workflows from "@/.claude/mcp/servers/database/workflows";
import * as conversations from "@/.claude/mcp/servers/database/conversations";
import * as analytics from "@/.claude/mcp/servers/database/analytics";

export class CustomDashboardService {
  /**
   * Get workflow performance report
   */
  async getWorkflowPerformanceReport(userId: string, days = 30) {
    const [topWorkflows, summary] = await Promise.all([
      analytics.getTopWorkflows(userId, days, 5),
      analytics.getWorkflowAnalyticsSummary(userId, days),
    ]);

    return {
      topPerformers: topWorkflows,
      overallStats: summary.totals,
      period: days,
    };
  }

  /**
   * Get conversation health metrics
   */
  async getConversationHealthMetrics(userId: string) {
    const [statusSummary, platformDist, weeklyTrend] = await Promise.all([
      conversations.getStatusSummary(userId, 30),
      conversations.getPlatformDistribution(userId),
      conversations.getWeeklyTrend(userId),
    ]);

    const resolvedRate = statusSummary.byStatus.resolved
      ? (statusSummary.byStatus.resolved / statusSummary.total) * 100
      : 0;

    return {
      totalConversations: statusSummary.total,
      resolvedRate,
      platformDistribution: platformDist,
      weeklyActivity: weeklyTrend,
      healthScore: this.calculateHealthScore(statusSummary, resolvedRate),
    };
  }

  /**
   * Get period-over-period growth
   */
  async getGrowthMetrics(userId: string, days = 7) {
    const comparison = await analytics.getPeriodComparison(userId, days);

    return {
      messagesGrowth: comparison.changes.messagesReceived,
      appointmentsGrowth: comparison.changes.appointmentsBooked,
      leadsGrowth: comparison.changes.leadsGenerated,
      currentPeriod: comparison.current,
      previousPeriod: comparison.previous,
      isGrowing: comparison.changes.messagesReceived > 0,
    };
  }

  private calculateHealthScore(
    statusSummary: any,
    resolvedRate: number,
  ): number {
    // Simple health score algorithm
    let score = 50; // Base score

    // Add points for resolved conversations
    score += Math.min(resolvedRate, 40);

    // Deduct points for abandoned conversations
    if (statusSummary.byStatus.abandoned) {
      const abandonedRate =
        (statusSummary.byStatus.abandoned / statusSummary.total) * 100;
      score -= abandonedRate;
    }

    return Math.max(0, Math.min(100, score));
  }
}
```

### Workflow Tier Checker

```typescript
// lib/utils/workflow-tier-checker.ts
import {
  getAllowedWorkflowsByTier,
  canAccessWorkflow,
} from "@/.claude/mcp/servers/database/workflows";

export class WorkflowTierChecker {
  /**
   * Get upgrade suggestions for a user
   */
  getUpgradeSuggestions(currentTier: string, desiredWorkflows: string[]) {
    const currentAllowed = getAllowedWorkflowsByTier(currentTier);
    const missing = desiredWorkflows.filter((w) => !currentAllowed.includes(w));

    if (missing.length === 0) {
      return { needsUpgrade: false };
    }

    // Find minimum tier that includes all desired workflows
    const tiers = ["starter", "professional", "enterprise"];
    const currentIndex = tiers.indexOf(currentTier.toLowerCase());

    for (let i = currentIndex + 1; i < tiers.length; i++) {
      const tierWorkflows = getAllowedWorkflowsByTier(tiers[i]);
      const hasAll = missing.every((w) => tierWorkflows.includes(w));

      if (hasAll) {
        return {
          needsUpgrade: true,
          suggestedTier: tiers[i],
          additionalWorkflows: missing,
        };
      }
    }

    return {
      needsUpgrade: true,
      suggestedTier: "enterprise",
      additionalWorkflows: missing,
    };
  }

  /**
   * Validate multiple workflow access
   */
  validateAccess(tier: string, workflows: string[]) {
    return workflows.map((workflow) => ({
      workflowType: workflow,
      hasAccess: canAccessWorkflow(tier, workflow),
    }));
  }
}
```

---

## Token Comparison

### Before: Full Record Loading

```typescript
// ❌ BAD: Loads 165,000+ tokens
async function getBadDashboard(userId: string) {
  const conversations = await prisma.conversationLog.findMany({
    where: { userId },
    include: {
      messages: true, // Full message content
    },
  });

  const workflows = await prisma.userWorkflow.findMany({
    where: { userId },
    include: {
      user: true,
      config: true, // Full config objects
    },
  });

  const analytics = await prisma.workflowAnalytics.findMany({
    where: { userId },
    include: {
      metadata: true, // Full metadata
    },
  });

  // Tokens: ~165,000
  return { conversations, workflows, analytics };
}
```

### After: Summary Data

```typescript
// ✅ GOOD: Loads ~1,200 tokens
import { getWorkflowDashboardSummary } from "@/.claude/mcp/skills/workflow-dashboard-summary";

async function getGoodDashboard(userId: string, packageTier: string) {
  const summary = await getWorkflowDashboardSummary({
    userId,
    packageTier,
    includeWeeklyTrend: true,
  });

  // Tokens: ~1,200 (98% reduction)
  return summary;
}
```

---

## Error Handling

### Graceful Degradation

```typescript
// lib/services/dashboard-with-fallbacks.ts
import { getWorkflowDashboardSummary } from "@/.claude/mcp/skills/workflow-dashboard-summary";

export async function getDashboardWithFallbacks(
  userId: string,
  packageTier: string,
) {
  try {
    return await getWorkflowDashboardSummary({
      userId,
      packageTier,
      includeWeeklyTrend: true,
      includeTopWorkflows: true,
    });
  } catch (error) {
    console.error("Full dashboard failed, trying minimal:", error);

    // Fallback to minimal summary
    try {
      const minimal = await getMinimalDashboardSummary(userId, packageTier);
      return {
        summary: minimal,
        error: "Partial data only",
      };
    } catch (fallbackError) {
      console.error("Minimal dashboard failed:", fallbackError);

      // Return empty state
      return {
        summary: {
          activeWorkflows: 0,
          conversationsToday: 0,
          messagesHandled: 0,
          appointmentsBooked: 0,
        },
        error: "Failed to load dashboard data",
      };
    }
  }
}
```

### Retry Logic

```typescript
// lib/utils/retry-mcp-call.ts
export async function retryMCPCall<T>(
  fn: () => Promise<T>,
  maxRetries = 3,
  delay = 1000,
): Promise<T> {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (i === maxRetries - 1) throw error;

      console.warn(`Retry ${i + 1}/${maxRetries} after error:`, error);
      await new Promise((resolve) => setTimeout(resolve, delay * (i + 1)));
    }
  }

  throw new Error("Max retries exceeded");
}

// Usage
import { getWorkflowDashboardSummary } from "@/.claude/mcp/skills/workflow-dashboard-summary";

const summary = await retryMCPCall(() =>
  getWorkflowDashboardSummary({
    userId: "user_123",
    packageTier: "professional",
  }),
);
```

---

## Performance Tips

1. **Use Minimal Summary for Frequent Polls**

   ```typescript
   // Poll every 5 seconds with minimal data
   setInterval(async () => {
     const stats = await getMinimalDashboardSummary(userId, tier);
     updateUI(stats);
   }, 5000);
   ```

2. **Parallel Queries for Independent Data**

   ```typescript
   const [workflows, conversations, analytics] = await Promise.all([
     workflows.getWorkflowSummary(userId),
     conversations.getDailyConversationStats(userId, new Date()),
     analytics.getWorkflowAnalyticsSummary(userId, 7),
   ]);
   ```

3. **Cache Results**

   ```typescript
   const cache = new Map();

   async function getCachedSummary(userId: string) {
     if (cache.has(userId)) {
       return cache.get(userId);
     }

     const summary = await getMinimalDashboardSummary(userId, "professional");
     cache.set(userId, summary);
     setTimeout(() => cache.delete(userId), 30000); // 30s TTL

     return summary;
   }
   ```

---

## Testing Examples

```typescript
// __tests__/mcp/workflow-dashboard.test.ts
import { getWorkflowDashboardSummary } from "@/.claude/mcp/skills/workflow-dashboard-summary";
import { prisma } from "@/lib/db";

describe("Workflow Dashboard MCP", () => {
  const testUserId = "test_user_123";

  beforeEach(async () => {
    // Setup test data
    await prisma.userWorkflow.create({
      data: {
        userId: testUserId,
        workflowType: "ai_agent",
        status: "active",
      },
    });
  });

  it("should return dashboard summary", async () => {
    const summary = await getWorkflowDashboardSummary({
      userId: testUserId,
      packageTier: "professional",
    });

    expect(summary.summary.activeWorkflows).toBeGreaterThanOrEqual(1);
    expect(summary.package.tier).toBe("professional");
  });

  it("should respect tier limits", async () => {
    const summary = await getWorkflowDashboardSummary({
      userId: testUserId,
      packageTier: "starter",
    });

    expect(summary.package.allowedFeatures).toContain("ai_agent");
    expect(summary.package.allowedFeatures).not.toContain("social_media");
  });
});
```
