It's 5:40 on a Friday and a contractor just rolled off the project. Their laptop still holds a live key to your hosted MCP server. Rotating it means finding the right browser tab, clicking into the server, finding the keys panel, revoking the old key, minting a new one, and pasting it into every client config that used it. You'll do the same dance next quarter, and the quarter after that, and none of it will ever be written down anywhere a script can read.
A dashboard is a good way to look at an MCP server and a bad way to operate one. Every click is an ops task that can't be scripted, diffed, code reviewed, or run by CI. The fix is the same one infrastructure went through a decade ago: put the lifecycle behind a CLI and treat the dashboard as a viewer.
This post walks the whole lifecycle of a hosted MCP server through @protoboxai/cli: authenticate once, then manage tools, toolsets, server keys, knowledge, and skills from the shell, and finally wire the same commands into CI. If you haven't shipped an MCP server yet, start with build your first MCP server and come back when you are tired of clicking.
One login, then everything scripts
Authentication happens once per machine: install the CLI, paste a workspace API key, and every later command reuses the stored credential. There is no browser round trip in the loop after that.
npm install -g @protoboxai/cli
protobox login
# Paste your workspace API key at the promptlogin doesn't just store the key. It makes a real authenticated call, lists the MCP servers the key can reach, and only then writes the credential. A typo'd key fails at login, not three commands later.
From there, status is the orientation command. It prints the active profile, the platform URL, the workspace, every MCP server URL, connection state, and toolset count in one shot. whoami is the same command under a different name, for the muscle memory.
protobox statusTwo details matter for scripting before we go further. First, every command accepts a global --json flag that swaps the human tables for machine-readable output. Second, the stored key can be bypassed entirely with the PROTOBOX_API_KEY environment variable, which is how CI will authenticate later without ever touching the config file. PROTOBOX_PROFILE and PROTOBOX_BASE_URL get the same treatment: the environment always beats ~/.protobox/config.json, so a runner can pin its own workspace without a login step. Profiles (protobox login --profile staging, protobox config use staging, protobox config list) keep a staging and a production workspace on the same machine without cross-contamination.
That's the whole auth story. Now for the part you used to click through.
Tools without the tools page
Listing, inspecting, and running tools are each one command, and the same commands register your own APIs. The catalog behind a workspace is large (the backend serves over 1,400 actions, so the bare listing caps at 50 rows), which is exactly why searching it in a terminal beats scrolling it in a browser.
protobox tools --search "invoice"
protobox tools --app githubFound a candidate? get prints its schema as a table: each argument, whether it is required, its type, and which connection the tool needs before it will run.
protobox tools get GITHUB_CREATE_ISSUEAnd because reading a schema is not the same as trusting it, you can execute the tool directly and see the verdict, latency included:
protobox tools run GITHUB_CREATE_ISSUE \
-a owner=acme -a repo=api -a title="Test from CLI"Arguments stack as repeatable -a key=value pairs, or as one JSON object via --args '{"owner":"acme"}'. If the tool needs a connection you haven't made yet, the failure tells you the exact protobox connect <app> command to fix it. OAuth apps open a consent link; API-key apps take --api-key.
Your own API joins the catalog the same way. Point the CLI at an OpenAPI 3.x spec and every operation becomes a tool:
protobox tools add-api --spec ./openapi.json --slug billing
protobox tools --app billingThere is a sibling for code connectors (protobox tools add-code --file ./connector.py) and an undo (protobox tools remove billing). If you would rather define tools in TypeScript with the official SDK and full control over schemas, that build is the SDK companion post; the CLI path here is the fast lane for APIs you already have specs for.
The audit log is the last thing worth pulling out of the browser here. The dashboard shows it a page at a time; the CLI gives it to you as a stream. protobox tools logs --outcome failed filters recent executions down to what broke, and the same command narrows by tool name, caller, MCP client, or an ISO date window (--tool-name, --caller, --client, --from/--to) when you're chasing one specific incident. protobox tools trace <executionId> --out trace.json exports a single execution as an OTLP/JSON trace you can load into any OpenTelemetry backend. If you're building out that pipeline, the MCP observability guide covers where those traces should land.
Toolsets are your deploy unit
A toolset is a named subset of tools, and it is the thing an MCP server actually serves. Curating one from the terminal is a create plus an add, and policy changes apply to every connected client immediately, with no redeploy.
protobox toolsets create support-agent \
--description "What the support agent may touch"
protobox toolsets add support-agent GITHUB_CREATE_ISSUE HTTPBIN_GETREQUEST
protobox toolsets get support-agentThe interesting part is what you can do to a tool as the toolset serves it. Risky tools get a three-state policy: allow, approve (the call pauses until a human decides), or deny.
protobox toolsets policy support-agent GITHUB_CREATE_ISSUE approveThere's a subtler control in the same place: protobox toolsets override support-agent GITHUB_CREATE_ISSUE --name file_bug renames or re-describes a tool as this toolset serves it. What the model sees changes; the tool itself doesn't. That's how two servers can serve the same underlying tool with different framing for different agents, and like the policy change, it applies live.
Held calls land in a queue you drain from the same terminal: protobox approvals lists them, protobox approvals approve <id> replays the call server-side, protobox approvals deny <id> --reason "not in scope" kills it. An approval gate that used to be a dashboard vigil is now something a runbook can name.
Try scripting any of that with a mouse.
Publish the server, wire the clients
Publishing binds a toolset to a URL, and connecting a client is one command that edits the client's own config file for you. This is the step that used to be the most error-prone clicking of all: copying URLs and bearer tokens between a dashboard and four differently-shaped JSON files.
protobox mcp servers create support --toolset support-agent
protobox mcp urlcreate takes --auth api_key if you want bearer-key auth instead of the default OAuth mode. Then, instead of hand-editing claude_desktop_config.json:
protobox mcp connect claude
protobox mcp connect cursor
protobox mcp connect vscodeEach variant knows its client's quirks: Claude Desktop only runs local stdio servers, so the CLI bridges your remote URL through mcp-remote; Cursor takes url plus headers; VS Code wants a servers key with type: "http"; Windsurf (also supported) insists on serverUrl instead of url, the fourth spelling of the same idea. This is exactly the kind of trivia that should live in a tool, not in your head. The command prints the exact block, asks before writing, backs up the existing file, and merges rather than clobbers. protobox mcp connect raw prints a generic block to stdout for anything else, and --yes skips the confirmation for scripts. One nuance for multi-server workspaces: every mcp subcommand takes --server <slug>, implied when you have one server, required when you have several. The CLI makes you pick rather than guessing.
Before telling anyone the server is live, prove it. mcp test runs a real Streamable HTTP handshake, initialize through tools/list, and reports the tool count and latency:
protobox mcp testIt mints a temporary key for the handshake and revokes it afterward, so the test leaves no credential behind. A failed handshake exits non-zero with a targeted hint: connection refused points at the runtime, a 401 points at the key. That exit code is the seed of the CI job we will write in a minute.
Key rotation is two commands
The Friday scenario from the top compresses to this:
protobox mcp keys create --name "laptop-2026q4"
protobox mcp keys revoke <old-key-id>keys create prints the plaintext key exactly once, with its prefix, and warns you to store it. protobox mcp keys list shows every key with its prefix, last four characters, label, and revoked/active status, which is how you find the id to revoke without ever seeing a live secret. Labels are what make rotation auditable: name keys after the machine or the person, and keys list becomes an access review.
Because these are commands, the rotation can be a script in your repo with a date in its name, reviewed once and reused forever. The dashboard version of this knowledge lives in one person's head.
Knowledge that keeps itself in sync
The knowledge base behind your server ingests from the same shell, and the sync commands are where the CLI stops being a convenience and becomes the only sane option. Nobody re-uploads 40 markdown files through a browser after every docs change.
Single items first:
protobox kb add ./runbook.md
protobox kb add https://docs.acme.com/billing
protobox kb --search "refund policy"add handles a file path, a URL, or quoted text, and polls async ingestion to completion (up to two minutes before it tells you to check back). --search runs real retrieval against the store, not filename matching, so you're testing exactly what your MCP clients will get.
The scale move is mirroring a directory, one entry per file, keyed by relative path:
protobox kb sync ./docs
protobox kb sync ./docs --watch--watch keeps a foreground watcher running, tsc-style, debouncing bursts of file events into one sync about every five seconds. For a source of truth that lives in git, skip the local mirror entirely and connect the repo server-side:
protobox kb sync-repo acme/docs --branch main --path docs --every 24h--every 24h hands the schedule to the platform, so the knowledge base re-syncs daily with no cron job on your side. And when content quietly rots anyway, protobox kb stale lists entries that are actually being cited by agents but have not been updated or verified recently, which is a much better cleanup queue than "scroll the dashboard and squint at dates."
And there's an exit door, which matters more than vendors like to admit: protobox kb export ./backup downloads the whole knowledge base as markdown files, one per document. If you ever stop trusting the hosted store, your content walks out in a format grep understands.
Skills, the reusable prompts your MCP clients can pull, round out the content surface: protobox skills lists them, protobox skills create triage --file ./triage.md registers a prompt from a file that can live in your repo next to the code it instructs, and protobox skills import <github-url> installs every SKILL.md in a repo as skills, updating them in place on re-run. That last one turns a public skills repo into a distribution channel with no packaging step.
Put the whole thing in CI
Everything above runs headless with two ingredients: PROTOBOX_API_KEY in the environment and --json where you need to parse output. Commands exit non-zero on failure, so a pipeline fails the way pipelines should.
Here is the docs-deploy job that replaces the manual re-upload forever:
name: Sync docs to knowledge base
on:
push:
branches: [main]
paths: ["docs/**"]
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npx @protoboxai/cli kb sync ./docs
env:
PROTOBOX_API_KEY: ${{ secrets.PROTOBOX_API_KEY }}Yes, that's the whole job. One checkout, one npx, one secret, replacing the teammate who "usually handles the docs upload."
And the smoke test that runs after any change to tools or toolsets, using the handshake command from earlier:
npx @protoboxai/cli mcp test --jsonIf a tool behind your server needs its own credential, that is scriptable too: protobox secrets set OPENAI_API_KEY --value "$OPENAI_API_KEY" sets it non-interactively, which the CLI itself flags as the CI-only path since the interactive prompt keeps secrets out of shell history on a human machine.
The table version of the whole argument, for the ops doc you should be writing:
| Dashboard task | Terminal equivalent |
|---|---|
| Rotate a leaked key | protobox mcp keys create + keys revoke <id> |
| Add an internal API as tools | protobox tools add-api --spec openapi.json |
| Gate a risky tool behind a human | protobox toolsets policy <ts> <tool> approve |
| Re-upload changed docs | protobox kb sync ./docs in CI |
| Verify the server is actually up | protobox mcp test |
| Hand a teammate client config | protobox mcp connect claude --yes |
Where the dashboard still wins
The terminal isn't the whole story, and pretending otherwise would be its own kind of marketing. Creating the workspace and your first server happens at app.protobox.ai. Browsing an unfamiliar app catalog is genuinely better with thumbnails and descriptions than with a 50-row table. An approvals inbox with request context reads better on a screen built for it. The docs cover both surfaces, and the honest split is the boring one: explore in the browser, operate in the shell.
The same honesty applies one level up. If you're running the open-source runtime yourself, you already have this property, because your server config lives in your own repo. The managed value is having the hosted lifecycle keep that property instead of trading it away for a prettier settings page.
The test for any hosted developer tool is whether the second time you perform an ops task is faster than the first. Clicks reset to zero every time. Commands compound: into aliases, into scripts, into runbooks, into CI. If your MCP server matters enough to be in production, its lifecycle deserves to live somewhere git blame can see. The next contractor who rolls off should cost you two commands, not a Friday evening.
Manage your first server from the shell
If you are shipping MCP, the free tier covers your first server: one server, 1,000 requests a month, no credit card. The CLI works from the first login.
Start freeRelated reading on the Chanl blog: Your MCP tool descriptions are failing your agent.
Founder, Protobox
Building TBD bio at Protobox — tools, testing, and observability for customer experience.
Changelog MCP y notas para devs
Actualizaciones cortas y ocasionales sobre la spec MCP, nuevas funciones de Protobox y patrones que vemos en producción. Sin marketing innecesario.



