# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Repository Overview

This repository is a Model Context Protocol (MCP) server that integrates with DeepSource's code quality analysis platform. It serves as a bridge between DeepSource's GraphQL API and MCP-compatible AI assistants like Claude, providing access to code quality metrics and analysis results.

## Common Commands

## Environment Variables

The server uses the following environment variables:

- `DEEPSOURCE_API_KEY` (required): Your DeepSource API key for authentication
- `LOG_FILE` (optional): File path for log output. If not set, no logs will be written
- `LOG_LEVEL` (optional): Minimum log level (DEBUG, INFO, WARN, ERROR). Defaults to DEBUG

Example:
```bash
export DEEPSOURCE_API_KEY="your-api-key"
export LOG_FILE="/tmp/deepsource-mcp.log"
export LOG_LEVEL="DEBUG"
```

## Development Commands

```bash
# Install dependencies
pnpm install

# Build the TypeScript code
pnpm run build

# Start the server
pnpm run start

# Start the server in development mode (with auto-reload)
pnpm run dev

# Run all tests
pnpm run test

# Run tests with watching
pnpm run test:watch

# Run tests with coverage
pnpm run test:coverage

# Run ESLint
pnpm run lint

# Fix linting issues automatically
pnpm run lint:fix

# Format code with Prettier
pnpm run format

# Check code formatting
pnpm run format:check

# Type check without emitting files
pnpm run check-types

# Run the full CI check (format, lint, type check, build, test)
pnpm run ci

# Validate codebase (type check, lint, test)
pnpm run validate

# Inspect MCP server with inspector
pnpm run inspect

# Clean build artifacts
pnpm run clean
```

## Architecture Overview

The codebase is structured around two main components:

1. **MCP Server Integration (src/index.ts)**: 
   - Sets up the Model Context Protocol server
   - Registers and implements tool handlers for DeepSource API integration
   - Provides ten main tools for AI assistants: 
     - `projects` - List all available projects
     - `project_issues` - Get issues with filtering and pagination
     - `runs` - List analysis runs with filtering and pagination
     - `run` - Get details for a specific run
     - `recent_run_issues` - Get issues from the most recent run on a specific branch with pagination
     - `dependency_vulnerabilities` - Get dependency vulnerabilities with pagination
     - `quality_metrics` - Get quality metrics with optional filtering
     - `update_metric_threshold` - Update metric thresholds
     - `update_metric_setting` - Update metric settings for reporting and enforcement
     - `compliance_report` - Get security compliance reports (OWASP, SANS, MISRA-C)

2. **DeepSource Client (src/deepsource.ts)**:
   - Implements communication with DeepSource's GraphQL API
   - Handles authentication, error handling, and response parsing
   - Provides methods for retrieving projects, issues, and analysis runs
   - Supports both legacy and cursor-based Relay-style pagination

## Key Concepts

1. **Model Context Protocol (MCP)**: A protocol that enables AI assistants to interact with external services via standardized tool interfaces.

2. **DeepSource Integration**: This server provides AI assistants with access to DeepSource's code quality metrics through GraphQL API queries.

3. **Relay-style Pagination**: The API implements cursor-based pagination for efficient traversal of large result sets. This is used in both issue and run queries.

4. **Authentication**: The server requires a DeepSource API key, which is passed via the `DEEPSOURCE_API_KEY` environment variable.

## Development Notes

- The codebase uses TypeScript with ES modules.
- Tests are written using Jest. All handlers and client methods have comprehensive test coverage.
- The project follows a functional approach with clear separation of concerns.
- Error handling is robust throughout the codebase, with specific handling for various GraphQL and network errors.
- When making changes, ensure to maintain backward compatibility with MCP consumers.
- All DeepSource API interactions are encapsulated in the `DeepSourceClient` class.

## Code Quality Guidelines

DeepSource is used to maintain code quality. Here are the key patterns to follow:

### ESLint Guidelines

1. **Never disable ESLint rules unless absolutely necessary** - Fix the underlying issues instead of disabling rules.

