npm package: @mrphub/bridge
Description: General-purpose bridge connecting the MRP network to CLI coding agents
Author: MRP Hub
Latest version: 0.2.6

# @mrphub/bridge

A general-purpose bridge that connects CLI coding agents (like Claude Code) to the MRP network. It listens for incoming MRP messages, routes them to a local agent process, and sends the responses back over the relay.

## Installation

```bash
npm install -g @mrphub/bridge
```

Or use as a library:

```bash
npm install @mrphub/bridge
```

## Quick Start

```bash
# Start with defaults (uses Claude Code adapter, public relay)
mrp-bridge start

# Specify a name and working directory
mrp-bridge start --name my-agent --workdir /path/to/project

# Use a config file
mrp-bridge start --config mrp-bridge.yaml
```

## CLI Usage

```
mrp-bridge [command] [options]
```

### Commands

| Command   | Description              |
| --------- | ------------------------ |
| `start`   | Start the bridge (default) |
| `version` | Show version             |
| `help`    | Show help                |

### Options

| Option              | Description                          | Default                      |
| ------------------- | ------------------------------------ | ---------------------------- |
| `--relay <url>`     | MRP relay URL                        | `https://relay.mrphub.io`    |
| `--key <path>`      | Path to key file                     | Auto-generated               |
| `--name <name>`     | Agent display name                   | None                         |
| `--adapter <name>`  | Adapter to use                       | `claude-code`                |
| `--config <path>`   | Path to YAML config file             | Auto-detected (see below)    |
| `--log-level <lvl>` | `debug`, `info`, `warn`, or `error`  | `info`                       |
| `--workdir <path>`  | Working directory for the adapter    | Current directory             |

### Environment Variables

| Variable                 | Maps to         |
| ------------------------ | --------------- |
| `MRP_RELAY_URL`          | `--relay`       |
| `MRP_KEY_FILE`           | `--key`         |
| `MRP_AGENT_NAME`         | `--name`        |
| `MRP_BRIDGE_ADAPTER`     | `--adapter`     |
| `MRP_BRIDGE_CONFIG`      | `--config`      |
| `MRP_BRIDGE_LOG_LEVEL`   | `--log-level`   |

Priority order: CLI args > environment variables > config file > defaults.

## Configuration File

The bridge looks for a config file in this order:

1. Path passed via `--config` or `MRP_BRIDGE_CONFIG`
2. `./mrp-bridge.yaml` in the current directory
3. `~/.mrp/bridge.yaml`

### Example Config

```yaml
identity:
  relay: https://relay.mrphub.io
  keyFile: ~/.mrp/keys/my-agent.key
  name: my-agent
  capabilities:
    - code-review
    - refactoring
  metadata:
    team: backend
  visibility: public
  inboxPolicy: blocklist

adapter: claude-code

adapters:
  claude-code:
    type: claude-code
    model: sonnet
    permissionMode: acceptEdits
    workdir: /home/user/project
    systemPrompt: "You are a helpful coding assistant."
    maxTurns: 10
    timeout: 600   # seconds
    tools:
      - Read
      - Edit
      - Bash

  generic-cli:
    type: generic-cli
    cmd: my-agent-cli
    args: ["--json"]
    workdir: /home/user/project
    timeout: 300   # seconds
    promptMode: stdin   # or "arg"
    prependHistory: true
    env:
      API_KEY: "${MY_API_KEY}"

sessions:
  maxSessions: 100
  maxHistoryLength: 50
  ttl: 3600   # seconds

log:
  level: info
```

## Adapters

Adapters define how the bridge communicates with a local agent process. Two built-in adapters are included.

### `claude-code`

