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

# Any other client

> The raw protocol, for building your own agent.

Everything a client needs, without a client.

|                  |                                      |
| ---------------- | ------------------------------------ |
| Endpoint         | `https://api.minidesk.ai/mcp`        |
| Method           | `POST`                               |
| Transport        | Streamable HTTP                      |
| Protocol version | `2025-06-18`                         |
| Auth             | `Authorization: Bearer mdsk_mcp_...` |
| Content type     | `application/json`                   |

Requests are JSON-RPC 2.0. Every call is a single POST; there is no session to
open or keep alive.

## initialize

```bash theme={null}
curl -X POST https://api.minidesk.ai/mcp \
  -H "Authorization: Bearer $MINIDESK_MCP_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "jsonrpc": "2.0", "id": 1, "method": "initialize" }'
```

```json theme={null}
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2025-06-18",
    "capabilities": { "tools": {} },
    "serverInfo": { "name": "minidesk", "version": "1.0.0" }
  }
}
```

## tools/list

```bash theme={null}
curl -X POST https://api.minidesk.ai/mcp \
  -H "Authorization: Bearer $MINIDESK_MCP_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "jsonrpc": "2.0", "id": 2, "method": "tools/list" }'
```

Returns every tool with its `name`, `description`, and `inputSchema`. The list
is sorted by name, so it is stable between calls.

Discover the surface here rather than hard-coding it. Adding a tool is an
additive change we may make at any time; changing an existing tool's schema is
not.

## tools/call

```bash theme={null}
curl -X POST https://api.minidesk.ai/mcp \
  -H "Authorization: Bearer $MINIDESK_MCP_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 3,
    "method": "tools/call",
    "params": {
      "name": "list_oldest_unanswered",
      "arguments": { "limit": 5 }
    }
  }'
```

The result is MCP content blocks. Tool output is JSON inside a text block,
which is the interoperable shape: every client can read it, and structured
blocks are not widely supported yet.

```json theme={null}
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [
      { "type": "text", "text": "{\n  \"as_of\": \"2026-08-28T14:22:10Z\",\n  \"data\": []\n}" }
    ],
    "isError": false
  }
}
```

So reading a result means parsing `result.content[0].text` as JSON.

## Errors

Two layers, and they look different.

**Protocol errors** come back as JSON-RPC errors:

| Code     | Meaning                            |
| -------- | ---------------------------------- |
| `-32600` | The request was not valid JSON-RPC |
| `-32601` | Unknown method                     |

**Tool errors** are a successful JSON-RPC response with `isError: true`, and
the text block holds `{ "error": "..." }`. An unknown tool name is one of
these rather than a silent no-op, because a client that thinks it filed a
draft and got a quiet success is the worst outcome available.

**Transport errors** are ordinary HTTP. A `401` means the credential is
missing, malformed, revoked, or an API token rather than an MCP one. A `429`
means you are over [the rate limit](/guides/rate-limits) and `Retry-After`
says when to come back.

## A minimal client

```js theme={null}
async function callTool(name, args = {}) {
  const response = await fetch("https://api.minidesk.ai/mcp", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.MINIDESK_MCP_TOKEN}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      jsonrpc: "2.0",
      id: Date.now(),
      method: "tools/call",
      params: { name, arguments: args },
    }),
  });

  if (!response.ok) throw new Error(`HTTP ${response.status}`);

  const { result, error } = await response.json();

  if (error) throw new Error(error.message);

  return JSON.parse(result.content[0].text);
}

const summary = await callTool("get_support_summary");
```

## Using the official SDK

Any MCP SDK that speaks Streamable HTTP works. Point it at the endpoint and
pass the header.

```js theme={null}
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";

const transport = new StreamableHTTPClientTransport(
  new URL("https://api.minidesk.ai/mcp"),
  {
    requestInit: {
      headers: { Authorization: `Bearer ${process.env.MINIDESK_MCP_TOKEN}` },
    },
  },
);

const client = new Client({ name: "my-agent", version: "1.0.0" });
await client.connect(transport);

const { tools } = await client.listTools();
```
