/**
* Integration Tests: Tier Enforcement
*
* Tests subscription tier enforcement through MCP server:
*
* **Traditional Mode (STDIO):**
* - Rate limiting (BaseClickUpService)
* - All tools available (no tier restrictions)
*
* **Remote MCP Server (CloudFlare Workers) - Documented:**
* - Free tier rate limits (100 req/min)
* - Premium tier rate limits (500 req/min)
* - Tool access restrictions by tier
* - Tier upgrade flow
* - Stripe billing integration
* - Real-time tier updates via webhooks
*
* NOTE: This test suite documents Remote MCP Server tier enforcement.
* Full tier enforcement testing requires CloudFlare Workers deployment
* with Stripe integration (see docs-to-persist for deployment tests).
*/
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { MCPTestClient, createMCPTestClient } from './mcp-test-client';
import { setupTestEnvironment, teardownTestEnvironment } from './setup';
import { createTask, uniqueTestName, delay } from './utils';
describe('Tier Enforcement Integration Tests', () => {
let client: MCPTestClient;
let testEnv: any;
let listId: string;
beforeAll(async () => {
// Setup test environment
testEnv = await setupTestEnvironment();
listId = testEnv.listId;
// Connect MCP client
client = await createMCPTestClient({
apiKey: testEnv.apiKey,
teamId: testEnv.teamId,
logRequests: false,
logResponses: false
});
});
afterAll(async () => {
// Disconnect client
await client.disconnect();
// Cleanup test environment
await teardownTestEnvironment(false);
});
describe('Traditional Mode: Rate Limiting', () => {
it('should implement rate limiting in BaseClickUpService', async () => {
// Traditional mode implements rate limiting at service layer
// to protect ClickUp API from rate limit violations
const startTime = Date.now();
const taskCount = 5;
for (let i = 0; i < taskCount; i++) {
await createTask(client, listId, {
name: uniqueTestName(`Rate Limit ${i}`)
});
}
const duration = Date.now() - startTime;
console.log(`Created ${taskCount} tasks in ${duration}ms`);
console.log('Traditional Mode: Rate limiting via BaseClickUpService');
console.log('- Delay between requests prevents ClickUp API rate limits');
console.log('- No user-tier enforcement (all tools available)');
});
it('should allow all tools in Traditional Mode', async () => {
// Verify all tools are available (no tier restrictions)
const result = await client.listTools();
expect(result.tools).toBeDefined();
expect(result.tools.length).toBeGreaterThan(0);
console.log(`Total tools available: ${result.tools.length}`);
console.log('Traditional Mode: All tools available (no tiers)');
});
});
describe('Remote MCP Server: Free Tier', () => {
it('should document free tier features', () => {
console.log('\n📊 Free Tier Features:');
console.log('');
console.log('Pricing: $0/month (Free forever)');
console.log('');
console.log('Rate Limits:');
console.log('- 100 requests per minute');
console.log('- Rate limit tracked per user');
console.log('- Resets every 60 seconds');
console.log('');
console.log('Available Tools (Basic - 28 tools):');
console.log('✅ clickup_workspace_hierarchy_get');
console.log('✅ clickup_task_create');
console.log('✅ clickup_task_get');
console.log('✅ clickup_task_update');
console.log('✅ clickup_task_delete');
console.log('✅ clickup_task_search');
console.log('✅ clickup_list_tasks');
console.log('✅ clickup_task_add_comment');
console.log('✅ clickup_task_get_comments');
console.log('✅ ... (20 more basic tools)');
console.log('');
console.log('Restrictions:');
console.log('❌ No bulk operations');
console.log('❌ No time tracking');
console.log('❌ No custom fields');
console.log('❌ No automation tools');
console.log('❌ No advanced dependency management');
console.log('');
console.log('Session:');
console.log('- 24-hour JWT expiry');
console.log('- OAuth re-authentication required');
});
it('should document free tier rate limit enforcement', () => {
console.log('\n⏱️ Free Tier Rate Limiting:');
console.log('');
console.log('Implementation:');
console.log('```typescript');
console.log('// In worker.ts middleware');
console.log('const rateLimiter = new RateLimiter({');
console.log(' maxRequests: 100,');
console.log(' windowMs: 60000 // 1 minute');
console.log('});');
console.log('');
console.log('if (userTier === "free") {');
console.log(' const allowed = await rateLimiter.check(userId);');
console.log(' if (!allowed) {');
console.log(' return new Response(JSON.stringify({');
console.log(' error: "Rate limit exceeded",');
console.log(' limit: 100,');
console.log(' window: "1 minute",');
console.log(' upgradeUrl: "/pricing"');
console.log(' }), { status: 429 });');
console.log(' }');
console.log('}');
console.log('```');
console.log('');
console.log('Response Headers:');
console.log('- X-RateLimit-Limit: 100');
console.log('- X-RateLimit-Remaining: 85');
console.log('- X-RateLimit-Reset: 1234567890');
});
it('should document free tier tool restrictions', () => {
console.log('\n🔒 Free Tier Tool Access:');
console.log('');
console.log('Tool validation:');
console.log('```typescript');
console.log('// In MCP server tool handler');
console.log('const freeTierTools = [');
console.log(' "clickup_workspace_hierarchy_get",');
console.log(' "clickup_task_create",');
console.log(' "clickup_task_get",');
console.log(' "clickup_task_update",');
console.log(' "clickup_task_delete",');
console.log(' // ... 23 more basic tools');
console.log('];');
console.log('');
console.log('if (userTier === "free" && !freeTierTools.includes(toolName)) {');
console.log(' throw new Error(');
console.log(' `Tool "${toolName}" requires Premium subscription. ` +');
console.log(' `Upgrade at /pricing to unlock 44 additional tools.`');
console.log(' );');
console.log('}');
console.log('```');
console.log('');
console.log('Premium-only tools:');
console.log('❌ clickup_task_create_bulk');
console.log('❌ clickup_time_tracking_*');
console.log('❌ clickup_custom_field_*');
console.log('❌ clickup_goal_*');
console.log('❌ clickup_automation_*');
});
it('should document upgrade prompts', () => {
console.log('\n💎 Upgrade Prompts:');
console.log('');
console.log('Scenario 1: Rate limit exceeded');
console.log('```json');
console.log('{');
console.log(' "error": {');
console.log(' "code": "rate_limit_exceeded",');
console.log(' "message": "You\'ve reached the free tier limit of 100 requests/minute.",');
console.log(' "upgrade": {');
console.log(' "tier": "premium",');
console.log(' "price": "$4.99/month",');
console.log(' "benefits": [');
console.log(' "5x higher rate limit (500 req/min)",');
console.log(' "Access to all 72 tools",');
console.log(' "Priority support"');
console.log(' ],');
console.log(' "url": "https://clickup-mcp.com/pricing"');
console.log(' }');
console.log(' }');
console.log('}');
console.log('```');
console.log('');
console.log('Scenario 2: Premium tool access attempt');
console.log('```json');
console.log('{');
console.log(' "error": {');
console.log(' "code": "premium_required",');
console.log(' "message": "Custom fields require Premium subscription",');
console.log(' "tool": "clickup_custom_field_set",');
console.log(' "upgrade": {');
console.log(' "url": "https://clickup-mcp.com/pricing"');
console.log(' }');
console.log(' }');
console.log('}');
console.log('```');
});
});
describe('Remote MCP Server: Premium Tier', () => {
it('should document premium tier features', () => {
console.log('\n💎 Premium Tier Features:');
console.log('');
console.log('Pricing: $4.99/month');
console.log('');
console.log('Rate Limits:');
console.log('- 500 requests per minute (5x free tier)');
console.log('- Rate limit tracked per user');
console.log('- Resets every 60 seconds');
console.log('');
console.log('Available Tools: ALL 72 tools');
console.log('✅ All 28 free tier tools');
console.log('✅ Bulk operations (create_bulk, update_bulk, delete_bulk)');
console.log('✅ Time tracking (6 tools)');
console.log('✅ Custom fields (5 tools)');
console.log('✅ Goals (3 tools)');
console.log('✅ Automation (webhooks, views)');
console.log('✅ Advanced features (44 additional tools)');
console.log('');
console.log('Additional Benefits:');
console.log('✅ Priority support');
console.log('✅ Advanced analytics');
console.log('✅ Longer audit log retention');
console.log('✅ No upgrade prompts');
console.log('');
console.log('Session:');
console.log('- 24-hour JWT expiry');
console.log('- OAuth re-authentication required');
});
it('should document premium tier rate limits', () => {
console.log('\n⏱️ Premium Tier Rate Limiting:');
console.log('');
console.log('Implementation:');
console.log('```typescript');
console.log('if (userTier === "premium") {');
console.log(' const rateLimiter = new RateLimiter({');
console.log(' maxRequests: 500,');
console.log(' windowMs: 60000 // 1 minute');
console.log(' });');
console.log(' ');
console.log(' const allowed = await rateLimiter.check(userId);');
console.log(' if (!allowed) {');
console.log(' return new Response(JSON.stringify({');
console.log(' error: "Rate limit exceeded",');
console.log(' limit: 500,');
console.log(' window: "1 minute",');
console.log(' message: "Even premium users have limits!"');
console.log(' }), { status: 429 });');
console.log(' }');
console.log('}');
console.log('```');
console.log('');
console.log('Response Headers:');
console.log('- X-RateLimit-Limit: 500');
console.log('- X-RateLimit-Remaining: 423');
console.log('- X-RateLimit-Reset: 1234567890');
});
it('should document full tool access', () => {
console.log('\n🔓 Premium Tier: Full Tool Access');
console.log('');
console.log('No tool restrictions:');
console.log('```typescript');
console.log('// All 72 tools available');
console.log('if (userTier === "premium") {');
console.log(' // No tool filtering - all tools allowed');
console.log(' return executeToolHandler(toolName, args);');
console.log('}');
console.log('```');
console.log('');
console.log('Tool categories (all accessible):');
console.log('✅ Task Management (27 tools)');
console.log('✅ List Management (12 tools)');
console.log('✅ Workspace Operations (8 tools)');
console.log('✅ Time Tracking (6 tools)');
console.log('✅ Custom Fields (5 tools)');
console.log('✅ Space Management (4 tools)');
console.log('✅ Goal Tracking (3 tools)');
console.log('✅ User Management (2 tools)');
console.log('✅ Team Management (2 tools)');
console.log('✅ Comment Management (2 tools)');
console.log('✅ View Management (1 tool)');
});
});
describe('Tier Upgrade Flow', () => {
it('should document Stripe integration', () => {
console.log('\n💳 Stripe Integration:');
console.log('');
console.log('Subscription Flow:');
console.log('1. User clicks "Upgrade to Premium"');
console.log('2. Redirected to Stripe Checkout');
console.log(' - Price: $4.99/month');
console.log(' - Stripe handles payment');
console.log('3. User completes payment');
console.log('4. Stripe webhook fires: checkout.session.completed');
console.log('5. Worker receives webhook:');
console.log(' - Validates webhook signature');
console.log(' - Updates user tier in KV');
console.log(' - Logs upgrade event in R2');
console.log('6. User JWT refreshed with new tier');
console.log('7. Premium features immediately available');
console.log('');
console.log('Implementation:');
console.log('```typescript');
console.log('// In worker.ts webhook handler');
console.log('app.post("/webhook/stripe", async (c) => {');
console.log(' const sig = c.req.header("stripe-signature");');
console.log(' const event = stripe.webhooks.constructEvent(');
console.log(' await c.req.text(),');
console.log(' sig,');
console.log(' c.env.STRIPE_WEBHOOK_SECRET');
console.log(' );');
console.log(' ');
console.log(' if (event.type === "checkout.session.completed") {');
console.log(' const session = event.data.object;');
console.log(' const userId = session.client_reference_id;');
console.log(' ');
console.log(' // Update user tier');
console.log(' await c.env.SESSIONS.put(');
console.log(' `user:${userId}:tier`,');
console.log(' "premium"');
console.log(' );');
console.log(' ');
console.log(' // Log upgrade');
console.log(' await logAuditEvent({');
console.log(' type: "tier_upgrade",');
console.log(' userId,');
console.log(' fromTier: "free",');
console.log(' toTier: "premium"');
console.log(' });');
console.log(' }');
console.log(' ');
console.log(' return c.json({ received: true });');
console.log('});');
console.log('```');
});
it('should document tier downgrade handling', () => {
console.log('\n⬇️ Tier Downgrade:');
console.log('');
console.log('Scenarios:');
console.log('1. Subscription cancelled');
console.log('2. Payment failed');
console.log('3. Chargeback/dispute');
console.log('');
console.log('Stripe Webhooks:');
console.log('- customer.subscription.deleted');
console.log('- invoice.payment_failed');
console.log('- charge.refunded');
console.log('');
console.log('Downgrade Process:');
console.log('1. Stripe webhook fires');
console.log('2. Worker validates event');
console.log('3. Update user tier to "free"');
console.log('4. Log downgrade event');
console.log('5. Next JWT refresh includes tier: "free"');
console.log('6. Premium tools blocked immediately');
console.log('7. Rate limit reduced to 100 req/min');
console.log('');
console.log('Grace Period:');
console.log('- 7 days after payment failure');
console.log('- User retains premium access');
console.log('- Notification emails sent');
console.log('- After grace period: automatic downgrade');
});
it('should document real-time tier updates', () => {
console.log('\n⚡ Real-Time Tier Updates:');
console.log('');
console.log('JWT Refresh Flow:');
console.log('1. User makes MCP request with JWT');
console.log('2. Server validates JWT signature');
console.log('3. Server checks KV for latest tier');
console.log('4. If tier changed since JWT issued:');
console.log(' - Response includes X-Tier-Changed header');
console.log(' - Client should refresh JWT');
console.log('5. POST /auth/refresh returns new JWT');
console.log('6. New JWT includes updated tier claim');
console.log('');
console.log('Implementation:');
console.log('```typescript');
console.log('// In MCP request handler');
console.log('const jwtTier = payload.tier;');
console.log('const actualTier = await c.env.SESSIONS.get(');
console.log(' `user:${userId}:tier`');
console.log(');');
console.log('');
console.log('if (jwtTier !== actualTier) {');
console.log(' // Tier changed since JWT issued');
console.log(' return c.json({');
console.log(' error: "Tier mismatch",');
console.log(' message: "Please refresh your session",');
console.log(' refreshUrl: "/auth/refresh"');
console.log(' }, { status: 401 });');
console.log('}');
console.log('```');
});
});
describe('Billing Validation', () => {
it('should document subscription status checks', () => {
console.log('\n✅ Subscription Status Validation:');
console.log('');
console.log('Health Check Endpoint:');
console.log('GET /api/subscription/status');
console.log('Authorization: Bearer JWT_TOKEN');
console.log('');
console.log('Response:');
console.log('```json');
console.log('{');
console.log(' "tier": "premium",');
console.log(' "status": "active",');
console.log(' "currentPeriodEnd": 1234567890,');
console.log(' "cancelAtPeriodEnd": false,');
console.log(' "rateLimit": {');
console.log(' "max": 500,');
console.log(' "remaining": 432,');
console.log(' "resetAt": 1234567890');
console.log(' }');
console.log('}');
console.log('```');
console.log('');
console.log('Status Values:');
console.log('- active: Subscription active, premium features enabled');
console.log('- past_due: Payment failed, grace period active');
console.log('- canceled: Subscription ended, downgraded to free');
console.log('- unpaid: Payment failed, premium disabled');
});
it('should document payment failure handling', () => {
console.log('\n⚠️ Payment Failure Handling:');
console.log('');
console.log('Stripe Webhook: invoice.payment_failed');
console.log('');
console.log('Worker Actions:');
console.log('1. Log payment failure event');
console.log('2. Start 7-day grace period');
console.log('3. Send notification email');
console.log('4. Update subscription status to "past_due"');
console.log('5. Premium features remain active during grace');
console.log('6. After 7 days without payment:');
console.log(' - Downgrade to free tier');
console.log(' - Send final notification');
console.log(' - Update tier in KV');
console.log('');
console.log('User Experience:');
console.log('- Day 1-7: Premium access + payment reminder banner');
console.log('- Day 8+: Free tier + upgrade prompt');
console.log('');
console.log('Retry Logic:');
console.log('- Stripe auto-retries failed payments');
console.log('- If payment succeeds during grace: restore immediately');
console.log('- User never loses data/access during grace');
});
it('should document refund handling', () => {
console.log('\n💰 Refund Handling:');
console.log('');
console.log('Stripe Webhook: charge.refunded');
console.log('');
console.log('Full Refund:');
console.log('1. Immediately downgrade to free tier');
console.log('2. Revoke premium access');
console.log('3. Log refund event');
console.log('4. Send confirmation email');
console.log('');
console.log('Partial Refund:');
console.log('1. No tier change');
console.log('2. Log refund event');
console.log('3. Admin review');
console.log('');
console.log('Dispute/Chargeback:');
console.log('1. Automatic downgrade to free');
console.log('2. Account flagged for review');
console.log('3. Premium access revoked');
console.log('4. Cannot upgrade until dispute resolved');
});
});
describe('Performance Under Tier Limits', () => {
it('should handle operations near rate limit', async () => {
// Test behavior approaching rate limit
const requestCount = 10;
const timings: number[] = [];
for (let i = 0; i < requestCount; i++) {
const startTime = Date.now();
await createTask(client, listId, {
name: uniqueTestName(`Near Limit ${i}`)
});
const duration = Date.now() - startTime;
timings.push(duration);
await delay(50);
}
const avgTime = timings.reduce((a, b) => a + b, 0) / timings.length;
console.log(`\n📊 Performance near rate limit:`);
console.log(`- Average request time: ${avgTime.toFixed(0)}ms`);
console.log(`- Requests completed: ${requestCount}`);
console.log('');
console.log('Traditional Mode: No tier-based throttling');
console.log('Remote MCP Server: Would show rate limit headers');
});
});
describe('Tier Comparison', () => {
it('should document tier comparison table', () => {
console.log('\n📊 Tier Comparison:');
console.log('');
console.log('╔══════════════════════╦═══════════╦═══════════╗');
console.log('║ Feature ║ Free ║ Premium ║');
console.log('╠══════════════════════╬═══════════╬═══════════╣');
console.log('║ Price ║ $0/month ║ $4.99/mo ║');
console.log('║ Rate Limit ║ 100/min ║ 500/min ║');
console.log('║ Available Tools ║ 28 basic ║ All 72 ║');
console.log('║ Bulk Operations ║ ❌ ║ ✅ ║');
console.log('║ Time Tracking ║ ❌ ║ ✅ ║');
console.log('║ Custom Fields ║ ❌ ║ ✅ ║');
console.log('║ Goals ║ ❌ ║ ✅ ║');
console.log('║ Automation ║ ❌ ║ ✅ ║');
console.log('║ Priority Support ║ ❌ ║ ✅ ║');
console.log('║ Advanced Analytics ║ ❌ ║ ✅ ║');
console.log('║ Audit Logs ║ 7 days ║ 90 days ║');
console.log('║ Session Duration ║ 24 hours ║ 24 hours ║');
console.log('╚══════════════════════╩═══════════╩═══════════╝');
});
it('should document value proposition', () => {
console.log('\n💎 Premium Value Proposition:');
console.log('');
console.log('Why upgrade to Premium?');
console.log('');
console.log('1. 5x Higher Rate Limit (100 → 500 req/min)');
console.log(' - Perfect for AI agents with high activity');
console.log(' - Process 500 operations per minute');
console.log(' - No waiting, no interruptions');
console.log('');
console.log('2. 44 Additional Tools (28 → 72 total)');
console.log(' - Bulk operations for efficiency');
console.log(' - Time tracking for productivity');
console.log(' - Custom fields for agent state');
console.log(' - Goals for progress tracking');
console.log(' - Automation for workflows');
console.log('');
console.log('3. Priority Support');
console.log(' - Faster response times');
console.log(' - Direct communication channel');
console.log(' - Feature requests prioritized');
console.log('');
console.log('4. Advanced Features');
console.log(' - Extended audit logs (90 days)');
console.log(' - Usage analytics dashboard');
console.log(' - Early access to new features');
console.log('');
console.log('ROI: If you\'re an AI agent processing >1000 tasks/month,');
console.log('Premium saves 10+ hours of rate limit delays = $50+ value');
});
});
});