bsky-copilot-mcp
v0.5.0
Published
MCP server for Bluesky Copilot - analytics, AI post ideas, drafts and scheduling for one Bluesky account.
Maintainers
Readme
bsky-copilot-mcp
MCP server for Bluesky Copilot: analytics, AI post ideas grounded in your real posting history, drafts, and scheduling.
Works with Claude Desktop, Claude Code, and any other MCP client.
Setup
Create an API key at https://bskycopilot.com/settings/ (paid plan), then:
{
"mcpServers": {
"bsky-alice": {
"command": "npx",
"args": ["-y", "bsky-copilot-mcp@latest"],
"env": { "BSKYCOPILOT_API_KEY": "bskc_a1b2c3d4_..." }
}
}
}Check it works without involving a model -- it prints the handle the key drives:
BSKYCOPILOT_API_KEY=bskc_... npx -y bsky-copilot-mcp@latest --checkSeveral accounts
One server entry per account, named after the handle:
{
"mcpServers": {
"bsky-alice": { "command": "npx", "args": ["-y", "bsky-copilot-mcp@latest"],
"env": { "BSKYCOPILOT_API_KEY": "bskc_a1b2c3d4_..." } },
"bsky-brandco": { "command": "npx", "args": ["-y", "bsky-copilot-mcp@latest"],
"env": { "BSKYCOPILOT_API_KEY": "bskc_e5f6g7h8_..." } }
}
}Each server controls exactly one account and puts its handle into every tool description, so the model can see which account it is touching. That is why this is one-server-per-account rather than one server holding several keys: a leaked config exposes one account rather than all of them, and you can give one account a read-only key while another gets write access.
What it costs
Analytics, drafts and scheduling are free. Two tools —
generate_suggestions and rewrite_post — spend your own Anthropic or OpenAI
credit through Bluesky Copilot.
You usually do not need them. get_suggestion_prompt and get_rewrite_prompt
return the exact prompt Bluesky Copilot would have sent, with your real posts
already filled in, and the agent runs it itself. Free, and no AI key required.
The tool descriptions steer agents that way by default.
Safety
publish_draft posts to Bluesky immediately and deletes the draft. It is
annotated as destructive, requires an explicit confirm: true, and the server
instructions tell the model to ask you first. Everything else either reads, or
writes to drafts and the schedule where you can still change your mind.
The server cannot create or revoke API keys — that is browser-only, on purpose.
Environment
| Variable | Default |
| --- | --- |
| BSKYCOPILOT_API_KEY | required |
| BSKYCOPILOT_API_BASE | https://bskycopilot.com/api/public/v1 |
Build from source
npm install && npm run build
node dist/index.js --checkPublishing
Unscoped name, so there is no npm org to create.
cd agent/mcp
npm login # once per machine
npm publish # prepublishOnly runs the build for youCheck it before announcing it:
npm view bsky-copilot-mcp version
BSKYCOPILOT_API_KEY=bskc_... npx -y bsky-copilot-mcp@latest --checkThen the setup instructions above simplify to "command": "npx",
"args": ["-y", "bsky-copilot-mcp@latest"], and users need no clone and no build.
Releasing
Every documented config uses @latest, and that is deliberate: it is the only
spec npx actually re-resolves.
npx keys its cache by the exact spec string and, for anything that parses as a
version range, hands back the cached copy without ever contacting the
registry. npm-package-arg reads a bare pkg as the range * and [email protected] as
the range 0.3 -- both satisfied by whatever is already installed. That is how
a bare invocation kept running an 0.1.0 binary that predated the credential
store, and how a @0.3 "pin" kept serving 0.3.0 after 0.3.1 shipped.
A tag spec takes the other branch: libnpmexec fetches the manifest with
preferOnline and compares it against what is installed. So @latest is
current on every run, and @x.y.z is exactly what it says. Nothing else is.
A release is therefore two steps, with nothing to update afterwards:
npm version patch # or minor / major
npm publishUsers pick the new server up on their next start. Plugin skills still need
/plugin marketplace update bsky-copilot, since third-party marketplaces do not
auto-update by default.
The trade is that a bad publish reaches everyone immediately, so run
npm test and a --check against production before publishing. The server logs
its running version to stderr on startup, and warns when it is behind what the
registry reports, so what is actually running is always visible.
Only dist/, README.md and package.json are published; npm pack --dry-run
shows exactly what goes in.
