# How DBX Detects Database Capabilities Dynamically at Runtime

> Learn how DBX dynamically detects database capabilities at runtime using a JSON-RPC handshake. Adapt your applications without client rebuilds.

- Repository: [skyler/dbx](https://github.com/t8y2/dbx)
- Tags: internals
- Published: 2026-07-05

---

**DBX discovers driver capabilities through a lightweight JSON-RPC handshake performed immediately after the agent process starts, enabling runtime adaptation without client rebuilds.**

DBX (Database eXplorer) implements a **dynamic capability detection** system that allows the core client to adapt to different database drivers at runtime. Rather than hardcoding supported operations, the system performs a protocol handshake through a JSON-RPC channel to determine what each driver can execute. This architecture lets the `t8y2/dbx` project add new database features by updating only the agent code, with the client automatically respecting the advertised capability set on the next connection.

## The Handshake Protocol: Core Mechanism for Capability Detection

The capability detection relies on a **handshake** method exchanged over the JSON-RPC channel immediately after the agent process launches. This single request-response cycle establishes the entire API surface available for that session.

### Agent-Side Implementation

Each database driver implements the handshake within its `dispatch` function, returning a hardcoded JSON object that declares supported operations. The method signature accepts a method name and parameters map, then returns the capability list along with protocol version information.

In [`agents/drivers/xugu/main.go`](https://github.com/t8y2/dbx/blob/main/agents/drivers/xugu/main.go) and [`agents/drivers/oracle-go/main.go`](https://github.com/t8y2/dbx/blob/main/agents/drivers/oracle-go/main.go), the implementation follows this pattern:

```go
func (s *server) dispatch(method string, params map[string]json.RawMessage) (any, bool, error) {
    switch method {
    case "handshake":
        return map[string]any{
            "protocolVersion":      protocolVersion,
            "agentProtocolVersion": protocolVersion,
            "capabilities": []string{
                "connect",
                "test_connection",
                "metadata",
                "query",
                "ddl",
            },
        }, false, nil
    // … other methods …
    }
}

```

The `capabilities` slice explicitly lists every JSON-RPC method the driver supports, such as **connect**, **test_connection**, **metadata**, **query**, and **ddl**.

### Client-Side Usage

The DBX client initiates the handshake by sending a JSON-RPC request with method `handshake` and minimal parameters containing only the `appVersion`:

```json
{
  "jsonrpc": "2.0",
  "id": 7,
  "method": "handshake",
  "params": { "appVersion": "dev" }
}

```

Upon receiving the response, the client parses the `capabilities` array and stores it in runtime state. Subsequent operations validate against this list before transmission, ensuring the client never attempts to invoke unsupported methods. A typical response from the Xugu driver appears as:

```json
{
  "protocolVersion": 1,
  "agentProtocolVersion": 1,
  "capabilities": [
    "connect",
    "test_connection",
    "metadata",
    "query",
    "ddl"
  ]
}

```

## Runtime Dynamic Detection Without Rebuilding

Because the handshake executes every time the agent launches, the set of available capabilities can change dynamically without rebuilding the DBX core. Adding new functionality—such as a `bulk_load` method—requires only modifying the `capabilities` slice in the driver's `dispatch` function and rebuilding that specific agent.

The client automatically adapts on the next connection because it relies entirely on the handshake response to determine the available API surface. This decoupling eliminates version synchronization issues between the core client and individual database drivers.

## Implementation Examples by Driver

The handshake pattern is consistent across all drivers in the `agents/drivers/` directory. Each driver hardcodes its capability list in the `dispatch` switch statement:

- **Xugu Driver**: [`agents/drivers/xugu/main.go`](https://github.com/t8y2/dbx/blob/main/agents/drivers/xugu/main.go) (lines 13-21)
- **Oracle Driver**: [`agents/drivers/oracle-go/main.go`](https://github.com/t8y2/dbx/blob/main/agents/drivers/oracle-go/main.go) (lines 13-21)

Both files implement identical `dispatch` functions that return the `protocolVersion`, `agentProtocolVersion`, and `capabilities` array. This standardization ensures the core client can interact with any driver through the same JSON-RPC interface while respecting driver-specific limitations.

## Summary

- DBX uses a **JSON-RPC handshake** immediately after agent startup to detect capabilities dynamically at runtime.
- Drivers declare supported operations in the `dispatch` function within their respective [`main.go`](https://github.com/t8y2/dbx/blob/main/main.go) files.
- The client stores the capability list from the handshake response and filters subsequent commands accordingly.
- New capabilities can be added by updating only the driver code; the core client adapts automatically on the next connection.

## Frequently Asked Questions

### What is the handshake method in DBX?

The **handshake** method is a JSON-RPC call initiated by the DBX client immediately after connecting to a database agent. It returns a JSON object containing `protocolVersion` and a `capabilities` array listing all supported operations like `connect`, `query`, and `ddl`. This method enables the client to discover what the driver can do without hardcoding driver-specific logic.

### How does DBX handle unsupported capabilities?

The DBX client stores the capability list received during the handshake in its runtime state. Before sending any JSON-RPC request, the client checks whether the target method exists in the capability array. If a capability is not advertised, the client avoids sending that command, preventing runtime errors against drivers that lack specific functionality.

### Can capabilities vary between different database drivers?

Yes, capabilities vary by driver and are declared independently in each driver's source code. For example, the Xugu driver in [`agents/drivers/xugu/main.go`](https://github.com/t8y2/dbx/blob/main/agents/drivers/xugu/main.go) might advertise different capabilities than the Oracle driver in [`agents/drivers/oracle-go/main.go`](https://github.com/t8y2/dbx/blob/main/agents/drivers/oracle-go/main.go). The core client treats these declarations as the authoritative source of truth for what operations are available for that specific database connection.

### Where is the handshake implemented in the source code?

The handshake implementation resides in each driver's `dispatch` function within their [`main.go`](https://github.com/t8y2/dbx/blob/main/main.go) files. Specifically, you will find the switch case for `"handshake"` returning the capability map in [`agents/drivers/xugu/main.go`](https://github.com/t8y2/dbx/blob/main/agents/drivers/xugu/main.go) and [`agents/drivers/oracle-go/main.go`](https://github.com/t8y2/dbx/blob/main/agents/drivers/oracle-go/main.go). These functions return hardcoded capability lists that define the driver's API surface for that session.