rentbamboo-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +73 -0
- package/cli.js +87 -0
- package/package.json +19 -0
package/README.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# rentbamboo-mcp
|
|
2
|
+
|
|
3
|
+
A zero-dependency [MCP](https://modelcontextprotocol.io) **stdio bridge** for
|
|
4
|
+
RentBamboo. It connects any local AI agent (Claude Desktop, Cursor, VS Code,
|
|
5
|
+
PI, opm) to the hosted RentBamboo MCP server over Streamable HTTP using your
|
|
6
|
+
API key. The 55 Panda tools it exposes are **read-only** right now.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install -g rentbamboo-mcp
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Configure
|
|
15
|
+
|
|
16
|
+
Set your API key (get one in RentBamboo → Settings → MCP → API keys):
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
export RENTBAMBOO_API_KEY=rb_live_...
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Optionally point at a non-production endpoint:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
export RENTBAMBOO_MCP_URL=http://localhost:3000/api/mcp
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
For **Claude Desktop / Cursor / VS Code** (`claude_desktop_config.json`,
|
|
31
|
+
`mcp.json`, etc.):
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"mcpServers": {
|
|
36
|
+
"rentbamboo": {
|
|
37
|
+
"command": "rentbamboo-mcp",
|
|
38
|
+
"env": { "RENTBAMBOO_API_KEY": "rb_live_..." }
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
For **opm** (`~/.omp/agent/mcp.json`):
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"mcpServers": {
|
|
49
|
+
"rentbamboo": {
|
|
50
|
+
"type": "stdio",
|
|
51
|
+
"command": "rentbamboo-mcp",
|
|
52
|
+
"env": { "RENTBAMBOO_API_KEY": "rb_live_..." }
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
For **PI**, install the adapter first (`pi install npm:pi-mcp-adapter`), then
|
|
59
|
+
point it at `rentbamboo-mcp` the same way.
|
|
60
|
+
|
|
61
|
+
## How it works
|
|
62
|
+
|
|
63
|
+
`rentbamboo-mcp` reads JSON-RPC frames from stdin and forwards each one to the
|
|
64
|
+
hosted MCP endpoint (`POST https://rentbamboo.com/api/mcp`) with
|
|
65
|
+
`Authorization: Bearer <key>`, then writes the response back to stdout. It is a
|
|
66
|
+
thin proxy — all tools, permissions, and the read-only gate live server-side.
|
|
67
|
+
|
|
68
|
+
## Environment
|
|
69
|
+
|
|
70
|
+
| Variable | Required | Default |
|
|
71
|
+
| --------------------- | -------- | -------------------------------- |
|
|
72
|
+
| `RENTBAMBOO_API_KEY` | yes | — |
|
|
73
|
+
| `RENTBAMBOO_MCP_URL` | no | `https://rentbamboo.com/api/mcp` |
|
package/cli.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* rentbamboo-mcp — stdio↔HTTP MCP bridge for RentBamboo.
|
|
4
|
+
*
|
|
5
|
+
* A zero-dependency bridge: it presents a stdio MCP server to any local AI
|
|
6
|
+
* agent (Claude Desktop, PI, opm, Cursor, VS Code) and forwards every JSON-RPC
|
|
7
|
+
* request to the hosted RentBamboo MCP endpoint (Streamable HTTP) using your
|
|
8
|
+
* API key. The actual tools/tool-execution live on the hosted server; this
|
|
9
|
+
* package just proxies the wire protocol.
|
|
10
|
+
*
|
|
11
|
+
* Env:
|
|
12
|
+
* RENTBAMBOO_API_KEY (required) your rb_live_... / rb_test_... key
|
|
13
|
+
* RENTBAMBOO_MCP_URL (optional) default https://rentbamboo.com/api/mcp
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { createInterface } from "node:readline";
|
|
17
|
+
|
|
18
|
+
const DEFAULT_URL = "https://rentbamboo.com/api/mcp";
|
|
19
|
+
const URL = process.env.RENTBAMBOO_MCP_URL || DEFAULT_URL;
|
|
20
|
+
const KEY = process.env.RENTBAMBOO_API_KEY || process.env.RENTBAMBOO_MCP_KEY || "";
|
|
21
|
+
|
|
22
|
+
if (!KEY) {
|
|
23
|
+
console.error(
|
|
24
|
+
"[rentbamboo-mcp] Set RENTBAMBOO_API_KEY to your RentBamboo API key (rb_live_...).",
|
|
25
|
+
);
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Build a JSON-RPC error envelope for an upstream failure. */
|
|
30
|
+
function errorResponse(id, message) {
|
|
31
|
+
return { jsonrpc: "2.0", id: id ?? null, error: { code: -32603, message } };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function forward(message) {
|
|
35
|
+
const id = Array.isArray(message) ? null : message?.id ?? null;
|
|
36
|
+
try {
|
|
37
|
+
const res = await fetch(URL, {
|
|
38
|
+
method: "POST",
|
|
39
|
+
headers: {
|
|
40
|
+
"Content-Type": "application/json",
|
|
41
|
+
Accept: "application/json",
|
|
42
|
+
Authorization: `Bearer ${KEY}`,
|
|
43
|
+
},
|
|
44
|
+
body: typeof message === "string" ? message : JSON.stringify(message),
|
|
45
|
+
signal: AbortSignal.timeout(120_000),
|
|
46
|
+
});
|
|
47
|
+
const text = await res.text();
|
|
48
|
+
if (res.ok) {
|
|
49
|
+
if (!text) return null; // notification (202 empty) — no reply
|
|
50
|
+
try {
|
|
51
|
+
return JSON.parse(text);
|
|
52
|
+
} catch {
|
|
53
|
+
return errorResponse(id, `invalid upstream response (${text.slice(0, 120)})`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return errorResponse(id, `upstream ${res.status}: ${text.slice(0, 200)}`);
|
|
57
|
+
} catch (err) {
|
|
58
|
+
return errorResponse(id, `upstream unreachable: ${err?.message ?? "network error"}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Serialize forwards so stdout responses stay in request order, and keep the
|
|
63
|
+
// process alive until every in-flight forward has settled (even if stdin
|
|
64
|
+
// closes — otherwise a piped/short-lived input would exit before the reply).
|
|
65
|
+
let pending = Promise.resolve();
|
|
66
|
+
|
|
67
|
+
const rl = createInterface({ input: process.stdin, crlfDelay: Infinity });
|
|
68
|
+
rl.on("line", (line) => {
|
|
69
|
+
const trimmed = line.trim();
|
|
70
|
+
if (!trimmed) return;
|
|
71
|
+
let message;
|
|
72
|
+
try {
|
|
73
|
+
message = JSON.parse(trimmed);
|
|
74
|
+
} catch {
|
|
75
|
+
return; // malformed frame — ignore
|
|
76
|
+
}
|
|
77
|
+
pending = pending.then(async () => {
|
|
78
|
+
const result = await forward(message);
|
|
79
|
+
if (result !== null && result !== undefined) {
|
|
80
|
+
process.stdout.write(JSON.stringify(result) + "\n");
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
rl.on("close", async () => {
|
|
85
|
+
await pending;
|
|
86
|
+
process.exit(0);
|
|
87
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "rentbamboo-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Stdio MCP bridge to the RentBamboo MCP server. Exposes the RentBamboo Panda tools (read-only) to any MCP-capable AI agent.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"rentbamboo-mcp": "cli.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "cli.js",
|
|
10
|
+
"files": ["cli.js", "README.md"],
|
|
11
|
+
"engines": {
|
|
12
|
+
"node": ">=18"
|
|
13
|
+
},
|
|
14
|
+
"keywords": ["mcp", "rentbamboo", "crm", "pm", "ai", "agent", "panda"],
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
}
|
|
19
|
+
}
|