Postal Developers
MCP server

Compact mode

How responses are trimmed by default, and how to get the full payload.

Assistants pay for every token a tool returns. The Postal MCP server therefore returns compact objects by default and lets you opt into the raw API payload per call.

The detail parameter

Nine read tools accept detail: "compact" | "full":

list_tracks, get_track, search_tracks, list_track_versions, list_playlists, get_playlist, get_tag_taxonomy, list_composers, get_composer.

There is no server-wide switch. Pass detail: "full" on the call that needs it.

Where the compact shape comes from

The compact shape is the API's own. Each of these tools sends detail to the REST route as its view query parameter (view=compact or view=full, see the API reference), and the API answers with the trimmed object and an X-Postal-View header naming the view it applied. The MCP server passes the answer through untouched, so REST clients, the MCP server and Postal's own assistant all receive the same objects from one implementation. The tables below describe what you receive.

What every response looks like

Each tool returns a one-line human summary followed by pretty-printed JSON. The summary is rendered from a template the API publishes with the tool, read against the payload as served, so counts and paging cursors stay accurate when the body is trimmed.

Found 42 tracks (showing 20, next cursor: ck_…)
[
  { "id": "…", "title": "Night Drive", "artist": "…", "bpm": 92, … }
]

What compact keeps

ObjectKeptDropped
Trackid, title, artist, durationSec, bpm, key, createdAt, link, cid, tag names per category, autotagModelVersion (+ autotagModelVersions when mixed)audio file URLs, shareholders, share-link internals, per-tag confidence and modelVersion
Playlistmetadata, publicLink, per-track { id, title, artist, durationSec, order }download links, full audio profiles
Composercomposer fields, linked tracks as { id, name } (max 25, tracksTruncated: true beyond that)full track objects
Taxonomyplain name arrays per categoryids, codes, ordering
Search hitid, title, artist, bpm, key, durationSec, genres, moods, score, first two reasons, plus the interpretation blockremaining reasons, raw feature vectors
Dashboardeverything except entityImage on activity items (always trimmed)

For list_tracks, view=compact also makes the API read fewer columns, so a compact listing is cheaper to serve as well as to read. The API refuses view=compact combined with its fields parameter; the MCP server never sends both.

Mutations

Write tools return the API route's own response, exactly as a REST client would receive it: a created playlist, an updated version, a { "success": true } acknowledgement, whatever that route answers. The summary line says what happened in words, for example:

Added 3 tracks to playlist pl_123.

Earlier server versions replaced these responses with a minimal { "ok": true, … } confirmation; that is no longer the case.

Errors

An error result takes the same shape as a success: a sentence, a blank line, then a JSON body. The body carries the API's stable messageCode as error and the HTTP status, so an assistant can branch on the code rather than the wording. The sentence is the API's own message, which for a read on an ID that does not exist (or is not yours) names the ID and the list tool that returns valid ones:

Error: Track "does-not-exist" not found: it does not exist or is not yours. list_tracks or search_tracks return the track IDs in your library.

{
  "error": "not_found",
  "status": 404
}

Every read tool answers an unknown ID this way — get_track, get_composer, get_playlist, the version and brief reads, and get_track_analysis — so an existence check never passes on a compact object whose fields are all null. get_entity_stats keeps its partial answer with a notFound list and only errors when none of the IDs resolve.

A 401 or 403 adds a hint to the sentence (— check that the API key is valid, — the API key is missing a required scope for this action).

When the API answers { ok: false, … } inside a 200 the server converts it into the same error shape, with the payload's error as the code and (missing: …) appended to the sentence when the payload lists what was missing.

On this page