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

# Adding Sources

> Import tools from OpenAPI specs, GraphQL endpoints, MCP servers, and plugins.

A source is a unit of tool registration. Toolshed supports four source types, each with its own adapter that resolves a configuration into a set of tools.

## Source types

### OpenAPI

Fetches an OpenAPI/Swagger specification and auto-generates tools from each endpoint.

```json theme={null}
{
  "type": "openapi",
  "id": "billing-api",
  "namespace": "billing",
  "specUrl": "https://api.example.com/openapi.json",
  "auth": { "type": "bearer", "envVar": "BILLING_API_KEY" },
  "baseUrl": "https://api.example.com",
  "operationFilter": null
}
```

| Field             | Type         | Required | Description                                   |
| ----------------- | ------------ | -------- | --------------------------------------------- |
| `type`            | `"openapi"`  | Yes      | Source type                                   |
| `id`              | `string`     | Yes      | Unique source ID                              |
| `namespace`       | `string`     | Yes      | Tool path prefix                              |
| `specUrl`         | `string`     | Yes      | URL to the OpenAPI spec                       |
| `auth`            | `SourceAuth` | No       | Authentication config                         |
| `baseUrl`         | `string`     | No       | Override base URL                             |
| `operationFilter` | function     | No       | `({ method, path, operationId? }) => boolean` |

**Tool path generation:** `namespace.resource.action` (e.g., `billing.invoices.list`).
Action is derived from HTTP method: GET -> `list`/`get`, POST -> `create`, PUT -> `update`, PATCH -> `patch`, DELETE -> `delete`.

**Destructiveness:** Derived from HTTP method. GET, HEAD, OPTIONS are safe; all others are destructive.

### GraphQL

Introspects a GraphQL schema and generates tools from queries and mutations.

```json theme={null}
{
  "type": "graphql",
  "id": "cms-api",
  "namespace": "cms",
  "endpoint": "https://api.example.com/graphql",
  "auth": { "type": "bearer", "envVar": "CMS_API_KEY" },
  "headers": { "X-Custom": "value" }
}
```

| Field             | Type         | Required | Description                                                           |
| ----------------- | ------------ | -------- | --------------------------------------------------------------------- |
| `type`            | `"graphql"`  | Yes      | Source type                                                           |
| `id`              | `string`     | Yes      | Unique source ID                                                      |
| `namespace`       | `string`     | Yes      | Tool path prefix                                                      |
| `endpoint`        | `string`     | Yes      | GraphQL endpoint URL                                                  |
| `auth`            | `SourceAuth` | No       | Authentication config                                                 |
| `headers`         | `object`     | No       | Additional HTTP headers                                               |
| `operationFilter` | function     | No       | `({ name, type }) => boolean` where type is `"query"` or `"mutation"` |

**Tool path generation:** `namespace.field_name` (camelCase converted to snake\_case).

**Destructiveness:** Queries are safe, mutations are destructive.

### MCP

Connects to an external MCP server and imports its tools.

```json theme={null}
{
  "type": "mcp",
  "id": "external-tools",
  "namespace": "external",
  "transport": {
    "type": "http",
    "url": "https://mcp.example.com",
    "headers": { "Authorization": "Bearer token" }
  }
}
```

| Field       | Type         | Required | Description                                                                    |
| ----------- | ------------ | -------- | ------------------------------------------------------------------------------ |
| `type`      | `"mcp"`      | Yes      | Source type                                                                    |
| `id`        | `string`     | Yes      | Unique source ID                                                               |
| `namespace` | `string`     | Yes      | Tool path prefix                                                               |
| `transport` | object       | Yes      | `{ type: "http", url, headers? }` or `{ type: "stdio", command, args?, env? }` |
| `auth`      | `SourceAuth` | No       | Authentication config                                                          |

**Tool path generation:** `namespace.tool_name` (spaces and non-alphanumeric characters converted to underscores).

**Destructiveness:** Reads `annotations.destructiveHint` from MCP tool metadata.

<Note>Stdio transport is defined in the config schema but not yet implemented in the adapter.</Note>

### Plugin

Wraps a hand-written `definePlugin()` result as a source for registry consistency.

```json theme={null}
{
  "type": "plugin",
  "id": "github",
  "namespace": "github",
  "pluginId": "github"
}
```

| Field       | Type       | Required | Description              |
| ----------- | ---------- | -------- | ------------------------ |
| `type`      | `"plugin"` | Yes      | Source type              |
| `id`        | `string`   | Yes      | Unique source ID         |
| `namespace` | `string`   | Yes      | Tool path prefix         |
| `pluginId`  | `string`   | Yes      | ID of the plugin to wrap |

## Authentication types

The `auth` field supports four types:

| Type      | Fields                | Description                            |
| --------- | --------------------- | -------------------------------------- |
| `oauth2`  | `provider`, `scopes?` | OAuth2 via Toolshed's token vending    |
| `api_key` | `header`, `envVar?`   | API key sent as a custom header        |
| `bearer`  | `envVar?`             | Bearer token from environment variable |
| `none`    | --                    | No authentication needed               |

## Registering via API

```bash theme={null}
curl -X POST http://localhost:3000/api/registry/sources \
  -H "Authorization: Bearer $TOOLSHED_API_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "openapi",
    "id": "petstore",
    "namespace": "petstore",
    "specUrl": "https://petstore3.swagger.io/api/v3/openapi.json"
  }'
```

The server validates the config against `SourceConfigSchema`, calls `resolveSource()` to fetch and parse the spec, and registers all discovered tools in the catalog.
