Connect an MCP client
Working configuration for Claude Code, Claude Desktop, Cursor and VS Code.
Pick a transport, then copy the block for your client. Both transports expose
tools with the same schemas and draw on the same monthly pool of
weighted units. They differ in how a call is authenticated,
and — following from that — in what the per-minute burst limit is counted
against: the hosted server meters per organization, the local server per API key.
The hosted server serves every public operation; the local server catches up in the next
@upapi/mcp release (0.2.0 serves 63 and still withholds Social Media and Utility in directory mode).
See MCP server for what the tools look like once connected.
To let a coding agent do all of this itself, see Agent setup.
| Transport | Hosted | Local |
|---|---|---|
| Endpoint | https://app.upapi.io/api/mcp | npx -y @upapi/mcp (stdio) |
| Auth | sign in to upAPI in a browser | UPAPI_API_KEY in the config |
| Runs | on upAPI | on your machine |
| Best for | desktop clients and IDEs | scripts, CI, self-hosted agents |
Prefer the hosted server. It authorizes over OAuth 2.1 with PKCE against the same accounts system as the dashboard, so there is no key to paste into a file on disk and no key to rotate when a laptop is lost.
The hosted server needs a full account
A guest session cannot connect: the endpoint answers 401 GUEST_FORBIDDEN. Guest identities are temporary and get reaped, which would break a long-lived
integration in a way you could not diagnose from the client. Convert the guest account first — the
local server has no such restriction, since it authenticates with an API key.
For the local server, create a key at Dashboard → API keys first. It reads two environment variables:
| Variable | Required | Value |
|---|---|---|
UPAPI_API_KEY | Yes | an upapi_ key |
UPAPI_BASE_URL | No | gateway origin, defaults to https://api.upapi.io |
UPAPI_TOOL_MODE | No | compact (default), directory, claude or full — see below |
Which tools you get
Within a transport, every mode serves the same operations. What changes between modes is how
many of them are advertised in tools/list — a context-budget and
presentation choice, never an access one. An operation a mode does not list is
still callable by name.
| Mode | Advertises | Use it when |
|---|---|---|
compact | search_ops + call_op + three always-on operations | a long chat that re-sends its tool table every turn |
directory | 11 named flagship tools, read tools and write tools separated | a desktop client, or anywhere a human reads the tool list |
claude | 8 named tools upAPI computes itself, reads and writes split | the Claude connector listing |
full | one tool per public operation | a fixed workflow that wants every schema present without a lookup |
Every tool in every mode carries the four MCP behavioural hints —
readOnlyHint, destructiveHint, idempotentHint and openWorldHint — so a
client can decide what may run unattended without inferring it from a name.
The hosted server picks the mode from the URL and defaults to compact:
https://app.upapi.io/api/mcp # compact
https://app.upapi.io/api/mcp?tools=directory # named flagship tools
https://app.upapi.io/api/mcp?tools=claude # named tools upAPI computes itself
https://app.upapi.io/api/mcp?tools=full # one tool per operationThe local server reads UPAPI_TOOL_MODE and defaults to compact, the same shape the hosted
endpoint defaults to. full (one tool per operation, this server's original default) remains
available as a rollback for a client already configured against it. An unrecognized value falls
back to the default rather than refusing to start.
Claude Code
claude mcp add --transport http upapi https://app.upapi.io/api/mcpClaude Code opens a browser to authorize the connection on first use.
claude mcp add upapi --env UPAPI_API_KEY=upapi_YOUR_KEY -- npx -y @upapi/mcpClaude Desktop
The shortest path is the desktop extension. Download upapi.mcpb from the
latest release,
double-click it, and paste your API key when Claude Desktop asks: the key is
held as a sensitive setting rather than written into a config file on disk, and
the extension defaults to the directory tool table.
For the hosted server, add it through the app rather than the config file:
Settings → Connectors → Add → Add custom connector, then enter
https://app.upapi.io/api/mcp and click Add. Claude connects from Anthropic's
infrastructure rather than from your machine, which is fine here — the endpoint
is public.
The local server goes in claude_desktop_config.json:
{
"mcpServers": {
"upapi": {
"command": "npx",
"args": ["-y", "@upapi/mcp"],
"env": {
"UPAPI_API_KEY": "upapi_YOUR_KEY"
}
}
}
}Restart Claude Desktop; the operations appear in its tool list.
Cursor
One click installs the hosted server: Add upAPI to Cursor. The link only opens Cursor's install dialog — nothing is written until you confirm there.
Both forms also go in .cursor/mcp.json (project) or ~/.cursor/mcp.json
(global):
{
"mcpServers": {
"upapi": {
"url": "https://app.upapi.io/api/mcp"
}
}
}{
"mcpServers": {
"upapi": {
"command": "npx",
"args": ["-y", "@upapi/mcp"],
"env": {
"UPAPI_API_KEY": "upapi_YOUR_KEY"
}
}
}
}VS Code
VS Code uses servers rather than mcpServers, and wants an explicit type.
Put this in .vscode/mcp.json for one workspace, or in your user profile's
mcp.json for all of them:
{
"servers": {
"upapi": {
"type": "http",
"url": "https://app.upapi.io/api/mcp"
}
}
}For the local server, take the key from a prompted input rather than hardcoding
it — .vscode/mcp.json is usually committed:
{
"inputs": [
{
"type": "promptString",
"id": "upapi-key",
"description": "upAPI API key",
"password": true
}
],
"servers": {
"upapi": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@upapi/mcp"],
"env": {
"UPAPI_API_KEY": "${input:upapi-key}"
}
}
}
}Other clients
Any client that can launch a stdio server takes the same command
(npx -y @upapi/mcp) with UPAPI_API_KEY in its environment, and any client
that speaks remote MCP takes the hosted URL. Nothing in either transport is
client-specific.
Your key is a credential in a config file
Every UPAPI_API_KEY block above puts a live key in plain text on disk. Use a key created for
this purpose so you can delete it without disturbing production, keep the file out of dotfile
repositories, and prefer the hosted server or VS Code's inputs prompt where you can.