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¶
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¶
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¶
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¶
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¶
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¶
Note: This requires multiple team members to have MCP servers configured with their own API credentials.
Resource Planning¶
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¶
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¶
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¶
Project Comparisons¶
Productivity Analysis¶
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.