Linear MCP Server
by cpropster
- scripts
import { LinearAuth } from '../src/auth.js';
import { config } from 'dotenv';
import express from 'express';
import open from 'open';
// Load environment variables
config();
async function main() {
// Check if we're using PAT or OAuth
if (process.env.LINEAR_ACCESS_TOKEN) {
await testPat();
} else if (process.env.LINEAR_CLIENT_ID && process.env.LINEAR_CLIENT_SECRET && process.env.LINEAR_REDIRECT_URI) {
await testOAuth();
} else {
console.error('ERROR: Either LINEAR_ACCESS_TOKEN or OAuth credentials (LINEAR_CLIENT_ID, LINEAR_CLIENT_SECRET, LINEAR_REDIRECT_URI) are required');
process.exit(1);
}
}
async function testPat() {
const auth = new LinearAuth();
auth.initialize({
type: 'pat',
accessToken: process.env.LINEAR_ACCESS_TOKEN!
});
try {
const client = auth.getClient();
const viewer = await client.viewer;
console.log('\nPAT Authentication successful!');
console.log(`Connected as: ${viewer.name} (${viewer.email})`);
console.log('\nTest Credentials:\n');
console.log(`LINEAR_ACCESS_TOKEN=${process.env.LINEAR_ACCESS_TOKEN}`);
} catch (error) {
console.error('Authentication failed:', error);
process.exit(1);
}
}
async function testOAuth() {
const app = express();
const port = 3000;
const auth = new LinearAuth();
auth.initialize({
type: 'oauth',
clientId: process.env.LINEAR_CLIENT_ID!,
clientSecret: process.env.LINEAR_CLIENT_SECRET!,
redirectUri: process.env.LINEAR_REDIRECT_URI!
});
// Handle OAuth callback
app.get('/callback', async (req, res) => {
const { code, error } = req.query;
if (error) {
console.error('OAuth error:', error);
res.send('Authentication failed. Check console for details.');
return;
}
if (!code || typeof code !== 'string') {
console.error('No authorization code received');
res.send('No authorization code received');
return;
}
try {
// Exchange code for tokens
await auth.handleCallback(code);
// Get user info to verify authentication
const client = auth.getClient();
const viewer = await client.viewer;
console.log('\nOAuth Authentication successful!');
console.log(`Connected as: ${viewer.name} (${viewer.email})`);
console.log('\nTest Credentials:\n');
console.log(`LINEAR_AUTH_CODE=${code}`);
console.log(`LINEAR_REDIRECT_URI=${process.env.LINEAR_REDIRECT_URI}`);
// Get refresh token from auth instance
const tokenData = (auth as any).tokenData;
if (tokenData?.refreshToken) {
console.log(`LINEAR_REFRESH_TOKEN=${tokenData.refreshToken}`);
}
res.send('Authentication successful! Check console for test credentials.');
} catch (error) {
console.error('Token exchange failed:', error);
res.send('Token exchange failed. Check console for details.');
}
});
// Start server and open auth URL
const server = app.listen(port, () => {
console.log(`\nStarting OAuth flow...\n`);
// Get and open authorization URL
const authUrl = auth.getAuthorizationUrl();
console.log(`Opening: ${authUrl}\n`);
open(authUrl);
});
// Handle server cleanup
process.on('SIGINT', () => {
server.close();
process.exit();
});
}
main().catch((error) => {
console.error('Error:', error);
process.exit(1);
});