Skill: picseeinc/picsee-short-link (version 3.0.0)

--- name: picsee-short-link description: PicSee URL shortener via MCP — shorten URLs, generate QR codes, view rich click analytics (daily / platform / referrer / region / audience), and manage links. Use when the user asks to shorten a URL, see link analytics, list/search short links, edit/delete links, or mentions PicSee. Anonymous mode supports `create_short_link` only; OAuth 2.1 unlocks the full 14-tool authenticated surface. license: MIT compatibility: Requires an MCP-compatible client with Streamable HTTP transport (or a stdio bridge such as `mcp-remote`). Internet access to `api.picsee.io` and `public-api-oauth.picsee.io`. metadata: author: picsee version: "3.0.0" emoji: "🔗" repository: https://github.com/PicSeeInc/picsee-short-link mcp_url: https://api.picsee.io/mcp mcp_command: npx mcp-remote https://api.picsee.io/mcp oauth_authorization_server: https://public-api-oauth.picsee.io scopes: "user:read user:write" --- # PicSee Short Link URL shortener with **rich click analytics** and full **link management** — exposed to AI agents through the **PicSee MCP server** at `https://api.picsee.io/mcp`. The skill ships no code: it just teaches your agent how to call the MCP server. Authentication is handled by **OAuth 2.1 with PKCE** (Dynamic Client Registration), so no API tokens are ever stored on disk by the skill. --- ## Installation Add the PicSee MCP server to your AI client's MCP config. Pick the transport your client supports — most modern clients speak Streamable HTTP directly. ### Streamable HTTP (recommended) ```json { "mcpServers": { "picsee-short-link": { "url": "https://api.picsee.io/mcp" } } } ``` ### Stdio bridge (for clients without remote-MCP support) ```json { "mcpServers": { "picsee-short-link": { "command": "npx", "args": ["-y", "mcp-remote", "https://api.picsee.io/mcp"] } } } ``` See [README.md](README.md) for the exact config file path on each platform. --- ## Authentication ### Anonymous mode (no setup) `create_short_link` is callable with no credentials. Anonymous calls are pinned to `pse.is` and have no access to `externalId` filtering / attribution dashboards. ### Authenticated mode (OAuth 2.1) On the first authenticated tool call, the MCP client triggers an OAuth flow: 1. Dynamic Client Registration → `https://public-api-oauth.picsee.io/oauth/register` 2. Browser → `https://public-api-oauth.picsee.io/oauth/authorize` 3. User signs in to PicSee and grants `user:read` + `user:write` 4. Client receives access + refresh tokens via PKCE/S256 5. Token is stored by the MCP client — **never** by this skill All 14 authenticated tools become available after this flow. --- ## Tools 15 tools total. `create_short_link` is callable anonymously; the rest require OAuth. ### `create_short_link` *(anonymous OK)* Create a new short link. | Field | Required | Notes | |-------|----------|-------| | `url` | ✅ | Destination URL, ≤2048 chars | | `encodeId` | | Custom slug, 3–90 chars (letters / digits / `_` / `-` / Chinese). Must be globally unique — conflicts return `PUB00503` | | `domain` | | `pse.is` or a BSD from `get_my_domains`. **Ignored when called anonymously** | | `externalId` | | 1–100 chars. Agents SHOULD default this to their own product name — see [Attribution](#attribution) | | `utm` | | `{ source, medium, campaign, term, content }` | | `title` | | OG preview title, 3–300 chars | | `description` | | OG preview description, 3–300 chars | | `imageUrl` | | OG preview image URL | | `tags` | | Array of up to 3 tag names — use `get_my_tags` to offer a picker | | `targets` | | Device-specific redirects, see below | | `fbPixel` | | Meta Pixel ID — must already be saved in PicSee (`get_my_tracking_tools`) | | `gTag` | | GTM container ID — must already be saved in PicSee (`get_my_tracking_tools`) | | `pathFormat` | | `{ key: "<param-name>" }` — Path Parameterization add-on (paid Advanced) | `targets[].target` enum: `ios_android`, `ios`, `ios_store`, `android`, `android_store`, `ios_line`, `ios_safari`, `android_fb`, `pc_mac`, `pc`, `mac`, `facebook`, `twitter`. `ios_android` = all mobile; `pc_mac` = all desktop. App-store buckets only fire for users with the app installed. Returns `picseeUrl` (the shortened link). ### Account / discovery tools #### `get_api_status` No params. Returns the account's API plan, lifetime quota, current period usage, and plan expiration. **Call this before bulk operations** to confirm remaining quota. #### `get_api_usage_by_external_id` | Field | Required | Notes | |-------|----------|-------| | `startTime` | | Taipei time `YYYY-MM-DDTHH:mm:ss`. Defaults to 30 days before `endTime` | | `endTime` | | Taipei time `YYYY-MM-DDTHH:mm:ss`. Defaults to current hour. Max 31-day range | Returns API-link counts grouped by `externalId` — useful for attributing usage to agents / campaigns. #### `get_my_domains` No params. Lists every short-link domain on the account: brand short domains (BSDs), PicSee subdomains, shared root. Each entry flags HTTPS support and default status. **Call before `create_short_link`** if the user wants a non-default domain. #### `get_my_tags` No params. Returns `{ id, name }` pairs. `name` values are what `tags` accepts on `create_short_link` / `edit_short_link`. #### `get_my_tracking_tools` No params. Returns previously-used UTM sources / mediums, saved Meta Pixels, and saved GTM containers. Use to populate pickers instead of asking the user to retype IDs. ### `list_short_links` | Field | Notes | |-------|-------| | `limit` | 1–50, default 20 | | `startTime` | Taipei time `YYYY-MM-DDTHH:mm:ss`. **Returns links created _at or before_ this timestamp** — i.e. queries backward. Default = now | | `prevMapId` | Cursor: return links with `mapId` older than this. Combine with `startTime` for AND filtering | | `isAPI` | `true` (default) = only API-created links; `false` = only website-created | | `isStar` | `true` = starred only. Default `false` | | `externalId` | Exact-match filter | | `search.encodeId` | Exact slug — priority 1, overrides all other search fields | | `search.authorId` | Filter by author's PicSee user ID — priority 2 | | `search.tag` | Tag name, 3–30 chars — priority 3 | | `search.keyword` | Substring, 3–30 chars — priority 4 | **Tip**: when the user says "links from March 2026", pass `startTime: "2026-03-31T23:59:59"` (the end of the period) — the server queries backward from there. ### `edit_short_link` | Field | Required | Notes | |-------|----------|-------| | `encodeId` | ✅ | Slug of the link to edit | | `url` | | New destination. May be rejected with `PUB00510` if the new origin is on a different brand | | `domain` | | | | `title` / `description` / `imageUrl` | | 3–300 chars for text fields | | `tags` | | Up to 3 | | `targets` | | Same enum as `create_short_link` | | `fbPixel` / `gTag` | | Pass `null` to clear | | `utm` | | Pass `null` to clear all UTM params | | `expireTime` | | Future Taipei time `YYYY-MM-DDTHH:mm:ss`, or `null` to remove. Requires the expiration add-on | ### `delete_short_link` | Field | Required | Notes | |-------|----------|-------| | `encodeId` | ✅ | | | `value` | | `delete` (default) = move to trash; `recover` = restore from trash | - Starred links can't be deleted (`PUB00706`) — unstar via web first. - Links trashed for >30 days can't be recovered (`PUB00704`). ### Per-link analytics All five tools share the same shape: required `encodeId`, optional `startTime` / `endTime` (Taipei `YYYY-MM-DDTHH:mm:ss`). Default window is the last 30 days; Advanced plan can look back up to 365 days. | Tool | Returns | |------|---------| | `get_link_overview` | Total clicks, unique clicks, destination URL, domain, HTTPS flag, creation time. **Use for at-a-glance summaries** | | `get_link_daily_clicks` | Time-series of total + unique clicks aggregated by day. Use as raw data for chart rendering | | `get_link_platforms` | Unique-click breakdown by device (`iphone`, `android`, `windows`, `macintosh`, …). Aggregate to mobile/desktop client-side if needed | | `get_link_referrers` | Unique-click breakdown by referrer (search engines, social, AI agents, long-tail). Clicks without referrer info → `direct` | | `get_link_regions` | Unique-click breakdown by country (no city-level data). Unknown countries → `Others` (`code: "others"`) | | `get_link_audience_labels` | Interest + brand labels. **Privacy guard**: only returns data when the link has >100 lifetime unique clicks; otherwise both arrays come back empty. No `startTime` / `endTime` — covers link lifetime | --- ## Attribution The `create_short_link` schema asks the calling agent to set `externalId` to its own product name when the user hasn't specified one. PicSee account owners use this to attribute API usage in their dashboard. | Agent | Recommended `externalId` | |-------|--------------------------| | Claude Code | `Claude Code` | | Cursor | `Cursor` | | Codex / Codex CLI | `Codex` | | Antigravity | `Antigravity` | | OpenClaw / ClawHub | `OpenClaw` | | Gemini CLI | `Gemini CLI` | | GitHub Copilot | `Copilot` | | ChatGPT | `ChatGPT` | Rules: - Canonical product name only — no version numbers, session IDs, or user names. - If the user explicitly provides an `externalId`, **always honor their value** instead. --- ## Agent Recipes The MCP server intentionally doesn't ship QR or chart-rendering tools — those are easier to compose client-side from public services. ### Generate a QR code from a short link Construct a URL against [api.qrserver.com](https://goqr.me/api/): ``` https://api.qrserver.com/v1/create-qr-code/?size=300x300&data=<URL-encoded-short-link> ``` Surface the URL inline if your client renders images; otherwise return it as a link. For a larger code, change `size=500x500`. ### Render a daily-clicks chart 1. Call `get_link_daily_clicks` to get the time series. 2. Build a [QuickChart](https://quickchart.io) URL from the data: ``` https://quickchart.io/chart?c={type:'line',data:{labels:['2026-03-01',...],datasets:[{label:'Clicks',data:[12,38,...]}]}} ``` URL-encode the `c` parameter. Display inline if possible; otherwise return the link. --- ## Common Workflows ### Shorten a URL with full attribution 1. Call `create_short_link` with `url` and `externalId` = your agent name. 2. Return `picseeUrl` to the user. 3. If the user wanted a custom slug and got `PUB00503`, suggest an alternative. ### Pick a branded short domain 1. `get_my_domains` to enumerate BSDs + PicSee subdomains. 2. Offer the user a picker (note which is `isDefault`). 3. Pass the chosen `domain` to `create_short_link`. ### Show analytics for a link 1. `get_link_overview` for the headline numbers. 2. If the user wants breakdowns, call one or more of `get_link_daily_clicks` / `get_link_platforms` / `get_link_referrers` / `get_link_regions` / `get_link_audience_labels`. 3. For audience labels: warn the user if the link has ≤100 unique clicks (data will be empty due to the privacy guard). ### List the user's recent links 1. Call `list_short_links` with the user's filters. 2. If they say "March 2026", pass `startTime: "2026-03-31T23:59:59"`. 3. Paginate with `prevMapId` from the last result if they ask for more. ### Migrate a link to a new destination 1. `edit_short_link` with `encodeId` + new `url`. 2. If you get `PUB00510`, the brand of the new URL doesn't match. Tell the user. ### Track API usage by agent `get_api_usage_by_external_id` with no params returns the last 30 days, grouped by attribution tag. Useful for "which AI created most of my links?" --- ## Migration from v2.x v2.x was a Node.js CLI that stored an encrypted API token under `~/.openclaw/`. v3.0.0 removes that entirely — no CLI, no token files, no Node.js requirement on the agent side. ```bash # Clean up v2 artifacts rm -f ~/.openclaw/.picsee_token ~/.openclaw/.picsee_salt rm -rf ~/.claude/skills/picsee-short-link/cli rm -rf ~/.openclaw/workspace/skills/picsee-short-link/cli ``` Behavioral changes: - **Auth**: long-lived API token → OAuth 2.1 + PKCE (browser sign-in on first authenticated call) - **QR / chart**: were CLI subcommands → now agent recipes against `api.qrserver.com` / `quickchart.io` - **`delete` vs `recover`**: were two CLI commands → one tool `delete_short_link` with `value: "delete" | "recover"` - **Analytics**: was a single `analytics` command → split into 6 granular tools (`get_link_overview` + 5 dimensional breakdowns) - **Per-account discovery**: new tools `get_my_domains`, `get_my_tags`, `get_my_tracking_tools`, `get_api_status`, `get_api_usage_by_external_id` have no v2 equivalent --- ## Error codes | Code | Meaning | |------|---------| | `PUB00503` | `encodeId` (custom slug) already taken | | `PUB00510` | New `url` rejected on edit — different brand than the original | | `PUB00704` | Cannot recover a link that has been in trash >30 days | | `PUB00706` | Cannot delete a starred link — unstar it via the PicSee web app first | --- ## References - PicSee website: https://picsee.io - Developer docs: https://picsee.io/developers - MCP spec: https://modelcontextprotocol.io - OAuth 2.1 (MCP profile): https://modelcontextprotocol.io/specification/draft/basic/authorization

