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

# Get Service Tools (Authenticated)

> The tools of one service for a signed-in caller, with configuration hints when an MCP service is not usable yet

## Overview

Returns the stored tools of a service, each stamped with your `readiness`. When a service backed by an MCP server has no synced tools yet, the response is an object instead of a list and says what to do next: sync, configure credentials, or complete the server's own OAuth flow.

[Get Service Tools](/api-reference/endpoint/get_service_tools) at `/v1/services/public/{service_id}/tools` needs no auth, lists public services only, and always answers with a list.

**Auth:** Required. API key (`danube-api-key` header) or JWT. A private service is visible to its owner only; everyone else gets `404`.

## Path Parameters

<ParamField path="service_id" type="string" required>
  The service UUID or slug
</ParamField>

## Response

The response has two shapes. Check whether the body is an array before reading it.

### A list of tools

The common case: a bare JSON array of tool objects in the service's own order, or an empty array when a service that is not an MCP server has no tools. Each tool has `id`, `name`, `slug` (when set), `description`, `tags`, `base_url`, `path`, `method`, `version`, `parameters`, `output`, `security_schemes`, `tips`, `metadata`, `service_id`, `created_at`, `updated_at`, `is_paid`, `price_per_call_cents` (when set), `x402_enabled`, `x402_price_usdc_atomic` (when set), `deprecated`, `deprecation_message` and `sunset_date` (when set), plus:

<ResponseField name="readiness" type="string">
  `ready`, `needs_credential` or `unavailable` for this caller
</ResponseField>

<ResponseField name="configuration_url" type="string">
  Where to connect the service. Set only when `readiness` is `needs_credential`.
</ResponseField>

### An object, when an MCP service has no tools yet

`tools` is always `[]` in this shape. One of three variants is returned:

```json theme={null}
{
  "tools": [],
  "needs_sync": true,
  "tool_sync": {"status": "running", "started_at": "2026-09-13T21:43:40+00:00"},
  "message": "Notion is connected and its tools are being discovered. Read again in a few seconds."
}
```

You already hold a credential for the service and its tools are being registered in the background. This read is what starts that when nothing is running, so there is nothing else to call: read again every few seconds until `tool_sync.status` leaves `running` (it becomes `done`, with a `tools` count, or `failed`, with an `error`), then the list is returned as usual.

```json theme={null}
{
  "tools": [],
  "needs_configuration": true,
  "skipped": false,
  "configuration_info": {
    "service_id": "svc_example_001",
    "service_name": "Example",
    "message": "Configure credentials for Example to use its tools",
    "credential_schema": {"fields": [{"name": "api_key", "type": "string", "required": true}]},
    "configuration_url": "/dashboard/services/svc_example_001"
  }
}
```

The service declares how to authenticate and you have not connected it. `skipped` is always `false`.

```json theme={null}
{
  "tools": [],
  "needs_mcp_oauth": true,
  "mcp_oauth_info": {
    "service_id": "svc_notion_001",
    "service_name": "Notion",
    "message": "Notion requires authentication via its own OAuth flow",
    "authorization_endpoint": "https://mcp.notion.com/authorize",
    "token_endpoint": "https://mcp.notion.com/token",
    "registration_endpoint": "https://mcp.notion.com/register",
    "scopes_supported": ["mcp:tools"],
    "auth_server_url": "https://mcp.notion.com"
  }
}
```

The server uses its own OAuth flow, discovered by probing it. For a remote MCP server with no declared auth, the endpoint connects to the server on the spot; when that connection succeeds without OAuth, the tools are synced and returned as a list.

## Example

<RequestExample>
  ```bash cURL theme={null}
  curl -X GET "https://api.danubeai.com/v1/services/svc_github_001/tools" \
    -H "danube-api-key: YOUR_API_KEY"
  ```

  ```python Python SDK theme={null}
  from danube import DanubeClient

  with DanubeClient(api_key="YOUR_API_KEY") as client:
      result = client.services.get_tools("svc_github_001")
      if result.needs_configuration:
          print(f"Connect the service first: {result.configuration_url}")
      for tool in result.tools:
          print(tool.name)
  ```

  ```typescript TypeScript SDK theme={null}
  import { DanubeClient } from 'danube';

  const client = new DanubeClient({ apiKey: 'YOUR_API_KEY' });
  const result = await client.services.getTools('svc_github_001');
  if (result.needsConfiguration) {
    console.log('Connect the service first', result.configurationRequired);
  }
  for (const t of result.tools) {
    console.log(t.name, t.readiness);
  }
  ```
</RequestExample>

<ResponseExample>
  ```json theme={null}
  [
    {
      "id": "tool_abc123",
      "name": "GitHub - List Repository Issues",
      "slug": "github-list-repository-issues",
      "description": "List issues in a repository",
      "tags": ["issues", "repository"],
      "base_url": "https://api.github.com",
      "path": "/repos/{owner}/{repo}/issues",
      "method": "GET",
      "version": "1.0.0",
      "parameters": {
        "owner": {
          "name": "owner",
          "location": "path",
          "description": "Repository owner",
          "type": "string",
          "required": true
        },
        "repo": {
          "name": "repo",
          "location": "path",
          "description": "Repository name",
          "type": "string",
          "required": true
        }
      },
      "output": {},
      "security_schemes": {"bearerAuth": []},
      "tips": null,
      "metadata": {},
      "service_id": "svc_github_001",
      "created_at": "2026-06-28T09:00:00Z",
      "updated_at": "2026-09-10T12:30:00Z",
      "is_paid": false,
      "x402_enabled": false,
      "deprecated": false,
      "readiness": "ready",
      "configuration_url": null
    }
  ]
  ```
</ResponseExample>

Both SDKs send a `limit` query parameter that this endpoint does not read. The Python SDK cuts the list to `limit` on the client side; the TypeScript SDK returns the whole list.

## MCP Tool

This endpoint is also available as the `get_service_tools` MCP tool. The MCP tool always answers with an object, and derives `needs_configuration` from each tool's `readiness`:

```python theme={null}
result = await mcp.call_tool("get_service_tools", {
    "service_id": "svc_github_001",
    "limit": 50
})
```