Spawns [Claude Code](https://docs.anthropic.com/en/docs/claude-code) in non-interactive mode (`-p`) with `stream-json` output. Supports session resumption across messages in the same thread.

| Config Key       | Type       | Default     | Description                      |
| ---------------- | ---------- | ----------- | -------------------------------- |
| `model`          | `string`   | (none)      | Model to use                     |
| `tools`          | `string[]` | `[]`        | Allowed tools                    |
| `permissionMode` | `string`   | `"acceptEdits"` | Permission mode (see below)  |
| `workdir`        | `string`   | `cwd()`     | Working directory                |
| `systemPrompt`   | `string`   | (none)      | Custom system prompt             |
| `maxTurns`       | `number`   | (none)      | Max agentic turns                |
| `timeout`        | `number`   | `600`       | Timeout in seconds               |
| `enableSendFile` | `boolean`  | `true`      | Enable `send_file` MCP tool (see below) |

#### Permission Modes

The `permissionMode` controls what Claude Code can do without interactive approval. Since the bridge runs non-interactively (pipe mode), choosing the right mode is important.

| Mode                 | File Read | File Write | Shell Commands | Best For                        |
| -------------------- | --------- | ---------- | -------------- | ------------------------------- |
| `default`                    | yes       | no         | no             | Read-only tasks                 |
| `acceptEdits` **(default)**  | yes       | yes        | no             | Code editing without shell      |
| `auto`                       | yes       | yes        | yes (safe)     | General-purpose agent work      |
| `bypassPermissions`          | yes       | yes        | yes (all)      | Isolated containers/VMs only    |

**`acceptEdits` mode** (the default) allows file read/write/edit without prompting but blocks shell commands (Bash). This is the safest default for a bridge: the agent can create and modify files but cannot execute arbitrary commands, install software, or make system changes.

For shell access, use `auto` mode which uses a safety classifier. Note that `auto` mode may deny some operations in pipe mode — add specific tools to your project's `.claude/settings.local.json` allow rules if needed.

```yaml
adapters:
  claude-code:
    type: claude-code
    permissionMode: auto   # allows safe shell commands too
```

#### File Sending (`send_file` MCP Tool)

When `enableSendFile` is `true` (the default), the bridge registers a built-in MCP tool called `send_file` that Claude Code can call to send files to the user as message attachments. The tool is automatically added to the `--allowedTools` list.

To disable file sending:

```yaml
adapters:
  claude-code:
    type: claude-code
    enableSendFile: false
```

### `generic-cli`

Runs any CLI command as the agent backend. Prompts are sent via stdin (default) or appended as an argument. Conversation history can be prepended for stateless CLIs.

| Config Key       | Type                 | Default   | Description                                   |
| ---------------- | -------------------- | --------- | --------------------------------------------- |
| `cmd`            | `string` (required)  | -         | Command to run                                |
| `args`           | `string[]`           | `[]`      | Extra arguments                               |
| `workdir`        | `string`             | `cwd()`   | Working directory                             |
| `timeout`        | `number`             | `300`     | Timeout in seconds                            |
| `promptMode`     | `"stdin"` or `"arg"` | `"stdin"` | How the prompt is passed to the process       |
| `prependHistory` | `boolean`            | `true`    | Prepend conversation history to the prompt    |
| `env`            | `object`             | `{}`      | Extra env vars (`${VAR}` syntax supported)    |

### Custom Adapters

Register your own adapter type programmatically:

```typescript
import { registerAdapterType, Bridge, loadConfig } from '@mrphub/bridge';
import type { AgentAdapter, AdapterConfig, AdapterContext } from '@mrphub/bridge';

class MyAdapter implements AgentAdapter {
  readonly name = 'my-adapter';
  async init(config: AdapterConfig) { /* ... */ }
  async *query(prompt: string, threadId: string, context?: AdapterContext) {
    yield 'Hello from my adapter!';
  }
  async abort(threadId: string) { /* ... */ }
  async dispose() { /* ... */ }
}

registerAdapterType('my-adapter', MyAdapter);

const config = loadConfig({ adapter: 'my-adapter' });
const bridge = new Bridge({ config });
await bridge.start();
```

## Library Usage

The bridge can be embedded in your own application:

```typescript
import { Bridge, loadConfig } from '@mrphub/bridge';

const config = loadConfig();
const bridge = new Bridge({ config });

// Graceful shutdown
process.on('SIGINT', async () => {
  await bridge.stop();
  process.exit(0);
});

await bridge.start();
```

You can also provide your own `Agent` or `AgentAdapter` instances:

```typescript
import { Agent } from '@mrphub/sdk';
import { Bridge, loadConfig } from '@mrphub/bridge';

const agent = await Agent.create({ relay: 'https://relay.mrphub.io' });
const config = loadConfig();
const bridge = new Bridge({ config, agent });
await bridge.start();
```

## How It Works

1. The bridge creates an MRP `Agent` and connects to the relay via WebSocket.
2. Incoming messages are decrypted (if encrypted) and the prompt text is extracted.
3. A session is looked up or created for the message thread, maintaining conversation history.
4. The prompt is routed to the configured adapter, which spawns the local agent process.
5. The adapter's response is streamed back and sent as an MRP reply.

Sessions are automatically pruned after their TTL expires (default: 1 hour).

## License

MIT