Skip to main content
Glama
h-mergel
by h-mergel
README.md
# bru-mcp

An [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) server that exposes the [Bruno](https://www.usebruno.com/) CLI (`bru`) as tools for AI agents. It allows agents like Claude, GitHub Copilot, and others to discover, inspect, and execute Bruno API collections directly through the MCP protocol.

## Requirements

- [Node.js](https://nodejs.org/) 18 or later
- [Bruno CLI](https://docs.usebruno.com/bru-cli/overview) installed and available on your `PATH`

Install the Bruno CLI globally if you haven't already:

```bash
npm install -g @usebruno/cli
```

## Installation

### Option A — Clone and build

```bash
git clone https://github.com/h-mergel/bru-mcp.git
cd bru-mcp
npm install
npm run build
```

### Option B — Install globally from the cloned repo

After cloning and building, install the `bru-mcp` binary globally so it is available on your `PATH`:

```bash
npm install -g .
```

This makes `bru-mcp` available as a standalone command, which simplifies the MCP configuration (see below).

## MCP Configuration

Add `bru-mcp` as an MCP server in your client's configuration. The server communicates over **stdio**.

### Via npx — no local clone needed (recommended)

Since the compiled output is included in the repository, you can run `bru-mcp` directly from GitHub without cloning or building manually:

```json
{
  "mcpServers": {
    "bru-mcp": {
      "command": "npx",
      "args": ["github:h-mergel/bru-mcp"]
    }
  }
}
```

### Via global install

If you installed with `npm install -g .`:

```json
{
  "mcpServers": {
    "bru-mcp": {
      "command": "bru-mcp"
    }
  }
}
```

### Via local path

If you cloned the repository and prefer a direct path:

```json
{
  "mcpServers": {
    "bru-mcp": {
      "command": "node",
      "args": ["/absolute/path/to/bru-mcp/dist/src/index.js"]
    }
  }
}
```

### Claude Desktop

The configuration file is located at:

- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
- **Linux:** `~/.config/Claude/claude_desktop_config.json`

### OpenCode

Add the server to your OpenCode MCP configuration (`.opencode/config.json` or the global config). Any of the three snippets above works.

## Tools

The server exposes four tools. For single-collection setups, **auto-detection runs automatically** — just call `bru_list_requests`, `bru_run`, or `bru_run_collection` directly and the collection is resolved from the current working directory. Use `bru_find_collections` only when multiple collections are present or auto-detection fails.

### `bru_find_collections`

Recursively scans a directory for Bruno collections (identified by `bruno.json` files). Use this only when working with multiple collections or when auto-detection fails.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `startPath` | string | No | Directory to search from. Defaults to the current working directory. |

**Returns:** A list of collection paths, their available environments, and the number of requests in each.

---

### `bru_list_requests`

Lists all `.bru` request files in a collection, grouped by folder. Also shows available environments. The collection is auto-detected if `collectionPath` is omitted.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `collectionPath` | string | No | Path to the Bruno collection directory (the folder containing `bruno.json`). Reuse from a previous response to skip auto-detection. Takes precedence over `startPath`. |
| `startPath` | string | No | Directory to search for a Bruno collection. Checks well-known subdirectories (`bruno`, `.bruno`, `api-tests`, `api`, `tests`) first, then falls back to a recursive search. Defaults to the current working directory. |

**Returns:** A grouped list of requests and available environments, plus a structured JSON representation.

---

### `bru_run`

Runs a specific request file or folder within a collection using the `bru` CLI. The collection is auto-detected if `collectionPath` is omitted.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `collectionPath` | string | No | Path to the Bruno collection directory. Reuse from a previous response to skip auto-detection. Takes precedence over `startPath`. |
| `startPath` | string | No | Directory to search for a Bruno collection. Defaults to the current working directory. |
| `target` | string | Yes | Relative path to a `.bru` file or subfolder (e.g. `cards/find-cards.bru` or `cards`). |
| `env` | string | No | Environment name to use (e.g. `dev`, `prod`). Must exist in `environments/`. |
| `envVars` | object | No | Key-value pairs to override environment variables (e.g. `{"baseUrl": "http://localhost:3000"}`). |
| `recursive` | boolean | No | Run requests in subfolders recursively. Default: `false`. |
| `insecure` | boolean | No | Allow insecure (self-signed) TLS connections. Default: `false`. |
| `testsOnly` | boolean | No | Only run requests that have tests or assertions. Default: `false`. |
| `bail` | boolean | No | Stop after the first failing request. Default: `false`. |
| `tags` | string[] | No | Only run requests with these tags. |
| `excludeTags` | string[] | No | Exclude requests with these tags. |
| `verbose` | boolean | No | Enable verbose output. Default: `false`. |

**Returns:** The full CLI output, the constructed command, and parsed JSON results if available.

---

### `bru_run_collection`

Runs all requests in a collection recursively. Supports tag filtering and all the same options as `bru_run` (except `target` and `recursive`, which are implicit). The collection is auto-detected if `collectionPath` is omitted.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `collectionPath` | string | No | Path to the Bruno collection directory. Reuse from a previous response to skip auto-detection. Takes precedence over `startPath`. |
| `startPath` | string | No | Directory to search for a Bruno collection. Defaults to the current working directory. |
| `env` | string | No | Environment name to use. |
| `envVars` | object | No | Key-value pairs to override environment variables. |
| `tags` | string[] | No | Only run requests with these tags. |
| `excludeTags` | string[] | No | Exclude requests with these tags. |
| `insecure` | boolean | No | Allow insecure TLS connections. Default: `false`. |
| `testsOnly` | boolean | No | Only run requests that have tests. Default: `false`. |
| `bail` | boolean | No | Stop after first failure. Default: `false`. |
| `verbose` | boolean | No | Enable verbose output. Default: `false`. |

**Returns:** A summary with total/passed/failed/skipped counts, the full CLI output, and parsed JSON results.

## Development

```bash
# Compile TypeScript to dist/
npm run build

# Watch mode (recompiles on changes)
npm run dev

# Run tests (builds first)
npm test
```

### Project structure

```
bru-mcp/
├── src/
│   ├── helpers.ts       # Pure helper functions (collection discovery, arg building, JSON extraction)
│   └── index.ts         # MCP server setup and tool definitions
├── test/
│   ├── helpers.test.ts  # Unit tests for all helper functions
│   └── fixtures/        # Static Bruno collections used by tests
├── dist/src/            # Compiled output (committed to repo for npx usage)
├── package.json
├── tsconfig.json
├── AGENTS.md
├── LICENSE
└── README.md
```

### Running tests

Tests use the built-in `node:test` runner and run against the compiled output in `dist/`. No additional test framework is needed.

```bash
npm test
```

### Contributing

After making changes to the source code:

```bash
# 1. Run tests — must all pass before committing
npm test

# 2. Stage the updated compiled output along with the source changes
git add src/ dist/src/

# 3. Commit and push
git commit -m "..."
git push
```

The compiled `dist/src/` is committed to the repository so that users can run the server via `npx github:h-mergel/bru-mcp` without a local build step.

## Security notes

- **Path traversal:** The `target` parameter in `bru_run` is validated to ensure it cannot escape the collection directory (e.g. `../../etc/passwd` is rejected).
- **Shell injection:** The `bru` process is spawned without a shell on Linux/macOS (`shell: true` is only enabled on Windows where `.cmd` wrappers require it), so shell metacharacters in arguments are not interpreted.

## License

MIT

Maintenance

ActivityInactive
ResponsivenessNo issues