Prerequisites
- An organization you own or administer. Members use connected systems; only owners and admins connect them.
- For a system that is only reachable inside your network, an owner on the Team or Enterprise plan and a running data-plane agent. A database always runs through the agent on the hosted service.
- The one input: a base URL (and the key or token the API expects), an
env://orvault://reference to a connection string, or an MCP server URL.
1. Connect
Reachability
Both are visible to every member of the organization and nobody else. An
internal API is probed for an OpenAPI document at the usual paths (/openapi.json, /swagger.json, /v3/api-docs, and so on); a local_only one is not, since Danube never reaches it, but an openapi_url you pass is still read. A database defaults to local_only.
From the dashboard
1
Open Connect a system
Go to Dashboard > Connect a system and pick the organization.
2
Choose the kind and paste the one input
An API’s base URL with its authentication, a database’s engine and connection reference, or an MCP server URL. Choose Internal or Runs inside your network.
3
Preview
The preview is a dry run: discovery runs, the tools it would create are listed, and nothing is written. For a database you see the tables and columns it found.
4
Connect
The service appears on the Tools page under your organization’s tab, with its policy card and, for a database, the discovered tables ready for the allowlist.
Over the API
kind is api (with api.base_url, optional api.auth in the connector auth shape, optional api.openapi_url), database (with database.db_type and database.connection_ref, optionally database.schema to limit discovery and database.max_rows) or mcp (with mcp.server_url, mcp.transport, mcp.auth_type, mcp.auth_header_name). visibility is internal by default, local_only for a database. Run it once with "dry_run": true, then without.
The response is the same either way, with service.id null on a dry run:
discovered is stored on the service as metadata.discovery. For a database it carries tables, each with schema, name and columns (capped at 500 tables and 200 columns per table), which is what the allowlist picker on the service page reads. When discovery could not run, discovered.error says why (no_dataplane_agent is the usual one: connect the agent, then use Discover again on the service page, or POST /v1/organizations/{org_id}/connect/{service_id}/discover). sync is running for an MCP server whose tools are being listed in the background.
Every connect is recorded as service.create with the kind, the visibility and what discovery found.
Databases and infrastructure
In the dashboard, Connect a system > Database or infrastructure lists every connector. Pick one, give the system a name your team will recognize (“Orders DB”, “Prod cluster”, “Payments events”) and fill in the connection form, the same fields as the connector’s page describes. Then:- Test connection runs the connector’s Test Connection with what you typed and lists the system’s resources: tables, namespaces, topics, log groups, buckets, and so on. A failed test says whether authentication, the network or TLS failed, and nothing is created.
- Connect creates the system: its own copy of the connector’s tools, named after it and described with the resources discovery found, so agents (and search) can tell your databases apart.
- The connection is stored once as the organization’s shared credential, with the rule Shared: every member’s agent uses it, and nobody’s personal credential for the same service takes its place. Store secrets as
env://orvault://references to run the system on your data-plane agent instead of connecting from Danube.
connector:
GET /v1/infra-connectors/catalog lists the connector types with their connection forms. A system’s rules live in the policy’s connector section (see Govern below). Every connector also has a catalogue entry (“PostgreSQL”, “Kubernetes”) that one person can connect for themselves; its page links to setting it up for the organization instead.
2. Govern
A connected service carries an access policy (metadata.access_policy) that its generic tools obey. It starts strict: reads on every path, and no database table until you list some. GET /v1/organizations/{org_id}/services/{service_id}/policy reads it, PUT replaces it, and the policy card on the service page edits it.
A database or infrastructure system is governed by the connector section instead, and it starts open: everything the connection’s identity can reach, read-only unless the connection’s mode is read and write.
The rules apply to every call, whether it runs from Danube or on your data-plane agent: a parameter naming a resource is checked, so are the tables a SQL statement reads, list results only show allowed resources (
hidden_by_policy counts the rest), and a call that asks for every Kubernetes namespace is refused while the namespaces are narrowed.
A refusal is a normal failed call, not an outage:
error_type: permission_denied, fault: caller, with a message that names the method, path or table. Agents are told to read it that way (the Agent Skill says a refused path or table is policy, not a bug) and to call List tables and Describe table before Query. Named tools you promote are not subject to the policy; they do exactly what their definition says.
Two more layers apply to every tool of the service, generic or named:
- Grants (Policies) decide which members, teams and roles may call the service or a tool at all. With no grants, every member can. The first grant flips the organization to deny-by-default for its own tools; a member who is not granted a tool does not see it, and a call answers
403 Your organization does not have access to this tool. - Credentials. An internal service usually authenticates with one key the company holds. Store it once for the organization, and every member who has no credential of their own for the service uses it:
local_only service the value must not be a value at all: store a reference the agent resolves inside your network, env://VAR_NAME or vault://<mount>/<path>#<field>. A credential held only as a value in Danube is never shipped to the agent; the call fails with credential_reference_unresolved. A database’s only secret is the connection string, which lives behind the connection_ref you gave at connect time.
3. Curate
Generic tools get agents working on day one. The calls worth keeping become named tools, with a name an agent can search for and a fixed shape a reviewer can read. From the Audit Log, open atool.execute row on a Request or Query tool and choose Promote to tool. Over the API:
execution_id the call is read from the execution row: an HTTP call becomes a tool with that method and path, the path’s {placeholders} as path parameters and the query keys as optional parameters with the values used as defaults; a SQL call becomes a query template with its :name placeholders as parameters. Without one, pass the call yourself: "request": {"method": "GET", "path": "/items/{sku}", "query": {"expand": "supplier"}} or "sql": {"sql": "SELECT sku, stock FROM items WHERE stock < :threshold", "parameters": [{"name": "threshold", "type": "integer"}]}. In data residency mode the execution row holds only a digest of the parameters, so the explicit fields are required. The named tool is returned, and the write is recorded as tool.create with promoted_from.
The advanced paths are still there for a system that needs them: POST /v1/organizations/{org_id}/services registers a service from an OpenAPI document you have on hand, a hand-written connector spec or a set of query templates, and the Connector Builder edits those specs in the dashboard. Both produce named tools directly, without a generic surface or a policy.
4. Verify
- Test run. Open the service on the Tools page and run List tables or the Request tool with a
GET, or over the APIPOST /v1/tools/call/{tool_id}from a member’s key. Alocal_onlytool needs an agent online: the Data Plane page shows each agent’s Online badge. - Audit log. Filter Audit Log by the service. You should see the
service.createrow from the connect and onetool.executerow per call, with the key that made it and a hash of the parameters. Atool.deniedrow means a grant is missing; apermission_deniedfailure means the policy refused the method, path or table. - A second member. Have someone with the
memberrole search for the service. Seeing it confirms visibility and the grants.
5. Operate
Troubleshooting
Connect errors, fromPOST /v1/organizations/{org_id}/connect and the dashboard’s preview:
Promote errors, from
POST /v1/organizations/{org_id}/services/{service_id}/promote:
Execution errors, in the
error_type of a failed call:
And the two refusals that come back as an HTTP status:
403 Your organization does not have access to this tool (no grant, or an explicit deny; ask an admin for a grant) and 404 Tool not found for someone outside the organization, which is deliberate so an internal tool’s existence is not revealed.