2. **For exported enums** - If an enum is part of the public API and may not be directly referenced in the current file:
   - Add export usage examples in the documentation
   - Create a proper ESLint rule exception if needed with clear justification
   - Consider using TypeScript's `const enum` if the values are only needed at compile time

3. **For unused variables** - Use prefixed underscores to indicate intentionally unused variables:
   ```typescript
   try {
     // code
   } catch (_error) {
     // We don't use the error object
   }
   ```

### TypeScript Best Practices

1. **Avoid using `any` type** - Use specific types or `unknown` when the type is truly unknown. Consider using generics or type unions instead.
   ```typescript
   // Bad
   function process(data: any): any { ... }
   
   // Good
   function process<T>(data: T): Result<T> { ... }
   ```

2. **Prefer type guards over `instanceof` checks** - Use type predicates when possible.
   ```typescript
   // Instead of
   if (error instanceof CustomError) { ... }
   
   // Consider
   function isCustomError(error: unknown): error is CustomError {
     return error !== null && 
            typeof error === 'object' && 
            'customProp' in error;
   }
   ```

3. **Omit explicit type declarations when easily inferred** - TypeScript can infer types from initializers for variables, parameters, and properties. Explicit types add unnecessary verbosity in these cases.
   ```typescript
   // Bad
   const count: number = 5;
   const isActive: boolean = true;
   const name: string = 'John';
   
   // Good
   const count = 5;
   const isActive = true;
   const name = 'John';
   ```

4. **Use `@ts-expect-error` instead of `@ts-ignore`** - When suppressing TypeScript errors, use `@ts-expect-error` which will cause an error if the line it's applied to doesn't actually contain any type errors.
   ```typescript
   // Bad
   // @ts-ignore
   const value: string = 123;
   
   // Good
   // @ts-expect-error - Converting number to string intentionally
   const value: string = 123;
   ```

### Error Handling Patterns

1. **Avoid deeply nested try/catch blocks** - Refactor to use separate functions or middleware.
   ```typescript
   // Instead of nested try/catch
   try {
     try {
       // more code
     } catch (innerError) { ... }
   } catch (outerError) { ... }
   
   // Use separate functions
   function innerOperation() {
     try {
       // code
     } catch (error) {
       // handle specific errors
     }
   }
   
   function outerOperation() {
     try {
       innerOperation();
     } catch (error) {
       // handle other errors
     }
   }
   ```

2. **Centralize error logging** - Use a dedicated logger service instead of console calls.
   ```typescript
   // Instead of
   console.warn('Something went wrong');
   
   // Use
   logger.warn('Something went wrong');
   ```

### Code Structure

1. **Keep methods small and focused** - Methods should do one thing and do it well.

2. **Use instance methods when they need access to instance state** - Instance methods should be used when they require access to instance properties or methods. Methods that don't use `this` should be made static.

3. **Use proper null/undefined handling** - Use optional chaining and nullish coalescing operators.
   ```typescript
   // Bad
   if (data && data.property) {
     return data.property.value;
   }
   
   // Good
   return data?.property?.value;
   
   // Bad
   const value = data && data.property ? data.property : defaultValue;
   
   // Good
   const value = data?.property ?? defaultValue;
   ```

4. **Prefer early returns to reduce nesting** - This improves readability.
   ```typescript
   // Instead of
   function process(data) {
     if (isValid(data)) {
       // lots of code
     }
   }
   
   // Use
   function process(data) {
     if (!isValid(data)) return;
     // lots of code
   }
   ```

5. **Avoid unused expressions** - Expressions that don't affect the program state are often logic errors and should be avoided.
   ```typescript
   // Bad
   data.property; // This does nothing
   
   // Good
   const property = data.property; // Assign it if you need it
   doSomething(data.property); // Use it in a function call
   ```

