@context-engine-bridge/context-engine-mcp-bridge 0.0.19 → 0.0.21

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@context-engine-bridge/context-engine-mcp-bridge",
3
- "version": "0.0.19",
3
+ "version": "0.0.21",
4
4
  "description": "Context Engine MCP bridge (http/stdio proxy combining indexer + memory servers)",
5
5
  "bin": {
6
6
  "ctxce": "bin/ctxce.js",
package/src/cli.js CHANGED
@@ -23,6 +23,7 @@ export async function runCli() {
23
23
  let indexerUrl = process.env.CTXCE_INDEXER_URL || "http://localhost:8003/mcp";
24
24
  let memoryUrl = process.env.CTXCE_MEMORY_URL || null;
25
25
  let port = Number.parseInt(process.env.CTXCE_HTTP_PORT || "30810", 10) || 30810;
26
+ let collection = null;
26
27
 
27
28
  for (let i = 0; i < args.length; i += 1) {
28
29
  const a = args[i];
@@ -57,13 +58,20 @@ export async function runCli() {
57
58
  continue;
58
59
  }
59
60
  }
61
+ if (a === "--collection") {
62
+ if (i + 1 < args.length) {
63
+ collection = args[i + 1];
64
+ i += 1;
65
+ continue;
66
+ }
67
+ }
60
68
  }
61
69
 
62
70
  // eslint-disable-next-line no-console
63
71
  console.error(
64
- `[ctxce] Starting HTTP MCP bridge: workspace=${workspace}, port=${port}, indexerUrl=${indexerUrl}, memoryUrl=${memoryUrl || "disabled"}`,
72
+ `[ctxce] Starting HTTP MCP bridge: workspace=${workspace}, port=${port}, indexerUrl=${indexerUrl}, memoryUrl=${memoryUrl || "disabled"}, collection=${collection || "auto"}`,
65
73
  );
66
- await runHttpMcpServer({ workspace, indexerUrl, memoryUrl, port });
74
+ await runHttpMcpServer({ workspace, indexerUrl, memoryUrl, port, collection });
67
75
  return;
68
76
  }
69
77
 
@@ -72,10 +80,12 @@ export async function runCli() {
72
80
  // Supported flags:
73
81
  // --workspace / --path : workspace root (default: cwd)
74
82
  // --indexer-url : override MCP indexer URL (default env CTXCE_INDEXER_URL or http://localhost:8003/mcp)
83
+ // --collection : collection name to use for MCP calls
75
84
  const args = argv.slice(1);
76
85
  let workspace = process.cwd();
77
86
  let indexerUrl = process.env.CTXCE_INDEXER_URL || "http://localhost:8003/mcp";
78
87
  let memoryUrl = process.env.CTXCE_MEMORY_URL || null;
88
+ let collection = null;
79
89
 
80
90
  for (let i = 0; i < args.length; i += 1) {
81
91
  const a = args[i];
@@ -100,13 +110,20 @@ export async function runCli() {
100
110
  continue;
101
111
  }
102
112
  }
113
+ if (a === "--collection") {
114
+ if (i + 1 < args.length) {
115
+ collection = args[i + 1];
116
+ i += 1;
117
+ continue;
118
+ }
119
+ }
103
120
  }
104
121
 
105
122
  // eslint-disable-next-line no-console
106
123
  console.error(
107
- `[ctxce] Starting MCP bridge: workspace=${workspace}, indexerUrl=${indexerUrl}, memoryUrl=${memoryUrl || "disabled"}`,
124
+ `[ctxce] Starting MCP bridge: workspace=${workspace}, indexerUrl=${indexerUrl}, memoryUrl=${memoryUrl || "disabled"}, collection=${collection || "auto"}`,
108
125
  );
109
- await runMcpServer({ workspace, indexerUrl, memoryUrl });
126
+ await runMcpServer({ workspace, indexerUrl, memoryUrl, collection });
110
127
  return;
111
128
  }
112
129
 
@@ -117,7 +134,7 @@ export async function runCli() {
117
134
 
118
135
  // eslint-disable-next-line no-console
119
136
  console.error(
120
- `Usage: ${binName} mcp-serve [--workspace <path>] [--indexer-url <url>] [--memory-url <url>] | ${binName} mcp-http-serve [--workspace <path>] [--indexer-url <url>] [--memory-url <url>] [--port <port>] | ${binName} auth <login|status|logout> [--backend-url <url>] [--token <token>] [--username <name> --password <pass>]`,
137
+ `Usage: ${binName} mcp-serve [--workspace <path>] [--indexer-url <url>] [--memory-url <url>] [--collection <name>] | ${binName} mcp-http-serve [--workspace <path>] [--indexer-url <url>] [--memory-url <url>] [--port <port>] [--collection <name>] | ${binName} auth <login|status|logout> [--backend-url <url>] [--token <token>] [--username <name> --password <pass>]`,
121
138
  );
122
139
  process.exit(1);
123
140
  }
