Templatetypescriptnextjsbeginnerโœ“ Production ReadyFreeโœ… Code Verified

Connect Linear MCP Server to Claude Code

This recipe walks you through connecting a hosted Linear MCP Server to Claude Code, configuring API key authentication, and executing Linear project management tools directly from your AI assistant. Ideal for developers and teams who want to manage Linear issues, projects, and workflows without leaving their coding environment.

๐Ÿ“– 12 min readโš™๏ธ Setup: 25 minutesutilities
linearmcpclaude codetypescripthttpapiclaude-codenextjsproject-managementapi-integrationbeginner

Files(12)

# Linear MCP Server Environment Variables
# Copy this file to .env.local and fill in your values
# NEVER commit .env.local to version control

# Your Linear personal API key
# Get it from: Linear โ†’ Settings โ†’ API โ†’ Personal API Keys
LINEAR_API_KEY=lin_api_xxxxxxxxxxxxxxxxxxxx

# A secure random token to protect your MCP endpoint
# Generate with: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
MCP_AUTH_TOKEN=your_secure_random_token_here

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.

Overview

Linear is a modern project management tool built for software teams, and by connecting it to Claude Code via the Model Context Protocol (MCP), you can interact with your Linear workspace directly from your AI-powered coding environment. This recipe guides you through deploying a Linear MCP Server built with TypeScript and Next.js, configuring secure API key authentication, and wiring everything up to Claude Code.

Once connected, Claude Code gains the ability to create issues, list projects, update ticket statuses, and query your Linear workspace โ€” all without you switching tabs or breaking your development flow. This is especially useful during sprint planning, bug triage, or when you want to log a task while reviewing code.

This recipe is aimed at beginner-to-intermediate developers who are comfortable with TypeScript and Next.js but may be new to MCP servers. By the end, you will have a fully operational Linear MCP Server running locally or on a hosted platform, connected and authenticated with Claude Code.

What You'll Deploy

  • A Next.js TypeScript application exposing a /api/mcp endpoint that implements the MCP JSON-RPC protocol directly with NextRequest/NextResponse โ€” no MCP SDK dependency required
  • A Linear API integration using the official @linear/sdk for querying and mutating workspace data
  • API key middleware (constant-time comparison) for securing your MCP server endpoint
  • A Claude Code MCP configuration entry pointing to your deployed server
  • Five tool definitions: linear_list_issues, linear_create_issue, linear_update_issue, linear_list_projects, and linear_get_issue

Prerequisites

  • Node.js 20.9 or later and npm (Next.js 16 requires Node โ‰ฅ20.9; Node 18 is no longer supported)
  • A Linear account with API access (free or paid tier)
  • Claude Code installed and working on your machine
  • A Vercel account (or any hosting platform that supports Next.js) for deployment, or the ability to run the server locally
  • Basic familiarity with TypeScript and Next.js App Router
  • curl or a REST client like Postman for testing endpoints

Steps

Step 1: Set Up the Linear MCP Server Project

This recipe ships as a minimal Next.js App Router project โ€” deliberately smaller than what create-next-app scaffolds, since an MCP server needs no pages, styling, or client-side routing, just the two API routes.

Create the project structure:

mkdir linear-mcp-server && cd linear-mcp-server
mkdir -p app/api/mcp app/api/health scripts

Add a package.json:

{
  "name": "linear-mcp-server",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "eslint .",
    "typecheck": "tsc --noEmit"
  },
  "dependencies": {
    "@linear/sdk": "87.0.0",
    "next": "16.2.9",
    "react": "19.2.7",
    "react-dom": "19.2.7",
    "zod": "4.4.3"
  },
  "devDependencies": {
    "@types/node": "22.10.5",
    "@types/react": "19.0.2",
    "@types/react-dom": "19.0.2",
    "eslint": "9.17.0",
    "eslint-config-next": "16.2.9",
    "typescript": "5.7.2"
  },
  "engines": {
    "node": ">=20.0.0"
  }
}

