# Goshort

> Self-hosted URL shortener in Go — single binary, SQLite-backed, zero config. Custom aliases, expiration, CLI, Redis cache, MCP server for AI agents (Claude Code, Cursor). Deploy anywhere: Docker, Fly.io, bare VPS.

- **Type:** MCP server
- **Install:** `agentstack add mcp-anicedantfa-goshort`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [anIcedAntFA](https://agentstack.voostack.com/s/anicedantfa)
- **Installs:** 0
- **Category:** [Databases](https://agentstack.voostack.com/c/databases)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [anIcedAntFA](https://github.com/anIcedAntFA)
- **Source:** https://github.com/anIcedAntFA/goshort
- **Website:** https://goshort.app/

## Install

```sh
agentstack add mcp-anicedantfa-goshort
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

🔗 GoShort

  Self-hosted URL shortener — single binary, SQLite-backed, zero config to start.

  Turn long URLs into short, shareable links with click tracking, custom aliases, and AI agent integration.

[](https://github.com/anIcedAntFA/goshort/actions/workflows/ci.yml)
[](https://www.bestpractices.dev/projects/12838)
[](https://github.com/anIcedAntFA/goshort/actions/workflows/govulncheck.yml)
[](https://codecov.io/gh/anIcedAntFA/goshort)
[](https://goreportcard.com/report/github.com/anIcedAntFA/goshort)
[](https://github.com/anIcedAntFA/goshort/releases/latest)

[](LICENSE)
[](go.mod)
[](https://goshort.ngockhoi96.dev)
[](https://goshort.app/docs)
[](https://ko-fi.com/anIcedAntFA)

---

## ✨ Features

- **Zero-collision codes** — atomic SQLite counter + [Sqids](https://sqids.org): non-sequential, bijective, no retry loops
- **Custom aliases** — bring your own slug (`/my-link`); charset isolation prevents collision with generated codes
- **URL expiration** — configurable TTL with lazy expiry on read + hourly background cleanup; update expiry via `PATCH`
- **Batch creation** — `POST /api/v1/urls/batch` accepts up to 100 URLs; per-item success/failure
- **QR codes** — `GET /api/v1/urls/{code}/qr?format=png|jpeg|svg` returns a QR code for any short link in three formats
- **Link previews** — `title` and `description` auto-fetched on create (fail-open, private-IP blocked)
- **Spam detection** — optional Google Safe Browsing v4 integration; unsafe URLs rejected with 422 (fail-open)
- **Switchable cache** — `none | memory | redis` at config time; cache-aside with TTL capped to remaining expiry
- **API key auth** — constant-time comparison; per-IP token bucket rate limiting
- **CLI client** — `goshort-cli` for shorten, list, stats, delete from the terminal
- **Public shorten endpoint** — `POST /api/v1/urls/public`: no auth, 5 req/min rate limit, 30-day expiry; powers the landing page widget
- **Landing page** — [goshort.ngockhoi96.dev](https://goshort.ngockhoi96.dev): Astro static site on Cloudflare Workers with live shorten widget
- **MCP server** — AI agents (Claude Code, Cursor) can shorten, list, and manage URLs via [Model Context Protocol](https://modelcontextprotocol.io)
- **Prometheus metrics + structured logs** — `/metrics` endpoint, `slog` throughout, no extra dependencies
- **Self-documenting API** — OpenAPI 3.1 spec + interactive Scalar UI at `/docs`

---

## 🏗️ Architecture

Full architecture diagrams: [high-level](docs/sys-arch.png), [request flow](docs/request-flow.excalidraw), [layer boundaries](docs/layers.excalidraw).

---

## 🛠️ Tech Stack

| Component      | Technology                                                    |
|----------------|---------------------------------------------------------------|
| Language       | Go 1.26                                                       |
| HTTP           | [Chi](https://go-chi.io) v5                                   |
| Database       | SQLite via [sqlc](https://sqlc.dev) (pure Go, no CGO)         |
| Encoding       | [Sqids](https://sqids.org) (zero-collision, non-sequential)   |
| CLI            | [Cobra](https://cobra.dev)                                    |
| Config         | [Koanf](https://github.com/knadh/koanf) v2 (TOML + env vars) |
| Cache          | [go-redis](https://github.com/redis/go-redis) v9              |
| Metrics        | [Prometheus](https://github.com/prometheus/prometheus)        |
| Rate Limit     | [rate](https://pkg.go.dev/golang.org/x/time/rate) (token bucket) |
| MCP            | [go-sdk](https://github.com/modelcontextprotocol/go-sdk) v1.6 (official) |
| Migrations     | [goose](https://github.com/pressly/goose) v3 (embedded FS, versioned SQL) |
| QR codes       | [go-qrcode](https://github.com/skip2/go-qrcode) |
| Spam detection | Google Safe Browsing Lookup API v4 (optional, fail-open) |
| Reverse Proxy  | [Caddy](https://github.com/caddyserver/caddy) (Docker Compose) |
| Release        | [GoReleaser](https://github.com/goreleaser/goreleaser) + [GitHub Actions](https://github.com/features/actions) |
| Website        | [Astro](https://astro.build) v6, Tailwind CSS v4, [Biome](https://biomejs.dev) v2, Bun, Cloudflare Workers |

---

## 🚀 Quick Start

### a. Docker Compose (recommended)

```bash
curl -O https://raw.githubusercontent.com/anIcedAntFA/goshort/main/docker-compose.yml
curl -O https://raw.githubusercontent.com/anIcedAntFA/goshort/main/goshort.toml
docker compose up -d
```

Caddy handles TLS automatically. Edit `goshort.toml` to set your `base_url` and `api_key`.

### b. Binary (GitHub Releases)

```bash
curl -L https://github.com/anIcedAntFA/goshort/releases/latest/download/goshort_linux_amd64.tar.gz | tar xz
./goshort
```

Grab `goshort_darwin_arm64`, `goshort_windows_amd64`, etc. from the [releases page](https://github.com/anIcedAntFA/goshort/releases).

### c. go install

```bash
go install github.com/anIcedAntFA/goshort/cmd/server@latest
goshort
```

---

## 📡 Usage

**Create a short URL:**

```bash
curl -s -X POST http://localhost:8080/api/v1/urls \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-api-key" \
  -d '{"url": "https://example.com/very/long/path", "expires_in": "30d"}'
```

```json
{
  "short_code": "k7Xm2p",
  "short_url":  "http://localhost:8080/k7Xm2p",
  "original_url": "https://example.com/very/long/path",
  "expires_at": "2025-08-01T00:00:00Z"
}
```

**Redirect:**

```bash
curl -L http://localhost:8080/k7Xm2p
# → 302 to https://example.com/very/long/path
```

---

## 💻 CLI

```bash
# Install
go install github.com/anIcedAntFA/goshort/cmd/cli@latest

# Shorten a URL
goshort-cli shorten https://example.com/long --alias my-link --expires 7d

# List all URLs (paginated)
goshort-cli list --page 1 --per-page 20

# Inspect a short code or alias
goshort-cli stats k7Xm2p

# Delete a short URL
goshort-cli delete k7Xm2p
```

Config file (`~/.goshort.toml`):

```toml
server_url = "http://localhost:8080"
api_key    = "your-api-key"
```

Per-command overrides (precedence: flag > env > config):

| Flag         | Env var              |
|--------------|----------------------|
| `--server`   | `GOSHORT_SERVER_URL` |
| `--api-key`  | `GOSHORT_API_KEY`    |
| `--json`     | —                    |

---

## 🤖 MCP (AI Agent Integration)

GoShort ships an [MCP](https://modelcontextprotocol.io) server so AI agents like Claude Code and Cursor can shorten, list, and manage URLs directly.

### Local — stdio

```bash
make build
```

Create `.mcp.json` in your project root:

```json
{
  "mcpServers": {
    "goshort": {
      "command": "./bin/goshort",
      "args": ["--mcp"],
      "env": { "GOSHORT_STORAGE_SQLITE_PATH": "./data/goshort.db" }
    }
  }
}
```

### Remote — Streamable HTTP

The `/mcp` endpoint is served on the main port alongside the REST API. No separate server needed.

```bash
# Connect Claude Code to deployed instance
claude mcp add goshort-remote \
  --transport http \
  https://goshort.app/mcp \
  --header "X-API-Key: your-api-key"
```

### Tools

| Tool | Description |
|------|-------------|
| `shorten_url` | Create a short URL (alias + expiry optional) |
| `batch_shorten_urls` | Create up to 100 short URLs in one call |
| `list_urls` | List URLs with pagination |
| `get_url_stats` | Click count and full details for a URL |
| `delete_url` | Delete a short URL |
| `lookup_url` | Resolve a short code to its original URL |
| `update_url` | Update the expiry of an existing short URL |

### Resources

| URI | Description |
|-----|-------------|
| `goshort://stats/summary` | Total URL count and top URLs by clicks |
| `goshort://urls/{code}` | Full details for a specific short code |
| `goshort://urls/{code}/qr` | QR code blob for a short URL (PNG/JPEG/SVG via `?format=`) |

### Prompts

| Prompt | Description |
|--------|-------------|
| `shorten_and_share` | Shorten + format for sharing (platform-aware) |
| `batch_shorten` | Shorten multiple URLs and return a table |

---

## ⚙️ Configuration

```toml
[server]
port     = 8080
base_url = "https://short.yourdomain.com"

[auth]
api_key = "your-secret-key"   # empty = no auth

[cache]
driver = "none"               # none | memory | redis

[shortener]
default_expiry = "0"          # "0" = no expiry; or "7d", "30d", "365d"
```

Every key maps to `GOSHORT__` env var — e.g., `GOSHORT_AUTH_API_KEY=secret`. Full reference: [`goshort.toml`](goshort.toml).

---

## 📋 API

| Method   | Path                       | Auth | Description              |
|----------|----------------------------|------|--------------------------|
| `POST`   | `/api/v1/urls`             | Yes  | Create short URL         |
| `POST`   | `/api/v1/urls/batch`       | Yes  | Create up to 100 URLs    |
| `GET`    | `/api/v1/urls`             | Yes  | List URLs (paginated)    |
| `GET`    | `/api/v1/urls/:code`       | Yes  | Get URL details          |
| `PATCH`  | `/api/v1/urls/:code`       | Yes  | Update URL expiry        |
| `DELETE` | `/api/v1/urls/:code`       | Yes  | Delete short URL         |
| `POST`   | `/api/v1/urls/public`      | No   | Public shorten (30d TTL) |
| `GET`    | `/api/v1/urls/:code/qr`    | No   | QR code (PNG/JPEG/SVG)   |
| `GET`    | `/:code`                   | No   | Redirect (302)           |
| `GET`    | `/health`                  | No   | Health check             |
| `GET`    | `/metrics`                 | No   | Prometheus metrics       |
| `GET`    | `/docs`                    | No   | Interactive API docs     |
| `POST`   | `/mcp`                     | Yes  | MCP Streamable HTTP      |

**Auth:** `X-API-Key: ` header. **Redirect codes:** `302 Found`, `404 Not Found`, `410 Gone` (expired).

**POST `/api/v1/urls` body:**

| Field          | Type   | Required | Notes                                      |
|----------------|--------|----------|--------------------------------------------|
| `url`          | string | Yes      | Max 2048 chars                             |
| `custom_alias` | string | No       | `^[a-zA-Z0-9-]{3,30}$`                     |
| `expires_in`   | string | No       | `1h`, `7d`, `30d`, `90d`, `365d`, `never`  |

Interactive docs at [goshort.app/docs](https://goshort.app/docs). Landing page at [goshort.ngockhoi96.dev](https://goshort.ngockhoi96.dev).

---

## 📁 Project Structure

See [`docs/DESIGN.md`](docs/DESIGN.md) for the full architecture, layer boundaries, and design rationale.

---

## 🧑‍💻 Development

```bash
git clone https://github.com/anIcedAntFA/goshort
cd goshort
lefthook install        # install git hooks (once after clone)
make help               # list all targets
```

Run `make help` for the full list of targets. See [CONTRIBUTING.md](CONTRIBUTING.md) for the full development workflow including Redis integration tests and git hooks.

---

## 🚢 Deployment

See [`docs/DEPLOYMENT.md`](docs/DEPLOYMENT.md) for comprehensive guides.

**Docker Compose** — GoShort + Caddy (auto-TLS):

```bash
docker compose up -d
```

**Fly.io** — API + redirects + MCP at [goshort.app](https://goshort.app):

```bash
fly launch && fly deploy
```

**Landing page** — [goshort.ngockhoi96.dev](https://goshort.ngockhoi96.dev) (Cloudflare Workers, static Astro build):

```bash
make website/build && cd website && wrangler deploy
```

**Bare VPS** — Nginx + systemd + Certbot (see DEPLOYMENT.md)

---

## 🗺️ Roadmap

| Phase | Focus                                           | Status             |
|-------|-------------------------------------------------|--------------------|
| 1     | Core library — SQLite, sqlc, Sqids, TDD         | ✅ v0.1.0          |
| 2     | HTTP API, caching, config, Prometheus           | ✅ v0.2.0          |
| 3     | Auth, rate limiting, CLI, Docker, release infra | ✅ v0.3.0          |
| 3.5   | Deploy — Fly.io + Cloudflare CDN                | ✅ [goshort.app](https://goshort.app) |
| 4     | MCP server — Claude / Cursor integration        | ✅ v0.4.0          |
| 5     | Batch, QR codes, link previews, spam detection  | ✅ v0.5.0          |
| 6     | Landing page (Cloudflare Workers), public endpoint | ✅ v0.6.0       |
| 7+    | Analytics, PostgreSQL, Redis counter            | 🔲                 |

Each phase ships a working, deployable product.

---

## ⭐ Star History

[](https://star-history.com/#anIcedAntFA/goshort&Date)

---

## 📄 License

MIT — see [LICENSE](LICENSE).

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [anIcedAntFA](https://github.com/anIcedAntFA)
- **Source:** [anIcedAntFA/goshort](https://github.com/anIcedAntFA/goshort)
- **License:** MIT
- **Homepage:** https://goshort.app/

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-anicedantfa-goshort
- Seller: https://agentstack.voostack.com/s/anicedantfa
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