package/src/mcpServer.js CHANGED
@@ -415,18 +415,8 @@ async function fetchBridgeCollectionState({
415
415
  if (!resp.ok) {
416
416
  if (resp.status === 401 || resp.status === 403) {
417
417
  debugLog(
418
- `[ctxce] /bridge/state responded ${resp.status}; missing or invalid token/session, marking local session as expired.`,
418
+ `[ctxce] /bridge/state responded ${resp.status}; session may not be accepted by this endpoint.`,
419
419
  );
420
- if (backendHint) {
421
- try {
422
- const entry = loadAuthEntry(backendHint);
423
- if (entry) {
424
- saveAuthEntry(backendHint, { ...entry, expiresAt: 1 });
425
- }
426
- } catch {
427
- // ignore failures
428
- }
429
- }
430
420
  return null;
431
421
  }
432
422
  throw new Error(`bridge/state responded ${resp.status}`);
@@ -444,12 +434,15 @@ async function createBridgeServer(options) {
444
434
  const workspace = options.workspace || process.cwd();
445
435
  const indexerUrl = options.indexerUrl;
446
436
  const memoryUrl = options.memoryUrl;
437
+ const explicitCollection = options.collection;
447
438
 
448
439
  const config = loadConfig(workspace);
449
440
  const defaultCollection =
450
- config && typeof config.default_collection === "string"
451
- ? config.default_collection
452
- : null;
441
+ explicitCollection && typeof explicitCollection === "string"
442
+ ? explicitCollection
443
+ : config && typeof config.default_collection === "string"
444
+ ? config.default_collection
445
+ : null;
453
446
  const defaultMode =
454
447
  config && typeof config.default_mode === "string" ? config.default_mode : null;
455
448
  const defaultUnder =
@@ -503,8 +496,8 @@ async function createBridgeServer(options) {
503
496
  expiresAt > 0 &&
504
497
  expiresAt < Math.floor(Date.now() / 1000)
505
498
  ) {
506
- debugLog("[ctxce] Stored auth session appears expired; please run `ctxce auth login` again.");
507
- return "";
499
+ debugLog("[ctxce] Stored auth session has local expiry in the past; attempting to use it anyway (server will validate).");
500
+ return entry.sessionId;
508
501
  }
509
502
  return entry.sessionId;
510
503
  }
@@ -646,9 +639,34 @@ async function createBridgeServer(options) {
646
639
  }
647
640
  }
648
641
 
642
+ // Build requestInit with Authorization header for nginx auth_request passthrough.
643
+ // When the bridge connects to a remote endpoint (e.g. https://dev.example.com/indexer/mcp),
644
+ // nginx's auth_request subrequest checks the Authorization header. Without it, the
645
+ // connection is rejected with 401.
646
+ const transportOpts = {};
647
+ if (sessionId && !sessionId.startsWith("ctxce-")) {
648
+ transportOpts.requestInit = {
649
+ headers: {
650
+ Authorization: `Bearer ${sessionId}`,
651
+ },
652
+ };
653
+ debugLog(`[ctxce] Transport auth: injecting Authorization header (session ${sessionId.slice(0, 8)}...)`);
654
+ } else {
655
+ // Check for API key in environment as fallback
656
+ const envApiKey = (process.env.CTXCE_API_KEY || process.env.CTXCE_AUTH_TOKEN || "").trim();
657
+ if (envApiKey) {
658
+ transportOpts.requestInit = {
659
+ headers: {
660
+ Authorization: `Bearer ${envApiKey}`,
661
+ },
662
+ };
663
+ debugLog("[ctxce] Transport auth: injecting Authorization header (env API key/token)");
664
+ }
665
+ }
666
+
649
667
  let nextIndexerClient = null;
650
668
  try {
651
- const indexerTransport = new StreamableHTTPClientTransport(indexerUrl);
669
+ const indexerTransport = new StreamableHTTPClientTransport(indexerUrl, transportOpts);
652
670
  const client = new Client(
653
671
  {
654
672
  name: "ctx-context-engine-bridge-http-client",
@@ -672,7 +690,7 @@ async function createBridgeServer(options) {
672
690
  let nextMemoryClient = null;
673
691
  if (memoryUrl) {
674
692
  try {
675
- const memoryTransport = new StreamableHTTPClientTransport(memoryUrl);
693
+ const memoryTransport = new StreamableHTTPClientTransport(memoryUrl, transportOpts);
676
694
  const client = new Client(
677
695
  {
678
696
  name: "ctx-context-engine-bridge-memory-client",
@@ -971,7 +989,8 @@ export async function runHttpMcpServer(options) {
971
989
 
972
990
  // Pre-warm: validate upstream connectivity (best-effort)
973
991
  try {
974
- await createBridgeServer(options);
992
+ const warmupServer = await createBridgeServer(options);
993
+ await warmupServer.close();
975
994
  debugLog("[ctxce] HTTP bridge validated upstream connectivity");
976
995
  } catch (err) {
977
996
  debugLog("[ctxce] HTTP bridge warmup failed (non-fatal): " + String(err));
@@ -277,7 +277,11 @@ export function getLoginPage(redirectUri, clientId, state, codeChallenge, codeCh
277
277
  throw new Error('No redirect URL');
278
278
  }
279
279
  } catch (err) {
280
- result.innerHTML = '<p class="error">' + err.message + '</p>';
280
+ result.textContent = '';
281
+ var p = document.createElement('p');
282
+ p.className = 'error';
283
+ p.textContent = err.message;
284
+ result.appendChild(p);
281
285
  }
282
286
  });
283
287
  </script>