Why no @modelcontextprotocol/sdk? The MCP protocol is just JSON-RPC 2.0 over HTTP. app/api/mcp/route.ts implements initialize, tools/list, and tools/call directly, which keeps the server dependency-light and avoids pinning to a specific SDK release. If you'd rather build on the official SDK, see the MCP TypeScript SDK docs โ€” the wire format is the same either way.

Add a tsconfig.json, a minimal app/layout.tsx (the App Router will not build without a root layout, even for an API-only project), and an eslint.config.mjs:

// next.config.ts
import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  poweredByHeader: false,
};

export default nextConfig;
// app/layout.tsx
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  );
}
// eslint.config.mjs
import nextPlugin from 'eslint-config-next';

export default [...nextPlugin, { ignores: ['.next/**', 'node_modules/**'] }];

Note: the next lint subcommand was removed from the Next.js CLI in Next.js 16. The lint script above calls eslint . directly against a flat config built from eslint-config-next, which is the current supported approach.

Now install dependencies:

npm install

Create the core MCP handler at app/api/mcp/route.ts and the health check at app/api/health/route.ts. Both files are provided in full with this recipe โ€” copy them in as-is.

To run the server locally for development:

npm run dev
# Server is now running at http://localhost:3000
# MCP endpoint available at http://localhost:3000/api/mcp

Before deploying, confirm everything is clean:

npm run typecheck
npm run lint
npm run build

To deploy to Vercel:

npm install -g vercel
vercel deploy --prod
# Note the deployment URL, e.g. https://linear-mcp-server.vercel.app

Step 2: Configure API Key Authentication

Never expose your MCP server without authentication. This recipe uses a simple bearer-token middleware pattern, compared with crypto.timingSafeEqual to avoid timing attacks, to protect the /api/mcp endpoint.

First, generate a secure random API key:

node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
# Example output: a3f8c2d1e4b5a6f7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1

Copy .env.local.example to .env.local and fill in your credentials:

# .env.local
LINEAR_API_KEY=lin_api_xxxxxxxxxxxxxxxxxxxx
MCP_AUTH_TOKEN=a3f8c2d1e4b5a6f7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1

To get your Linear API key, go to Linear โ†’ Settings โ†’ API โ†’ Personal API Keys and create a new key with appropriate scopes (read and write for issues and projects).

If you are deploying to Vercel, add these environment variables through the Vercel dashboard or CLI:

vercel env add LINEAR_API_KEY production
vercel env add MCP_AUTH_TOKEN production
vercel deploy --prod

Verify the authentication is working by making a test request:

# This should return 401
curl -X POST https://your-deployment.vercel.app/api/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

# This should return the tools list
curl -X POST https://your-deployment.vercel.app/api/mcp \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer a3f8c2d1e4b5a6f7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Or use the included smoke-test script, which runs both checks plus initialize and tools/list in one pass:

chmod +x scripts/test-mcp.sh
./scripts/test-mcp.sh https://your-deployment.vercel.app a3f8c2d1e4b5a6f7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1

Step 3: Add the MCP Server to Claude Code

Claude Code manages MCP servers through the claude mcp CLI rather than a single settings file you hand-edit. Where the configuration lands depends on the scope you choose:

ScopeLoads inShared with teamStored in
Local (default)current project onlyNo~/.claude.json
Projectcurrent project onlyYes, via git.mcp.json in project root
Userall your projectsNo~/.claude.json

The fastest path is the CLI:

claude mcp add --transport http linear \
  https://your-deployment.vercel.app/api/mcp \
  --header "Authorization: Bearer YOUR_MCP_AUTH_TOKEN"

For local development, point at localhost instead:

claude mcp add --transport http linear \
  http://localhost:3000/api/mcp \
  --header "Authorization: Bearer YOUR_MCP_AUTH_TOKEN"

If you'd rather share the server with your whole team via version control, add --scope project. This writes (or updates) a .mcp.json file at your project root:

claude mcp add --transport http linear \
  https://your-deployment.vercel.app/api/mcp \
  --header "Authorization: Bearer YOUR_MCP_AUTH_TOKEN" \
  --scope project

claude-mcp-settings.json, included with this recipe, is already formatted as a drop-in .mcp.json:

{
  "mcpServers": {
    "linear": {
      "type": "http",
      "url": "https://YOUR_DEPLOYMENT_URL.vercel.app/api/mcp",
      "headers": {
        "Authorization": "Bearer YOUR_MCP_AUTH_TOKEN"
      }
    }
  }
}

Fill in your real deployment URL and token, then either paste this into .mcp.json at your project root (project scope, checked into git) or feed it to claude mcp add-json linear '<paste JSON here>' to register it without hand-editing any file.

Project-scoped servers require a one-time approval the first time Claude Code loads them in a workspace โ€” confirm it interactively when prompted. Verify the server is registered:

claude mcp list
claude mcp get linear

Step 4: Verify Available Tools

With Claude Code running and connected to your Linear MCP server, verify that tool discovery works correctly. Inside a Claude Code session, run:

/mcp

You should see linear listed as connected, with a tool count next to it. You can also just ask Claude Code directly:

What Linear tools do you have available?

Claude Code should respond with a list of tools similar to:

I have access to the following Linear tools:
- linear_list_issues: List issues from your Linear workspace
- linear_create_issue: Create a new issue in a Linear project
- linear_update_issue: Update the status or properties of an existing issue
- linear_list_projects: List all projects in your Linear workspace
- linear_get_issue: Get details about a specific Linear issue

You can also verify directly via the MCP protocol using curl:

curl -X POST https://your-deployment.vercel.app/api/mcp \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_MCP_AUTH_TOKEN" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/list",
    "params": {}
  }'

Expected response structure:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": [
      {
        "name": "linear_list_issues",
        "description": "List issues from your Linear workspace. Optionally filter by team ID and limit the number of results.",
        "inputSchema": {
          "type": "object",
          "properties": {
            "teamId": { "type": "string" },
            "limit": { "type": "number" }
          }
        }
      }
    ]
  }
}

If you see an empty tools array or an error, revisit Steps 1 and 2 before continuing.

Step 5: Execute a Linear Issue Command

Now that tools are verified, execute real Linear commands through Claude Code. Try these example prompts:

List recent issues:

Show me the 5 most recent issues in my Linear workspace

Create a new issue:

Create a Linear issue titled "Fix authentication timeout bug" in the Backend project 
with high priority

Update an issue status:

Mark Linear issue LIN-142 as "In Progress"

You can also invoke tools directly via curl to verify the underlying API calls work:

# Create an issue directly
curl -X POST https://your-deployment.vercel.app/api/mcp \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_MCP_AUTH_TOKEN" \
  -d '{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tools/call",
    "params": {
      "name": "linear_create_issue",
      "arguments": {
        "title": "Test issue from MCP server",
        "description": "This issue was created via the Linear MCP Server integration",
        "teamId": "YOUR_LINEAR_TEAM_ID"
      }
    }
  }'

A successful response will include the created issue ID and URL:

{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "Issue created successfully: LIN-247 - Test issue from MCP server\nhttps://linear.app/your-team/issue/LIN-247"
      }
    ]
  }
}

Step 6: Troubleshoot Common Connection Problems

Problem: Claude Code shows no Linear tools

Check server status from inside a session, or list registered servers from the shell:

claude mcp list
claude mcp get linear

Inside Claude Code, /mcp shows live connection status and the tool count for each server. If you edited .mcp.json or ~/.claude.json by hand, validate the JSON first:

node -e "JSON.parse(require('fs').readFileSync('.mcp.json', 'utf8')); console.log('Valid JSON')"

Problem: 401 Unauthorized errors

Verify the token in your Claude Code config exactly matches the one in your server's environment:

# Check if env var is set on Vercel
vercel env ls production

# Test auth manually
curl -v -X POST https://your-deployment.vercel.app/api/mcp \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

Problem: Linear API errors (403 or rate limits)

Verify your Linear API key has the correct scopes:

# Test your Linear API key directly
curl -X POST https://api.linear.app/graphql \
  -H "Authorization: YOUR_LINEAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query": "{ viewer { id name } }"}'

Problem: Server cold starts causing timeouts

Vercel serverless functions can experience cold starts. Add a keep-alive ping or upgrade to a paid plan with warmed instances. For local development, this is never an issue.

