npm package: @osiris-ai/linear-sdk
Description: Osiris Linear SDK
Latest version: 0.1.1

# @osiris-ai/linear-sdk

OAuth 2.0 Linear authenticator for building authenticated MCPs with Linear project management integration.

[![npm version](https://badge.fury.io/js/@osiris-ai%2Flinear-sdk.svg)](https://badge.fury.io/js/@osiris-ai%2Flinear-sdk)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

## Overview

The Linear SDK provides seamless OAuth 2.0 authentication for Linear in the [Osiris](https://docs.osirislabs.xyz) ecosystem. Build powerful MCPs (Model Context Protocol) that can interact with Linear issues, projects, teams, and workflows with enterprise-grade security and zero-configuration authentication.

**Key Features:**
- 🔐 **Zero-config OAuth** - No client credentials or setup required
- 📊 **GraphQL API** - Full access to Linear's GraphQL API
- 🏢 **Organization Support** - Multi-organization workspace access
- 🔄 **Auto Token Refresh** - Automatic token lifecycle management
- 🛡️ **Enterprise Security** - Built on Osiris Hub authentication
- 📝 **Full TypeScript** - Complete type safety and IDE support
- 🔑 **Dual Auth Modes** - Both OAuth and API key authentication

## Installation

```bash
npm install @osiris-ai/linear-sdk @osiris-ai/sdk
```

## Quick Start

### Hub Authentication (Recommended)

The Linear authenticator works automatically through the Osiris Hub - no Linear OAuth app setup required.

```typescript
import { createMcpServer, getAuthContext } from '@osiris-ai/sdk';
import { createSuccessResponse, createErrorResponse } from '../utils/types.js';
import { z } from 'zod';

await createMcpServer({
  name: 'linear-mcp',
  version: '1.0.0',
  auth: {
    useHub: true,
    hubConfig: {
      baseUrl: process.env.HUB_BASE_URL!,
      clientId: process.env.OAUTH_CLIENT_ID!,
      clientSecret: process.env.OAUTH_CLIENT_SECRET!,
    }
  },
  configure: (server) => {
    // Create Linear issue
    server.tool(
      'create_linear_issue',
      'Create a new Linear issue',
      {
        title: z.string(),
        description: z.string(),
        teamId: z.string(),
        priority: z.number().min(0).max(4).optional()
      },
      async ({ title, description, teamId, priority }) => {
        try {
          const { token, context } = getAuthContext("osiris");
          if (!token || !context) {
            return createErrorResponse("User not authenticated");
          }

          // GraphQL mutation to create issue
          const mutation = `
            mutation CreateIssue($input: IssueCreateInput!) {
              issueCreate(input: $input) {
                success
                issue {
                  id
                  title
                  url
                  identifier
                }
              }
            }
          `;

          const response = await fetch(`https://api.osirislabs.xyz/v1/hub/action/${context.deploymentId}/linear/graphql`, {
            method: 'POST',
            headers: {
              'Authorization': `Bearer ${token.access_token}`,
              'Content-Type': 'application/json'
            },
            body: JSON.stringify({
              query: mutation,
              variables: {
                input: { title, description, teamId, priority }
              }
            })
          });

          const result = await response.json();
          
          if (result.data?.issueCreate?.success) {
            const issue = result.data.issueCreate.issue;
            return createSuccessResponse('Issue created successfully', {
              issueId: issue.id,
              identifier: issue.identifier,
              url: issue.url
            });
          } else {
            return createErrorResponse('Failed to create issue');
          }
        } catch (error) {
          return createErrorResponse(error);
        }
      }
    );
  }
});
```

### Available Linear Scopes

Configure your MCP to request specific Linear permissions:

All slack scopes are supported and they all need to prefixed with `linear:`

## Local Authentication (Advanced)

For custom authentication flows or enterprise requirements:

```typescript
import { LinearAuthenticator } from '@osiris-ai/linear-sdk';
import { createMcpServer } from '@osiris-ai/sdk';

