MCP

b59.link MCP Server

Authentication

The server works without signing in at 2 requests per minute (with a small burst so a client can connect). Signed-in clients get 300 requests per minute and own the trackers and links they create.

  1. Call the auth tool with your api_key (on your profile), or with an email and then email + otp. The same flow is POST /api/auth on the REST API.
  2. Put the returned session key in your client's MCP config as an HTTP header. It lasts 30 days.
{
  "mcpServers": {
    "b59link": {
      "type": "http",
      "url": "https://b59.link/api/mcp",
      "headers": { "Authorization": "Bearer <session_key>" }
    }
  }
}

A wrong or expired key gets HTTP 401 — drop the header or sign in again. Tools return stats URLs; the stats themselves are viewed on b59.link.

Overview

b59.link exposes a Model Context Protocol (MCP) server at https://b59.link/api/mcp. Connect MCP, OpenAI, or Gemini agents to create page-view trackers, shorten links, make QR codes, and find stats pages — no sign-up needed.

Available tools

auth

Sign in for 300 requests/minute. api_key gives a session key at once; email sends a 6-digit code, then email + otp gives a session key (and signs new emails up). Send it as the Authorization header on every request.

Parameters

api_key?: string   // 256-char account key
email?: string     // to get a code
otp?: string       // the code from the email

Returns

{ otp_sent: true, email, expires_in_seconds }
// or
{
  session_key: "b59s_...",
  token_type: "Bearer",
  expires_at: string,
  email: string,
  api_key?: string   // after email + otp
}
create_tracker

Create a page-view tracker for a site. Returns the tag image URL and snippets to put on the site's pages, plus the stats URL. Owned by your account when signed in.

Parameters

site_url: string   // e.g. example.com
name?: string

Returns

{
  tracker_id: string,
  tag_url: string,       // https://b59.link/tag?<id>
  snippet_img: string,
  snippet_js: string,
  stats_url: string,
  manage_token?: string  // when not signed in
}
get_stats_url

Find the stats page for a slug, short URL, page URL, domain, tracker id or tag URL — anything tracked by a short link, QR code or tracker tag. Returns URLs, not numbers.

Parameters

identifier: string

Returns

{
  found: boolean,
  results: [{
    type: "short_link" | "page_tracker",
    stats_url: string,
    ...
  }]
}
shorten_url

Shorten a long URL. Returns a short_url and stats_url. Custom slug optional.

Parameters

url: string       // required
slug?: string    // optional custom slug

Returns

{
  slug: string,
  short_url: string,
  stats_url: string
}
generate_qr

Make a trackable QR code for a URL. Creates a short link at the same time so scans are counted.

Parameters

url: string   // required

Returns

{
  slug: string,
  short_url: string,
  stats_url: string,
  qr_code_data: string  // base64 PNG
}
make_qr_image

QR image for any text (link, Wi-Fi, email, phone) with colors, size and SVG. No short link. Returns an image block plus a permanent image URL.

Parameters

data: string
size?: number      // 64-1200, default 300
fg?: string        // hex, e.g. 000000
bg?: string        // hex, e.g. ffffff
format?: "png" | "svg"

Returns

{ image_url, format, size }
+ image content (PNG), or svg text
lookup_url

Check if a URL already has a b59 link. Handles http/https/www/trailing-slash variations.

Parameters

url: string   // required

Returns

{ found: false }
// or
{
  found: true,
  slug: string,
  short_url: string,
  stats_url: string,
  qr_code_data: string | null
}

Use with Claude (claude.ai)

In Claude's settings, add a new MCP server with the URL below. Claude will automatically discover the available tools and can call them during conversation.

https://b59.link/api/mcp

Example prompt: "Shorten https://my-long-url.com/path and give me a QR code."

Use with Claude Code (CLI)

Add b59.link as an MCP server in your ~/.claude/claude.json or via the CLI:

Via CLI

claude mcp add b59link --transport http https://b59.link/api/mcp

Or add to claude.json manually

{
  "mcpServers": {
    "b59link": {
      "type": "http",
      "url": "https://b59.link/api/mcp"
    }
  }
}

After adding, restart Claude Code. Type /mcp to verify the server is connected.

Use with OpenAI

Fetch the OpenAI-compatible function schema and pass it as the tools parameter. Route tool calls to POST /api/mcp.

import OpenAI from "openai";

const openai = new OpenAI();

// 1. Fetch tool definitions
const schemaRes = await fetch("https://b59.link/api/mcp/schema");
const { tools } = await schemaRes.json();

// 2. Call the model
const response = await openai.chat.completions.create({
  model: "gpt-4o",
  messages: [{ role: "user", content: "Shorten https://example.com/long/path" }],
  tools,
  tool_choice: "auto",
});

// 3. Execute tool calls
const msg = response.choices[0].message;
if (msg.tool_calls) {
  for (const call of msg.tool_calls) {
    const mcpRes = await fetch("https://b59.link/api/mcp", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        jsonrpc: "2.0",
        id: 1,
        method: "tools/call",
        params: {
          name: call.function.name,
          arguments: JSON.parse(call.function.arguments),
        },
      }),
    });
    const result = await mcpRes.json();
    console.log(result.result.content[0].text);
  }
}

Use with Gemini

Gemini uses the same function-calling schema as OpenAI. Fetch the schema and convert it to Gemini's FunctionDeclaration format.

import { GoogleGenerativeAI } from "@google/generative-ai";

const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY);

// Fetch and convert tool schema
const { tools: openaiTools } = await fetch("https://b59.link/api/mcp/schema").then(r => r.json());
const tools = [{
  functionDeclarations: openaiTools.map(t => ({
    name: t.function.name,
    description: t.function.description,
    parameters: t.function.parameters,
  })),
}];

const model = genAI.getGenerativeModel({ model: "gemini-1.5-pro", tools });
const chat = model.startChat();
const result = await chat.sendMessage("Shorten https://example.com for me.");

// Handle function calls
const response = result.response;
const calls = response.functionCalls();
if (calls) {
  for (const call of calls) {
    const mcpRes = await fetch("https://b59.link/api/mcp", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        jsonrpc: "2.0", id: 1,
        method: "tools/call",
        params: { name: call.name, arguments: call.args },
      }),
    });
    const toolResult = await mcpRes.json();
    console.log(toolResult.result.content[0].text);
  }
}

Raw JSON-RPC

The MCP server speaks JSON-RPC 2.0 over HTTP POST. Supported methods: initialize, tools/list, tools/call, ping. Notifications (requests without an id) get HTTP 202.

List tools

curl -X POST https://b59.link/api/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

Call a tool

curl -X POST https://b59.link/api/mcp \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <session_key>" \
  -d '{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tools/call",
    "params": {
      "name": "shorten_url",
      "arguments": {
        "url": "https://example.com/very/long/path",
        "slug": "my-link"
      }
    }
  }'