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

# Discover, Install, and Invoke

> Find tools at runtime, add them to your agent, and call them

Discover tools on demand instead of loading hundreds into context.

1. **Discover** — `capabilities_discover` with a task description
2. **Install** — `capability_details` with tool names (map to your model's function-calling format)
3. **Invoke** — `tools/call` on the server path

Both discovery tools live on `/pinkfish-sidekick`. For full parameter schemas, see the [Pinkfish Workflow Building server reference](/api-reference/mcp-servers/embedded/pinkfish-sidekick).

## End-to-End Example

```javascript theme={null}
const MCP_URL = "https://mcp.app.pinkfish.ai";
const TOKEN = "<YOUR_PLATFORM_JWT>";

const headers = {
  Authorization: `Bearer ${TOKEN}`,
  "Content-Type": "application/json",
  Accept: "application/json",
};

async function callTool(serverPath, toolName, args) {
  const resp = await fetch(`${MCP_URL}${serverPath}`, {
    method: "POST",
    headers,
    body: JSON.stringify({
      jsonrpc: "2.0",
      method: "tools/call",
      params: { name: toolName, arguments: args },
      id: 1,
    }),
  });
  const result = await resp.json();
  if (result.error) throw new Error(result.error.message);
  return result.result;
}

function parseResult(r) {
  if (r?.structuredContent) return r.structuredContent;
  return JSON.parse(r?.content?.[0]?.text ?? "{}");
}

async function discover(task) {
  const r = await callTool("/pinkfish-sidekick", "capabilities_discover", { request: task });
  return parseResult(r);
}

async function getDetails(items) {
  const r = await callTool("/pinkfish-sidekick", "capability_details", { items });
  return parseResult(r);
}

// 1. Discover
const capabilities = await discover("search the web for AI news");
const topTool = capabilities.tools?.[0];
if (!topTool) throw new Error("No tools found");

// 2. Install (optional — get schema when you need parameter details)
const details = await getDetails([topTool.name]);

// 3. Invoke
const result = await callTool(`/${topTool.serverName}`, topTool.name, {
  q: "latest AI news 2026",
});
console.log(parseResult(result));
```

<Note>Node.js 18+ or browser. Python: `requests.post()` with same JSON-RPC payload.</Note>

## `capabilities_discover`

Describe the task; get matching tools and connections.

```bash theme={null}
curl -s -X POST "https://mcp.app.pinkfish.ai/pinkfish-sidekick" \
  -H "Authorization: Bearer $PINKFISH_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "tools/call",
    "params": {
      "name": "capabilities_discover",
      "arguments": {
        "request": "search my gmail for unread emails"
      }
    },
    "id": 1
  }'
```

**Parameters:**

| Parameter | Required | Description                                                                                     |
| --------- | -------- | ----------------------------------------------------------------------------------------------- |
| `request` | Yes      | Natural language description of the task                                                        |
| `types`   | No       | Filter results: `["tool"]`, `["connection"]`, `["resource"]`, `["agentSkill"]`, or combinations |
| `context` | No       | `"workflow-creation"` or `"agent-execution"` — filters available skills                         |

**Response:**

```json theme={null}
{
  "tools": [
    {
      "name": "gmail_search_emails",
      "serverName": "gmail",
      "hasSkill": false,
      "confidence": 0.95
    }
  ],
  "connections": [
    {
      "name": "My Gmail",
      "id": "abc123-pcid",
      "application": "gmail",
      "confidence": 0.95
    }
  ],
  "resources": [],
  "skills": []
}
```

| Field                | Use                                   |
| -------------------- | ------------------------------------- |
| `tools[].name`       | Tool name for `tools/call`            |
| `tools[].serverName` | Server path (e.g. `gmail` → `/gmail`) |
| `connections[].id`   | PCID for application tools            |

## `capability_details`

Pass tool names; get full parameter schemas.

```bash theme={null}
curl -s -X POST "https://mcp.app.pinkfish.ai/pinkfish-sidekick" \
  -H "Authorization: Bearer $PINKFISH_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "tools/call",
    "params": {
      "name": "capability_details",
      "arguments": {
        "items": ["gmail_search_emails"]
      }
    },
    "id": 1
  }'
```

**Parameters:**

| Parameter | Required | Description                                                            |
| --------- | -------- | ---------------------------------------------------------------------- |
| `items`   | Yes      | Tool names from discovery (use `tools[].name`, not `serverName`)       |
| `types`   | No       | Filter: `["tool"]`, `["connection"]`, `["resource"]`, `["agentSkill"]` |

## Key Points

* Embedded tools: no PCID required. Application tools: use PCID from discovery or see [Connecting to MCPs](/api-reference/platform/connections).
* Pass `tool.name` to `capability_details`, not `serverName`.
* Install only what the user needs (typically 1–5 tools per task).

## Custom Agents

Bootstrap with these two discovery tools. On user task: discover → fetch schemas → map to your model's function-calling format → add to agent context. Route model tool calls through `tools/call`.

## Fixed tool sets — invoke via `gateway_invoke`

The example above invokes a discovered tool by calling `tools/call` **directly on its server path**
(`/${serverName}`). That works when your agent can issue arbitrary HTTP calls at runtime. Many agents can't:
no-code and low-code agent platforms have a **fixed set of pre-registered tools** and no way to add an endpoint
per discovered tool.

For these, register **three fixed tools** and route every discovered tool through **`gateway_invoke`** on
`/gateway`, which dispatches internally by `server` + `tool`:

```bash theme={null}
curl -s -X POST "https://mcp.app.pinkfish.ai/gateway" \
  -H "Authorization: Bearer $PINKFISH_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "tools/call",
    "params": {
      "name": "gateway_invoke",
      "arguments": {
        "server": "gmail",
        "tool": "gmail_send_email",
        "arguments": { "PCID": "abc123-pcid", "to": "jane@acme.com", "subject": "Hi", "body": "…" }
      }
    },
    "id": 1
  }'
```

So the three tools you give the agent are: `capabilities_discover` and `capability_details` (both on
`/pinkfish-sidekick`), and `gateway_invoke` (on `/gateway`). The agent never calls a discovered tool directly —
it passes the discovered `serverName`/`name` into `gateway_invoke`. See
[Gateway](/api-reference/mcp-servers/embedded/gateway) for the full meta-tool set and the
[Bring Your Own Agent](/api-reference/platform/agent-prompt) prompt variant.

<Note>If your platform's tools are strongly typed and can't express a nested `arguments` object, pass
`gateway_invoke`'s `arguments` as a JSON **string** and have the tool inject it into the request body so it
renders as real JSON.</Note>

## Two invocation modes at a glance

| Your agent can…                                               | Invoke a discovered tool by…                                            |
| ------------------------------------------------------------- | ----------------------------------------------------------------------- |
| Make arbitrary HTTP calls / add tools at runtime              | `tools/call` on `/${serverName}` with the tool name (shown above)       |
| Only use a fixed, pre-registered tool set (no-code platforms) | `gateway_invoke` on `/gateway`, passing `server` + `tool` + `arguments` |

## Code Execution Shortcut

[Code Execution](/api-reference/platform/code-execution) chains tools without installing them. Discover tools, then pass tool calls into a single `code-execution_execute` invocation.
