shebang-mcp
Allows managing Pages, Files, Short links, and Postgres databases on the shebang platform, accessed via dash.shebang.pro.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@shebang-mcpCreate a short link to https://example.com"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
shebang-mcp
One MCP server and CLI for hosting pages, sharing files, making short links,
running a Postgres database, and managing API keys — all through a single
shb_… key, for accounts on shebang.pro.
Full docs live at docs.shebang.pro, with an
agent-oriented index at
docs.shebang.pro/llms.txt — and every
page there is also available as plain Markdown at <page-url>.md.
Quickstart
Claude Code:
claude mcp add shebang -- npx -y shebang-mcp
npx -y shebang-mcp loginAny other stdio-based MCP harness, add this server entry:
{
"mcpServers": {
"shebang": {
"command": "npx",
"args": ["-y", "shebang-mcp"]
}
}
}then run npx -y shebang-mcp login once from a terminal on the same
machine (or set SHEBANG_API_KEY directly — see
Env vars).
shebang-mcp is on npm: npmjs.com/package/shebang-mcp.
To install from source instead — for example, to run the latest commit
on main ahead of the next published release —
npx -y github:New-Kringster/shebang-mcp runs that commit instead of
the published release.
Related MCP server: Modular MCP Server
The login flow
login runs an RFC 8628 device
authorization flow against the shebang platform:
The CLI calls the platform, gets back a short user code and a verification URL, and prints both — then tries to open your browser to that URL automatically.
In the browser, you sign in to your shebang.pro account (if not already) and see a page showing the device name and the same user code the terminal printed — check they match, then click Approve (or Deny).
The CLI has been polling in the background (honouring the server's advertised interval, and backing off further if told to
slow_down); once approved, it writes the issued key to~/.config/shebang/credentials.json(mode0600) and prints the key's prefix.
From then on, every harness on that machine that runs this server picks the key up automatically — no per-project configuration.
$ npx -y shebang-mcp login
Confirm this code in your browser:
x 7 w y 6 x 3 a
https://dash.shebang.pro/authorize-agent?user_code=x7wy6x3a
Opening your browser… (if nothing opens, visit the URL above)
Waiting for approval....
Logged in. Key: shb_examplexxxxxxxx… (master)
Saved to ~/.config/shebang/credentials.json
Your agent can now use shebang.shebang-mcp status shows the current key's prefix and tier;
shebang-mcp logout deletes the local credentials file (it does not
revoke the key — see below).
Device flow endpoints
Two dash endpoints back the flow above, both accepting either
application/x-www-form-urlencoded (per the RFC) or JSON:
POST /api/agent-login/device_authorization—{client_name}(optional, defaults to"agent") →{device_code, user_code, verification_uri, verification_uri_complete, expires_in, interval}.POST /api/agent-login/token—{grant_type: "urn:ietf:params:oauth:grant-type:device_code", device_code}→200 {access_token, token_type: "shb", scope: "master", expires_in: null}once, or a400with{error}∈authorization_pending,slow_down(with a growninterval),access_denied,expired_token,invalid_grant,invalid_request,unsupported_grant_type.
Key tiers
Master — what
loginmints. Full authority over the account: every app, plus minting and revoking other keys. One master key per login.App — scoped to a subset of
page,serve,link,base. Mint one for a sub-agent via thekey_create_apptool so it only gets the access it needs; the plaintext key is shown exactly once in the response.
A key cannot revoke itself while it's the one authenticating the call —
revoke a key from a different key (usually the master that minted it, via
the key_revoke tool) or from the shebang.pro dashboard's account page.
shebang-mcp logout only forgets the key locally; it prints this same
reminder.
On the wire, a shb_… key is sent as Authorization: Bearer shb_... —
on the platform API directly, and by every tool in this MCP server.
Tool reference
Pages (sherpage)
Tool | What it does |
| Publish a new page from a bundle of files |
| List your pages |
| Get one page's details |
| Update title/slug/expiry/view budget |
| Change access level (private/password/allow-list/public) |
| Archive or restore a page |
| Permanently delete a page and its files |
Files (sherserve)
Tool | What it does |
| Upload a local file as a new object (stdio only — see Hosted MCP) |
| List your uploaded objects |
| Get one object's details by slug or id |
| Permanently delete an object and its file |
Short links (sherlink)
Tool | What it does |
| List all your short links across apps |
| Get one link's details by code, alias, or id |
| Change access, password, expiry, or view budget |
| Set or clear a custom vanity alias |
| Delete a link and the page/file it wraps — irreversible |
Projects (platform, master-only unless noted)
A Project groups your keys, databases, files, links, and pages for
dashboard organization and access control. A key always reaches its own
home Project in full; a master key, or an app key holding a grant, can
also reach another Project (at read or full level).
How projects scope your calls
Every tool defaults to the calling key's own home Project — you never have
to pass project for normal use. To target a different Project, pass
project (a slug) to that call: a master key can name any of the account's
other Projects; an app key can only reach one it's been explicitly granted
read or full access to via project_grant_key (naming one it can't
reach fails as insufficient_scope, never a not-found error, so existence
is never leaked to a key that can't reach it). Each call is scoped
independently — passing project on one call doesn't change what a later
call defaults to, so a tool like link_list still returns your home
Project's links unless you pass project again on that call too, even
right after publishing something into a different Project.
Tool | What it does |
| Create a new Project (name, tag, color, slug) |
| List every Project on the account |
| Get one Project's details by id |
| Update a Project's name, tag, color, slug, or OAuth client |
| List every key, database, file, link, and page in a Project |
| Permanently delete a Project by id — irreversible |
| Attribute an existing resource to a Project |
| Move a resource to your account's default Project |
| Grant a key |
| Revoke a key's grant on another Project |
project_create/project_set's color must be one of the platform's
curated palette, not an arbitrary hex value:
#ef4444 #f97316 #f59e0b #84cc16 #22c55e #14b8a6 #06b6d4
#3b82f6 #6366f1 #8b5cf6 #a855f7 #ec4899
Databases (sherbase)
Tool | What it does |
| Provision a new Postgres database (database + role) |
| List your databases |
| Run one SQL statement against a database |
| Permanently drop a database — irreversible |
| Rotate a database's Data API secret key — old one stops working immediately |
| Enable the Data API for a database created before it had one |
| Reload a database's Data API schema cache after DDL run outside |
Keys (master-only)
Tool | What it does |
| Mint a scoped app key, typically for a sub-agent — optionally bound to a Project ( |
| List every key on the account (never hashes or plaintext) |
| Permanently revoke a key by id — irreversible |
Email (master-only)
Tool | What it does |
| Send a plain-text email from the platform's address, reply-to your account — limited to 10/day |
OAuth (master-only)
Tool | What it does |
| List registered sherlock OAuth clients |
| Register a new OAuth client (returns a one-time secret) |
Visibility
Pages and uploaded files default to access: "private" — reachable only by
your own account — whether or not you set access at creation. To make one
public:
A page —
sherpage_set_access({ id, access: "public" }).An uploaded file — via the short link that
store_upload_file/store_upload_contentcreates for it automatically:link_set_access({ code_or_id, access: "public" }).
Or pass access: "public" up front, at sherpage_publish/store_upload_file/
store_upload_content time, to skip the second call.
Data API
Every database created with base_create_database gets a Supabase-shaped
Data API on by default — a PostgREST endpoint plus sherlock-backed auth —
at https://api.shebang.pro/db/<slug>. Databases created before this
existed don't have it until you call base_enable_api {database}, which
returns the same fields base_create_database does: api_url,
publishable_key, and (only the first time) secret_key, shown once and
never retrievable again.
publishable_key(sb_publishable_…) is safe to ship in client code — pair it with a signed-in user's sherlock session for row-level security to apply per-user.secret_key(sb_secret_…) bypasses row-level security entirely — server-side only, never in a browser. Lost or compromised, rotate it withbase_rotate_secret {database, confirm}(confirmmust exactly equaldatabase); the old secret stops working immediately.
Point supabase-js at it like a normal Supabase project:
import { createClient } from "@supabase/supabase-js";
const supabase = createClient(
"https://api.shebang.pro/db/<slug>",
"sb_publishable_<slug>_…",
);
// Sign in through sherlock — the platform's own auth — same as any
// Supabase Auth call:
await supabase.auth.signInWithPassword({ email, password });
const { data, error } = await supabase.from("todos").select("*");Sign in with sherlock (redirect)
Use this when you want your app to send users to sherlock to sign in and get them back with tokens — no password form lives in your app, and a user already signed in to one shebang app is signed in to every other app on the same sherlock account.
1. Register a client. Dynamic client registration, against the
issuer's discovery document
(https://auth.shebang.pro/auth/v1/.well-known/openid-configuration):
curl -X POST https://auth.shebang.pro/auth/v1/oauth/clients/register \
-H "Content-Type: application/json" \
-d '{
"client_name": "My app",
"redirect_uris": ["https://myapp.example.com/callback"],
"token_endpoint_auth_method": "none"
}'token_endpoint_auth_method: "none" registers a public client (a
browser app or CLI, with no secret to protect); use "client_secret_post"
instead for a confidential client (a server that can hold one), and
the response includes a client_secret. Or skip the curl and call the
MCP oauth_create_client tool, which does the same registration.
2. Send the user to the authorize URL, with a PKCE challenge (S256
only — plain isn't supported) and a state you'll check on the way back:
https://auth.shebang.pro/auth/v1/oauth/authorize
?response_type=code
&client_id=<client_id>
&redirect_uri=<redirect_uri>
&scope=openid email profile
&code_challenge=<S256 challenge>
&code_challenge_method=S256
&state=<random state>The consent screen the user sees names your app and lists these scopes.
3. Handle the callback at your redirect_uri (?code=...&state=...),
check state matches what you sent, then exchange the code for tokens
(form-encoded):
curl -X POST https://auth.shebang.pro/auth/v1/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=authorization_code" \
--data-urlencode "code=<code>" \
--data-urlencode "redirect_uri=<redirect_uri>" \
--data-urlencode "client_id=<client_id>" \
--data-urlencode "code_verifier=<verifier>"You get back access_token, refresh_token, and id_token (a JWT
carrying the user's email and sub). The access_token is a sherlock
user JWT (aud: "authenticated") — pass it as a Bearer token to your
database's Data API, or to api.shebang.pro (the platform API), and
either accepts it as that signed-in user.
4. Use the access token with supabase-js, so row-level security sees the signed-in user:
const supabase = createClient(api_url, publishable_key, {
global: { headers: { Authorization: `Bearer ${access_token}` } },
});5. Refresh when the access token expires:
curl -X POST https://auth.shebang.pro/auth/v1/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=refresh_token" \
--data-urlencode "refresh_token=<refresh_token>" \
--data-urlencode "client_id=<client_id>"6. Log out by dropping the tokens client-side; sherlock sessions end with sign-out-everywhere, not a per-app revoke.
This is an alternative to the embedded-form flow — signing in directly
via supabase-js calls like signInWithPassword, or signUp/
verifyOtp (see above, and Sign-up for your app's users below). Pick
redirect for one account shared across apps with no password handling
in your own code; pick embedded when you want the sign-in form itself
to live inside your app's UI.
Sign-up for your app's users
Your app's end users sign up through sherlock — the platform's own auth —
directly via supabase-js, never through this MCP server. Two supported
flows:
Email + password, confirmed with a 6-digit code sent by email (not a confirmation link):
supabase.auth.signUp({ email, password }), thensupabase.auth.verifyOtp({ email, token: "<6-digit code>", type: "signup" }).OTP-only sign-in (no password at all):
supabase.auth.signInWithOtp({ email }), thensupabase.auth.verifyOtp({ email, token: "<6-digit code>", type: "email" }).
The app owner's own shebang.pro account (the one login authenticates as)
is entirely separate from these end users — signing a user up in your
app's database never touches the owner's platform account.
If a table or column you just created over base_run_sql, the direct
connection, or the pooler isn't showing up on the Data API yet, call
base_reload_schema {database} to refresh PostgREST's schema cache
without waiting for the gateway to restart on its own. Calling it before
the Data API is enabled returns a clear "enable the Data API first"
error instead of a confusing one.
The direct connection and pooler strings shown in the dashboard use
sslmode=verify-full and sslrootcert=system. Clients older than libpq
16 need a CA file instead of sslrootcert=system: download the
ISRG Root X1 certificate
and use sslrootcert=<path>.
Migrating from 0.3.x
0.4.0 is additive — no tool was renamed or removed. base_list_databases
and base_create_database gain api_url, publishable_key, and
api_enabled fields on every database they return (base_create_database
additionally returns secret_key once, on a newly created database's
first Data API key pair). Three new tools cover the sherbase Data API
this release ships: base_rotate_secret, base_enable_api, and
base_reload_schema — see Data API. Every 0.3.x call keeps
working unchanged.
Migrating from 0.4.0
0.5.0 removes the one-release aliases 0.2.0 and 0.4.0 introduced. Nothing here was renamed or changed shape — these names simply stop working. Update any already-configured agent before upgrading.
Removed tools (registered but undocumented since 0.2.0/0.4.0 — call the tool in the "Use instead" column):
Removed | Use instead |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Removed arguments:
base_run_sql's deprecatedslugargument alias is gone — passdatabase(now required).key_create_app's deprecatedapp_id(a Project id) argument is gone — passproject(a Project slug). The underlyingPOST /api/platform/v1/keysroute now 400sinvalid_bodyifapp_idis present in the request body at all.
Removed response field: base_list_databases's result (and the
underlying GET .../databases routes) no longer carry the duplicate
projects key — read databases, which has carried the identical array
since 0.2.0.
0.5.1
project_create/project_set's color is now a curated enum with a
client-side rejection message listing every accepted value, store_upload_content
infers a file extension from contentType when the path has none, and this
README gained the docs noted above (project scoping, visibility, sign-up).
Hosted MCP
https://api.shebang.pro/mcp runs the same registerTools this package
exports, over the same tool schemas — with one difference: local file
paths are not available on the hosted server. store_upload_file reads
a path off whatever filesystem the MCP server process can see; over
stdio that's your own machine, but the hosted server runs inside
shebang's own dash container, so a path argument there would name a
file on shebang's infrastructure, not yours. The hosted endpoint omits
store_upload_file entirely and registers store_upload_content in its
place — upload by supplying the bytes directly (contentBase64 or
text) instead of a path. Every other tool is identical between the two
servers.
Env vars
Variable | Purpose |
| The |
| Platform base URL; defaults to |
| Written by |
The platform
The MCP server and CLI in this repo are a client only — no secrets, no server code, nothing that talks to a database directly. The platform itself (accounts, keys, pages, files, links, databases, OAuth) is operated at shebang.pro; an account there is required to use this client.
License
MIT — see LICENSE.
This server cannot be deployed
Maintenance
Related MCP Connectors
Publish HTML, Markdown, and multi-file sites as shareable URLs instantly via MCP.
An MCP server that provides read access to your cloud storage providers, bank accounts and more.
Build, deploy, and host full-stack web apps from any MCP client. DB, auth, storage, cron included.
A MCP server built for developers enabling Git based project management with project and personal…
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceA unified MCP server with composable tools for GitHub operations, file management, shell execution, kanban boards, Discord messaging, and package management. Features role-based security, HTTP/stdio transports, and a web-based development UI.-
- FlicenseBqualityDmaintenanceA config-driven, zero-dependency MCP server with plugin architecture that enables filesystem operations, shell commands, HTTP requests, and utilities through simple JSON configuration.31-
- FlicenseNot gradedqualityCmaintenanceA production-ready MCP server providing file, system, math, and text utilities through a simple CLI client.-
- AlicenseNot gradedqualityCmaintenanceA secure remote MCP server for self-hosted Supabase installations, enabling database schema management, SQL queries, and interaction with local Supabase services like Auth, Storage, and Edge Functions.1,792 npmMIT