> ## Documentation Index
> Fetch the complete documentation index at: https://docs.paperzilla.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP endpoint (developer appendix)

> Technical MCP endpoint details for developers integrating Paperzilla clients with projects, full-feed search, paper detail, and markdown.

export const AiAgents = ({path}) => <Tip>
    <b>AI agents</b>: This page is available as <a href={path + '.md'}>markdown</a>. See also the <a href="/llms.txt">docs index</a> and <a href="/llms-full.txt">full docs</a>.
  </Tip>;

<AiAgents path="/api-reference/mcp" />

This page is a technical appendix for developers.

If you are a Paperzilla user setting up MCP, start with [Use Paperzilla with MCP](/guides/mcp).

Paperzilla exposes a Streamable HTTP MCP endpoint:

```text theme={null}
POST /api/mcp
```

Base URL example:

```text theme={null}
https://paperzilla.ai/api/mcp
```

If you want the short version of how discovery works, see [How do clients discover the Paperzilla MCP URL and tools?](/answers/how-do-clients-discover-paperzilla-mcp).

## Authentication

Send your MCP API key in either of these ways:

```http theme={null}
Authorization: Bearer pzmcp_<prefix>_<secret>
```

```text theme={null}
https://paperzilla.ai/api/mcp/?key=pzmcp_<prefix>_<secret>
```

Use the header form when your client supports custom headers. Use the query-string form when your client only accepts a URL, including Claude's custom connector flow.

For most users, create/revoke this key from **MCP API key** in the top-right of the [dashboard](https://paperzilla.ai/dashboard).

Get or rotate that key from app-authenticated endpoints:

* `GET /api/auth/mcp-key`
* `POST /api/auth/mcp-key/rotate`
* `DELETE /api/auth/mcp-key`

These key-management endpoints use your normal app JWT, not your MCP key.

## Key management endpoints (developer use)

```text theme={null}
GET /api/auth/mcp-key
POST /api/auth/mcp-key/rotate
DELETE /api/auth/mcp-key
```

## MCP methods currently used

Paperzilla supports standard MCP flows including:

* `initialize`
* `tools/list`
* `tools/call`
* `prompts/list`
* `prompts/get`

## Initialize example

The examples below use header auth.

```bash theme={null}
curl -s -X POST https://paperzilla.ai/api/mcp \
  -H "Authorization: Bearer pzmcp_..." \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc":"2.0",
    "id":1,
    "method":"initialize",
    "params":{
      "protocolVersion":"2025-11-05",
      "capabilities":{},
      "clientInfo":{"name":"probe","version":"1.0"}
    }
  }'
```

## Tools

| Tool             | Input                                                                                                                                                    |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `projects_list`  | `{}`                                                                                                                                                     |
| `projects_get`   | `{ "project_id": "uuid" }`                                                                                                                               |
| `feed_get`       | `{ "project_id": "uuid", "must_read"?: boolean, "since"?: string, "limit"?: 1..100, "offset"?: 0.. }`                                                    |
| `feed_search`    | `{ "project_id": "uuid", "q": "string (3..200 chars after trim)", "feedback_filter"?: "enum", "must_read"?: boolean, "limit"?: 1..100, "offset"?: 0.. }` |
| `feed_atom_url`  | `{ "project_id": "uuid" }`                                                                                                                               |
| `paper_get`      | `{ "paper_id": "uuid-or-short-id-or-feed-item-id" }`                                                                                                     |
| `paper_markdown` | `{ "paper_id": "uuid-or-short-id-or-feed-item-id" }`                                                                                                     |

Legacy dotted names such as `paper.get` remain accepted for direct `tools/call` compatibility, but Claude-compatible clients should use the underscore names above. The feed search alias is `feed.search`.

`paper_get` accepts the same identifier forms as the paper API:

* paper UUID
* paper `short_id`
* `project_paper` UUID
* `project_paper` `short_id`

`projects_*` and `feed_*` outputs follow the same shape as the corresponding API responses.

`feed_search` is the MCP path for full-feed text search. It searches title, author, abstract, and summary text across the entire project feed.

`feed_search.feedback_filter` accepts:

* `all`
* `unrated`
* `liked`
* `disliked`
* `starred`
* `not-relevant`
* `low-quality`

`feed_search` returns:

* `items`
* `limit`
* `offset`
* `has_more`
* `query`

Search semantics:

* query terms use prefix matching, so `Proxi` matches `Proximity`
* search is rank-first, not browse-order-first
* no exact `total` is returned in v1

`paper_get` returns the same paper detail fields as the authenticated paper API, including `markdown_ready`.

PubMed paper details use `PMID <number>` as `reference_label`, preserve a DOI separately when present, and link to the PubMed record. `pdf_url` can be `null`; do not infer that a PubMed record has public full text.

`paper_markdown` always returns a structured object:

* ready:
  ```json theme={null}
  {
    "status": "ready",
    "paper_id": "uuid",
    "markdown": "# Markdown...",
    "mime_type": "text/markdown",
    "markdown_ready": true
  }
  ```
* queued:
  ```json theme={null}
  {
    "status": "queued",
    "detail": "Markdown queued",
    "code": "markdown_queued",
    "job_id": "uuid",
    "created": true
  }
  ```
* unavailable:
  ```json theme={null}
  {
    "status": "unavailable",
    "detail": "Markdown source unavailable",
    "code": "markdown_source_unavailable"
  }
  ```

## Tool call examples

List projects:

```bash theme={null}
curl -s -X POST https://paperzilla.ai/api/mcp \
  -H "Authorization: Bearer pzmcp_..." \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc":"2.0",
    "id":2,
    "method":"tools/call",
    "params":{
      "name":"projects_list",
      "arguments":{}
    }
  }'
```

Search a full project feed:

```bash theme={null}
curl -s -X POST https://paperzilla.ai/api/mcp \
  -H "Authorization: Bearer pzmcp_..." \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc":"2.0",
    "id":3,
    "method":"tools/call",
    "params":{
      "name":"feed_search",
      "arguments":{
        "project_id":"20a9c4fd-779a-41c7-92e9-efabc5e9eea5",
        "q":"latent retrieval",
        "feedback_filter":"all",
        "limit":20,
        "offset":0
      }
    }
  }'
```

## Prompt

Prompt name:

* `feed_title_filter`

Arguments:

* `project_id` (required)
* `title_keyword` (required)
* `must_read` (optional)
* `feedback_filter` (optional)
* `limit` (optional)

The prompt instructs the model to call `feed_search` and explain that the search is server-side across the full feed.

## Error semantics

* Invalid/missing key: HTTP `401`
* Disallowed `Origin`: HTTP `403`
* Invalid MCP method/JSON-RPC shape: protocol-level error
* Business/domain errors (ownership, missing project, missing paper, ambiguous short ID): tool result with `isError: true`
* `paper_markdown` queueing and source-unavailable cases are normal tool results, not tool errors
