Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions .cursor/rules/api-client-patterns.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# API Client Patterns

## Client Structure

The [src/api/client.ts](mdc:src/api/client.ts) implements the `MotionApiClient` class with:

- **Axios instance** with base configuration
- **Rate limiting** using `p-queue` (configurable via environment)
- **Error handling** with proper HTTP status interpretation
- **Request queuing** to respect Motion API limits

## HTTP Methods

- **GET**: List and retrieve operations
- **POST**: Create operations
- **PATCH**: Update operations
- **DELETE**: Delete operations

## Rate Limiting

- Default: **12 requests per minute** (configurable via `MOTION_RATE_LIMIT_PER_MINUTE`)
- Uses **p-queue** with `concurrency: 1` and `intervalCap`
- All requests go through the rate-limited queue

## Error Handling Pattern

```typescript
if (status === 429) {
throw new Error(`Rate limit exceeded. Please try again later. ${message}`);
} else if (status === 401) {
throw new Error(`Authentication failed. Check your API key. ${message}`);
} else if (status === 404) {
throw new Error(`Resource not found. ${message}`);
}
```

## Request Method Pattern

```typescript
private async request<T>(method: string, path: string, data?: any, params?: any): Promise<T> {
return this.queue.add(async () => {
const response = await this.axios.request<T>({
method,
url: path,
data,
params,
});
return response.data;
}) as Promise<T>;
}
```

## API Method Patterns

- **List methods**: Accept optional filter parameters, return arrays
- **Get methods**: Take ID parameter, return single object
- **Create methods**: Take creation parameters, return created object
- **Update methods**: Take ID + update parameters, return updated object
- **Delete methods**: Take ID parameter, return void

## Type Safety

- All methods use **generic types** with Motion interfaces
- Parameters use **specific interfaces** (e.g., `MotionTaskCreateParams`)
- Return types match **Motion API response structures**

## Configuration

Configuration is loaded from [src/config.ts](mdc:src/config.ts):

```typescript
{
apiKey: string; // MOTION_API_KEY (required)
baseUrl: string; // MOTION_API_BASE_URL (optional)
rateLimitPerMinute: number; // MOTION_RATE_LIMIT_PER_MINUTE (optional)
}
```
description: API client implementation patterns
---
124 changes: 124 additions & 0 deletions .cursor/rules/data-validation.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# Data Validation Patterns

## Zod Schema Patterns

All tool handlers use **Zod schemas** for runtime validation following these patterns:

### Basic Types

```typescript
const schema = z.object({
id: z.string().min(1), // Required string
name: z.string().optional(), // Optional string
count: z.number().min(0), // Number with constraint
enabled: z.boolean(), // Boolean
items: z.array(z.string()), // Array of strings
});
```

### Motion-Specific Patterns

```typescript
// Task priorities
priority: z.enum(['ASAP', 'HIGH', 'MEDIUM', 'LOW']).optional()

// Deadline types
deadlineType: z.enum(['HARD', 'SOFT', 'NONE']).optional()

// Duration (string or number)
duration: z.union([z.string(), z.number()]).optional()

// ISO date strings
dueDate: z.string().optional()

// Array of status strings
status: z.array(z.string()).optional()
```

### Complex Objects

```typescript
// Auto-scheduling configuration
autoScheduled: z.union([
z.object({
startDate: z.string(),
deadlineType: z.enum(['HARD', 'SOFT', 'NONE']).optional(),
schedule: z.string().optional(),
}),
z.null(),
]).optional()
```

## Validation Workflow

1. **Define schema** at the top of handler function
2. **Parse input** with `schema.parse(args)`
3. **Use validated data** with full TypeScript support
4. **Let errors bubble** up to MCP error handler

```typescript
handler: async (args: unknown) => {
const schema = z.object({
taskId: z.string().min(1),
name: z.string().optional(),
});

const validated = schema.parse(args);
return await client.updateTask(validated.taskId, validated);
}
```

## Common Validation Patterns

### ID Validation
```typescript
taskId: z.string().min(1) // Non-empty string
workspaceId: z.string().min(1) // Non-empty string
```

### Optional Parameters
```typescript
cursor: z.string().optional() // Pagination cursor
includeAllStatuses: z.boolean().optional() // Filter flag
```

### Filter Arrays
```typescript
labels: z.array(z.string()).optional() // Array of label names
assignees: z.array(z.string()).optional() // Array of user IDs
```

## Schema Reuse

For complex schemas, consider extracting to constants:

```typescript
const CreateTaskSchema = z.object({
name: z.string().min(1),
workspaceId: z.string().min(1),
// ... other fields
});

const UpdateTaskSchema = CreateTaskSchema.partial().extend({
taskId: z.string().min(1),
});
```

## Motion Type Integration

Validation schemas should align with Motion types from [src/types/motion.ts](mdc:src/types/motion.ts):

- Use **same field names** as Motion interfaces
- Apply **same constraints** as API requirements
- Support **same optional/required** patterns

## Error Messages

