# sources operations

MCP tools and operation permissions for sources.

Generated from the shared operation catalog. Use [the JSON catalog](https://bytesmap.com/docs/reference/operations.json) for complete input schemas. Required dependency checks can be stricter than the resource permission listed below.

## source_promotion_schema_capture

Explicitly read bounded PostgreSQL/MySQL/MariaDB catalog metadata and save fresh promotion compatibility evidence. Does not read application rows, accept SQL or accept caller-supplied schema. Read purpose follows the configured read replica; write purpose checks the primary and additionally requires data Write. Requires source Read and SQL Run, current versioned credentials, a supported bounded adapter, and finishes or cancels within ten seconds. Returns observation counts and fingerprint only.

- **HTTP:** `POST /api/sources/:id/promotion-schema`
- **SDK:** `client.sources.capturePromotionSchema(input)`
- **Access:** workspace; sql / run
- **Effect annotation:** May change state or run effects

| Input | Requirement | Description |
| --- | --- | --- |
| `purpose` | Required | See schema |
| `id` | Required | string |

## source_databases_refresh

Refresh database names, connection readiness and setup choices for an unexpired connectionToken from source_databases_browse. Reuses the authenticated connection draft; does not create a database login or save a source.

- **HTTP:** `POST /api/sources/databases/refresh`
- **SDK:** `client.sources.refreshDatabases(input)`
- **Access:** workspace; source / write
- **Effect annotation:** May change state or run effects

| Input | Requirement | Description |
| --- | --- | --- |
| `connectionToken` | Required | string |

## source_database_login_create

Explicitly create a read-only database login and grant it access to the selected discovered databases, optionally including future tables. Requires the setup connectionToken and administrative access through a saved server. Changes database access; generated credentials stay sealed and are not returned.

- **HTTP:** `POST /api/sources/databases/login`
- **SDK:** `client.sources.createDatabaseLogin(input)`
- **Access:** workspace; source / write
- **Effect annotation:** May change state or run effects

| Input | Requirement | Description |
| --- | --- | --- |
| `connectionToken` | Required | string |
| `databases` | Required | array |
| `username` | Required | string |
| `futureTables` | Required | boolean |

## source_databases_browse

Test a draft database connection and list its accessible databases before saving sources. Use source_kinds_list for connection fields; a saved server may supply the existing connection. Returns an expiring connectionToken for refresh, reader setup and source creation. Does not create a login or save a source.

- **HTTP:** `POST /api/sources/databases`
- **SDK:** `client.sources.browseDatabases(input)`
- **Access:** workspace; source / write
- **Effect annotation:** May change state or run effects

| Input | Requirement | Description |
| --- | --- | --- |
| `kind` | Required | string |
| `values` | Optional | object |
| `fromContainer` | Optional | string |
| `serverId` | Optional | string |
| `dbHost` | Optional | string |
| `dbPort` | Optional | integer |
| `tunnel` | Optional | object |
| `serverAccess` | Optional | object |

## source_list

List the data sources connected to this workspace.

- **HTTP:** `GET /api/sources`
- **SDK:** `client.sources.list(input)`
- **Access:** workspace; source / read
- **Effect annotation:** Read-only

See the JSON schema for this input contract.

## source_kinds_list

List the data source kinds this build can connect, and the connection fields each one needs. Call this before POST /api/sources: the `fields` array gives the exact keys to send as `values`, which are required, their defaults, and which one is the secret. Kinds with `ready: false` have no driver in this build. `tunnel.transports` lists the tunnel transports this deployment permits; when it is empty, do not send a `tunnel` object — it will be refused.

- **HTTP:** `GET /api/sources/kinds`
- **SDK:** `client.sources.kinds(input)`
- **Access:** workspace; source / read
- **Effect annotation:** Read-only

See the JSON schema for this input contract.

## source_write

Connect a data source. Call GET /api/sources/kinds first to learn which kinds this build implements and what fields each needs, then pass those as `values`. The connection is opened and verified before anything is stored, so a failure means nothing was written. Passwords are sealed in the secret store; a literal connection string is refused.

- **HTTP:** `POST /api/sources`
- **SDK:** `client.sources.create(input)`
- **Access:** workspace; source / write
- **Effect annotation:** May change state or run effects

| Input | Requirement | Description |
| --- | --- | --- |
| `name` | Required | string |
| `connectionToken` | Optional | string |
| `database` | Optional | string |
| `serverAccess` | Optional | object |
| `kind` | Required | string |
| `values` | Optional | object |
| `secretRef` | Optional | string |
| `fromContainer` | Optional | string |
| `replicaValues` | Optional | object |
| `replicaSecretRef` | Optional | string |
| `tunnel` | Optional | object |
| `serverId` | Optional | string |
| `dbHost` | Optional | string |
| `dbPort` | Optional | integer |
| `replicaTarget` | Optional | Replica endpoint as reached from the SSH server. Never reuses the primary forward. |
| `statementTimeoutMs` | Optional | integer |
| `maxRows` | Optional | integer |
| `maxBytes` | Optional | integer |
| `concurrency` | Optional | integer |

## source_read

Read a saved data source, its public connection fields, limits and saved server association. Does not reveal passwords, private keys or secret values.

- **HTTP:** `GET /api/sources/:id`
- **SDK:** `client.sources.get(input)`
- **Access:** workspace; source / read
- **Effect annotation:** Read-only

| Input | Requirement | Description |
| --- | --- | --- |
| `id` | Required | string |

## source_update

Edit a saved source name, connection fields, limits, replica reference or server/tunnel association. Omitted fields retain their stored values and secrets. New connection settings are checked by the normal source service; does not mutate source database records.

- **HTTP:** `PATCH /api/sources/:id`
- **SDK:** `client.sources.update(input)`
- **Access:** workspace; source / write
- **Effect annotation:** May change state or run effects

| Input | Requirement | Description |
| --- | --- | --- |
| `name` | Optional | string |
| `values` | Optional | object |
| `replicaValues` | Optional | See schema |
| `replicaSecretRef` | Optional | See schema |
| `replicaTarget` | Optional | See schema |
| `tunnel` | Optional | See schema |
| `serverId` | Optional | See schema |
| `dbHost` | Optional | string |
| `dbPort` | Optional | integer |
| `statementTimeoutMs` | Optional | integer |
| `maxRows` | Optional | integer |
| `maxBytes` | Optional | integer |
| `concurrency` | Optional | integer |
| `id` | Required | string |

## source_remove

Remove a saved data source connection from BytesMap and close its connection pool. Requires source Admin; managed dataset sources are removed through their dataset instead. Does not drop the external database or delete its records.

- **HTTP:** `DELETE /api/sources/:id`
- **SDK:** `client.sources.remove(input)`
- **Access:** workspace; source / admin
- **Effect annotation:** May change state or run effects; destructive operation

| Input | Requirement | Description |
| --- | --- | --- |
| `id` | Required | string |

## source_schema_read

Read a source's tables, columns and relationships.

- **HTTP:** `GET /api/sources/:id/schema`
- **SDK:** `client.sources.schema(input)`
- **Access:** workspace; schema / read
- **Effect annotation:** Read-only

| Input | Requirement | Description |
| --- | --- | --- |
| `id` | Required | string |

## source_stats_read

Read a source's live health and resource metrics: size, connections, cache hit rate, uptime.

- **HTTP:** `GET /api/sources/:id/stats`
- **SDK:** `client.sources.stats(input)`
- **Access:** workspace; source / read
- **Effect annotation:** Read-only

| Input | Requirement | Description |
| --- | --- | --- |
| `id` | Required | string |

## source_sql_run

Run a query against a source and get rows back. Example input: {id:"SOURCE_ID", query:{kind:"native", sourceKind:"postgres", statement:"select id, name from customers limit 10"}}. query is an object, never a raw SQL string. Takes either the portable IR — {kind:'growth'|'row-count'|'top-values'|'histogram'|'chart'|'rows', …}, which this translates to whatever language the source speaks — or {kind:"native"} with a statement in the driver's own language. Results carry honesty flags: `estimated`, A chart or rows query may read a table, or a joined relation {base, joins}; joined fields use alias.column. `sampled` and `truncated` in `meta` must be surfaced, not dropped. `meta.page` says which slice you got; `meta.totalRows` is present only if you passed `count:true`, so absent means unknown rather than zero. Pass `explain:true` for `meta.plan` — the query as this engine received it, which is how you check what the IR compiled to. Pass chart:{title,spec} to display the result using the same encoding as chart_create. Channels refer to result column names. ClickHouse uses sourceKind:"clickhouse"; managed dataset sources expose only their scoped events relation.

- **HTTP:** `POST /api/sources/:id/query`
- **SDK:** `client.sources.run(input)`
- **Access:** workspace; sql / run
- **Effect annotation:** Read-only

| Input | Requirement | Description |
| --- | --- | --- |
| `chart` | Optional | Display returned data as a chart. Channels use result column names. Uses the chart_create encoding without saving a query or chart. |
| `query` | Required | A bytesmap query. Either the portable IR — {kind:"growth"\|"row-count"\|"top-values"\|"histogram"\|"column-stats"\|"orphans"\|"chart"\|"rows", …} — or the escape hatch {kind:"native", sourceKind:"<this source's kind>", statement:"…"}. A native statement is in the driver's own language: SQL for SQL engines, a JSON aggregation pipeline for MongoDB. It is refused if written for a different engine, if it writes, and is still subject to the row cap and statement timeout. For {kind:"chart"}: `dimensions[].role` is "group" (an axis, at most two) or "series" (a breakdown, at most one) — and when you use a series, set `seriesLimit` rather than relying on `limit`, because `limit` cuts ROWS of the joint group-by and can leave a series with only some of its buckets. `measures[].filter` is a per-measure WHERE, so sum(total) where status='paid' sits beside sum(total) in one query; `having` filters the aggregates and its leaves name measure aliases (m0, m1) rather than columns; `offset` pages; `totals` is "none"\|"with"\|"only" and "with" adds meta.totals, the same query ungrouped. `from` is a table ref or a derived relation {isDerived:true, statement, sourceKind, aggregated, columns} — your own SELECT as the FROM, which the rest of the query then groups, filters and pages normally. `expression` on a measure or dimension is a raw fragment in this engine's dialect; it is read-only-checked and makes the query non-portable to other engines. |
| `maxRows` | Optional | integer |
| `count` | Optional | Also return meta.totalRows: how many rows the query would return in total. Costs a second pass that scans everything the query touches, so ask for it only when the exact number is the point — meta.truncated already tells you whether more rows exist. |
| `explain` | Optional | Also return meta.plan: the query as this engine received it — {form:"sql", sql, params} for a SQL source, {form:"mongo", collection, pipeline} for MongoDB. Costs nothing; the compiled artefact already exists. Placeholders are NOT substituted — `params` is listed separately, in order, because a statement with values spliced in is the one form this system never sends. |
| `id` | Required | string |

## source_keys_scan

Scan a key/value source. Continue with the returned cursor until it is "0", including after an empty page. count is a scan hint.

- **HTTP:** `POST /api/sources/:id/keys/scan`
- **SDK:** `client.sources.scanKeys(input)`
- **Access:** workspace; sql / run
- **Effect annotation:** Read-only

| Input | Requirement | Description |
| --- | --- | --- |
| `cursor` | Optional | string |
| `match` | Optional | string |
| `count` | Optional | integer |
| `id` | Required | string |

## source_key_read

Read a bounded key/value preview by the opaque key id from source_keys_scan. Includes key type, expiry, size, and whether the preview was truncated.

- **HTTP:** `POST /api/sources/:id/keys/read`
- **SDK:** `client.sources.readKey(input)`
- **Access:** workspace; sql / run
- **Effect annotation:** Read-only

| Input | Requirement | Description |
| --- | --- | --- |
| `key` | Required | The opaque base64 key id returned by the key scan. |
| `id` | Required | string |
