Templatetypescriptexpressintermediateโœ“ Production ReadyFreeโœ… Code Verified

Linear API Client Template

A production-ready TypeScript MCP server template using Express and HTTP transport, secured with API key authentication. Implements a full-featured Linear API client with GraphQL query support, automatic retries, response normalization, rate limiting, structured Pino logging, and health monitoring for seamless integration with Claude Desktop and other MCP clients.

๐Ÿ“– 12 min readโš™๏ธ Setup: 20 minutesutilities
linearmcptypescriptapi-clientgraphqlproject-management

Files(21)

# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
# Linear MCP Server โ€” Environment Variables
# Copy this file to .env and fill in the values.
# Never commit .env to version control.
# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

# โ”€โ”€ Required โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

# Your Linear personal API key or OAuth token.
# Generate one at: https://linear.app/settings/api
LINEAR_API_KEY=lin_api_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# Secret key that MCP clients must send in the x-api-key header.
# Generate a strong key: openssl rand -hex 32
MCP_API_KEY=change-me-to-a-long-random-secret-key

# โ”€โ”€ Server โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

# HTTP port the server listens on.
PORT=3000

# Runtime environment. Set to "production" in deployed environments.
# Affects log formatting (pretty in dev, JSON in prod).
NODE_ENV=development

# โ”€โ”€ Logging โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

# Pino log level. Options: trace | debug | info | warn | error | fatal
# Use "info" or higher in production.
LOG_LEVEL=info

# โ”€โ”€ Linear API โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

# Linear GraphQL API endpoint. Override for testing with a mock server.
LINEAR_API_URL=https://api.linear.app/graphql

# Maximum number of retry attempts for failed Linear API requests.
LINEAR_MAX_RETRIES=3

# Initial delay in milliseconds before the first retry. Doubles each attempt.
LINEAR_RETRY_DELAY_MS=500

# Timeout in milliseconds for each Linear API request.
LINEAR_REQUEST_TIMEOUT_MS=10000

# โ”€โ”€ Rate Limiting โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

# Time window for rate limiting in milliseconds (default: 1 minute).
RATE_LIMIT_WINDOW_MS=60000

# Maximum number of requests allowed per window per IP address.
RATE_LIMIT_MAX_REQUESTS=100

Interactive tester

Test Your Server

Enter a deployed HTTP MCP server URL and API key to run live browser checks.

No signup

Use the public MCP endpoint, not a dashboard URL or local stdio command.

The key stays in this browser check and is sent to the endpoint you enter.

For local servers, use the local testing guide or MCP Inspector. This online tester works best with deployed HTTP MCP servers.

Linear API Client โ€” MCP Server Template

Overview

This template provides a production-ready Model Context Protocol (MCP) server that exposes the Linear project management API to AI assistants like Claude. Built with TypeScript and Express, it acts as a structured bridge between MCP clients and Linear's GraphQL API, handling authentication, retries, rate limiting, and response normalization so your AI workflows can query issues, projects, teams, and users without boilerplate.

The server is designed for teams that want to give Claude or other MCP-compatible assistants direct, safe access to their Linear workspace. Every tool call is validated, logged with a correlation ID, and executed through a resilient HTTP client that respects Linear's rate limits. The architecture keeps business logic cleanly separated from transport concerns, making it straightforward to extend with new Linear endpoints or swap out the underlying HTTP transport.

This template is ideal for engineering teams building internal AI tooling, developers prototyping Linear-powered automation, and anyone who wants a battle-tested starting point for an MCP server that talks to a third-party GraphQL API.

What You'll Learn

  • How to scaffold a fully typed MCP server using the @modelcontextprotocol/sdk package with HTTP/SSE transport
  • How to implement API key authentication middleware that protects every MCP endpoint
  • How to build a reusable GraphQL client with automatic retries and exponential back-off
  • How to enforce rate limiting per client using express-rate-limit to protect upstream APIs
  • How to set up Pino for structured JSON logging with per-request correlation IDs
  • How to register and validate MCP tools using Zod schemas for runtime input safety
  • How to write a /health endpoint that checks Linear API reachability and reports structured JSON status
  • How to create a multi-stage Dockerfile that produces a minimal, secure production image
  • How to wire up environment-based configuration with typed defaults and validation at startup
  • How to write integration-style tests with Jest and Supertest covering auth, health, and tool execution
  • How to handle Linear GraphQL errors, network timeouts, and upstream failures gracefully
  • How to normalise Linear's nested GraphQL responses into flat, LLM-friendly structures

Architecture

MCP Client (Claude Desktop / Cursor)
  โ”‚
  โ”‚  HTTP POST /mcp  (MCP JSON-RPC)
  โ–ผ