Zod provides detailed error messages automatically. For custom validation:

```typescript
z.string().min(1, "Task name cannot be empty")
z.number().min(0, "Duration must be positive")
```
description: Data validation patterns using Zod
---
87 changes: 87 additions & 0 deletions .cursor/rules/development-workflow.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Development Workflow

## Available Scripts

From [package.json](mdc:package.json):

- `npm run build` - Compile TypeScript to `dist/`
- `npm run dev` - Watch mode development with `tsx`
- `npm start` - Run compiled server from `dist/`
- `npm run typecheck` - Type checking without compilation
- `npm run lint` - ESLint validation
- `npm run format` - Prettier code formatting

## Environment Setup

Required environment variables:

```bash
MOTION_API_KEY=your_api_key_here
MOTION_API_BASE_URL=https://api.usemotion.com/v1 # optional
MOTION_RATE_LIMIT_PER_MINUTE=12 # optional
```

## Development Server

Run in development mode:

```bash
npm run dev
```

This uses `tsx watch` to automatically restart on file changes.

## Testing with MCP

To test the MCP server:

1. **Build the project**: `npm run build`
2. **Run the server**: `npm start`
3. **Test with MCP client** or integration

## Adding New Tools

1. **Create tool file** in `src/tools/` (e.g., `newFeature.ts`)
2. **Export register function**: `export function registerNewFeatureTools(client: MotionApiClient): Tool[]`
3. **Register in main server**: Add to imports and tools array in [src/index.ts](mdc:src/index.ts)
4. **Follow existing patterns** from [src/tools/task.ts](mdc:src/tools/task.ts)

## Code Quality

- **Type safety**: Use TypeScript strictly, no `any` types
- **Validation**: Zod schemas for all inputs
- **Error handling**: Proper error messages and types
- **Formatting**: Prettier with [.prettierrc](mdc:.prettierrc) config
- **Linting**: ESLint with [.eslintrc.json](mdc:.eslintrc.json) config

## Debugging

- Use `console.error()` for debugging (goes to stderr)
- Check Motion API documentation for parameter requirements
- Test rate limiting with multiple rapid requests
- Verify environment variables are loaded correctly

## API Documentation

Reference the Motion API documentation and [docs/MOTION_API_REFERENCE.md](mdc:docs/MOTION_API_REFERENCE.md) for:

- **Endpoint specifications**
- **Parameter requirements**
- **Response formats**
- **Rate limiting details**

## Common Issues

1. **Rate limiting**: Respect the 12 requests/minute default limit
2. **Authentication**: Ensure `MOTION_API_KEY` is set correctly
3. **Validation**: Zod schemas must match Motion API requirements
4. **ESM imports**: Use `.js` extensions in import statements

## Build Process

- **TypeScript compilation** to `dist/` directory
- **Preserve file structure** from `src/`
- **Include type definitions** for better IDE support
- **Executable binary** at `dist/index.js`
description: Development workflow, testing, and debugging patterns
---
81 changes: 81 additions & 0 deletions .cursor/rules/error-handling.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Error Handling Patterns

## MCP Error Types

Use `McpError` from `@modelcontextprotocol/sdk/types.js` for MCP-specific errors:

```typescript
import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js';

// Tool not found
throw new McpError(ErrorCode.MethodNotFound, `Tool ${toolName} not found`);

// Tool execution failed
throw new McpError(ErrorCode.InternalError, `Tool execution failed: ${error.message}`);
```

## API Client Error Handling

The API client in [src/api/client.ts](mdc:src/api/client.ts) handles common HTTP errors:

- **429 (Rate Limited)**: "Rate limit exceeded. Please try again later."
- **401 (Unauthorized)**: "Authentication failed. Check your API key."
- **404 (Not Found)**: "Resource not found."
- **Other errors**: Generic API error with status code

## Validation Error Handling

Use Zod for input validation in tool handlers:

```typescript
try {
const validated = schema.parse(args);
// ... use validated data
} catch (error) {
// Zod errors will be caught by MCP error handler
throw error;
}
```

## Configuration Error Handling

Configuration errors are thrown immediately in [src/config.ts](mdc:src/config.ts):

```typescript
if (!apiKey) {
throw new Error('MOTION_API_KEY environment variable is required');
}
```

## Server Error Handling

The main server in [src/index.ts](mdc:src/index.ts) has global error handling:

```typescript
main().catch((error) => {
console.error('Fatal error starting Motion MCP server:', error);
process.exit(1);
});
```

## Error Response Format

Tool handlers should return structured error information when possible:

```typescript
return {
success: false,
error: 'Specific error message',
details: additionalContext
};
```

## Best Practices

1. **Be specific**: Include relevant context in error messages
2. **Don't expose internals**: Sanitize error messages for user consumption
3. **Log appropriately**: Use `console.error` for debugging information
4. **Fail fast**: Validate inputs early and throw meaningful errors
5. **Chain errors**: Preserve original error context when re-throwing
description: Error handling patterns and conventions
---
Loading