6. **Use regular strings when template literals aren't needed** - Only use template literals when you need string interpolation, multiline strings, or special characters. Use single quotes for regular strings unless you need to include a single quote in the string.
   ```typescript
   // Bad
   const name = `John`;
   const greeting = `Hello World`;
   
   // Good - prefer single quotes
   const name = 'John';
   const greeting = 'Hello World';
   
   // Good - use double quotes when the string contains single quotes
   const message = "Don't forget to save!";
   
   // Good use of template literals
   const fullGreeting = `Hello, ${name}!`;
   const multiline = `This is a
   multiline string`;
   ```

### Git Commit Guidelines

1. **NEVER use --no-verify flag** - Do not bypass pre-commit hooks when committing code. Pre-commit hooks are essential for maintaining code quality and catching issues before they're committed.

## DeepSource Issue Prevention Guidelines

The following guidelines are based on frequent DeepSource issues detected in this codebase. Following these practices will help prevent common code quality issues.

### Avoiding Type Safety Issues

1. **Never use the `any` type (JS-0323)** - This is the most common issue found in the codebase. Replace all `any` types with more specific types:
   ```typescript
   // Bad
   function process(data: any): any { ... }
   typeof (error as any).message === 'string'
   
   // Good
   function process<T>(data: unknown): Result<T> { ... }
   typeof (error as Record<string, unknown>).message === 'string'
   ```
   
   - When accessing properties on an object of unknown type, use `Record<string, unknown>` instead of `any`:
   ```typescript
   // Bad
   const value = (someObject as any).property;
   
   // Good
   const value = (someObject as Record<string, unknown>).property;
   ```

2. **Avoid unnecessary type declarations (JS-0331)** - Omit explicit type declarations when they can be easily inferred by TypeScript:
   ```typescript
   // Bad - unnecessary type declaration
   const count: number = 5;
   const items: string[] = ['a', 'b', 'c'];
   
   // Good - let TypeScript infer the types
   const count = 5;
   const items = ['a', 'b', 'c'];
   ```

### Avoiding String Handling Issues

1. **Avoid useless template literals (JS-R1004)** - Use regular strings instead of template literals when no interpolation is needed:
   ```typescript
   // Bad
   const greeting = `Hello World`;
   const name = `John`;
   
   // Good
   const greeting = 'Hello World';
   const name = 'John';
   
   // Only use template literals when needed for interpolation
   const message = `Hello, ${name}!`;
   ```

2. **Use template literals for string concatenation (JS-0246)** - Prefer template literals over string concatenation:
   ```typescript
   // Bad
   const message = 'Hello, ' + name + '!';
   
   // Good
   const message = `Hello, ${name}!`;
   ```

3. **Use optional chaining for nested property access (JS-W1044)** - Use optional chaining (?.) for nested property access, but use logical operators for other purposes:
   ```typescript
   // Bad - for nested property access
   function getUserName(user) {
     return user && user.profile && user.profile.name;
   }
   
   // Good - for nested property access
   function getUserName(user) {
     return user?.profile?.name;
   }
   
   // Bad - for method calls
   const callback = someObj && someObj.callback;
   if (callback) {
     callback();
   }
   
   // Good - for method calls
   someObj?.callback?.();
   
   // Still use logical operators when appropriate:
   // Good - for boolean checks
   const isValid = input && input.length > 0;
   
   // Good - for nullish coalescing (prefer ?? over || for default values)
   const timeout = config.timeout ?? 5000;
   const name = user.name ?? 'Anonymous';
   ```

### Improving Method Organization

1. **Make instance methods static when they don't use `this` (JS-0105)** - Methods that don't reference instance properties or methods should be static:
   ```typescript
   // Bad
   class Utilities {
     formatDate(date: Date): string {
       // Doesn't use 'this'
       return date.toISOString();
     }
   }
   
   // Good
   class Utilities {
     static formatDate(date: Date): string {
       return date.toISOString();
     }
   }
   ```