Express Server
  โ”‚
  โ”œโ”€โ–บ API Key Auth Middleware  โ”€โ”€โ”€โ”€ 401 if invalid
  โ”œโ”€โ–บ Rate Limit Middleware    โ”€โ”€โ”€โ”€ 429 if exceeded
  โ”œโ”€โ–บ Pino Request Logger      โ”€โ”€โ”€โ”€ correlation ID injected
  โ”‚
  โ–ผ
MCP SDK Router (StreamableHTTPServerTransport)
  โ”‚
  โ”œโ”€โ–บ Tool: list_issues
  โ”œโ”€โ–บ Tool: get_issue
  โ”œโ”€โ–บ Tool: create_issue
  โ”œโ”€โ–บ Tool: list_projects
  โ””โ”€โ–บ Tool: list_teams
        โ”‚
        โ–ผ
   Linear GraphQL Client
        โ”‚  (retries + back-off)
        โ–ผ
   Linear API  (api.linear.app/graphql)

Project Structure

linear-mcp-server/
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ __tests__/
โ”‚   โ”‚   โ”œโ”€โ”€ server.test.ts        # Jest + Supertest integration tests
โ”‚   โ”‚   โ””โ”€โ”€ setup.ts              # Test environment variables
โ”‚   โ”œโ”€โ”€ linear/
โ”‚   โ”‚   โ”œโ”€โ”€ client.ts             # Reusable GraphQL client with retries
โ”‚   โ”‚   โ”œโ”€โ”€ queries.ts            # All Linear GraphQL query strings
โ”‚   โ”‚   โ””โ”€โ”€ types.ts              # Full TypeScript types for Linear responses
โ”‚   โ”œโ”€โ”€ tools/
โ”‚   โ”‚   โ”œโ”€โ”€ issues.ts             # list_issues, get_issue, create_issue tools
โ”‚   โ”‚   โ”œโ”€โ”€ projects.ts           # list_projects tool
โ”‚   โ”‚   โ””โ”€โ”€ teams.ts              # list_teams tool
โ”‚   โ”œโ”€โ”€ auth.ts                   # API key authentication middleware
โ”‚   โ”œโ”€โ”€ config.ts                 # Typed config loaded from environment
โ”‚   โ”œโ”€โ”€ health.ts                 # /health endpoint with dependency checks
โ”‚   โ”œโ”€โ”€ logger.ts                 # Pino structured logger
โ”‚   โ””โ”€โ”€ server.ts                 # Express app + MCP server entrypoint
โ”œโ”€โ”€ .env.example                  # All environment variables documented
โ”œโ”€โ”€ .gitignore
โ”œโ”€โ”€ babel.config.js               # Babel config for ESM node-fetch in Jest
โ”œโ”€โ”€ docker-compose.yml
โ”œโ”€โ”€ Dockerfile
โ”œโ”€โ”€ package.json
โ””โ”€โ”€ tsconfig.json

Prerequisites

  • Node.js 20 or later
  • npm 9 or later (or pnpm/yarn)
  • A Linear account with an API key (Settings โ†’ API โ†’ Personal API keys)
  • Docker (optional, for containerised deployment)
  • Claude Desktop or another MCP client for end-to-end testing

Quick Start

# 1. Clone or download the template
git clone https://github.com/mcpforge/linear-mcp-server.git
cd linear-mcp-server

# 2. Install dependencies
npm install

# 3. Configure environment
cp .env.example .env
# Edit .env โ€” at minimum set LINEAR_API_KEY and MCP_API_KEY
# Generate a secure MCP_API_KEY: openssl rand -hex 32

# 4. Start in development mode (hot reload)
npm run dev

# 5. Verify the server is healthy (no API key required)
curl http://localhost:3000/health

# 6. Test the MCP endpoint (API key and Accept header required)
curl -s -X POST http://localhost:3000/mcp \
  -H "X-API-Key: <your-MCP_API_KEY>" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

# 7. Run the test suite
npm test

# 8. Build and run in production
npm run build
npm start

To connect Claude Desktop, add this to your claude_desktop_config.json:

{
  "mcpServers": {
    "linear": {
      "command": "npx",
      "args": ["mcp-remote", "http://localhost:3000/mcp"],
      "env": { "MCP_API_KEY": "your-mcp-api-key" }
    }
  }
}

Features

  • 5 Linear tools โ€” list issues, get a single issue, create an issue, list projects, list teams
  • GraphQL client with configurable retries, exponential back-off, and timeout
  • API key authentication protecting every MCP and health endpoint
  • Rate limiting โ€” configurable requests-per-minute per client IP
  • Pino structured logging with JSON output and per-request correlation IDs
  • Health endpoint that pings the Linear API and reports latency
  • Zod input validation on every tool โ€” bad inputs are rejected before they reach Linear
  • Response normalisation โ€” nested GraphQL edges/nodes flattened to clean arrays
  • Multi-stage Dockerfile producing a ~120 MB production image
  • docker-compose.yml for instant local development
  • Jest + Supertest test suite covering auth, health, and tool execution
  • Typed configuration โ€” startup fails fast if required env vars are missing

Works With

  • Claude Desktop โ€” add as an MCP server in claude_desktop_config.json
  • Claude Code โ€” use mcp add with the HTTP endpoint
  • Cursor โ€” configure under Settings โ†’ MCP Servers
  • Windsurf โ€” add to windsurf_mcp_config.json
  • Continue โ€” add as an MCP server in config.json

Configuration

VariableDescriptionRequired
LINEAR_API_KEYLinear personal or OAuth API keyโœ… Required
MCP_API_KEYSecret key MCP clients must send in x-api-key headerโœ… Required
PORTHTTP port the server listens onOptional (default: 3000)
LOG_LEVELPino log level: trace debug info warn errorOptional (default: info)
LINEAR_API_URLLinear GraphQL endpoint overrideOptional (default: https://api.linear.app/graphql)
LINEAR_MAX_RETRIESMax retry attempts for failed Linear requestsOptional (default: 3)
LINEAR_RETRY_DELAY_MSInitial retry delay in millisecondsOptional (default: 500)
LINEAR_REQUEST_TIMEOUT_MSPer-request timeout for Linear API callsOptional (default: 10000)
RATE_LIMIT_WINDOW_MSRate limit window in millisecondsOptional (default: 60000)
RATE_LIMIT_MAX_REQUESTSMax requests per window per IPOptional (default: 100)
NODE_ENVRuntime environment (development / production)Optional (default: development)

Deployment

# Build the production image
docker build -t linear-mcp-server .

# Run with environment variables
docker run -d \
  -p 3000:3000 \
  -e LINEAR_API_KEY=lin_api_xxxx \
  -e MCP_API_KEY=your-secret-key \
  --name linear-mcp \
  linear-mcp-server

docker-compose (local dev)

docker-compose up --build

Railway

npm install -g @railway/cli
railway login
railway init
railway up
# Set env vars in the Railway dashboard

Fly.io

npm install -g flyctl
fly auth login
fly launch --name linear-mcp-server
fly secrets set LINEAR_API_KEY=lin_api_xxxx MCP_API_KEY=your-secret-key
fly deploy

Production Checklist

  • LINEAR_API_KEY is a dedicated service key, not a personal developer key
  • MCP_API_KEY is at least 32 random characters (use openssl rand -hex 32)
  • NODE_ENV=production is set in the deployment environment
  • LOG_LEVEL=info or warn โ€” never trace or debug in production
  • Rate limiting values reviewed and tuned for your expected traffic
  • Docker image built from the production stage (not builder)
  • Health endpoint /health is monitored by your uptime service
  • Container restarts automatically on failure (--restart unless-stopped)
  • Secrets are injected via environment variables โ€” never baked into the image
  • LINEAR_REQUEST_TIMEOUT_MS is set to a value your clients can tolerate
  • Log output is collected by a log aggregator (Datadog, Logtail, etc.)
  • Network egress to api.linear.app is allowed from your hosting environment
  • Image is scanned for vulnerabilities before deployment (docker scout or Snyk)
  • Resource limits (CPU/memory) are set on the container

Testing

Automated tests

# Run all tests
npm test

# Watch mode during development
npm run test:watch

# With coverage report
npm run test:coverage

The test suite covers:

  • GET /health returns HTTP 200 with valid JSON
  • Auth middleware rejects missing or incorrect x-api-key with HTTP 401
  • POST /mcp with a valid tools/list call returns the registered tools
  • list_issues tool returns normalised issue objects
  • create_issue tool validates required inputs and rejects bad data

Manual testing with curl

# Health check
curl -H "x-api-key: your-mcp-api-key" http://localhost:3000/health

# List MCP tools
curl -X POST http://localhost:3000/mcp \
  -H "Content-Type: application/json" \
  -H "x-api-key: your-mcp-api-key" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

# Call list_teams tool
curl -X POST http://localhost:3000/mcp \
  -H "Content-Type: application/json" \
  -H "x-api-key: your-mcp-api-key" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"list_teams","arguments":{}}}'

โœ… Template ready. What's next?

  1. 1.Copy or download the template above
  2. 2.Deploy your MCP server (Railway, Vercel)
  3. 3.Test your deployment
  4. 4.Verify production readiness