# Development Guide
## Getting Started
### Prerequisites
Ensure you have the following installed:
- Bun 1.0.0 or higher (or Node.js 18.0.0+)
- Git
### Installation
1. Clone the repository and install dependencies:
```bash
bun install
```
2. Set up your environment:
```bash
cp .env.example .env
# Edit .env and add your LINEAR_API_KEY
```
3. Build the project:
```bash
bun run build
```
## Development Workflow
### Development Mode
Run TypeScript in watch mode for active development:
```bash
bun run dev
```
## Development Workflow
### Development Mode
Run TypeScript in watch mode for active development:
```bash
bun run dev
```
This will recompile TypeScript files automatically when you make changes.
### Testing Changes
After making changes, rebuild and test:
```bash
bun run build
bun start
```
The server will start and wait for MCP client connections via stdio.
### Type Checking
Run TypeScript type checking without emitting files:
```bash
bun run typecheck
```
### Linting and Formatting
```bash
# Run ESLint
bun run lint
# Format code with Prettier
bun run format
```
## Project Structure
### Core Files
- **`src/index.ts`**: Main MCP server entry point
- Defines all MCP tools
- Sets up request handlers
- Manages server lifecycle
- **`src/linear-client.ts`**: Linear API client wrapper
- Provides type-safe methods for all Linear operations
- Handles error formatting and response normalization
- Abstracts the Linear SDK complexity
### Tool Modules
Each tool module exports handler functions:
- **`src/tools/issues.ts`**: Issue management tools
- **`src/tools/projects.ts`**: Project listing tools
- **`src/tools/cycles.ts`**: Cycle/sprint management
- **`src/tools/teams.ts`**: Team and workflow state tools
- **`src/tools/labels.ts`**: Label management
- **`src/tools/users.ts`**: User listing tools
### Schemas
- **`src/schemas/index.ts`**: Zod validation schemas for all tool inputs
- Provides runtime type validation
- Generates TypeScript types for type safety
- Includes helpful descriptions for LLM clients
## Adding New Tools
To add a new Linear operation:
1. **Define the Zod schema** in `src/schemas/index.ts`:
```typescript
export const MyNewToolSchema = z.object({
param1: z.string().describe('Description for LLM clients'),
param2: z.number().optional().describe('Optional parameter'),
});
export type MyNewToolInput = z.infer<typeof MyNewToolSchema>;
```
2. **Add the method to LinearAPIClient** in `src/linear-client.ts`:
```typescript
async myNewOperation(data: MyNewToolInput) {
try {
const result = await this.client.someLinearMethod(data);
return this.formatResult(result);
} catch (error) {
throw new Error(`Failed to perform operation: ${this.getErrorMessage(error)}`);
}
}
```
3. **Create the tool handler** in the appropriate file under `src/tools/`:
```typescript
export async function myNewTool(client: LinearAPIClient, args: unknown) {
const params = MyNewToolSchema.parse(args);
const result = await client.myNewOperation(params);
return {
content: [
{
type: 'text' as const,
text: JSON.stringify(result, null, 2),
},
],
};
}
```
4. **Register the tool** in `src/index.ts`:
Add to the `TOOLS` array:
```typescript
{
name: 'linear_my_new_tool',
description: 'Clear description for LLM clients about what this tool does',
inputSchema: {
type: 'object',
properties: {
param1: {
type: 'string',
description: 'Parameter description',
},
// ... more parameters
},
required: ['param1'],
},
}
```
Add to the switch statement in the CallToolRequestSchema handler:
```typescript
case 'linear_my_new_tool':
return await myModule.myNewTool(client, args);
```
## Testing
### Manual Testing
1. Build the project:
```bash
bun run build
```
2. Run the server:
```bash
bun run dist/index.js
# or with Node.js:
node dist/index.js
```
2. Run the server:
```bash
node dist/index.js
```
3. Send MCP requests via stdio. Example using node:
```javascript
const request = {
jsonrpc: '2.0',
id: 1,
method: 'tools/list',
params: {},
};
console.log(JSON.stringify(request));
```
### Integration Testing
Test with your MCP client:
1. Update your MCP client's config with the development build path
2. Restart your MCP client
3. Try using the Linear tools
## Debugging
### Enable Debug Logging
Add debug output in your code:
```typescript
console.error('[DEBUG]', 'Your debug message', data);
```
Output goes to stderr and won't interfere with MCP communication (which uses stdout).
### Common Issues
**"LINEAR_API_KEY is required"**
- Ensure the environment variable is set
- Check your MCP client's config has the `env` section
- Verify no extra spaces in the API key
**Tool not appearing in MCP client**
- Rebuild the project: `bun run build`
- Check the tool is registered in `TOOLS` array
- Restart your MCP client
**Type errors during build**
- Run `bun run typecheck` to see all errors
- Ensure imports use `.js` extension (required for ES modules)
- Check Zod schemas match TypeScript types
**Linear API errors**
- Check the Linear API documentation for the specific endpoint
- Verify your API key has the required permissions
- Check if you're hitting rate limits
## Code Style
### TypeScript Guidelines
- Use strict TypeScript settings (all strict flags enabled)
- Prefer `const` over `let`
- Use async/await over promises
- Avoid `any` type (use `unknown` and type guards)
- Export types alongside implementations
### Error Handling
Always catch and format errors:
```typescript
try {
const result = await linearOperation();
return result;
} catch (error) {
throw new Error(`Context about what failed: ${this.getErrorMessage(error)}`);
}
```
### Validation
Use Zod schemas for all external input:
```typescript
const params = MySchema.parse(args); // Throws if validation fails
```
### Response Formatting
Return consistent response format:
```typescript
return {
content: [
{
type: 'text' as const,
text: JSON.stringify(data, null, 2),
},
],
};
```
## Performance Considerations
### API Efficiency
- Use `first` parameter to limit results instead of fetching all
- Leverage Linear's filter capabilities instead of client-side filtering
- Consider pagination for large datasets
### Caching
The Linear SDK includes some built-in caching. For additional caching:
- Cache team/user lookups (they change infrequently)
- Be cautious with issue caching (they change frequently)
- Consider implementing a TTL-based cache for repeated queries
### Rate Limiting
Linear API has rate limits:
- 120 requests per minute per API key
- 5000 requests per hour per API key
Best practices:
- Batch operations when possible
- Add delays for bulk operations
- Handle rate limit errors gracefully
## Release Process
1. Update version in `package.json`
2. Update docs/CHANGELOG.md with changes
3. Build and test:
```bash
bun run build
bun run lint
bun run typecheck
```
4. Commit changes
5. Create git tag: `git tag v1.0.0`
6. Push with tags: `git push --tags`
## Resources
- [Linear API Documentation](https://developers.linear.app/)
- [Linear SDK on GitHub](https://github.com/linear/linear)
- [Model Context Protocol Spec](https://modelcontextprotocol.io/)
- [MCP SDK on GitHub](https://github.com/modelcontextprotocol/sdk)
- [Zod Documentation](https://zod.dev/)
- [TypeScript Handbook](https://www.typescriptlang.org/docs/handbook/intro.html)
## Getting Help
- Check existing GitHub issues
- Review Linear API documentation
- Consult MCP specification
- Ask in the MCP community channels