2. **Implement all empty methods** - Add proper implementation to all methods, even if they are placeholders:
   ```typescript
   // Bad
   private static logPaginationWarning(): void {
     // Empty method without implementation
   }
   
   // Good
   private static logPaginationWarning(message?: string): void {
     // Proper implementation with meaningful behavior
     const warningMessage = message || 'Non-standard pagination used';
     this.logger.warn(warningMessage);
   }
   ```

### Type Validation and Conversion

1. **Use consistent type validation patterns** - Create reusable validation functions for common type checks:
   ```typescript
   // Helper function for validating object types
   private static isValidObject(value: unknown): value is Record<string, unknown> {
     return value !== null && typeof value === 'object';
   }
   
   // Helper for extracting string values safely
   private static validateString(value: unknown, defaultValue = ''): string {
     return typeof value === 'string' ? value : defaultValue;
   }
   ```

2. **Create type predicates for complex type validation** - For complex objects, create type predicates that verify the required structure:
   ```typescript
   // Type predicate for validating a specific structure
   private static isValidConfiguration(config: unknown): config is Configuration {
     return (
       typeof config === 'object' &&
       config !== null &&
       'apiKey' in config &&
       typeof (config as Record<string, unknown>).apiKey === 'string'
     );
   }
   ```

### Test Coverage Best Practices

1. **Maintain high test coverage (TCV-001)** - Ensure all code paths, especially edge cases, are well-tested:
   ```typescript
   // For edge cases in error handling
   test('should handle null input gracefully', () => {
     expect(processData(null)).toEqual({ error: 'Invalid input' });
   });
   
   // For conditional branches
   test('should use default value when config is missing', () => {
     expect(getConfig(undefined).retryCount).toBe(3);
   });
   ```

2. **Mock external dependencies** - When testing functions that depend on external services:
   ```typescript
   test('handles API errors correctly', () => {
     // Setup a mock
     jest.spyOn(apiService, 'fetchData').mockRejectedValue(new Error('Network error'));
     
     // Test error handling
     return expect(client.getData()).rejects.toThrow('Failed to fetch data');
   });
   ```

3. **Test both success and failure paths** - Especially for async operations:
   ```typescript
   describe('API client', () => {
     it('handles successful response', async () => {
       // Test happy path
     });
     
     it('handles timeouts', async () => {
       // Test timeout path
     });
     
     it('handles service unavailable errors', async () => {
       // Test server error path
     });
   });
   ```

4. **Test code before merging** - DeepSource flags lines that aren't covered by tests as critical issues:
   ```typescript
   // Before adding new methods or classes
   // 1. Write tests first (TDD approach)
   // 2. Implement the feature
   // 3. Verify test coverage with 'pnpm run test:coverage'
   
   // Prioritize testing:
   // - Error handling branches
   // - Edge cases (null, undefined, empty values)
   // - Complex business logic
   // - Public API methods
   ```

5. **Write test cases for all possible scenarios** - Consider all possible paths through the code:
   ```typescript
   // For a function with multiple conditions:
   test('returns correct result when all conditions are met', () => { /* ... */ });
   test('throws error when first condition fails', () => { /* ... */ });
   test('returns fallback when second condition fails', () => { /* ... */ });
   ```

### Import and Module Best Practices

1. **Avoid wildcard imports (JS-C1003)** - Use explicit imports instead of importing everything from a module:
   ```typescript
   // Bad
   import * as utils from './utils';
   
   // Good
   import { formatDate, validateInput } from './utils';
   ```

2. **Use named imports for better clarity** - This makes it easier to track dependencies:
   ```typescript
   // Bad - obscures which parts of the library you're using
   import * as _ from 'lodash';
   
   // Good - clearly indicates which functions you're using
   import { isEmpty, isEqual, cloneDeep } from 'lodash';
   ```

3. **Add comments for necessary wildcard imports** - When a library requires wildcard imports:
   ```typescript
   // skipcq: JS-C1003 - This library does not expose itself as an ES Module
   import * as Sentry from '@sentry/node';
   ```

### Function Complexity Management

1. **Reduce cyclomatic complexity (JS-R1005)** - Break down complex functions with many decision points:
   ```typescript
   // Bad - high cyclomatic complexity
   function processPayment(payment) {
     if (payment.type === 'credit') {
       if (payment.amount > 1000) {
         if (payment.verified) {
           // Process verified high-value credit payment
         } else {
           // Request verification for high-value payment
         }
       } else {
         // Process regular credit payment
       }
     } else if (payment.type === 'debit') {
       // Similar nested conditions for debit
     } else if (payment.type === 'crypto') {
       // Similar nested conditions for crypto
     }
   }
   
   // Good - extract functions and use early returns
   function processPayment(payment) {
     if (payment.type === 'credit') {
       return processCreditPayment(payment);
     } else if (payment.type === 'debit') {
       return processDebitPayment(payment);
     } else if (payment.type === 'crypto') {
       return processCryptoPayment(payment);
     }
     return { error: 'Unsupported payment type' };
   }
   
   function processCreditPayment(payment) {
     if (payment.amount <= 1000) {
       return processRegularCreditPayment(payment);
     }
     
     return payment.verified
       ? processVerifiedHighValueCreditPayment(payment)
       : requestVerificationForHighValuePayment(payment);
   }
   ```

2. **Use lookup tables instead of long if-else chains** - Simplify decision trees:
   ```typescript
   // Bad - long if-else chain
   function getCountryCode(country) {
     if (country === 'United States') return 'US';
     else if (country === 'United Kingdom') return 'UK';
     else if (country === 'Canada') return 'CA';
     else if (country === 'Australia') return 'AU';
     // ... many more conditions
     else return 'UNKNOWN';
   }
   
   // Good - lookup table
   function getCountryCode(country) {
     const countryMap = {
       'United States': 'US',
       'United Kingdom': 'UK',
       'Canada': 'CA',
       'Australia': 'AU',
       // ... many more mappings
     };
     
     return countryMap[country] || 'UNKNOWN';
   }
   ```

3. **Separate concerns into different functions** - Each function should have a single responsibility:
   ```typescript
   // Bad - function doing too much
   function processOrder(order) {
     // Validate order
     // Calculate tax
     // Apply discounts
     // Process payment
     // Update inventory
     // Send confirmation email
   }
   
   // Good - separated concerns
   function processOrder(order) {
     if (!validateOrder(order)) {
       return { error: 'Invalid order' };
     }
     
     const orderWithTax = calculateTax(order);
     const finalOrder = applyDiscounts(orderWithTax);
     
     const paymentResult = processPayment(finalOrder);
     if (!paymentResult.success) {
       return { error: 'Payment failed', details: paymentResult.error };
     }
     
     updateInventory(finalOrder);
     sendConfirmationEmail(finalOrder);
     
     return { success: true, orderId: finalOrder.id };
   }
   ```

### Advanced TypeScript Best Practices

1. **Use branded types for type safety** - Create distinct types for values of the same primitive type:
   ```typescript
   // Branded type for user IDs
   type UserID = string & { readonly __brand: unique symbol };
   
   // Branded type for project keys
   type ProjectKey = string & { readonly __brand: unique symbol };
   
   // Functions can now be specific about which type they accept
   function getUserDetails(id: UserID) { /* ... */ }
   function getProjectDetails(key: ProjectKey) { /* ... */ }
   
   // Prevents passing a project key where a user ID is expected
   getUserDetails(projectKey); // Type error
   ```

2. **Prefer interfaces for public APIs** - Use interfaces for external contracts and types for internal structures:
   ```typescript
   // Public API interface
   export interface ClientOptions {
     apiKey: string;
     timeout?: number;
     retries?: number;
   }
   
   // Internal type
   type RateLimitConfig = {
     maxRequests: number;
     timeWindow: number;
     strategy: 'queue' | 'error' | 'exponential';
   };
   ```

3. **Use discriminated unions for complex state management** - Makes type narrowing more precise:
   ```typescript
   type RequestState = 
     | { status: 'idle' }
     | { status: 'loading' }
     | { status: 'success', data: Response }
     | { status: 'error', error: Error };
   
   function handleRequest(state: RequestState) {
     switch (state.status) {
       case 'loading':
         // TypeScript knows no data or error exists here
         showLoadingIndicator();
         break;
       case 'success':
         // TypeScript knows data exists here
         displayData(state.data);
         break;
     }
   }
   ```

4. **Use const assertions for literal types** - Preserve literal types in object literals:
   ```typescript
   // Without const assertion
   const config = {
     environment: 'production',
     features: ['metrics', 'logging']
   };
   // config.environment has type 'string'
   
   // With const assertion
   const config = {
     environment: 'production',
     features: ['metrics', 'logging']
   } as const;
   // config.environment has type 'production'
   // config.features has type readonly ['metrics', 'logging']
   ```

## Development Workflow Best Practices

To avoid common DeepSource issues and maintain high code quality, follow these steps when making changes:

### Pre-Coding Workflow

1. **Plan your changes**
   - Review existing patterns in the codebase for consistency
   - Write tests before implementing features (TDD approach) 
   - Design functions and classes to minimize complexity

2. **Setup proper tooling**
   - Use IDE extensions for ESLint, Prettier, and TypeScript
   - Configure pre-commit hooks for automated checks
   - Familiarize yourself with DeepSource issues in the project

### Implementation Checklist

1. **Type Safety**
   - Use `unknown` instead of `any` for unknown types
   - Use `Record<string, unknown>` for objects with unknown structure
   - Create proper type guards with type predicates for complex objects
   - Omit explicit type declarations when TypeScript can infer them
   - Use branded types for IDs and similar primitive values

2. **Method Organization**
   - Convert non-instance methods to static (those not using `this`)
   - Keep methods small and focused with a single responsibility
   - Break down complex functions to reduce cyclomatic complexity
   - Use lookup tables instead of long if-else chains
   - Use early returns to reduce nesting

3. **Code Style**
   - Use regular strings instead of template literals when no interpolation is needed
   - Use template literals for string concatenation instead of the plus operator
   - Use optional chaining (?.) instead of logical operators (&&) for nested property access
   - Use nullish coalescing (??) instead of logical OR for default values
   - Add JSDoc comments for all public methods

4. **Import Management**
   - Use named imports instead of wildcard imports
   - Explicitly import only what you need from modules
   - Add appropriate comments for necessary wildcard imports

### Pre-Commit Verification

Run these commands before committing changes:

```bash
# Check for type errors
pnpm run check-types

# Run linter to catch potential issues
pnpm run lint

# Format code according to codebase standards
pnpm run format

# Verify test coverage
pnpm run test:coverage

# Run full CI check (combines several checks)
pnpm run ci
```

Manually verify:
- No instances of `any` type remain
- All public methods have proper JSDoc documentation
- Non-instance methods are marked as static
- Template literals are used appropriately
- Complex functions are broken down
- Error handling is robust

### Memories

- Do not use the any type. Use never, unknown, or Record<string, unknown> instead.
- Prefer Record<string, unknown> over any when working with objects of unknown structure.
- Use template literals only when needed for interpolation or multiline strings.
- Convert instance methods that don't use 'this' to static methods.
- Implement proper functionality in all methods, never leave empty method bodies.
- Create reusable type validation helpers for commonly validated types.
- Use branded types to prevent mixing similar primitive values (like different string IDs).
- Use discriminated unions for complex state management.
- Add comprehensive tests for edge cases, not just the happy paths.
- Use const assertions to preserve literal types in object literals.
- Use optional chaining (?.) instead of logical operators (&&) for nested property access.
- Avoid wildcard imports; use named imports for better clarity.
- Break down complex functions to reduce cyclomatic complexity.
- Use lookup tables instead of long if-else chains for mapping values.
- Separate concerns into different functions with single responsibilities.
- Always maintain high test coverage to prevent TCV-001 (Lines not covered in tests) issues.
- **Do not change .gitignore unless explicitly asked to do so**