Skip to main content
Glama
iamperegrine

dub-mcp

by iamperegrine
README.md
# Dub MCP Server

A Model Context Protocol (MCP) server for [Dub](https://dub.co), the link shortening platform. This server exposes Dub's API functionality to MCP clients.

## Tools

- **create_link** - Create new short links
- **update_link** - Modify existing short links  
- **delete_link** - Delete short links
- **get_link_analytics** - Retrieve link analytics data
- **get_links** - List and search existing links

## Installation

### Prerequisites

- Node.js 18.0.0 or higher
- A Dub account with API access
- Dub API key from [app.dub.co/settings/tokens](https://app.dub.co/settings/tokens)

### Setup

1. Clone this repository:

   ```bash
   git clone <repository-url>
   cd dub-mcp
   ```

2. Install dependencies:

   ```bash
   npm install
   ```

3. Set up environment variables:

   ```bash
   cp env.template .env
   ```

   Edit `.env` and add your Dub API key:

   ```env
   DUB_API_KEY=your_actual_api_key_here
   ```

4. Build the server:

   ```bash
   npm run build
   ```

## Usage

### Running the Server

Development mode:

```bash
npm run dev
```

Production mode:

```bash
npm start
```

### MCP Client Configuration

Add this server to your MCP client configuration. For Claude Desktop:

```json
{
  "mcpServers": {
    "dub": {
      "command": "node",
      "args": ["/path/to/dub-mcp/dist/index.js"],
      "env": {
        "DUB_API_KEY": "your_api_key_here"
      }
    }
  }
}
```

## Tools Reference

### create_link

Creates a new short link.

**Parameters:**

- `url` (required): The destination URL to shorten
- `domain` (optional): Custom domain to use
- `key` (optional): Custom short link slug
- `title` (optional): Title for the link
- `tags` (optional): Array of tags to associate with the link
- `expiresAt` (optional): Expiration date in ISO 8601 format
- `password` (optional): Password to protect the link
- `publicStats` (optional): Whether to make stats public

**Example:**

```json
{
  "url": "https://example.com/my-long-url",
  "domain": "yourdomain.com",
  "key": "my-link",
  "title": "My Example Link",
  "tags": ["marketing", "campaign"],
  "publicStats": true
}
```

### update_link

Updates an existing short link. Identify the link using linkId, shortUrl, or domain+key combination.

**Parameters:**

- `linkId` (optional): The ID of the link to update
- `shortUrl` (optional): The short URL to update (e.g., "<https://dub.sh/abc123>")  
- `domain` (optional): The custom domain (for identification or update)
- `key` (optional): Custom short link slug (for identification or update)
- All other parameters from create_link are optional

**Example:**

```json
{
  "linkId": "clm2k8qr40000...",
  "url": "https://newdestination.com",
  "title": "Updated Title"
}
```

### delete_link

Deletes a short link permanently.

**Parameters:**

- `linkId` (required): The ID of the link to delete

**Example:**

```json
{
  "linkId": "clm2k8qr40000..."
}
```

### get_link_analytics

Retrieves analytics data for links.

**Parameters:**

- `event` (optional): Event type (`clicks`, `leads`, `sales`, `composite`)
- `linkId` (optional): Filter analytics for a specific link
- `domain` (optional): Filter analytics by domain
- `key` (optional): Filter by short link key (with domain)
- `interval` (optional): Time interval (`24h`, `7d`, `30d`, `90d`, `1y`, `mtd`, `qtd`, `ytd`, `all`)
- `groupBy` (optional): Group data by dimension (e.g., `countries`, `cities`, `devices`, `browsers`, `utm_sources`)
- `start`/`end` (optional): Custom date range (takes precedence over interval)
- `timezone` (optional): IANA timezone code (e.g., "America/New_York")
- `country` (optional): Filter by 2-letter country code
- `device` (optional): Filter by device type
- Additional geographic, UTM, and filtering options available
- `startDate`/`endDate` (optional): Legacy date format (YYYY-MM-DD)

**Examples:**

Get overall analytics:

```json
{
  "interval": "7d"
}
```

Get analytics for a specific link:

```json
{
  "linkId": "clm2k8qr40000...",
  "interval": "30d"
}
```

Get analytics grouped by country:

```json
{
  "groupBy": "country",
  "interval": "7d"
}
```

### get_links

List and search existing links with filtering options.

**Parameters:**

- `domain` (optional): Filter by domain
- `key` (optional): Filter by key  
- `search` (optional): Search links by URL, title, or description
- `tagId` (optional): Filter by tag ID
- `sort` (optional): Sort order (`createdAt`, `clicks`, `lastClicked`)
- `page` (optional): Page number for pagination
- `showArchived` (optional): Include archived links
- `withTags` (optional): Include tag information

**Examples:**

Search all links:

```json
{
  "search": "example"
}
```

Get links for a specific domain:

```json
{
  "domain": "dub.sh",
  "sort": "clicks"
}
```

## Configuration

### Environment Variables

- `DUB_API_KEY` (required): Your Dub API key
- `DUB_API_BASE_URL` (optional): Override the default API base URL (defaults to `https://api.dub.co`)

### Error Handling

The server handles the following error types:

- Authentication errors (invalid API key)
- Validation errors (missing or invalid parameters)
- API errors (Dub API failures)
- Network errors (connectivity issues)

All errors return descriptive messages.

## Development

### Project Structure

```
src/
├── index.ts              # Main server entry point
├── dub-client.ts         # Dub API client
└── tools/
    ├── index.ts          # Tool exports
    ├── create-link.ts    # Create link tool
    ├── update-link.ts    # Update link tool
    ├── delete-link.ts    # Delete link tool
    ├── get-links.ts      # Get links tool
    └── analytics.ts      # Analytics tool
```

### Scripts

- `npm run build` - Build TypeScript to JavaScript
- `npm run dev` - Run in development mode
- `npm run watch` - Run with auto-restart on changes
- `npm start` - Run the built server

### Dependencies

- `@modelcontextprotocol/sdk` - MCP SDK for building servers
- `axios` - HTTP client for API requests  
- `dotenv` - Environment variable loading
- `zod` - Runtime type validation

## License

MIT License - see LICENSE file for details.