# tools/list (/docs/reference/mcp/tools-list)

`POST https://api.corespeed.io/mcp` — JSON-RPC method `tools/list`

`tools/list` is the authority on what this caller can **see**. It is filtered
per request by connected accounts (your own and those shared with you), your
organization's remote MCP servers, organization plus member capability
settings, and the features enabled for your organization — never cache it
across identities, and never build a static tool inventory in application code.

Visibility is not executability. The list carries every `manage__*` tool for
an API-key caller too; a call runs with what the key holds, so an agent key
is refused on a permission-gated write (`admin_required`,
`insufficient_role`) and on a member's own act (`member_principal_required`),
and every key on a mint (`api_key_cannot_mint`). It also carries tools from
connectors in `needs_reauth`, which fail until the account is reauthorized.
An account shared with you for only some tools lists every tool of its
connector; the others answer `tool_not_granted`. Inside an
[environment](/docs/mcp#environments-a-session-with-fewer-accounts)
(`/mcp/env/<name>`, or a key bound to one), the list holds only the connectors
the environment includes, and within each only the tools its entries allow.
Absence proves a tool cannot be called; presence does not prove it can. Branch on
the result, not on membership in this list.

No `manage__*` tool is reserved to a session: apart from those refusals and
`manage__switch_org` (browser sign-ins only), every one runs for an API key as
its principal — [Authentication](/docs/authentication#what-a-credential-may-do)
has the table. The `remote_*` writes check `connections:org`;
`connectors_wait` answers only for the caller's own accounts and
`approval_wait` only for the caller's own requests. `approval_wait` is listed
only where Smart Approvals is available to your organization, the three
`connectors_*` tools only where connect links are, and `send_feedback` only
where feedback is. See [tools/call](/docs/reference/mcp/tools-call).

#### Authorizations

* `Authorization` (string, header, required) — `Bearer <token>` — an MCP OAuth token, an `sk-cs-…` API key or `sk-csa-…` agent key, or a user session JWT. `x-api-key: <sk-cs-…>` is accepted in its place.
* `Accept` (string, header, required) — `application/json, text/event-stream` — the Streamable HTTP transport requires both media types. This 2025-era request is answered as one `text/event-stream` event; its `data:` line is the JSON-RPC response.
* `Content-Type` (string, header, required) — `application/json`. The transport rejects anything else with `415`.

#### Request

* `params` (object, optional) — Send `{}`. CoreSpeed returns the full visible surface in one response; there is no pagination cursor to follow today.

#### Response fields

* `tools[].name` (string, required) — The wire name, `<capability-id>__<operation>`. Pass it verbatim to `tools/call`.
* `tools[].description` (string, optional) — Model-facing description of when to use the tool. Optional in the MCP schema — CoreSpeed's own tools always set it, but a tool proxied from an org-registered remote MCP server may omit it. Do not require it.
* `tools[].inputSchema` (object, required) — JSON Schema for the `arguments` object. Validate against this rather than against examples.
* `tools[].outputSchema` (object, optional) — JSON Schema for `structuredContent` on a successful call. Only some tools declare it.
* `tools[].annotations` (object, optional) — Display title plus behavior hints (`readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint`). Useful for deciding what needs a human in the loop.

A connector contributes tools as soon as the caller has a stored visible
credential for it — including an account in `needs_reauth`, whose tool calls
then fail until the account is reauthorized. Presence in `tools/list` means
visible, not necessarily healthy; check `GET /connectors` for account health.

**curl**

```bash
curl https://api.corespeed.io/mcp \
  -H "Authorization: Bearer $CORESPEED_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}'
```

**TypeScript**

```ts
const res = await fetch("https://api.corespeed.io/mcp", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.CORESPEED_API_KEY}`,
    "Content-Type": "application/json",
    Accept: "application/json, text/event-stream",
  },
  body: JSON.stringify({
    jsonrpc: "2.0",
    id: 2,
    method: "tools/list",
    params: {},
  }),
});

// One SSE event: the JSON-RPC response is its data line.
const data = (await res.text()).split("\n").filter((line) => line.startsWith("data: ")).at(-1)!;
const { result } = JSON.parse(data.slice("data: ".length));
for (const tool of result.tools) {
  console.log(tool.name);
}
```

**Python**

```python
import json
import os
import httpx

res = httpx.post(
    "https://api.corespeed.io/mcp",
    headers={
        "Authorization": f"Bearer {os.environ['CORESPEED_API_KEY']}",
        "Content-Type": "application/json",
        "Accept": "application/json, text/event-stream",
    },
    json={"jsonrpc": "2.0", "id": 2, "method": "tools/list", "params": {}},
)

# One SSE event: the JSON-RPC response is its data line.
data = [line for line in res.text.splitlines() if line.startswith("data: ")][-1]
for tool in json.loads(data[len("data: "):])["result"]["tools"]:
    print(tool["name"])
```

**Go**

```go
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
)

func main() {
	body, _ := json.Marshal(map[string]any{
		"jsonrpc": "2.0",
		"id":      2,
		"method":  "tools/list",
		"params":  map[string]any{},
	})

	req, _ := http.NewRequest("POST", "https://api.corespeed.io/mcp", bytes.NewReader(body))
	req.Header.Set("Authorization", "Bearer "+os.Getenv("CORESPEED_API_KEY"))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Accept", "application/json, text/event-stream")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	// One SSE event: the JSON-RPC response is its data line.
	raw, _ := io.ReadAll(res.Body)
	var data string
	for _, line := range strings.Split(string(raw), "\n") {
		if strings.HasPrefix(line, "data: ") {
			data = strings.TrimPrefix(line, "data: ")
		}
	}

	var out struct {
		Result struct {
			Tools []struct {
				Name string `json:"name"`
			} `json:"tools"`
		} `json:"result"`
	}
	json.Unmarshal([]byte(data), &out)
	for _, tool := range out.Result.Tools {
		fmt.Println(tool.Name)
	}
}
```

**200 OK** — Visible surface (truncated)

```json
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "tools": [
      {
        "name": "memory__search",
        "description": "Search saved long-term memories for facts relevant to the current question or task.",
        "inputSchema": {
          "type": "object",
          "properties": {
            "query": { "type": "string" }
          },
          "required": ["query"]
        },
        "annotations": {
          "title": "Search memory",
          "readOnlyHint": true,
          "destructiveHint": false,
          "idempotentHint": true,
          "openWorldHint": false
        }
      },
      {
        "name": "notion__create_page",
        "description": "Create a new Notion page under a parent page, with a title and optional plain-text content (one paragraph per line).",
        "inputSchema": {
          "type": "object",
          "properties": {
            "parent_page_id": { "type": "string" },
            "title": { "type": "string" }
          },
          "required": ["parent_page_id", "title"]
        },
        "annotations": {
          "readOnlyHint": false,
          "destructiveHint": false,
          "idempotentHint": false,
          "openWorldHint": true
        }
      }
    ]
  }
}
```

**400 Bad Request** — Batch rejected

A JSON array body is refused before any tool runs: one rate-limit slot must not
carry an unbounded number of tool calls.

```json
{
  "jsonrpc": "2.0",
  "id": null,
  "error": {
    "code": -32600,
    "message": "JSON-RPC batch requests are not supported; send one request per tool call."
  }
}
```