@bridge_gpt/mcp-server 0.1.4 → 0.1.6
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 +17 -2
- package/build/index.js +165 -13
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,6 +9,7 @@ MCP server for [Bridge API](https://bridgegpt-api.com) — exposes Jira integrat
|
|
|
9
9
|
| `BAPI_BASE_URL` | Yes | `https://bridgegpt-api.com` | Bridge API base URL |
|
|
10
10
|
| `BAPI_REPO_NAME` | Yes | _(none)_ | Jira project/repository identifier configured in Bridge API |
|
|
11
11
|
| `BAPI_API_KEY` | Yes | _(none)_ | API key obtained from the Bridge API setup UI |
|
|
12
|
+
| `BAPI_PROJECT_ROOT` | No | _(auto-set by --init)_ | Absolute path to project root. Anchors BAPI_DOCS_DIR and BAPI_PIPELINES_DIR resolution. Set automatically by --init. |
|
|
12
13
|
| `BAPI_DOCS_DIR` | No | `docs/tmp` | Local directory for saving plans, critiques, and research reports |
|
|
13
14
|
| `BAPI_PIPELINES_DIR` | No | `.bridge/pipelines` | Directory for user-defined custom pipeline JSON files |
|
|
14
15
|
|
|
@@ -62,7 +63,7 @@ claude mcp add bridge-api -- npx -y @bridge_gpt/mcp-server \
|
|
|
62
63
|
}
|
|
63
64
|
```
|
|
64
65
|
|
|
65
|
-
### Cursor (
|
|
66
|
+
### Cursor (.cursor/mcp.json — project-local)
|
|
66
67
|
|
|
67
68
|
```json
|
|
68
69
|
{
|
|
@@ -81,8 +82,12 @@ claude mcp add bridge-api -- npx -y @bridge_gpt/mcp-server \
|
|
|
81
82
|
}
|
|
82
83
|
```
|
|
83
84
|
|
|
85
|
+
> **Global fallback:** If project-local config is not supported in your Cursor version, use `~/.cursor/config/mcp.json` instead.
|
|
86
|
+
|
|
84
87
|
### Windsurf (~/.codeium/windsurf/mcp_config.json)
|
|
85
88
|
|
|
89
|
+
> **Note:** Windsurf only supports global MCP configuration. `--init` detects Windsurf projects and outputs a ready-to-paste config snippet to the console.
|
|
90
|
+
|
|
86
91
|
```json
|
|
87
92
|
{
|
|
88
93
|
"mcpServers": {
|
|
@@ -122,7 +127,17 @@ Bridge API ships pre-built slash commands for Claude Code and Cursor. To scaffol
|
|
|
122
127
|
npx @bridge_gpt/mcp-server --init
|
|
123
128
|
```
|
|
124
129
|
|
|
125
|
-
|
|
130
|
+
Run from your project root. `--init` performs the following:
|
|
131
|
+
|
|
132
|
+
1. **IDE detection** — checks for `.vscode/`, `.cursor/`, `.windsurf/`, and `.windsurfrules` to determine which IDEs are in use.
|
|
133
|
+
2. **MCP config files** — creates or updates `.mcp.json`, `.vscode/mcp.json`, and `.cursor/mcp.json` with sensible defaults and placeholder values (`YOUR_API_KEY`, `YOUR_REPO_NAME`). Only creates IDE-specific configs when that IDE is detected. Existing configs are preserved — only the `bridge-api` entry is added or updated.
|
|
134
|
+
3. **Gitignore** — newly created config files are automatically added to `.gitignore` to prevent committing API key placeholders.
|
|
135
|
+
4. **Slash commands** — writes command files to `.claude/commands/` (always) and `.cursor/commands/` (when Cursor is detected).
|
|
136
|
+
5. **Windsurf** — since Windsurf only supports global config, outputs a ready-to-paste JSON snippet to the console.
|
|
137
|
+
|
|
138
|
+
Re-run after upgrading the package to get updated commands. Replace placeholder values (`YOUR_API_KEY`, `YOUR_REPO_NAME`) with your actual credentials from the Bridge API setup UI.
|
|
139
|
+
|
|
140
|
+
> **Codex users:** `--init` does not modify `~/.codex/config.toml`. Set `BAPI_PROJECT_ROOT` manually in your Codex MCP config.
|
|
126
141
|
|
|
127
142
|
## Available Tools
|
|
128
143
|
|
package/build/index.js
CHANGED
|
@@ -27,8 +27,9 @@ let userPipelineKeys = new Set();
|
|
|
27
27
|
const BASE_URL = process.env.BAPI_BASE_URL ?? "https://bridgegpt-api.com";
|
|
28
28
|
const REPO_NAME = process.env.BAPI_REPO_NAME ?? "";
|
|
29
29
|
const API_KEY = process.env.BAPI_API_KEY ?? "";
|
|
30
|
-
const
|
|
31
|
-
const
|
|
30
|
+
const PROJECT_ROOT = process.env.BAPI_PROJECT_ROOT ?? process.cwd();
|
|
31
|
+
const BAPI_DOCS_DIR = path.resolve(PROJECT_ROOT, process.env.BAPI_DOCS_DIR ?? "docs/tmp");
|
|
32
|
+
const BAPI_PIPELINES_DIR = path.resolve(PROJECT_ROOT, process.env.BAPI_PIPELINES_DIR ?? ".bridge/pipelines");
|
|
32
33
|
const GET_HEADERS = { "X-API-Key": API_KEY };
|
|
33
34
|
const POST_HEADERS = {
|
|
34
35
|
"X-API-Key": API_KEY,
|
|
@@ -205,19 +206,164 @@ async function pollForResult(getUrl, timeoutMs, label) {
|
|
|
205
206
|
}
|
|
206
207
|
}
|
|
207
208
|
// ---------------------------------------------------------------------------
|
|
208
|
-
// CLI: --init scaffolds slash commands into the current project
|
|
209
|
+
// CLI: --init scaffolds slash commands and MCP configs into the current project
|
|
209
210
|
// ---------------------------------------------------------------------------
|
|
211
|
+
function buildBridgeApiEntry(cwd) {
|
|
212
|
+
return {
|
|
213
|
+
command: "npx",
|
|
214
|
+
args: ["-y", "@bridge_gpt/mcp-server"],
|
|
215
|
+
env: {
|
|
216
|
+
BAPI_BASE_URL: "https://bridgegpt-api.com",
|
|
217
|
+
BAPI_REPO_NAME: "YOUR_REPO_NAME",
|
|
218
|
+
BAPI_API_KEY: "YOUR_API_KEY",
|
|
219
|
+
BAPI_DOCS_DIR: "docs/tmp",
|
|
220
|
+
BAPI_PROJECT_ROOT: cwd,
|
|
221
|
+
},
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
async function ensureGitignored(cwd, filePath) {
|
|
225
|
+
const gitignorePath = path.join(cwd, ".gitignore");
|
|
226
|
+
const entry = filePath.startsWith("/") ? path.relative(cwd, filePath) : filePath;
|
|
227
|
+
let content = "";
|
|
228
|
+
try {
|
|
229
|
+
content = await readFile(gitignorePath, "utf-8");
|
|
230
|
+
}
|
|
231
|
+
catch { /* .gitignore doesn't exist yet */ }
|
|
232
|
+
// Check if already present (exact line match)
|
|
233
|
+
const lines = content.split("\n");
|
|
234
|
+
if (lines.some((line) => line.trim() === entry))
|
|
235
|
+
return;
|
|
236
|
+
const separator = content.length > 0 && !content.endsWith("\n") ? "\n" : "";
|
|
237
|
+
await writeFile(gitignorePath, content + separator + entry + "\n", "utf-8");
|
|
238
|
+
}
|
|
210
239
|
if (process.argv.includes("--init")) {
|
|
240
|
+
// Guard: must be run from project root
|
|
241
|
+
try {
|
|
242
|
+
await stat(path.join(process.cwd(), "package.json"));
|
|
243
|
+
}
|
|
244
|
+
catch {
|
|
245
|
+
console.error("Error: No package.json found in current directory.\n" +
|
|
246
|
+
"--init must be run from your project root (the directory containing package.json).");
|
|
247
|
+
process.exit(1);
|
|
248
|
+
}
|
|
211
249
|
try {
|
|
212
250
|
const cwd = process.cwd();
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
251
|
+
// ---- Phase 1: IDE Detection ----
|
|
252
|
+
const ideDetection = {
|
|
253
|
+
claude: true,
|
|
254
|
+
vscode: false,
|
|
255
|
+
cursor: false,
|
|
256
|
+
windsurf: false,
|
|
257
|
+
};
|
|
258
|
+
try {
|
|
259
|
+
await stat(path.join(cwd, ".vscode"));
|
|
260
|
+
ideDetection.vscode = true;
|
|
261
|
+
}
|
|
262
|
+
catch { }
|
|
263
|
+
try {
|
|
264
|
+
await stat(path.join(cwd, ".cursor"));
|
|
265
|
+
ideDetection.cursor = true;
|
|
266
|
+
}
|
|
267
|
+
catch { }
|
|
268
|
+
if (!ideDetection.cursor && process.env.CURSOR_TRACE_DIR)
|
|
269
|
+
ideDetection.cursor = true;
|
|
270
|
+
try {
|
|
271
|
+
await stat(path.join(cwd, ".windsurf"));
|
|
272
|
+
ideDetection.windsurf = true;
|
|
273
|
+
}
|
|
274
|
+
catch { }
|
|
275
|
+
if (!ideDetection.windsurf) {
|
|
276
|
+
try {
|
|
277
|
+
await stat(path.join(cwd, ".windsurfrules"));
|
|
278
|
+
ideDetection.windsurf = true;
|
|
279
|
+
}
|
|
280
|
+
catch { }
|
|
281
|
+
}
|
|
282
|
+
const detectedIDEs = Object.entries(ideDetection)
|
|
283
|
+
.filter(([, v]) => v)
|
|
284
|
+
.map(([k]) => k);
|
|
285
|
+
console.log(`Bridge API --init: detected IDEs: ${detectedIDEs.join(", ")}`);
|
|
286
|
+
// ---- Phase 2: Windsurf manual instructions ----
|
|
287
|
+
if (ideDetection.windsurf) {
|
|
288
|
+
const windsurfSnippet = JSON.stringify({ mcpServers: { "bridge-api": buildBridgeApiEntry(cwd) } }, null, 2);
|
|
289
|
+
console.log("\n⚠ Windsurf does not support project-local MCP configuration.\n" +
|
|
290
|
+
"Add the following to ~/.codeium/windsurf/mcp_config.json:\n\n" +
|
|
291
|
+
windsurfSnippet + "\n");
|
|
292
|
+
}
|
|
293
|
+
// ---- Phase 3: Config file handling ----
|
|
294
|
+
const configTargets = [
|
|
295
|
+
{ path: ".mcp.json", topLevelKey: "mcpServers", shouldCreate: true },
|
|
296
|
+
{ path: ".vscode/mcp.json", topLevelKey: "servers", shouldCreate: ideDetection.vscode },
|
|
297
|
+
{ path: ".cursor/mcp.json", topLevelKey: "mcpServers", shouldCreate: ideDetection.cursor },
|
|
216
298
|
];
|
|
299
|
+
const configActions = [];
|
|
300
|
+
let anyCreatedOrAdded = false;
|
|
301
|
+
for (const target of configTargets) {
|
|
302
|
+
const fullPath = path.join(cwd, target.path);
|
|
303
|
+
let fileExists = false;
|
|
304
|
+
try {
|
|
305
|
+
await stat(fullPath);
|
|
306
|
+
fileExists = true;
|
|
307
|
+
}
|
|
308
|
+
catch { }
|
|
309
|
+
if (!target.shouldCreate && !fileExists) {
|
|
310
|
+
configActions.push({ path: target.path, action: "skipped — IDE not detected" });
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
if (fileExists) {
|
|
314
|
+
// Read and parse existing file
|
|
315
|
+
const raw = await readFile(fullPath, "utf-8");
|
|
316
|
+
let parsed;
|
|
317
|
+
try {
|
|
318
|
+
parsed = JSON.parse(raw);
|
|
319
|
+
}
|
|
320
|
+
catch {
|
|
321
|
+
console.warn(` ${target.path} skipped — invalid JSON format`);
|
|
322
|
+
configActions.push({ path: target.path, action: "skipped — invalid JSON" });
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
const topLevel = parsed[target.topLevelKey];
|
|
326
|
+
if (topLevel && topLevel["bridge-api"]) {
|
|
327
|
+
// Entry exists — update BAPI_PROJECT_ROOT only
|
|
328
|
+
if (!topLevel["bridge-api"].env)
|
|
329
|
+
topLevel["bridge-api"].env = {};
|
|
330
|
+
topLevel["bridge-api"].env.BAPI_PROJECT_ROOT = cwd;
|
|
331
|
+
await writeFile(fullPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
|
|
332
|
+
configActions.push({ path: target.path, action: "updated BAPI_PROJECT_ROOT" });
|
|
333
|
+
}
|
|
334
|
+
else {
|
|
335
|
+
// Entry missing — add it, preserving existing content
|
|
336
|
+
if (!parsed[target.topLevelKey])
|
|
337
|
+
parsed[target.topLevelKey] = {};
|
|
338
|
+
parsed[target.topLevelKey]["bridge-api"] = buildBridgeApiEntry(cwd);
|
|
339
|
+
await writeFile(fullPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
|
|
340
|
+
configActions.push({ path: target.path, action: "added entry" });
|
|
341
|
+
anyCreatedOrAdded = true;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
else {
|
|
345
|
+
// Create new file
|
|
346
|
+
await mkdir(path.dirname(fullPath), { recursive: true });
|
|
347
|
+
const content = { [target.topLevelKey]: { "bridge-api": buildBridgeApiEntry(cwd) } };
|
|
348
|
+
await writeFile(fullPath, JSON.stringify(content, null, 2) + "\n", "utf-8");
|
|
349
|
+
await ensureGitignored(cwd, target.path);
|
|
350
|
+
configActions.push({ path: target.path, action: "created" });
|
|
351
|
+
anyCreatedOrAdded = true;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
console.log("\nMCP config files:");
|
|
355
|
+
for (const entry of configActions) {
|
|
356
|
+
console.log(` ${entry.path}: ${entry.action}`);
|
|
357
|
+
}
|
|
358
|
+
// ---- Phase 4: Scaffold slash command directories ----
|
|
359
|
+
const commandDirs = [path.join(cwd, ".claude", "commands")];
|
|
360
|
+
if (ideDetection.cursor) {
|
|
361
|
+
commandDirs.push(path.join(cwd, ".cursor", "commands"));
|
|
362
|
+
}
|
|
217
363
|
const writtenFiles = new Set();
|
|
218
364
|
const skippedFiles = new Set();
|
|
219
365
|
const overwrittenFiles = new Set();
|
|
220
|
-
for (const dir of
|
|
366
|
+
for (const dir of commandDirs) {
|
|
221
367
|
await mkdir(dir, { recursive: true });
|
|
222
368
|
for (const [filename, content] of Object.entries(COMMANDS)) {
|
|
223
369
|
const target = path.join(dir, filename);
|
|
@@ -238,17 +384,18 @@ if (process.argv.includes("--init")) {
|
|
|
238
384
|
for (const f of writtenFiles)
|
|
239
385
|
skippedFiles.delete(f);
|
|
240
386
|
const total = Object.keys(COMMANDS).length;
|
|
241
|
-
|
|
387
|
+
const dirNames = commandDirs.map((d) => path.relative(cwd, d)).join(" and ");
|
|
388
|
+
console.log(`\nSlash commands: scaffolded ${total} commands into ${commandDirs.length} director${commandDirs.length === 1 ? "y" : "ies"}`);
|
|
242
389
|
if (writtenFiles.size > 0)
|
|
243
390
|
console.log(` Written: ${writtenFiles.size}`);
|
|
244
391
|
if (overwrittenFiles.size > 0)
|
|
245
392
|
console.log(` Overwritten (content changed): ${overwrittenFiles.size}`);
|
|
246
393
|
if (skippedFiles.size > 0)
|
|
247
394
|
console.log(` Skipped (unchanged): ${skippedFiles.size}`);
|
|
248
|
-
console.log(`
|
|
249
|
-
// Scaffold custom pipeline directories
|
|
250
|
-
const pipelinesDir = BAPI_PIPELINES_DIR;
|
|
251
|
-
const instrDir = path.join(path.dirname(
|
|
395
|
+
console.log(` ${dirNames}`);
|
|
396
|
+
// ---- Phase 5: Scaffold custom pipeline directories ----
|
|
397
|
+
const pipelinesDir = path.resolve(cwd, process.env.BAPI_PIPELINES_DIR ?? ".bridge/pipelines");
|
|
398
|
+
const instrDir = path.join(path.dirname(pipelinesDir), "instructions");
|
|
252
399
|
await mkdir(pipelinesDir, { recursive: true });
|
|
253
400
|
await mkdir(instrDir, { recursive: true });
|
|
254
401
|
const readmePath = path.join(pipelinesDir, "README.md");
|
|
@@ -369,6 +516,11 @@ automatically provided by the server.
|
|
|
369
516
|
console.log(` ${path.relative(cwd, examplePath)} (written)`);
|
|
370
517
|
}
|
|
371
518
|
console.log(` ${path.relative(cwd, instrDir)}/ (ensured)`);
|
|
519
|
+
// ---- Phase 6: Final summary ----
|
|
520
|
+
if (anyCreatedOrAdded) {
|
|
521
|
+
console.log("\nUpdate BAPI_API_KEY and BAPI_REPO_NAME in your config files — " +
|
|
522
|
+
"get these values from the Bridge API setup UI at https://bridgegpt-api.com");
|
|
523
|
+
}
|
|
372
524
|
process.exit(0);
|
|
373
525
|
}
|
|
374
526
|
catch (err) {
|
|
@@ -1116,7 +1268,7 @@ server.registerTool("request_ticket_critique", {
|
|
|
1116
1268
|
}
|
|
1117
1269
|
const confirmationText = `Ticket critique requested for ${ticket_number}. ` +
|
|
1118
1270
|
`Processing typically takes 1-5 minutes. ` +
|
|
1119
|
-
`Use
|
|
1271
|
+
`Use get_ticket_critique with ticket_number "${ticket_number}" to retrieve the results once processing completes.`;
|
|
1120
1272
|
return { content: [{ type: "text", text: confirmationText }] };
|
|
1121
1273
|
});
|
|
1122
1274
|
// ---------------------------------------------------------------------------
|