# This recipe already ships a health check endpoint โ€” confirm the server is warm:
curl https://your-deployment.vercel.app/api/health

Production Checklist

  • MCP_AUTH_TOKEN is at least 32 bytes of cryptographically random data
  • LINEAR_API_KEY is stored only in environment variables, never committed to git
  • .env.local is listed in .gitignore
  • The /api/mcp endpoint returns 401 for requests without a valid Authorization header
  • All Linear tool inputs are validated with Zod before being passed to the Linear SDK
  • Error responses from Linear API are caught and returned as structured MCP errors, not raw stack traces
  • npm run typecheck, npm run lint, and npm run build all pass before every deploy
  • Rate limiting or request throttling is in place to prevent Linear API quota exhaustion
  • The server logs are monitored and connected to an alerting service (e.g., Vercel logs, Datadog)
  • You have tested all five tools (list issues, create issue, update issue, list projects, get issue) end-to-end
  • Your Claude Code MCP configuration (.mcp.json or CLI-registered entry) is backed up or stored in a dotfiles/team repository
  • The Linear API key used has the minimum required scopes (not a super-admin key)
  • You have documented the MCP server URL and auth method in your team's internal runbook

Common Mistakes

1. Committing secrets to version control The most dangerous mistake is accidentally committing your LINEAR_API_KEY or MCP_AUTH_TOKEN to git. Always add .env.local to .gitignore before your first commit, and use a secret scanning tool like git-secrets or GitHub's built-in secret scanning.

2. Using an incorrect Authorization header format The header must be Authorization: Bearer YOUR_TOKEN โ€” not Authorization: YOUR_TOKEN and not X-API-Key: YOUR_TOKEN. The MCP server middleware must match whatever format you configure. Mismatches between the Claude Code config headers and the server middleware are a very common source of 401 errors.

3. Assuming next lint still exists Next.js 16 removed the next lint CLI subcommand. If you're following older tutorials or scaffolding with an old create-next-app template, your lint script will fail with "Invalid project directory provided." Call ESLint directly (eslint .) against a flat eslint.config.mjs, as shown in Step 1.

4. Using a Linear API key with insufficient scopes If your Linear API key only has read permissions, write operations like linear_create_issue and linear_update_issue will silently fail or return cryptic errors. Always verify your key's scopes in the Linear settings panel before integrating.

5. Not handling Linear team IDs correctly Many Linear API operations require a teamId. This is not the same as the team name or slug โ€” it is a UUID. You can retrieve it by calling the linear_list_projects tool first, or by querying the Linear API directly with { teams { nodes { id name } } }. Note also that the Linear SDK's ProjectFilter type does not have a teams field โ€” team-scoped project filters use accessibleTeams: { some: { id: { eq: teamId } } } }. Guessing the field name here is a common source of TypeScript build errors.

6. Forgetting that Claude Code needs a fresh reconnect after config edits If you hand-edit .mcp.json or ~/.claude.json while Claude Code is running, run /mcp inside the session (or restart Claude Code) to pick up the change โ€” it doesn't hot-reload config file edits mid-session the way CLI commands like claude mcp add do.

Key Takeaways

  • You deployed a Next.js TypeScript MCP server that exposes Linear project management capabilities as structured tools consumable by Claude Code, without depending on the MCP TypeScript SDK
  • API key authentication using the Authorization: Bearer pattern keeps your MCP endpoint secure without complex OAuth flows
  • Claude Code discovers tools automatically via the MCP tools/list protocol method โ€” no manual registration required once the server is added
  • The claude mcp add --transport http CLI command is the recommended way to register a server; hand-editing .mcp.json or ~/.claude.json works too, but requires a manual reconnect
  • The MCP protocol uses JSON-RPC 2.0 under the hood, making it easy to test and debug with standard HTTP tools like curl
  • Once connected, Claude Code can create, update, and query Linear issues in natural language, turning your AI assistant into a fully integrated project management interface nextjs typescript utilities linear mcp claude code typescript http api claude-code nextjs project-management api-integration beginner

โœ… 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