shrtnrBLOCK
MCP server, REST API and typed SDKs for short links. Per-user ownership, bundle analytics. Self-hosted on Cloudflare Workers, free tier.
Overview
From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.
[](https://www.npmjs.com/package/@oddbit/shrtnr) [](https://pypi.org/project/shrtnr/) [](https://pub.dev/packages/shrtnr)
shrtnr is a self-hosted URL shortener you drive from code and from AI assistants, not only from a dashboard. Every deployment ships a REST API with an OpenAPI spec, typed SDKs on npm, PyPI and pub.dev, and a native MCP server that Claude, Copilot and any other MCP client connect to through OAuth on Cloudflare Access. Links belong to the person who created them, several slugs can point at one destination, and bundles roll the clicks of a whole campaign into one report. It runs on Cloudflare Workers and D1, inside the free tier.
[](https://oddb.it/shrtnr-deploy-top)
Who this is for
- Teams that need per-person permissions, not a shared password. Sign-in runs through Cloudflare Access, so every teammate arrives with their own identity. Links and bundles record who created them, and only the creator can edit, disable or delete them. Everyone can read everything. API keys are issued per person and act as that person. Permission model.
- Developers integrating links into an app. A REST API documented by an OpenAPI 3.1 spec, with a live reference at
/_/api/docson your deployment. Typed SDKs for TypeScript, Python and Dart, generated from that spec. Bearer keys withreadandcreatescopes. Link creation is idempotent, and QR codes come ba
a58d748d1565OBSERVED · 2026-10-08Connect
Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control. Replace the environment placeholders with a token scoped to the least it needs.
claude mcp add shrtnr --env SHRTNR_TEST_API_KEY=${SHRTNR_TEST_API_KEY} -- npx -y @oddbit/[email protected]{
"mcpServers": {
"shrtnr": {
"command": "npx",
"args": [
"-y",
"@oddbit/[email protected]"
],
"env": {
"SHRTNR_TEST_API_KEY": "${SHRTNR_TEST_API_KEY}"
}
}
}
}Exposed tools (39)
24 read · 11 write · 4 destructive. Blast radius: 4 tools can delete or overwrite — an agent that can be talked into calling a tool can be talked into calling this one.
| Tool | Risk | Description |
|---|---|---|
OSS | read | something |
_execute_action | write | Shorten the current tab with shrtnr |
add_custom_slug | write | |
add_link_to_bundle | write | |
archive_bundle | read | |
compare_links | read | |
create_bundle | write | |
create_link | write | |
delete_bundle | destructive | |
delete_link | destructive | |
disable_link | write | |
disable_slug | write | |
enable_link | write | |
enable_slug | write | |
get_bundle | read | |
get_bundle_analytics | read | |
get_clicks_by_country | read | |
get_clicks_by_device | read | |
get_clicks_by_referrer | read | |
get_dashboard_stats | read | |
get_link | read | |
get_link_analytics | read | |
get_link_breakdown | read | |
get_link_qr | read | |
get_link_timeline | read | |
get_total_clicks | read | |
get_trending_links | read | |
health | read | |
list_bundle_links | read | |
list_bundles | read | |
list_bundles_for_link | read | |
list_links | read | |
list_links_by_owner | read | |
remove_link_from_bundle | destructive | |
remove_slug | destructive | |
search_links | read | |
unarchive_bundle | read | |
update_bundle | write | |
update_link | write |
Trust audit
BLOCKgrade D · trust 69/100 Do not install this without reading the findings. The audit found something that could harm you or your machine.
| Layer | What it checks | Result |
|---|---|---|
| L0 | Provenance & inventory | PASS |
| L1 | Static analysis of the code | FAIL |
| L2 | Instruction surface (what it tells the agent) | PASS |
| L3 | Class-specific surface | WARN |
| L4 | Behavioural (sandbox) | SKIPPED |
What the source does
- Filesystem
- declared (3 observation(s))
- Network
- declared (8 observation(s))
- Shell
- none-observed
- Dependencies
- not all pinned
- Secrets in source
- none-found
Findings (25)
preact ~ react
URL="http://127.0.0.1:${PORT}"delete_bundle, delete_link, remove_link_from_bundle, remove_slug
.dev.vars.example
.node-version
AGENTS.md
const factory = new Function(
const factory = new Function("document", code) as (doc: unknown) => {const factory = new Function("api", "toast", "t", "document", "window", code) as (const factory = new Function(code) as () => (key: string, params?: Record<string, unknown>) => string;
import { ShrtnrClient } from "../../src";import { applyMigrations, resetData } from "../../setup";import { getCacheVersion } from "../../../admin/widgets/cache";import worker from "../../../index";
import { applyMigrations, resetData } from "../../setup";[".internal hostname", "http://metadata.google.internal/computeMetadata/v1/"],
["link-local / cloud metadata", "http://169.254.169.254/latest/meta-data/"],
["fully qualified .internal hostname", "http://metadata.google.internal./computeMetadata/v1/"],
.mockResolvedValueOnce(redirectResponse("http://169.254.169.254/latest/meta-data/"))["IPv4 loopback", "http://127.0.0.1:8787/"],
["IPv4 loopback, other address in /8", "http://127.1.2.3/"],
["unspecified 0.0.0.0", "http://0.0.0.0/"],
["RFC 1918 10/8", "http://10.0.0.5/"],
return JSON.parse(atob(parts[1]));
@oddbit/shrtnr, preact, @testing-library/preact, @types/chrome, esbuild, happy-dom, typescript, vitest
Gates applied: no_behavioural_pass.
a58d748d1565full audit observations/trust-audit/mcp-server/oddbit__shrtnr.json · Report an issue / request a re-scanAudit history
Every audit this server has had. A grade with a past is a grade somebody is still checking.
| Date | Source | Verdict | Grade | Score | Change |
|---|---|---|---|---|---|
| 2026-10-08 | a58d748d1565 | BLOCK | D | 69 | first audit |
Questions
What is the shrtnr MCP server?
MCP server, REST API and typed SDKs for short links. Per-user ownership, bundle analytics. Self-hosted on Cloudflare Workers, free tier.
What tools does shrtnr expose?
39 in total: 24 read-only, 11 that write, and 4 that can delete or overwrite (delete_bundle, delete_link, remove_link_from_bundle, remove_slug). Every one is listed on this page with its risk.
Is shrtnr safe to connect to an agent?
No — not without reading the findings first. The audit graded it D (69/100) and found 1 critical or high issue in the source. Each one is listed on this page with the file and line it is on. Separately from the audit: 4 of its tools can destroy data, so scope the token you give it to what you actually need.
What credentials does shrtnr need?
It reads SHRTNR_TEST_API_KEY from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.
How does shrtnr run?
It speaks streamable-http, so it runs as a service you connect to over the network. It is published on npm as @oddbit/shrtnr at 1.2.1.
How current is this page?
The grade is for one exact copy of the source (a58d748d1565), read on 2026-10-08. The repository is watched and re-audited when it changes.