MCP
Emits exposes its verbs as Model Context Protocol tools, so an agent client publishes by making tool calls instead of driving the CLI. There is one set of tools and two transports: a local server the client launches as a subprocess, and a hosted endpoint for clients that cannot.
The tools
| Tool | What it does | Scope |
|---|---|---|
publish |
Create a page from HTML passed as a string; returns the live URL | pages:write |
update |
Replace a page's contents; the URL does not change | pages:write |
list |
List the account's pages | pages:read |
unpublish |
Take a page offline | pages:write |
Both transports serve exactly these four, identically described: the tool definitions are shared, so a tool cannot exist locally and be missing remotely.
The local server
emit mcp
runs the server on stdio, which every subprocess-capable client can launch with no port, no TLS, and no inbound network. A typical client configuration:
{
"mcpServers": {
"emits": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@mzedstudio/emits-cli", "mcp"]
}
}
}
Auth is the CLI's: the server reads the credential
emit login stored in ~/.emits/, re-reading it
on each call, so logging in from another terminal mid-session is picked up
and credentials never leave the machine or appear on a socket.
The remote server
Clients that cannot launch a subprocess (browser-hosted connectors, hosted agents) connect to:
https://api.emits.app/mcp
There is no key to mint and no client to register by hand; the endpoint bootstraps a conforming client from a single unauthenticated request:
The client
POSTs without a token and receives a401whoseWWW-Authenticateheader carries aresource_metadataURL:WWW-Authenticate: Bearer resource_metadata="https://api.emits.app/.well-known/oauth-protected-resource/mcp"It fetches that RFC 9728 document and learns which authorization server can issue it a token.
It registers itself with dynamic client registration.
It runs the authorization-code grant with PKCE, sending its human to a browser consent screen that names the client and the scopes.
It retries with the bearer token it was issued.
The token rides the Authorization header only: the MCP spec forbids tokens
in the query string, and so does the endpoint.
Which transport to choose
Prefer the local server whenever the client can launch one: the credential stays on the machine and there is no OAuth handshake to perform. The hosted endpoint deliberately makes the opposite trade: it is reachable from anywhere, and pays for that with the browser consent flow above. Approved clients appear in the console under Settings → API access, one entry per client, where access can be revoked.