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

# Advanced Agent Configuration

> Configure MCP servers, hooks, and the human-in-the-loop approval flow for production-grade agents.

Beyond basic tools and knowledge bases, agents take three further configuration options: MCP (Model Context Protocol) servers for external tool integrations, hooks for triggering webhooks on agent lifecycle events, and an approval flow that pauses execution until a human approves sensitive tool calls. This guide walks through each one.

<Note>
  **Prerequisites:**

  * An agent created (see Build an Agent guide)
</Note>

<Steps>
  <Step title="Add an MCP server">
    Connect an external MCP server to your agent. The agent discovers and calls tools exposed by the MCP server over HTTP transport (default; SSE is also accepted) during runs.

    **Endpoint:** `POST /api/agents/{id}/mcp-servers`

    <Note>
      The agent connects to the MCP server at the start of each run to discover available tools. Tools are then available alongside builtin tools and knowledge base search.
    </Note>

    <CodeGroup>
      ```python Python theme={null}
      response = requests.post(
          f"{BASE_URL}/api/agents/{agent_id}/mcp-servers",
          headers=headers,
          json={
              "name": "GitHub Tools",
              "url": "https://mcp.example.com/github/mcp",
              "transport": "http",
              "headers": {
                  "Authorization": "Bearer ghp_your_token_here",
              },
          },
      )
      mcp_server = response.json()
      print(f"MCP server added: {mcp_server['id']}")
      print(f"Available tools will be discovered at runtime")
      ```

      ```typescript TypeScript theme={null}
      const response = await fetch(`${BASE_URL}/api/agents/${agentId}/mcp-servers`, {
        method: "POST",
        headers,
        body: JSON.stringify({
          name: "GitHub Tools",
          url: "https://mcp.example.com/github/mcp",
          transport: "http",
          headers: {
            Authorization: "Bearer ghp_your_token_here",
          },
        }),
      });
      const mcpServer = await response.json();
      console.log("MCP server added:", mcpServer.id);
      ```

      ```bash cURL theme={null}
      curl -X POST '{BASE_URL}/api/agents/{agent_id}/mcp-servers' \
        -H "apikey: {API_KEY}" \
        -H "Authorization: Bearer {API_KEY}" \
        -H "Content-Type: application/json" \
        -d '{
          "name": "GitHub Tools",
          "url": "https://mcp.example.com/github/mcp",
          "transport": "http",
          "headers": {
            "Authorization": "Bearer ghp_your_token_here"
          }
        }'
      ```
    </CodeGroup>

    **Response:**

    ```json theme={null}
    {
      "id": "mcp-uuid",
      "agent_id": "agent-uuid",
      "name": "GitHub Tools",
      "url": "https://mcp.example.com/github/mcp",
      "transport": "http",
      "headers": { "Authorization": "Bearer ..." },
      "config": {},
      "enabled": true,
      "created_at": "2026-01-01T00:00:00Z",
      "updated_at": "2026-01-01T00:00:00Z"
    }
    ```
  </Step>

  <Step title="Configure a webhook hook">
    Add an HTTP webhook hook that fires before each tool call. Use hooks to log tool usage, enforce policies, or notify external systems.

    **Endpoint:** `POST /api/agents/{id}/hooks`

    <Note>
      This example uses `PreToolUse`, but hooks fire at six lifecycle events (`OnRunStart`, `PreToolUse`, `OnDelegation`, `PostToolUse`, `PreResponse`, `OnRunComplete`) and come in three types (`http`, `rule`, `approval`). Use the optional `matcher` field to target a specific tool by name. See [Hooks & Middleware](/concepts/agents-tools#hooks--middleware) for the full event semantics and the webhook request/response contract.
    </Note>

    <CodeGroup>
      ```python Python theme={null}
      response = requests.post(
          f"{BASE_URL}/api/agents/{agent_id}/hooks",
          headers=headers,
          json={
              "event": "PreToolUse",
              "type": "http",
              "config": {
                  "url": "https://your-app.com/webhooks/tool-calls",
              },
          },
      )
      hook = response.json()
      print(f"Hook created: {hook['id']}")
      print(f"Event: {hook['event']}, Type: {hook['type']}")
      ```

      ```typescript TypeScript theme={null}
      const response = await fetch(`${BASE_URL}/api/agents/${agentId}/hooks`, {
        method: "POST",
        headers,
        body: JSON.stringify({
          event: "PreToolUse",
          type: "http",
          config: {
            url: "https://your-app.com/webhooks/tool-calls",
          },
        }),
      });
      const hook = await response.json();
      console.log("Hook created:", hook.id);
      console.log("Event:", hook.event, "Type:", hook.type);
      ```

      ```bash cURL theme={null}
      curl -X POST '{BASE_URL}/api/agents/{agent_id}/hooks' \
        -H "apikey: {API_KEY}" \
        -H "Authorization: Bearer {API_KEY}" \
        -H "Content-Type: application/json" \
        -d '{
          "event": "PreToolUse",
          "type": "http",
          "config": {"url": "https://your-app.com/webhooks/tool-calls"}
        }'
      ```
    </CodeGroup>
  </Step>

  <Step title="Enable approval flow">
    Add an approval hook to the agent. When a tool call matches, the run pauses and emits an `approval_requested` SSE event. The run waits until you approve or reject via the API.

    **Endpoint:** `POST /api/agents/{id}/hooks`

    <Note>
      Set matcher to a specific tool name to only require approval for that tool, or omit matcher to require approval for all tool calls.
    </Note>

    <CodeGroup>
      ```python Python theme={null}
      # Add an approval hook — pauses on database_query calls
      response = requests.post(
          f"{BASE_URL}/api/agents/{agent_id}/hooks",
          headers=headers,
          json={
              "event": "PreToolUse",
              "type": "approval",
              "matcher": "database_query",
              "config": {"message": "Approve this database query?"},
          },
      )
      print(f"Approval hook added: {response.json()['id']}")

      # Stream a run — watch for approval_requested events
      response = requests.post(
          f"{BASE_URL}/api/agents/{agent_id}/run/stream",
          headers=headers,
          json={"message": "Delete all inactive users from the database"},
          stream=True,
      )

      import json

      for line in response.iter_lines():
          if not line:
              continue
          text = line.decode("utf-8")
          if not text.startswith("data: "):
              continue
          event = json.loads(text[6:])

          if event["event"] == "approval_requested":
              print(f"Approval needed for: {event['tool_name']}")
              print(f"Input: {json.dumps(event.get('tool_input', {}), indent=2)}")
              print(f"Run ID: {event['run_id']}")
              # The stream pauses here — approve or reject via the API
              break

          elif event["event"] == "chunk":
              print(event["content"], end="")
      ```

      ```typescript TypeScript theme={null}
      // Add an approval hook — pauses on database_query calls
      await fetch(`${BASE_URL}/api/agents/${agentId}/hooks`, {
        method: "POST",
        headers,
        body: JSON.stringify({
          event: "PreToolUse",
          type: "approval",
          matcher: "database_query",
          config: { message: "Approve this database query?" },
        }),
      });

      // Stream a run and watch for approval_requested events
      const response = await fetch(`${BASE_URL}/api/agents/${agentId}/run/stream`, {
        method: "POST",
        headers,
        body: JSON.stringify({ message: "Delete all inactive users from the database" }),
      });

      const reader = response.body!.getReader();
      const decoder = new TextDecoder();

      while (true) {
        const { done, value } = await reader.read();
        if (done) break;
        for (const line of decoder.decode(value).split("\n")) {
          if (!line.startsWith("data: ")) continue;
          const event = JSON.parse(line.slice(6));

          if (event.event === "approval_requested") {
            console.log(`Approval needed for: ${event.tool_name}`);
            console.log("Input:", JSON.stringify(event.tool_input ?? {}, null, 2));
            console.log(`Run ID: ${event.run_id}`);
            // Stream pauses here — approve or reject via the API
            break;
          }

          if (event.event === "chunk") {
            process.stdout.write(event.content);
          }
        }
      }
      ```

      ```bash cURL theme={null}
      # Add an approval hook for database_query
      curl -X POST '{BASE_URL}/api/agents/{agent_id}/hooks' \
        -H "apikey: {API_KEY}" \
        -H "Authorization: Bearer {API_KEY}" \
        -H "Content-Type: application/json" \
        -d '{
          "event": "PreToolUse",
          "type": "approval",
          "matcher": "database_query",
          "config": {"message": "Approve this database query?"}
        }'

      # Stream a run — look for approval_requested events
      curl -N -X POST '{BASE_URL}/api/agents/{agent_id}/run/stream' \
        -H "apikey: {API_KEY}" \
        -H "Authorization: Bearer {API_KEY}" \
        -H "Content-Type: application/json" \
        -d '{"message": "Delete all inactive users from the database"}'
      ```
    </CodeGroup>
  </Step>

  <Step title="Approve a pending tool call">
    When an approval\_requested event pauses a run, call the approve endpoint to let execution continue, or reject to skip the tool call.

    **Endpoint:** `POST /api/agents/runs/{run_id}/approve`

    <Note>
      After approval, the SSE stream resumes and the tool executes normally. After rejection, the agent skips the tool call and may try a different approach or respond to the user directly.
    </Note>

    <CodeGroup>
      ```python Python theme={null}
      # Approve the pending tool call
      response = requests.post(
          f"{BASE_URL}/api/agents/runs/{run_id}/approve",
          headers=headers,
          json={"approved": True},
      )
      print(f"Approved: {response.json()}")

      # Or reject
      response = requests.post(
          f"{BASE_URL}/api/agents/runs/{run_id}/approve",
          headers=headers,
          json={"approved": False},
      )
      print(f"Rejected: {response.json()}")
      ```

      ```typescript TypeScript theme={null}
      // Approve the pending tool call
      const approveRes = await fetch(
        `${BASE_URL}/api/agents/runs/${runId}/approve`,
        {
          method: "POST",
          headers,
          body: JSON.stringify({ approved: true }),
        },
      );
      console.log("Approved:", await approveRes.json());

      // Or reject
      const rejectRes = await fetch(
        `${BASE_URL}/api/agents/runs/${runId}/approve`,
        {
          method: "POST",
          headers,
          body: JSON.stringify({ approved: false }),
        },
      );
      console.log("Rejected:", await rejectRes.json());
      ```

      ```bash cURL theme={null}
      # Approve
      curl -X POST '{BASE_URL}/api/agents/runs/{run_id}/approve' \
        -H "apikey: {API_KEY}" \
        -H "Authorization: Bearer {API_KEY}" \
        -H "Content-Type: application/json" \
        -d '{"approved": true}'

      # Reject
      curl -X POST '{BASE_URL}/api/agents/runs/{run_id}/approve' \
        -H "apikey: {API_KEY}" \
        -H "Authorization: Bearer {API_KEY}" \
        -H "Content-Type: application/json" \
        -d '{"approved": false}'
      ```
    </CodeGroup>
  </Step>
</Steps>

## What's Next

<CardGroup cols={2}>
  <Card title="Agents & Tools" href="/concepts/agents-tools">
    Understand the full tool system including MCP, builtins, and custom tools.
  </Card>

  <Card title="Orchestration" href="/guides/orchestration">
    Coordinate multiple agents working together.
  </Card>

  <Card title="Agents API Reference" href="/api-reference/agents">
    Full endpoint documentation for agents.
  </Card>
</CardGroup>
