Skip to content

Usage Guide

Advanced usage patterns, real-world examples, and best practices for the EARLY MCP Server.

Overview

This guide covers practical usage scenarios, advanced configurations, and tips for getting the most out of the EARLY MCP Server. For basic setup, see Getting Started.

Real-World Usage Patterns

Daily Time Tracking Workflow

The most common pattern for professional time tracking:

Morning Setup

"List my active projects and start a timer for today's first task"

Claude will: 1. Call list_activities to show your projects 2. Let you choose which project to work on 3. Call start_timer to begin tracking

During Work Day

"Switch my timer to client work"

Claude will: 1. Stop the current timer automatically 2. Start a new timer for the specified project 3. Confirm the switch

End of Day Review

"Show me today's time breakdown and total hours"

Claude will: 1. Call get_time_entries for today 2. Calculate totals by project 3. Present a summary report

Project Time Analysis

For managers and consultants tracking billable hours:

Weekly Project Review

"Show me all time spent on the Johnson project this week"

Example workflow: 1. Get project ID: list_activities → find "Johnson Project" 2. Get week's entries: get_time_entries with date range + project filter 3. Calculate totals and present breakdown

Monthly Billing Preparation

"Generate a report for all billable projects in October 2024"

Process: 1. Query all time entries for October 2. Filter by billable projects 3. Group by client/project 4. Calculate totals and rates

Team Time Management

For teams using shared EARLY accounts:

Project Coordination

"Check if anyone else is working on the website project right now"

Note: This requires multiple team members to have MCP servers configured with their own API credentials.

Resource Planning

"How much time did we spend on development tasks this month?"

Advanced Tool Combinations

Retroactive Time Logging

When you forget to track time in real-time:

Log Yesterday's Work

"I worked on three things yesterday: client meeting 2-3pm, development 3:30-6pm, and admin tasks 6-6:30pm"

Claude will create multiple time entries:

[
  {
    "tool": "create_time_entry",
    "args": {
      "projectId": "client_project_id",
      "description": "Client meeting",
      "startTime": "2024-01-15T14:00:00Z",
      "endTime": "2024-01-15T15:00:00Z"
    }
  },
  {
    "tool": "create_time_entry", 
    "args": {
      "projectId": "development_project_id",
      "description": "Development work",
      "startTime": "2024-01-15T15:30:00Z",
      "endTime": "2024-01-15T18:00:00Z"
    }
  }
]

Bulk Time Entry Creation

For logging an entire week retroactively, you can ask Claude to create multiple entries in sequence.

Time Entry Corrections

Fix Incorrect Times

"I need to change yesterday's client meeting from 2-3pm to 1:30-2:30pm"

Process: 1. get_time_entries to find the entry 2. edit_time_entry to update the times 3. Confirm the change

Move Time Between Projects

"Move the last 30 minutes of my development time to the testing project"

Complex workflow: 1. Find the development time entry 2. Edit it to reduce duration by 30 minutes 3. Create new testing entry for those 30 minutes

Advanced Reporting

Custom Time Ranges

"Show me my time tracking from December 15th to January 5th"

Project Comparisons

"Compare my time spent on Project A vs Project B this quarter"

Productivity Analysis

"What are my most and least productive days based on tracked time?"

MCP Resources Usage

The server provides 4 MCP resources that give direct access to data:

Today's Time Data

Access: early://time-entries/today

Use case: Dashboard displays, quick status checks

// Example: Custom dashboard showing today's total
const todayData = await readResource("early://time-entries/today");
const entries = JSON.parse(todayData).entries;
const totalMinutes = entries.reduce((sum, entry) => sum + entry.duration, 0);

Weekly Time Summary

Access: early://time-entries/week

Use case: Weekly reports, team coordination

// Example: Weekly summary for status meetings
const weekData = await readResource("early://time-entries/week");
const weekSummary = processWeeklyData(JSON.parse(weekData));

Activities Management

Access: early://activities or early://activities/active

Use case: Project selection UIs, activity management

// Example: Populate project dropdown
const activities = await readResource("early://activities/active");
const activeProjects = JSON.parse(activities).activities;

Integration Patterns

Claude Desktop Natural Language

Claude Desktop provides the most natural experience. You can use conversational language:

Time Tracking Commands

"Start timing my work on the mobile app"
"I've been working for 2 hours, create a time entry for API development"
"Stop my timer and show me today's summary"
"Change yesterday's 3pm meeting to start at 2:30pm instead"

Questions and Analysis

"How productive was I last week?"
"Which project am I spending the most time on?"
"Did I forget to track any time today?"
"What's my average daily work time this month?"

Custom MCP Client Integration

For developers building custom integrations:

Time Tracking Widget

// Example: Simple time tracking widget
class EarlyTimeWidget {
  async startTimer(projectName) {
    const activities = await this.mcpClient.callTool('list_activities');
    const project = activities.find(a => a.name.includes(projectName));

    if (project) {
      await this.mcpClient.callTool('start_timer', {
        projectId: project.id,
        description: `Working on ${projectName}`
      });
    }
  }

  async stopTimer() {
    return await this.mcpClient.callTool('stop_timer');
  }
}

Automated Reporting

// Example: Generate weekly report
async function generateWeeklyReport() {
  const entries = await mcpClient.callTool('get_time_entries', {
    startDate: getWeekStart(),
    endDate: getWeekEnd()
  });

  return processTimeEntries(entries);
}

Performance and Optimization

Efficient API Usage

Batch Operations

Instead of multiple individual calls, batch related operations:

