# MCP server (https://upapi.io/docs/mcp)



The Model Context Protocol lets an AI assistant call tools. upAPI publishes its
operations over MCP, so an operation becomes a tool the assistant can invoke —
with your key, your quota and the same schemas as the REST gateway.

There are two ways to connect, described below. They differ in how you authorize
and in how much of the catalog they serve. For the configuration to paste into a
specific client, see [Connect an MCP client](https://upapi.io/docs/mcp-clients).

## Hosted server [#hosted-server]

`https://app.upapi.io/api/mcp` speaks MCP over streamable HTTP and authorizes
over OAuth 2.1 with PKCE, against the same accounts system as the dashboard. A
client connects by signing in through a browser, so no API key is ever written
into a config file.

Each request re-establishes your identity from the access token, and tool calls
execute on exactly the path the marketplace try-it panel uses — the same plan
gating and the same meter. A [guest session](https://upapi.io/docs/quickstart#1-create-an-account)
cannot connect; see [Connect an MCP client](https://upapi.io/docs/mcp-clients) for why.

Clients normally register themselves through dynamic client registration.
Marketplaces whose tenant admins cannot (Microsoft 365 Copilot, Gemini
Enterprise) get a static confidential client instead: the operator lists it in
the `OAUTH_STATIC_CLIENTS` environment variable (client id, secret, name,
exact redirect URIs, token-endpoint auth method), and every boot upserts it
into the same client table. Such a client authenticates with its secret, never
expires, and is left in place if it is later removed from the variable.

The hosted server serves **every public operation**, the same catalog as the
REST gateway. Operations that write something, such
as posting a comment or opening a mailbox, carry `readOnlyHint: false`, so your
client can ask before it runs them.

## Local server [#local-server]

The `upapi-mcp` command speaks MCP over stdio and forwards each tool call to
`api.upapi.io` with your API key. It runs on your machine, alongside the client.

It authenticates with the key in `UPAPI_API_KEY` and validates nothing itself —
your key is checked at the same gateway choke point as any other call, so an
MCP tool call is metered and rate-limited exactly like the equivalent `curl`.
Point it at a different gateway origin with `UPAPI_BASE_URL` if you need to.

The hosted server serves every public operation. The local server catches up in the next
`@upapi/mcp` release: 0.2.0 serves 63 operations and still withholds Social Media and Utility in
`directory` mode.

{/* TODO(mcp-release, 2026-10-08): drop the qualifier after @upapi/mcp 0.3.0 ships (order: sdk → mirror --only mcp → mcp → registry → mcpb → GH release) */}

## What the tools look like [#what-the-tools-look-like]

Each public operation becomes one tool, with the operation's input schema as its
parameter schema. The assistant sees the same field names, types and
descriptions the marketplace shows you, so it can fill arguments without
guessing.

How many of those tools are advertised at once is a choice — `compact`,
`directory` or `full`, set on the URL for the hosted server and in
`UPAPI_TOOL_MODE` for the local one. All three are built from the same tool
table, so the mode changes what is listed and never what is reachable. See
[Which tools you get](https://upapi.io/docs/mcp-clients#which-tools-you-get).

Every tool declares the four MCP behavioural hints — `readOnlyHint`,
`destructiveHint`, `idempotentHint` and `openWorldHint` — and they describe what
the worker actually does rather than what the slug's `.get`/`.post` suffix
suggests. `openWorldHint` is true on every operation except two: upAPI is a
marketplace, so nearly every operation exists to reach a system upAPI does not
own. `text-analyze.post` and `email-generate-address.post` run entirely inside
the worker and make no network call, so they declare `openWorldHint: false`.

A tool's **name is not the slug**: MCP names have to be identifier-safe, so it
is the operation id — the slug with dots and hyphens replaced by underscores.
`github-trending.get` is the tool `github_trending_get`. The tool's description
names the slug it maps to, and what a call costs, so you can cross-read these
docs from a `tools/list` dump.

Results come back as the operation's output object, JSON-encoded into a text
block — no tool declares an `outputSchema`, and none returns `structuredContent`.
That is deliberate: MCP obliges a server that declares an output schema to return
matching structured content, and these outputs describe live third-party
payloads, where one unexpected null would turn a successful call into a protocol
error. Failures arrive with the [standard error code](https://upapi.io/docs/errors), which means
an assistant can tell "you are out of quota" apart from "that operation does not
exist" and say something useful about it.

## Cost [#cost]

MCP tool calls are ordinary gateway calls: they consume the operation's
[weighted units](https://upapi.io/docs/rate-limits) and count against the same monthly quota as
your application traffic.

Worth knowing before you point an agent at the catalog: an assistant exploring
on its own can spend a lot more than a deliberate script, and the heaviest
operations in the catalog cost 20 units per call. Check
[`/api/usage`](https://upapi.io/docs/usage-api) after a long session, and keep an eye on the
[quota notifications](https://upapi.io/docs/platform/notifications) at **70% and 90%**.