const linearAuth = new LinearAuthenticator(
  ['read', 'write', 'issues:write'],
  {
    clientId: process.env.LINEAR_CLIENT_ID!,
    clientSecret: process.env.LINEAR_CLIENT_SECRET!,
    redirectUri: 'http://localhost:3000/linear/callback',
    apiKey: process.env.LINEAR_API_KEY // Optional: for API key mode
  }
);

await createMcpServer({
  name: 'linear-mcp',
  version: '1.0.0',
  auth: {
    useHub: false,
    directAuth: {
      linear: linearAuth
    }
  },
  configure: (server) => {
    // Your Linear tools here
  }
});
```

## API Reference

### LinearAuthenticator

The main authenticator class for Linear OAuth integration.

```typescript
class LinearAuthenticator extends OAuthAuthenticator<LinearCallbackParams, LinearTokenResponse>
```

#### Constructor

```typescript
new LinearAuthenticator(allowedScopes: string[], config: LinearAuthenticatorConfig)
```

**Parameters:**
- `allowedScopes`: Array of Linear OAuth scopes your MCP requires
- `config`: Linear OAuth application configuration

#### Methods

##### `getAuthenticationURL(scopes: string[], options: AuthenticationURLOptions): string`

Generate Linear OAuth authorization URL with actor support.

##### `callback(params: LinearCallbackParams): Promise<LinearTokenResponse>`

Handle OAuth callback and exchange code for tokens.

##### `refreshToken(refreshToken: string): Promise<LinearTokenResponse>`

Refresh an expired access token.

##### `getUserInfo(accessToken: string): Promise<LinearUserInfo>`

Get authenticated user information via GraphQL.

##### `action(params: ActionParams, accessToken: string, refreshToken?: string): Promise<ActionResponse>`

Execute Linear GraphQL operations with automatic token refresh.

## Error Handling

The Linear authenticator provides robust error handling with automatic retries and detailed error messages:

```typescript
server.tool('resilient_linear_tool', 'Linear tool with error handling', schema, async (params) => {
  try {
    const { token, context } = getAuthContext("osiris");
    if (!token || !context) {
      return createErrorResponse("🔐 Please connect your Linear account first");
    }

    const query = `
      query {
        viewer {
          id
          name
          organization {
            name
          }
        }
      }
    `;

    const response = await fetch(`https://api.osirislabs.xyz/v1/hub/action/${context.deploymentId}/linear/graphql`, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${token.access_token}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ query })
    });

    if (!response.ok) {
      if (response.status === 401) {
        return createErrorResponse("❌ Linear authentication expired. Please reconnect your account.");
      }
      if (response.status === 403) {
        return createErrorResponse("❌ Insufficient Linear permissions. Please grant additional scopes.");
      }
      return createErrorResponse(`Linear API error: ${response.statusText}`);
    }

    const result = await response.json();
    if (result.errors) {
      return createErrorResponse(`GraphQL errors: ${result.errors.map(e => e.message).join(', ')}`);
    }

    return createSuccessResponse('Linear data retrieved', result.data);
  } catch (error: any) {
    return createErrorResponse(`Linear error: ${error.message}`);
  }
});
```

## Getting Started

1. **Install the Osiris CLI:**
   ```bash
   npm install -g @osiris-ai/cli
   ```

2. **Set up authentication:**
   ```bash
   npx @osiris-ai/cli register
   npx @osiris-ai/cli create-client
   npx @osiris-ai/cli connect-auth
   ```

3. **Create your Linear MCP:**
   ```bash
   npx @osiris-ai/cli create-mcp my-linear-mcp
   ```

4. **Add Linear integration:**
   ```bash
   npm install @osiris-ai/linear-sdk
   ```

## Contributing

We welcome contributions! Please see our [Contributing Guide](https://github.com/fetcchx/osiris-ai/blob/main/CONTRIBUTING.md) for details.

## Support

- **Documentation:** [https://docs.osirislabs.xyz](https://docs.osirislabs.xyz)
- **GitHub Issues:** [https://github.com/fetcchx/osiris-ai/issues](https://github.com/fetcchx/osiris-ai/issues)
- **Discord Community:** [Join our Discord](https://discord.osirislabs.xyz)

## License

MIT License - see [LICENSE](LICENSE) file for details.

---

Built with ❤️ by the [Osiris Labs](https://osirislabs.xyz) team.