@context-engine-bridge/context-engine-mcp-bridge 0.0.13 → 0.0.14
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/AGENTS.md +319 -0
- package/package.json +1 -1
package/AGENTS.md
ADDED
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
<!-- Parent: ../AGENTS.md -->
|
|
2
|
+
# Context-Engine MCP Bridge
|
|
3
|
+
|
|
4
|
+
## Purpose
|
|
5
|
+
|
|
6
|
+
TypeScript/Node.js MCP bridge server that acts as a proxy between MCP clients (Claude Code, Cursor, Windsurf) and the Context Engine backend. Provides SSE/HTTP transport, OAuth 2.0 authentication, and transparent path mapping between local and container filesystems.
|
|
7
|
+
|
|
8
|
+
## Key Responsibilities
|
|
9
|
+
|
|
10
|
+
1. **MCP Protocol Translation**: Converts stdio/HTTP requests from MCP clients to HTTP requests for the Python backend
|
|
11
|
+
2. **Authentication**: Manages OAuth 2.0 flows and session persistence for multi-user environments
|
|
12
|
+
3. **Path Mapping**: Translates container paths (`/work/repo/...`) to local workspace paths for client consumption
|
|
13
|
+
4. **Session Management**: Maintains per-connection session state and default collection/workspace settings
|
|
14
|
+
5. **Tool Routing**: Routes `memory.*` tools to memory server, other tools to indexer server
|
|
15
|
+
|
|
16
|
+
## Architecture
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
┌────────────────────────────────────────────────────────┐
|
|
20
|
+
│ MCP Client (Claude Code, etc.) │
|
|
21
|
+
└──────────────┬─────────────────────────────────────────┘
|
|
22
|
+
│ stdio or HTTP
|
|
23
|
+
┌──────────────▼─────────────────────────────────────────┐
|
|
24
|
+
│ ctx-mcp-bridge (src/mcpServer.js) │
|
|
25
|
+
│ ┌─────────────────────────────────────────────────┐ │
|
|
26
|
+
│ │ MCP SDK Server (stdio/HTTP transport) │ │
|
|
27
|
+
│ │ - tools/list → merge indexer + memory tools │ │
|
|
28
|
+
│ │ - tools/call → route to appropriate backend │ │
|
|
29
|
+
│ └────────────────┬────────────────────────────────┘ │
|
|
30
|
+
│ │ │
|
|
31
|
+
│ ┌────────────────▼─────────────┐ ┌─────────────────┐ │
|
|
32
|
+
│ │ MCP HTTP Client (indexer) │ │ HTTP Client │ │
|
|
33
|
+
│ │ http://localhost:8003/mcp │ │ (memory) │ │
|
|
34
|
+
│ └──────────────────────────────┘ └─────────────────┘ │
|
|
35
|
+
└────────────────────────────────────────────────────────┘
|
|
36
|
+
│
|
|
37
|
+
┌──────────────▼─────────────────────────────────────────┐
|
|
38
|
+
│ Python Backend (indexer_mcp.py, memory_mcp.py) │
|
|
39
|
+
└────────────────────────────────────────────────────────┘
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Core Files
|
|
43
|
+
|
|
44
|
+
### src/mcpServer.js (800+ lines)
|
|
45
|
+
|
|
46
|
+
Main MCP server implementation. Key functions:
|
|
47
|
+
|
|
48
|
+
- `createBridgeServer()`: Initializes MCP server with dual backend clients
|
|
49
|
+
- `initializeRemoteClients()`: Connects to indexer and memory servers via StreamableHTTPClientTransport
|
|
50
|
+
- `ListToolsRequestSchema` handler: Merges tools from both backends, deduplicates
|
|
51
|
+
- `CallToolRequestSchema` handler: Routes tools, injects session ID, handles retries
|
|
52
|
+
- `selectClientForTool()`: Routes `memory.*` tools to memory server, others to indexer
|
|
53
|
+
- `fetchBridgeCollectionState()`: Queries `/bridge/state` for active collection overrides
|
|
54
|
+
- Session retry logic: Detects `"No valid session ID"` errors and reinitializes clients
|
|
55
|
+
|
|
56
|
+
**Environment Variables**:
|
|
57
|
+
- `CTXCE_INDEXER_URL`: Default `http://localhost:8003/mcp`
|
|
58
|
+
- `CTXCE_MEMORY_URL`: Default `http://localhost:8002/mcp` (optional)
|
|
59
|
+
- `CTXCE_SESSION_ID`: Explicit session ID (overrides derived session)
|
|
60
|
+
- `CTXCE_TOOL_TIMEOUT_MSEC`: Tool call timeout (default 300000 = 5 min)
|
|
61
|
+
- `CTXCE_TOOL_RETRY_ATTEMPTS`: Retry count for transient errors (default 2)
|
|
62
|
+
- `CTXCE_BRIDGE_STATE_TOKEN`: Auth token for `/bridge/state` endpoint
|
|
63
|
+
|
|
64
|
+
### src/oauthHandler.js (586 lines)
|
|
65
|
+
|
|
66
|
+
OAuth 2.0 implementation (RFC9728 Protected Resource Metadata + RFC7591 Dynamic Client Registration):
|
|
67
|
+
|
|
68
|
+
- **Endpoints**:
|
|
69
|
+
- `GET /.well-known/oauth-authorization-server`: OAuth metadata
|
|
70
|
+
- `POST /oauth/register`: Dynamic client registration (auto-approve local clients)
|
|
71
|
+
- `GET /oauth/authorize`: Authorization flow (shows login page or auto-approves if session exists)
|
|
72
|
+
- `POST /oauth/store-session`: Stores session from login page, returns auth code
|
|
73
|
+
- `POST /oauth/token`: Exchanges auth code for bearer token
|
|
74
|
+
|
|
75
|
+
- **Security**:
|
|
76
|
+
- PKCE code_challenge validation (TODO: currently skipped for local bridge)
|
|
77
|
+
- Client ID and redirect URI validation against registered clients
|
|
78
|
+
- Origin/Referer header validation (localhost-only for `/oauth/store-session`)
|
|
79
|
+
- 10-minute auth code expiry, 24-hour token expiry
|
|
80
|
+
- Binds to `127.0.0.1` only (no remote access)
|
|
81
|
+
|
|
82
|
+
- **Storage**: In-memory `tokenStore`, `pendingCodes`, `registeredClients` (not persisted across restarts)
|
|
83
|
+
|
|
84
|
+
### src/resultPathMapping.js (507 lines)
|
|
85
|
+
|
|
86
|
+
Bidirectional path translation between container and client filesystems:
|
|
87
|
+
|
|
88
|
+
**Request Path Mapping** (`maybeRemapToolArgs`):
|
|
89
|
+
- Detects `/work/<repo>/...` container paths in tool args
|
|
90
|
+
- Extracts repo-relative POSIX path (e.g., `/work/myrepo/src/main.py` → `src/main.py`)
|
|
91
|
+
- Handles `path`, `under`, `root`, `subdir`, `path_glob`, `not_glob` parameters
|
|
92
|
+
- Recursively processes nested objects and arrays
|
|
93
|
+
|
|
94
|
+
**Response Path Mapping** (`maybeRemapToolResult`):
|
|
95
|
+
- Parses JSON from `content[].text` or `structuredContent`
|
|
96
|
+
- For each hit object:
|
|
97
|
+
- Computes `rel_path` from container path
|
|
98
|
+
- Joins `rel_path` to workspace root to produce `client_path`
|
|
99
|
+
- Prefers existing `host_path` if it exists and is within workspace
|
|
100
|
+
- Optionally overrides `hit.path` with `client_path` (default: enabled via `CTXCE_BRIDGE_OVERRIDE_PATH=1`)
|
|
101
|
+
- Remaps `related_paths` arrays to absolute local paths
|
|
102
|
+
|
|
103
|
+
**Environment Variables**:
|
|
104
|
+
- `CTXCE_BRIDGE_MAP_PATHS=1`: Enable/disable path mapping (default: enabled)
|
|
105
|
+
- `CTXCE_BRIDGE_OVERRIDE_PATH=1`: Replace `path` field with `client_path` (default: enabled)
|
|
106
|
+
- `CTXCE_BRIDGE_CLIENT_PATH_STRICT=0`: Use `workspace_join` always vs preferring `host_path`
|
|
107
|
+
- `CTXCE_BRIDGE_PATH_DIAGNOSTICS=0`: Add debug fields `client_path_source`, `client_path_joined`
|
|
108
|
+
|
|
109
|
+
### src/authConfig.js (not shown, ~100 lines)
|
|
110
|
+
|
|
111
|
+
Auth entry persistence to `~/.ctxce/auth.json`:
|
|
112
|
+
|
|
113
|
+
- `loadAuthEntry(backendUrl)`: Load session for specific backend
|
|
114
|
+
- `saveAuthEntry(backendUrl, {sessionId, userId, expiresAt})`: Persist session
|
|
115
|
+
- `deleteAuthEntry(backendUrl)`: Remove session
|
|
116
|
+
- `loadAnyAuthEntry()`: Find any stored session (fallback)
|
|
117
|
+
|
|
118
|
+
### src/authCli.js (285 lines)
|
|
119
|
+
|
|
120
|
+
CLI commands for auth management:
|
|
121
|
+
|
|
122
|
+
- `ctxce auth login`: Calls `/auth/login` or `/auth/login/password`, saves session
|
|
123
|
+
- `ctxce auth status`: Checks stored session, prints human or JSON output
|
|
124
|
+
- `ctxce auth logout`: Deletes stored session
|
|
125
|
+
|
|
126
|
+
**Fallback logic**: If `--backend-url` omitted, tries stored sessions, then `CTXCE_UPLOAD_ENDPOINT`, then `http://localhost:8004`
|
|
127
|
+
|
|
128
|
+
### src/cli.js (124 lines)
|
|
129
|
+
|
|
130
|
+
Main CLI dispatcher:
|
|
131
|
+
|
|
132
|
+
- `ctxce mcp-serve`: Starts stdio MCP bridge (default mode for MCP clients)
|
|
133
|
+
- `ctxce mcp-http-serve`: Starts HTTP MCP bridge on port 30810 (used by VS Code extension)
|
|
134
|
+
- `ctxce auth <subcmd>`: Delegates to `authCli.js`
|
|
135
|
+
|
|
136
|
+
**Flags**:
|
|
137
|
+
- `--workspace` / `--path`: Workspace root (default: cwd)
|
|
138
|
+
- `--indexer-url`: Override indexer URL
|
|
139
|
+
- `--memory-url`: Override memory URL (or omit to disable)
|
|
140
|
+
- `--port`: HTTP port (for `mcp-http-serve`)
|
|
141
|
+
|
|
142
|
+
### bin/ctxce.js (2 lines)
|
|
143
|
+
|
|
144
|
+
Shebang wrapper: `#!/usr/bin/env node`, imports `runCli()` from `src/cli.js`
|
|
145
|
+
|
|
146
|
+
## Key Features
|
|
147
|
+
|
|
148
|
+
### 1. Tool Routing
|
|
149
|
+
|
|
150
|
+
```javascript
|
|
151
|
+
function selectClientForTool(name, indexerClient, memoryClient) {
|
|
152
|
+
const lowered = name.toLowerCase();
|
|
153
|
+
if (memoryClient && lowered.includes("memory")) {
|
|
154
|
+
return memoryClient;
|
|
155
|
+
}
|
|
156
|
+
return indexerClient;
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Tools starting with `memory.` or containing "memory" route to memory server; all others route to indexer.
|
|
161
|
+
|
|
162
|
+
### 2. Session Injection
|
|
163
|
+
|
|
164
|
+
Bridge injects `session` parameter into all tool calls:
|
|
165
|
+
1. Explicit `CTXCE_SESSION_ID` env var
|
|
166
|
+
2. Stored auth session from `~/.ctxce/auth.json`
|
|
167
|
+
3. Fallback: `ctxce-<workspace-hash>` (deterministic per workspace)
|
|
168
|
+
|
|
169
|
+
### 3. Retry Logic
|
|
170
|
+
|
|
171
|
+
Automatic retry on transient errors (timeouts, network errors, 502/503/504):
|
|
172
|
+
- Default: 2 attempts with 200ms delay
|
|
173
|
+
- Detects session errors (`"No valid session ID"`) and reinitializes clients
|
|
174
|
+
- Configurable via `CTXCE_TOOL_RETRY_ATTEMPTS` and `CTXCE_TOOL_RETRY_DELAY_MSEC`
|
|
175
|
+
|
|
176
|
+
### 4. Collection State Override
|
|
177
|
+
|
|
178
|
+
Queries `/bridge/state?collection=...&repo_name=...` on startup to resolve active collection:
|
|
179
|
+
- Prefers `serving_collection` from backend over `ctx_config.json`
|
|
180
|
+
- Falls back to `default_collection` from `ctx_config.json`
|
|
181
|
+
- Logs active collection for transparency
|
|
182
|
+
|
|
183
|
+
### 5. Path Mapping Examples
|
|
184
|
+
|
|
185
|
+
**Request**: Client sends `path: "/Users/dev/myrepo/src/main.py"`
|
|
186
|
+
→ Bridge normalizes to `src/main.py` (repo-relative)
|
|
187
|
+
→ Backend receives `path: "src/main.py"`
|
|
188
|
+
|
|
189
|
+
**Response**: Backend returns `path: "/work/myrepo/src/main.py"`, `container_path: "/work/myrepo/src/main.py"`
|
|
190
|
+
→ Bridge computes `rel_path: "src/main.py"`, `client_path: "/Users/dev/myrepo/src/main.py"`
|
|
191
|
+
→ Client receives `path: "/Users/dev/myrepo/src/main.py"` (if `CTXCE_BRIDGE_OVERRIDE_PATH=1`)
|
|
192
|
+
|
|
193
|
+
## Usage Patterns
|
|
194
|
+
|
|
195
|
+
### Stdio Mode (for MCP clients)
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
ctxce mcp-serve --workspace /path/to/repo
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Add to Claude Desktop `claude_desktop_config.json`:
|
|
202
|
+
```json
|
|
203
|
+
{
|
|
204
|
+
"mcpServers": {
|
|
205
|
+
"context-engine": {
|
|
206
|
+
"command": "ctxce",
|
|
207
|
+
"args": ["mcp-serve", "--workspace", "/path/to/repo"]
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### HTTP Mode (for VS Code extension)
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
ctxce mcp-http-serve --workspace /path/to/repo --port 30810
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Extension uses HTTP transport to avoid stdio buffering issues.
|
|
220
|
+
|
|
221
|
+
### Authentication Flow
|
|
222
|
+
|
|
223
|
+
1. User initiates OAuth via browser: `GET /oauth/authorize?client_id=...&redirect_uri=...&code_challenge=...`
|
|
224
|
+
2. Bridge checks for existing session in `~/.ctxce/auth.json`
|
|
225
|
+
3. If no session, shows login page with backend URL input
|
|
226
|
+
4. User submits credentials, page POSTs to backend `/auth/login`
|
|
227
|
+
5. Backend returns `session_id`, page POSTs to `/oauth/store-session`
|
|
228
|
+
6. Bridge saves session to `~/.ctxce/auth.json`, generates auth code, redirects with code
|
|
229
|
+
7. Client exchanges code for bearer token via `/oauth/token`
|
|
230
|
+
8. Client includes `Authorization: Bearer <token>` in subsequent MCP requests
|
|
231
|
+
|
|
232
|
+
## Testing
|
|
233
|
+
|
|
234
|
+
No automated tests currently. Manual testing via:
|
|
235
|
+
|
|
236
|
+
1. Start backend: `docker-compose up -d`
|
|
237
|
+
2. Run bridge: `ctxce mcp-http-serve --workspace /path/to/repo`
|
|
238
|
+
3. Test OAuth flow: Open `http://127.0.0.1:30810/oauth/authorize?client_id=test&redirect_uri=http://localhost/callback&code_challenge=...`
|
|
239
|
+
4. Test MCP tools: Use MCP client (Claude Code) or `curl` to POST tool calls to `/mcp`
|
|
240
|
+
|
|
241
|
+
## Debugging
|
|
242
|
+
|
|
243
|
+
Set `CTXCE_DEBUG_LOG=/tmp/ctxce.log` to log all bridge activity:
|
|
244
|
+
```bash
|
|
245
|
+
export CTXCE_DEBUG_LOG=/tmp/ctxce.log
|
|
246
|
+
ctxce mcp-serve --workspace /path/to/repo
|
|
247
|
+
tail -f /tmp/ctxce.log
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Common issues:
|
|
251
|
+
- **Session errors**: Check `~/.ctxce/auth.json` has valid `sessionId`
|
|
252
|
+
- **Path mapping issues**: Set `CTXCE_BRIDGE_PATH_DIAGNOSTICS=1` to see `client_path_source`
|
|
253
|
+
- **Tool routing issues**: Check tool name includes `"memory"` for memory server routing
|
|
254
|
+
- **Timeout errors**: Increase `CTXCE_TOOL_TIMEOUT_MSEC` for slow queries
|
|
255
|
+
|
|
256
|
+
## Integration Points
|
|
257
|
+
|
|
258
|
+
### Upstream (MCP Clients)
|
|
259
|
+
- **Claude Code**: Uses stdio transport via `claude_desktop_config.json`
|
|
260
|
+
- **Cursor**: Supports MCP via settings
|
|
261
|
+
- **VS Code Extension**: Uses HTTP transport on port 30810
|
|
262
|
+
|
|
263
|
+
### Downstream (Python Backend)
|
|
264
|
+
- **indexer_mcp.py**: Provides 30+ search/graph tools on port 8003
|
|
265
|
+
- **memory_mcp.py**: Provides memory storage tools on port 8002
|
|
266
|
+
- **upload_service.py**: Auth backend on port 8004 (`/auth/login`, `/bridge/state`)
|
|
267
|
+
|
|
268
|
+
## Security Considerations
|
|
269
|
+
|
|
270
|
+
1. **Local-only binding**: HTTP server binds to `127.0.0.1` only (no remote access)
|
|
271
|
+
2. **Origin validation**: `/oauth/store-session` requires `Origin` or `Referer` header from localhost
|
|
272
|
+
3. **Client validation**: OAuth endpoints validate `client_id` and `redirect_uri` against registered clients
|
|
273
|
+
4. **Session persistence**: `~/.ctxce/auth.json` stores sessions (file permissions: 0600)
|
|
274
|
+
5. **Token expiry**: Auth codes expire in 10 min, bearer tokens in 24 hours
|
|
275
|
+
6. **PKCE**: Code challenge method `S256` supported (validation TODO)
|
|
276
|
+
|
|
277
|
+
## Configuration Files
|
|
278
|
+
|
|
279
|
+
### ~/.ctxce/auth.json
|
|
280
|
+
|
|
281
|
+
```json
|
|
282
|
+
{
|
|
283
|
+
"http://localhost:8004": {
|
|
284
|
+
"sessionId": "sess_abc123",
|
|
285
|
+
"userId": "user-456",
|
|
286
|
+
"expiresAt": 1704974400
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### ctx_config.json (in workspace)
|
|
292
|
+
|
|
293
|
+
```json
|
|
294
|
+
{
|
|
295
|
+
"default_collection": "myrepo-abc123",
|
|
296
|
+
"default_mode": "refrag",
|
|
297
|
+
"default_under": "src/",
|
|
298
|
+
"repo_name": "myrepo"
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
Bridge reads this on startup and sends to backend via `set_session_defaults`.
|
|
303
|
+
|
|
304
|
+
## Future Enhancements
|
|
305
|
+
|
|
306
|
+
1. **PKCE validation**: Implement `code_verifier` hash validation in `/oauth/token`
|
|
307
|
+
2. **Persistent storage**: Migrate OAuth state to Redis/SQLite (currently in-memory)
|
|
308
|
+
3. **Token refresh**: Support `refresh_token` grant type for long-lived sessions
|
|
309
|
+
4. **Multi-workspace**: Allow clients to switch workspaces without restarting bridge
|
|
310
|
+
5. **Rate limiting**: Add per-client rate limits for tool calls
|
|
311
|
+
6. **Metrics**: Expose Prometheus metrics for tool call latency, error rates
|
|
312
|
+
|
|
313
|
+
## Related Documentation
|
|
314
|
+
|
|
315
|
+
- [MCP SDK Documentation](https://modelcontextprotocol.io/docs)
|
|
316
|
+
- [OAuth 2.0 RFC9728](https://www.rfc-editor.org/rfc/rfc9728.html) (Protected Resource Metadata)
|
|
317
|
+
- [OAuth 2.0 RFC7591](https://www.rfc-editor.org/rfc/rfc7591.html) (Dynamic Client Registration)
|
|
318
|
+
- [Context Engine Python Backend](../scripts/AGENTS.md)
|
|
319
|
+
- [VS Code Extension Integration](../README.md#vs-code-extension)
|
package/package.json
CHANGED