path: _meta.json
content: ownerId: kn79bca45p4fjz523s6zyswkvd81bs8z
slug: picsee-short-link
version: 3.0.0
publishedAt: 1779235200000

path: README.md
content: # 🔗 Skill for PicSee URL Shortener

[![Agent Skills](https://img.shields.io/badge/Agent_Skills-Open_Standard-blue.svg)](https://agentskills.io)
[![MCP](https://img.shields.io/badge/MCP-Streamable_HTTP-green.svg)](https://modelcontextprotocol.io)
[![OAuth 2.1](https://img.shields.io/badge/OAuth_2.1-PKCE-orange.svg)](https://modelcontextprotocol.io/specification/draft/basic/authorization)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

An **MCP-based [Agent Skill](https://agentskills.io)** for [PicSee](https://picsee.io) — URL shortening, QR code generation, click analytics, and link management.

The skill is just documentation: it points your AI agent at the public PicSee MCP server (`https://api.picsee.io/mcp`) and explains how to use the tools. No Node.js install, no CLI, no local token files — authentication is handled by **OAuth 2.1 + PKCE** via the MCP client.

---

## 🌟 What's new in v3.0.0

- **CLI → MCP**: the entire v2.x CLI (`node cli/dist/cli.js …`) is gone. All functionality is now exposed as MCP tools served from `api.picsee.io/mcp`.
- **OAuth 2.1 + PKCE**: replaces local AES-256 token encryption. Tokens are managed by your MCP client, not by this skill. Dynamic Client Registration means there's no manual app setup.
- **Anonymous mode still works**: `create_short_link` is callable without auth — perfect for one-off shortenings.
- **No Node.js requirement**: works in any MCP-capable client, including ones that can't execute Node (e.g. Cursor, web-based agents).
- **Agent attribution built in**: the server documents the convention of setting `externalId` to the AI agent's name (`Claude Code`, `Cursor`, `Codex`, …) so account owners can see which agent created which link.

Migrating from v2.x? See the [Migration](#migration-from-v2x) section.

---

## ⚙️ Installation by Platform

The skill consists of two parts:

1. **Skill content** (`SKILL.md` + this README) — placed in the platform's skills directory so the agent auto-discovers usage instructions.
2. **MCP server registration** — added to the platform's MCP config so the agent can actually call the tools.

### Claude Code

```bash
# 1. Install the skill
cp -r picsee-short-link ~/.claude/skills/picsee-short-link

# 2. Register the MCP server
claude mcp add --transport http picsee-short-link https://api.picsee.io/mcp
```

Or add manually to `~/.claude.json` (or project `.mcp.json`):

```json
{
  "mcpServers": {
    "picsee-short-link": { "type": "http", "url": "https://api.picsee.io/mcp" }
  }
}
```

### Cursor

Place the skill in `.cursor/skills/picsee-short-link/`, then edit `~/.cursor/mcp.json` (global) or `.cursor/mcp.json` (project):

```json
{
  "mcpServers": {
    "picsee-short-link": { "url": "https://api.picsee.io/mcp" }
  }
}
```

### Antigravity

Add via Antigravity's MCP settings panel (Settings → MCP Servers → Add), or edit the config file directly:

```json
{
  "mcpServers": {
    "picsee-short-link": { "url": "https://api.picsee.io/mcp" }
  }
}
```

Place `SKILL.md` in Antigravity's skills directory so the agent picks up usage guidance.

### Codex / Codex CLI

Add to `~/.codex/config.toml`:

```toml
[mcp_servers.picsee-short-link]
command = "npx"
args = ["-y", "mcp-remote", "https://api.picsee.io/mcp"]
```

`mcp-remote` bridges stdio ↔ Streamable HTTP and handles OAuth in a browser. (Direct HTTP transport in Codex CLI is improving rapidly — check `codex mcp add --help` on your version.)

Place `SKILL.md` in `.codex/skills/picsee-short-link/` for skill discovery.

### OpenClaw / ClawHub

```bash
clawhub install picsee-short-link
```

Or browse: [https://clawhub.ai/PicSeeInc/picsee-short-link](https://clawhub.ai/PicSeeInc/picsee-short-link)

ClawHub auto-registers the MCP server from the skill's metadata.

### claude.ai (Web)

Upload the skill folder under **Customize → Skills**. Add the MCP server in **Settings → Connectors → Add custom connector** with URL `https://api.picsee.io/mcp`.

### Generic MCP client

Any client that speaks **MCP Streamable HTTP** can register the server directly:

```json
{
  "mcpServers": {
    "picsee-short-link": { "url": "https://api.picsee.io/mcp" }
  }
}
```

For clients that only support stdio, use the `mcp-remote` bridge from npm:

```json
{
  "mcpServers": {
    "picsee-short-link": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://api.picsee.io/mcp"]
    }
  }
}
```

---

## 🤖 Compatibility Matrix

| Platform | Skill discovery | MCP transport | OAuth flow | Status |
|:---------|:----------------|:--------------|:-----------|:-------|
| Claude Code | `~/.claude/skills/` | HTTP (native) | Browser popup, token in `~/.claude` | ✅ |
| Cursor | `.cursor/skills/` | HTTP (native) | Browser popup, token in Cursor config | ✅ |
| Antigravity | Antigravity skills dir | HTTP (native) | Browser popup | ✅ |
| Codex CLI | `.codex/skills/` | stdio via `mcp-remote` | Browser popup via `mcp-remote` | ✅ |
| OpenClaw / ClawHub | auto (via `clawhub install`) | HTTP | Browser popup | ✅ |
| claude.ai | Customize → Skills | HTTP connector | Browser popup | ✅ |
| Gemini CLI | `.gemini/skills/` | stdio via `mcp-remote` | Browser popup via `mcp-remote` | ✅ |
| VS Code Copilot | `.github/skills/` | HTTP (1.95+) | Browser popup | ✅ |

> Any MCP-compliant client should work — the matrix above is just the integrations we've tested.

---

## 🧩 Tools

`create_short_link` is the only tool callable anonymously. The other 14 require OAuth.

| Group | Tool | Auth |
|:------|:-----|:-----|
| **Create** | `create_short_link` | optional |
| **Account** | `get_api_status` | required |
| | `get_api_usage_by_external_id` | required |
| | `get_my_domains` | required |
| | `get_my_tags` | required |
| | `get_my_tracking_tools` | required |
| **Manage** | `list_short_links` | required |
| | `edit_short_link` | required |
| | `delete_short_link` (covers delete + recover) | required |
| **Analytics** | `get_link_overview` | required |
| | `get_link_daily_clicks` | required |
| | `get_link_platforms` | required |
| | `get_link_referrers` | required |
| | `get_link_regions` | required |
| | `get_link_audience_labels` | required |

> **No QR or chart tool on the server** — those are agent recipes against public services (`api.qrserver.com`, `quickchart.io`). See [SKILL.md → Agent Recipes](SKILL.md#agent-recipes).

Full parameter tables for every tool live in [SKILL.md](SKILL.md). The MCP server is also self-describing via `tools/list` — that is the source of truth.

---

## 🔑 Authentication

1. Register the MCP server in your client (see [Installation](#-installation-by-platform)).
2. Ask the agent to do something that requires auth (e.g. "show me analytics for my last link").
3. The MCP client opens a browser to `https://public-api-oauth.picsee.io/oauth/authorize`.
4. Sign in to PicSee and approve the `user:read` / `user:write` scopes.
5. Done — the client stores the token. Future calls are silent until the refresh token expires.

The skill folder never touches your token. All credential handling lives in your MCP client.

---

## 🔒 Security

| Aspect | v2.x (legacy) | v3.0.0 (current) |
|:-------|:--------------|:-----------------|
| Auth model | Long-lived API token | OAuth 2.1 + PKCE (S256) |
| Token storage | Local file, AES-256-CBC | MCP client (per-client policy) |
| Scopes | All-or-nothing | `user:read`, `user:write` |
| Revocation | Manual via PicSee dashboard | Per-client, revocable from PicSee account |
| Dynamic Client Registration | n/a | ✅ (RFC 7591) |

OAuth metadata is published at [`https://api.picsee.io/.well-known/oauth-protected-resource`](https://api.picsee.io/.well-known/oauth-protected-resource), with the authorization server at [`https://public-api-oauth.picsee.io/.well-known/oauth-authorization-server`](https://public-api-oauth.picsee.io/.well-known/oauth-authorization-server).

---

## 🧭 Agent attribution

The MCP server asks calling agents to set `externalId` to their own product name on `create_short_link`, so PicSee account owners can attribute API usage. The skill tells your agent to default to:

`Claude Code` · `Cursor` · `Codex` · `Antigravity` · `OpenClaw` · `Gemini CLI` · `Copilot` · `ChatGPT`

Users can always override by explicitly passing their own `externalId`.

---

## 📁 Project Structure

```
picsee-short-link/
├── SKILL.md     # Agent Skills definition — read by your agent
├── README.md    # This file — read by humans
└── _meta.json   # ClawHub registry metadata
```

No `cli/` and no `references/` in v3 — the MCP server is self-describing via `tools/list`, and the REST API is now an implementation detail of the server.

---

## Migration from v2.x

```bash
# 1. Remove the old encrypted token + salt files
rm -f ~/.openclaw/.picsee_token ~/.openclaw/.picsee_salt

# 2. Remove the old CLI build artifacts wherever the skill was installed
rm -rf ~/.claude/skills/picsee-short-link/cli
rm -rf ~/.openclaw/workspace/skills/picsee-short-link/cli
rm -rf .cursor/skills/picsee-short-link/cli

# 3. Reinstall the v3 skill (see Installation above) and register the MCP server.
# 4. Ask the agent to do something authenticated — sign in via browser when prompted.
```

No API token migration is needed — OAuth issues fresh credentials from scratch.

---

## 📖 Resources

- **PicSee Website:** [https://picsee.io](https://picsee.io)
- **Developer Docs:** [https://picsee.io/developers](https://picsee.io/developers)
- **MCP Spec:** [https://modelcontextprotocol.io](https://modelcontextprotocol.io)
- **Agent Skills Spec:** [https://agentskills.io](https://agentskills.io)

---

## 📄 License

MIT


path: .clawhub/origin.json
content: version: 1
registry: https://clawhub.ai
slug: picsee-short-link
installedVersion: 1.0.0
installedAt: 1772251930206

Security scan verdicts — ClawScan: clean | static analysis: suspicious | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)