// Efficient: Get all needed data first
const [activities, todayEntries] = await Promise.all([
  mcpClient.callTool('list_activities'),
  mcpClient.callTool('get_time_entries')
]);

// Then use the data for multiple operations

Caching Strategies

For applications making frequent calls:

// Cache activities list (changes infrequently)
class EarlyCache {
  constructor(mcpClient) {
    this.mcpClient = mcpClient;
    this.activitiesCache = null;
    this.cacheExpiry = null;
  }

  async getActivities() {
    if (!this.activitiesCache || Date.now() > this.cacheExpiry) {
      this.activitiesCache = await this.mcpClient.callTool('list_activities');
      this.cacheExpiry = Date.now() + (5 * 60 * 1000); // 5 minutes
    }
    return this.activitiesCache;
  }
}

Error Handling Best Practices

Retry Logic

async function callWithRetry(toolName, args, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await mcpClient.callTool(toolName, args);
    } catch (error) {
      if (i === maxRetries - 1) throw error;

      // Exponential backoff
      await sleep(1000 * Math.pow(2, i));
    }
  }
}

Graceful Degradation

async function getTimeEntries(fallbackToCache = true) {
  try {
    return await mcpClient.callTool('get_time_entries');
  } catch (error) {
    if (fallbackToCache && cachedEntries) {
      console.warn('Using cached time entries due to API error');
      return cachedEntries;
    }
    throw error;
  }
}

Security Best Practices

Credential Management

Environment Variables

# Production .env
EARLY_API_KEY=prod_key_here
EARLY_API_SECRET=prod_secret_here

# Development .env  
EARLY_API_KEY=dev_key_here
EARLY_API_SECRET=dev_secret_here

Rotation Strategy

# Monthly API key rotation script
#!/bin/bash
echo "Rotating EARLY API keys..."

# Get new credentials from EARLY
# Update .env file
# Restart MCP server
# Verify connectivity

echo "API key rotation completed"

Access Control

User Permissions

  • Each user should have their own API credentials
  • Don't share API keys between team members
  • Use EARLY's built-in access controls

Network Security

// Optional: Restrict network access
const allowedHosts = ['api.early.app'];

if (!allowedHosts.includes(new URL(apiUrl).hostname)) {
  throw new Error('Unauthorized API endpoint');
}

Monitoring and Debugging

Health Checks

Server Status Monitoring

// Example: Health check endpoint
async function healthCheck() {
  try {
    const activities = await mcpClient.callTool('list_activities');
    return {
      status: 'healthy',
      timestamp: new Date().toISOString(),
      activitiesCount: activities.length
    };
  } catch (error) {
    return {
      status: 'unhealthy',
      error: error.message,
      timestamp: new Date().toISOString()
    };
  }
}

Automated Testing

# Daily automated test
#!/bin/bash
echo "Testing EARLY MCP Server..."

npm test > test_results.log 2>&1

if [ $? -eq 0 ]; then
  echo "Tests passed"
else
  echo "Tests failed - check test_results.log"
  # Send alert notification
fi

Usage Analytics

Track API Usage

class UsageTracker {
  constructor() {
    this.callCounts = {};
    this.errorCounts = {};
  }

  recordCall(toolName) {
    this.callCounts[toolName] = (this.callCounts[toolName] || 0) + 1;
  }

  recordError(toolName, error) {
    this.errorCounts[toolName] = (this.errorCounts[toolName] || 0) + 1;
  }

  generateReport() {
    return {
      totalCalls: Object.values(this.callCounts).reduce((a, b) => a + b, 0),
      mostUsedTool: Object.keys(this.callCounts).sort((a, b) => 
        this.callCounts[b] - this.callCounts[a])[0],
      errorRate: Object.values(this.errorCounts).reduce((a, b) => a + b, 0) /
                 Object.values(this.callCounts).reduce((a, b) => a + b, 0)
    };
  }
}

Development and Extension

Adding Custom Tools

When you need functionality not provided by the standard tools:

Custom Tool Template

// src/handlers/custom-handlers.ts
export async function handleCustomTool(apiClient: EarlyApiClient, args: CustomArgs) {
  try {
    checkApiCredentials();

    // Your custom logic here
    const result = await apiClient.customOperation(args);

    return {
      content: [{
        type: 'text',
        text: `Custom operation completed: ${JSON.stringify(result)}`
      }]
    };
  } catch (error) {
    return createToolErrorResponse(error, {
      hasApiKey: !!process.env.EARLY_API_KEY,
      hasApiSecret: !!process.env.EARLY_API_SECRET,
      args
    });
  }
}

Register Custom Tool

// In src/index.ts setupHandlers method
case 'custom_tool':
  return await this.handleCustomTool(request.params.arguments as CustomArgs);

Testing Custom Integrations

Unit Tests

// tests/custom-integration.test.ts
describe('Custom Integration', () => {
  it('should handle custom workflow', async () => {
    const mockClient = new MockEarlyApiClient();
    const result = await handleCustomWorkflow(mockClient, testArgs);

    expect(result).toBeDefined();
    expect(mockClient.callCount).toBe(3);
  });
});

Integration Tests

// tests/integration.test.ts
describe('End-to-End Integration', () => {
  it('should complete full workflow', async () => {
    // Test complete user workflow
    const activities = await mcpServer.callTool('list_activities');
    const timer = await mcpServer.callTool('start_timer', {
      projectId: activities[0].id
    });
    // ... continue workflow
  });
});

For more specific integration help, see the Integration Guide or Troubleshooting Guide.