bru-mcp
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
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues