@essentialai/cc-bridge-mcp-server 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/LICENSE +15 -0
- package/README.md +289 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +18 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +28 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +35 -0
- package/dist/config.js.map +1 -0
- package/dist/constants.d.ts +3 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +6 -0
- package/dist/constants.js.map +1 -0
- package/dist/errors.d.ts +40 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +53 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +66 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +22 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +74 -0
- package/dist/logger.js.map +1 -0
- package/dist/services/cc-cli.d.ts +3 -0
- package/dist/services/cc-cli.d.ts.map +1 -0
- package/dist/services/cc-cli.js +57 -0
- package/dist/services/cc-cli.js.map +1 -0
- package/dist/services/health-check.d.ts +23 -0
- package/dist/services/health-check.d.ts.map +1 -0
- package/dist/services/health-check.js +96 -0
- package/dist/services/health-check.js.map +1 -0
- package/dist/services/peer-registry.d.ts +9 -0
- package/dist/services/peer-registry.d.ts.map +1 -0
- package/dist/services/peer-registry.js +207 -0
- package/dist/services/peer-registry.js.map +1 -0
- package/dist/startup.d.ts +2 -0
- package/dist/startup.d.ts.map +1 -0
- package/dist/startup.js +119 -0
- package/dist/startup.js.map +1 -0
- package/dist/tools/deregister-peer.d.ts +3 -0
- package/dist/tools/deregister-peer.d.ts.map +1 -0
- package/dist/tools/deregister-peer.js +37 -0
- package/dist/tools/deregister-peer.js.map +1 -0
- package/dist/tools/get-history.d.ts +3 -0
- package/dist/tools/get-history.d.ts.map +1 -0
- package/dist/tools/get-history.js +39 -0
- package/dist/tools/get-history.js.map +1 -0
- package/dist/tools/health-check.d.ts +3 -0
- package/dist/tools/health-check.d.ts.map +1 -0
- package/dist/tools/health-check.js +27 -0
- package/dist/tools/health-check.js.map +1 -0
- package/dist/tools/list-peers.d.ts +3 -0
- package/dist/tools/list-peers.d.ts.map +1 -0
- package/dist/tools/list-peers.js +35 -0
- package/dist/tools/list-peers.js.map +1 -0
- package/dist/tools/register-peer.d.ts +3 -0
- package/dist/tools/register-peer.d.ts.map +1 -0
- package/dist/tools/register-peer.js +47 -0
- package/dist/tools/register-peer.js.map +1 -0
- package/dist/tools/send-message.d.ts +3 -0
- package/dist/tools/send-message.d.ts.map +1 -0
- package/dist/tools/send-message.js +103 -0
- package/dist/tools/send-message.js.map +1 -0
- package/dist/types.d.ts +31 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/wizard/detect.d.ts +4 -0
- package/dist/wizard/detect.d.ts.map +1 -0
- package/dist/wizard/detect.js +21 -0
- package/dist/wizard/detect.js.map +1 -0
- package/dist/wizard/index.d.ts +5 -0
- package/dist/wizard/index.d.ts.map +1 -0
- package/dist/wizard/index.js +140 -0
- package/dist/wizard/index.js.map +1 -0
- package/dist/wizard/prompts.d.ts +18 -0
- package/dist/wizard/prompts.d.ts.map +1 -0
- package/dist/wizard/prompts.js +66 -0
- package/dist/wizard/prompts.js.map +1 -0
- package/dist/wizard/scaffold-demo.d.ts +6 -0
- package/dist/wizard/scaffold-demo.d.ts.map +1 -0
- package/dist/wizard/scaffold-demo.js +37 -0
- package/dist/wizard/scaffold-demo.js.map +1 -0
- package/dist/wizard/scaffold-real.d.ts +16 -0
- package/dist/wizard/scaffold-real.d.ts.map +1 -0
- package/dist/wizard/scaffold-real.js +64 -0
- package/dist/wizard/scaffold-real.js.map +1 -0
- package/dist/wizard/templates.d.ts +9 -0
- package/dist/wizard/templates.d.ts.map +1 -0
- package/dist/wizard/templates.js +175 -0
- package/dist/wizard/templates.js.map +1 -0
- package/package.json +66 -0
- package/server.json +60 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 cc-bridge-mcp-server contributors
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
10
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
11
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
12
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
13
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
14
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
15
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
# @essentialai/cc-bridge-mcp-server
|
|
2
|
+
|
|
3
|
+
Claude Code Bridge from Essential AI Solutions (essentialai.uk) — MCP server for inter-Claude-Code session communication.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
**Step 1:** Add `.mcp.json` to **both** project repositories:
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"mcpServers": {
|
|
12
|
+
"cc-bridge": {
|
|
13
|
+
"command": "npx",
|
|
14
|
+
"args": ["-y", "@essentialai/cc-bridge-mcp-server"],
|
|
15
|
+
"env": {}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Or use the CLI:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
claude mcp add --transport stdio cc-bridge -- npx -y @essentialai/cc-bridge-mcp-server
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**Step 2:** Restart Claude Code in both repos. The bridge tools are now available.
|
|
28
|
+
|
|
29
|
+
## What It Does
|
|
30
|
+
|
|
31
|
+
Two Claude Code instances -- one working on a backend repo, another on a frontend repo -- need to negotiate testing scenarios and debug collaboratively in real-time without mixing their accumulated project context.
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
CC_Backend CC_Frontend
|
|
35
|
+
| |
|
|
36
|
+
+-- .mcp.json --> @essentialai/cc-bridge-mcp-server |
|
|
37
|
+
| | |
|
|
38
|
+
| +-- ~/cloud_code_bridge/cc-bridge-state.json
|
|
39
|
+
| | |
|
|
40
|
+
| | <-- .mcp.json ---+
|
|
41
|
+
| |
|
|
42
|
+
+-- claude --resume <sessionId> -p "msg" -+
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Each CC instance spawns its own MCP server process via stdio transport. Shared state is persisted to `~/cloud_code_bridge/cc-bridge-state.json` with file locking so both processes see the same peer registry and message history.
|
|
46
|
+
|
|
47
|
+
Messages are relayed by calling `claude --resume <sessionId> -p "message"` as a subprocess. File locking uses `fs.writeFile` with `flag: "wx"` (O_CREAT | O_EXCL), stale lock detection via `process.kill(pid, 0)`, and atomic writes via temp-file-then-rename.
|
|
48
|
+
|
|
49
|
+
## Tools Reference
|
|
50
|
+
|
|
51
|
+
The server exposes six tools, all prefixed with `cc_`:
|
|
52
|
+
|
|
53
|
+
### cc_register_peer
|
|
54
|
+
|
|
55
|
+
Register a Claude Code session as a named peer on the bridge.
|
|
56
|
+
|
|
57
|
+
| Parameter | Type | Required | Description |
|
|
58
|
+
|-------------|--------|----------|--------------------------------------------------------------|
|
|
59
|
+
| `peerId` | string | yes | Unique identifier, e.g. `"backend"` or `"frontend"` |
|
|
60
|
+
| `sessionId` | string | yes | Claude Code session ID (used with `--resume`) |
|
|
61
|
+
| `cwd` | string | yes | Absolute path to the project working directory |
|
|
62
|
+
| `label` | string | yes | Human-readable label, e.g. `"CC_Backend"` or `"CC_Frontend"` |
|
|
63
|
+
|
|
64
|
+
### cc_deregister_peer
|
|
65
|
+
|
|
66
|
+
Remove a previously registered peer from the bridge.
|
|
67
|
+
|
|
68
|
+
| Parameter | Type | Required | Description |
|
|
69
|
+
|-----------|--------|----------|---------------------------------------|
|
|
70
|
+
| `peerId` | string | yes | Peer ID to deregister, e.g. `"backend"` |
|
|
71
|
+
|
|
72
|
+
### cc_send_message
|
|
73
|
+
|
|
74
|
+
Send a message from one registered peer to another. The message is relayed by resuming the target's Claude Code session via CLI subprocess. Returns the target's response.
|
|
75
|
+
|
|
76
|
+
| Parameter | Type | Required | Description |
|
|
77
|
+
|--------------|--------|----------|--------------------------------------------|
|
|
78
|
+
| `fromPeerId` | string | yes | Peer ID of the sender, e.g. `"backend"` |
|
|
79
|
+
| `toPeerId` | string | yes | Peer ID of the recipient, e.g. `"frontend"` |
|
|
80
|
+
| `message` | string | yes | The message content to send |
|
|
81
|
+
|
|
82
|
+
### cc_list_peers
|
|
83
|
+
|
|
84
|
+
List all currently registered peers. Returns peer IDs, session IDs, working directories, labels, and a `potentiallyStale` flag for peers idle beyond the configured timeout. No parameters.
|
|
85
|
+
|
|
86
|
+
### cc_get_history
|
|
87
|
+
|
|
88
|
+
Retrieve the message history for the bridge. Returns messages in chronological order, most recent last.
|
|
89
|
+
|
|
90
|
+
| Parameter | Type | Required | Description |
|
|
91
|
+
|-----------|--------|----------|------------------------------------------------|
|
|
92
|
+
| `peerId` | string | no | Filter history to messages involving this peer |
|
|
93
|
+
| `limit` | number | no | Maximum number of messages to return (default 50) |
|
|
94
|
+
|
|
95
|
+
### cc_health_check
|
|
96
|
+
|
|
97
|
+
Diagnose the bridge's operational status. No parameters required.
|
|
98
|
+
|
|
99
|
+
**Checks performed:**
|
|
100
|
+
|
|
101
|
+
- **State file** -- Can the state directory be read and written?
|
|
102
|
+
- **Lock mechanism** -- Can file locks be acquired and released?
|
|
103
|
+
- **Claude CLI** -- Is the `claude` binary available and responsive?
|
|
104
|
+
|
|
105
|
+
**Response fields:**
|
|
106
|
+
|
|
107
|
+
| Field | Type | Description |
|
|
108
|
+
|-----------------|---------|-----------------------------------------|
|
|
109
|
+
| `healthy` | boolean | All checks passed |
|
|
110
|
+
| `serverVersion` | string | Current server version |
|
|
111
|
+
| `statePath` | string | Path to state file |
|
|
112
|
+
| `claudePath` | string | Path to Claude CLI |
|
|
113
|
+
| `checks` | object | Per-check pass/fail with detail messages |
|
|
114
|
+
| `timestamp` | string | ISO timestamp of the check |
|
|
115
|
+
|
|
116
|
+
## Configuration
|
|
117
|
+
|
|
118
|
+
All settings are configured via environment variables with sensible defaults:
|
|
119
|
+
|
|
120
|
+
| Variable | Default | Description |
|
|
121
|
+
|----------|---------|-------------|
|
|
122
|
+
| `CC_BRIDGE_STATE_PATH` | `~/cloud_code_bridge` | Directory for state file and logs |
|
|
123
|
+
| `CC_BRIDGE_TIMEOUT_MS` | `120000` (2 min) | CLI subprocess timeout in milliseconds |
|
|
124
|
+
| `CC_BRIDGE_CHAR_LIMIT` | `0` (unlimited) | Max characters in relayed message (0 = no limit) |
|
|
125
|
+
| `CC_BRIDGE_LOG_LEVEL` | `info` | Log verbosity: `debug`, `info`, `warn`, `error` |
|
|
126
|
+
| `CC_BRIDGE_CLAUDE_PATH` | `claude` | Path to the Claude Code CLI executable |
|
|
127
|
+
| `CC_BRIDGE_STALE_TIMEOUT_MS` | `1800000` (30 min) | Idle time before peer is flagged stale (0 = disabled) |
|
|
128
|
+
|
|
129
|
+
To override defaults, set environment variables in your `.mcp.json`:
|
|
130
|
+
|
|
131
|
+
```json
|
|
132
|
+
{
|
|
133
|
+
"mcpServers": {
|
|
134
|
+
"cc-bridge": {
|
|
135
|
+
"command": "npx",
|
|
136
|
+
"args": ["-y", "@essentialai/cc-bridge-mcp-server"],
|
|
137
|
+
"env": {
|
|
138
|
+
"CC_BRIDGE_STATE_PATH": "/custom/path",
|
|
139
|
+
"CC_BRIDGE_LOG_LEVEL": "debug"
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Usage Workflow
|
|
147
|
+
|
|
148
|
+
1. Start two Claude Code sessions, one per repo. Note each session ID.
|
|
149
|
+
|
|
150
|
+
2. In CC_Backend, register both peers:
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
Use cc_register_peer:
|
|
154
|
+
peerId: "backend", sessionId: "<backend-session-id>",
|
|
155
|
+
cwd: "/path/to/backend", label: "CC_Backend"
|
|
156
|
+
|
|
157
|
+
Use cc_register_peer:
|
|
158
|
+
peerId: "frontend", sessionId: "<frontend-session-id>",
|
|
159
|
+
cwd: "/path/to/frontend", label: "CC_Frontend"
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
3. Send a message from backend to frontend:
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
Use cc_send_message:
|
|
166
|
+
fromPeerId: "backend", toPeerId: "frontend",
|
|
167
|
+
message: "What endpoint does the login form POST to?"
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
4. The bridge resumes the frontend CC session, delivers the message, and returns the response.
|
|
171
|
+
|
|
172
|
+
5. Check message history at any time:
|
|
173
|
+
|
|
174
|
+
```
|
|
175
|
+
Use cc_get_history to see all exchanges, or filter by peerId.
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
6. When done, deregister peers:
|
|
179
|
+
|
|
180
|
+
```
|
|
181
|
+
Use cc_deregister_peer:
|
|
182
|
+
peerId: "backend"
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Troubleshooting
|
|
186
|
+
|
|
187
|
+
### NVM/PATH: "npx not found" or server fails to start
|
|
188
|
+
|
|
189
|
+
MCP servers are spawned as subprocesses and may not inherit your NVM configuration.
|
|
190
|
+
|
|
191
|
+
**Option 1: Use absolute path to npx**
|
|
192
|
+
|
|
193
|
+
Find your npx path with `which npx` (e.g., `/Users/you/.nvm/versions/node/v22.11.0/bin/npx`), then update `.mcp.json`:
|
|
194
|
+
|
|
195
|
+
```json
|
|
196
|
+
{
|
|
197
|
+
"mcpServers": {
|
|
198
|
+
"cc-bridge": {
|
|
199
|
+
"command": "/Users/you/.nvm/versions/node/v22.11.0/bin/npx",
|
|
200
|
+
"args": ["-y", "@essentialai/cc-bridge-mcp-server"]
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
**Option 2: Use `claude mcp add` (handles PATH automatically)**
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
claude mcp add --transport stdio cc-bridge -- npx -y @essentialai/cc-bridge-mcp-server
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
**Option 3: Ensure NVM loads in non-interactive shells**
|
|
213
|
+
|
|
214
|
+
Add to `~/.zshrc` or `~/.bashrc`:
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
export NVM_DIR="$HOME/.nvm"
|
|
218
|
+
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### State file location
|
|
222
|
+
|
|
223
|
+
The bridge stores state at `~/cloud_code_bridge/cc-bridge-state.json` by default.
|
|
224
|
+
|
|
225
|
+
- Override with: `CC_BRIDGE_STATE_PATH=/your/path`
|
|
226
|
+
- Logs are stored at: `<state-path>/logs/`
|
|
227
|
+
- First-run config is persisted to `~/.cc-bridge-config.json`
|
|
228
|
+
|
|
229
|
+
### Common errors
|
|
230
|
+
|
|
231
|
+
| Error | Cause | Fix |
|
|
232
|
+
|-------|-------|-----|
|
|
233
|
+
| `CLI_NOT_FOUND` | `claude` not on PATH | Install Claude Code or set `CC_BRIDGE_CLAUDE_PATH` |
|
|
234
|
+
| `CLI_TIMEOUT` | Response took > 2 min | Increase `CC_BRIDGE_TIMEOUT_MS` |
|
|
235
|
+
| `LOCK_TIMEOUT` | Lock held by dead process | Delete `<state-path>/cc-bridge-state.json.lock` |
|
|
236
|
+
| `STATE_CORRUPT` | Invalid JSON in state | Auto-recovers; backup saved as `.corrupt.<timestamp>` |
|
|
237
|
+
| `PEER_NOT_FOUND` | Target peer not registered | Register both peers before sending messages |
|
|
238
|
+
|
|
239
|
+
## Development
|
|
240
|
+
|
|
241
|
+
Build from source:
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
git clone https://github.com/eaisdevelopment/cc-bridge-mcp-server.git
|
|
245
|
+
cd cc-bridge-mcp-server
|
|
246
|
+
npm install
|
|
247
|
+
npm run build
|
|
248
|
+
npm test
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Project Structure
|
|
252
|
+
|
|
253
|
+
```
|
|
254
|
+
src/
|
|
255
|
+
├── index.ts # Server entry point, registers tools, starts stdio transport
|
|
256
|
+
├── config.ts # Environment variable loading and validation (zod)
|
|
257
|
+
├── constants.ts # Server name and version from package.json
|
|
258
|
+
├── errors.ts # BridgeError class and error code enum
|
|
259
|
+
├── logger.ts # Timestamped file + stderr logger
|
|
260
|
+
├── startup.ts # First-run prompt, config loading, CLI validation
|
|
261
|
+
├── types.ts # Core interfaces (PeerInfo, MessageRecord, etc.)
|
|
262
|
+
├── services/
|
|
263
|
+
│ ├── cc-cli.ts # CLI subprocess wrapper (execFile with claude --resume)
|
|
264
|
+
│ ├── health-check.ts # State file, lock, and CLI diagnostic checks
|
|
265
|
+
│ └── peer-registry.ts # File-based shared state with locking
|
|
266
|
+
└── tools/
|
|
267
|
+
├── register-peer.ts # cc_register_peer
|
|
268
|
+
├── deregister-peer.ts # cc_deregister_peer
|
|
269
|
+
├── send-message.ts # cc_send_message
|
|
270
|
+
├── list-peers.ts # cc_list_peers
|
|
271
|
+
├── get-history.ts # cc_get_history
|
|
272
|
+
└── health-check.ts # cc_health_check
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### npm Scripts
|
|
276
|
+
|
|
277
|
+
| Script | Command | Description |
|
|
278
|
+
|--------|---------|-------------|
|
|
279
|
+
| `npm run build` | `tsc` | Compile TypeScript to `dist/` |
|
|
280
|
+
| `npm run dev` | `tsx watch src/index.ts` | Development mode with auto-reload |
|
|
281
|
+
| `npm start` | `node dist/index.js` | Run compiled server |
|
|
282
|
+
| `npm run clean` | `rm -rf dist` | Remove build artifacts |
|
|
283
|
+
| `npm test` | `vitest run` | Run test suite |
|
|
284
|
+
| `npm run test:watch` | `vitest` | Run tests in watch mode |
|
|
285
|
+
| `npm run test:coverage` | `vitest run --coverage` | Run tests with coverage report |
|
|
286
|
+
|
|
287
|
+
## License
|
|
288
|
+
|
|
289
|
+
ISC
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,wBAAsB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAU5C"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
export async function runCli() {
|
|
3
|
+
const command = process.argv[2];
|
|
4
|
+
if (command === "init") {
|
|
5
|
+
const { runWizard } = await import("./wizard/index.js");
|
|
6
|
+
await runWizard();
|
|
7
|
+
}
|
|
8
|
+
else {
|
|
9
|
+
// Default: start MCP server (existing behavior)
|
|
10
|
+
await import("./index.js");
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
runCli().catch((err) => {
|
|
14
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
15
|
+
process.stderr.write(`Fatal error: ${msg}\n`);
|
|
16
|
+
process.exit(1);
|
|
17
|
+
});
|
|
18
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,MAAM,CAAC,KAAK,UAAU,MAAM;IAC1B,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAEhC,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QACvB,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAC;QACxD,MAAM,SAAS,EAAE,CAAC;IACpB,CAAC;SAAM,CAAC;QACN,gDAAgD;QAChD,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;IAC7B,CAAC;AACH,CAAC;AAED,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IAC9B,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC7D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IAC9C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const configSchema: z.ZodObject<{
|
|
3
|
+
CC_BRIDGE_STATE_PATH: z.ZodDefault<z.ZodString>;
|
|
4
|
+
CC_BRIDGE_TIMEOUT_MS: z.ZodDefault<z.ZodNumber>;
|
|
5
|
+
CC_BRIDGE_CHAR_LIMIT: z.ZodDefault<z.ZodNumber>;
|
|
6
|
+
CC_BRIDGE_LOG_LEVEL: z.ZodDefault<z.ZodEnum<["debug", "info", "warn", "error"]>>;
|
|
7
|
+
CC_BRIDGE_CLAUDE_PATH: z.ZodDefault<z.ZodString>;
|
|
8
|
+
CC_BRIDGE_STALE_TIMEOUT_MS: z.ZodDefault<z.ZodNumber>;
|
|
9
|
+
}, "strip", z.ZodTypeAny, {
|
|
10
|
+
CC_BRIDGE_STATE_PATH: string;
|
|
11
|
+
CC_BRIDGE_TIMEOUT_MS: number;
|
|
12
|
+
CC_BRIDGE_CHAR_LIMIT: number;
|
|
13
|
+
CC_BRIDGE_LOG_LEVEL: "info" | "debug" | "warn" | "error";
|
|
14
|
+
CC_BRIDGE_CLAUDE_PATH: string;
|
|
15
|
+
CC_BRIDGE_STALE_TIMEOUT_MS: number;
|
|
16
|
+
}, {
|
|
17
|
+
CC_BRIDGE_STATE_PATH?: string | undefined;
|
|
18
|
+
CC_BRIDGE_TIMEOUT_MS?: number | undefined;
|
|
19
|
+
CC_BRIDGE_CHAR_LIMIT?: number | undefined;
|
|
20
|
+
CC_BRIDGE_LOG_LEVEL?: "info" | "debug" | "warn" | "error" | undefined;
|
|
21
|
+
CC_BRIDGE_CLAUDE_PATH?: string | undefined;
|
|
22
|
+
CC_BRIDGE_STALE_TIMEOUT_MS?: number | undefined;
|
|
23
|
+
}>;
|
|
24
|
+
export type Config = z.infer<typeof configSchema>;
|
|
25
|
+
export declare function loadConfig(env?: Record<string, string | undefined>): Config;
|
|
26
|
+
export declare function getConfig(): Config;
|
|
27
|
+
export declare function resetConfig(): void;
|
|
28
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;EASvB,CAAC;AAEH,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAIlD,wBAAgB,UAAU,CACxB,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GACpD,MAAM,CAUR;AAED,wBAAgB,SAAS,IAAI,MAAM,CAGlC;AAED,wBAAgB,WAAW,IAAI,IAAI,CAElC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
const defaultStatePath = path.join(os.homedir(), "cloud_code_bridge");
|
|
5
|
+
export const configSchema = z.object({
|
|
6
|
+
CC_BRIDGE_STATE_PATH: z.string().default(defaultStatePath),
|
|
7
|
+
CC_BRIDGE_TIMEOUT_MS: z.coerce.number().int().min(1000).default(120_000),
|
|
8
|
+
CC_BRIDGE_CHAR_LIMIT: z.coerce.number().int().min(0).default(0),
|
|
9
|
+
CC_BRIDGE_LOG_LEVEL: z
|
|
10
|
+
.enum(["debug", "info", "warn", "error"])
|
|
11
|
+
.default("info"),
|
|
12
|
+
CC_BRIDGE_CLAUDE_PATH: z.string().default("claude"),
|
|
13
|
+
CC_BRIDGE_STALE_TIMEOUT_MS: z.coerce.number().int().min(0).default(1_800_000),
|
|
14
|
+
});
|
|
15
|
+
let _config = null;
|
|
16
|
+
export function loadConfig(env = process.env) {
|
|
17
|
+
const result = configSchema.safeParse(env);
|
|
18
|
+
if (!result.success) {
|
|
19
|
+
const issues = result.error.issues
|
|
20
|
+
.map((i) => ` ${i.path.join(".")}: ${i.message}`)
|
|
21
|
+
.join("\n");
|
|
22
|
+
throw new Error(`Invalid configuration:\n${issues}`);
|
|
23
|
+
}
|
|
24
|
+
_config = Object.freeze(result.data);
|
|
25
|
+
return _config;
|
|
26
|
+
}
|
|
27
|
+
export function getConfig() {
|
|
28
|
+
if (!_config)
|
|
29
|
+
throw new Error("Config not loaded. Call loadConfig() first.");
|
|
30
|
+
return _config;
|
|
31
|
+
}
|
|
32
|
+
export function resetConfig() {
|
|
33
|
+
_config = null;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,mBAAmB,CAAC,CAAC;AAEtE,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,oBAAoB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,gBAAgB,CAAC;IAC1D,oBAAoB,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;IACxE,oBAAoB,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAC/D,mBAAmB,EAAE,CAAC;SACnB,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;SACxC,OAAO,CAAC,MAAM,CAAC;IAClB,qBAAqB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC;IACnD,0BAA0B,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;CAC9E,CAAC,CAAC;AAIH,IAAI,OAAO,GAAkB,IAAI,CAAC;AAElC,MAAM,UAAU,UAAU,CACxB,MAA0C,OAAO,CAAC,GAAG;IAErD,MAAM,MAAM,GAAG,YAAY,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAC3C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM;aAC/B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC;aACjD,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,2BAA2B,MAAM,EAAE,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACrC,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IAC7E,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,OAAO,GAAG,IAAI,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,WAAW,oEAAoE,CAAC;AAC7F,eAAO,MAAM,cAAc,QAAc,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
const require = createRequire(import.meta.url);
|
|
3
|
+
const pkg = require("../package.json");
|
|
4
|
+
export const SERVER_NAME = "Claude Code Bridge from Essential AI Solutions (essentialai.uk)";
|
|
5
|
+
export const SERVER_VERSION = pkg.version;
|
|
6
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,GAAG,GAAG,OAAO,CAAC,iBAAiB,CAAwB,CAAC;AAE9D,MAAM,CAAC,MAAM,WAAW,GAAG,iEAAiE,CAAC;AAC7F,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,CAAC,OAAO,CAAC"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export declare enum BridgeErrorCode {
|
|
2
|
+
CLI_NOT_FOUND = "CLI_NOT_FOUND",
|
|
3
|
+
CLI_TIMEOUT = "CLI_TIMEOUT",
|
|
4
|
+
CLI_EXEC_FAILED = "CLI_EXEC_FAILED",
|
|
5
|
+
STATE_CORRUPT = "STATE_CORRUPT",
|
|
6
|
+
STATE_WRITE_FAILED = "STATE_WRITE_FAILED",
|
|
7
|
+
LOCK_TIMEOUT = "LOCK_TIMEOUT",
|
|
8
|
+
LOCK_STALE = "LOCK_STALE",
|
|
9
|
+
PEER_NOT_FOUND = "PEER_NOT_FOUND",
|
|
10
|
+
INVALID_INPUT = "INVALID_INPUT",
|
|
11
|
+
STARTUP_FAILED = "STARTUP_FAILED",
|
|
12
|
+
DIR_NOT_WRITABLE = "DIR_NOT_WRITABLE"
|
|
13
|
+
}
|
|
14
|
+
export declare class BridgeError extends Error {
|
|
15
|
+
readonly code: BridgeErrorCode;
|
|
16
|
+
readonly suggestion?: string;
|
|
17
|
+
constructor(code: BridgeErrorCode, message: string, suggestion?: string);
|
|
18
|
+
}
|
|
19
|
+
export declare function toolResult(text: string, isError?: boolean): {
|
|
20
|
+
isError?: true | undefined;
|
|
21
|
+
content: {
|
|
22
|
+
type: "text";
|
|
23
|
+
text: string;
|
|
24
|
+
}[];
|
|
25
|
+
};
|
|
26
|
+
export declare function errorResult(error: unknown): {
|
|
27
|
+
isError?: true | undefined;
|
|
28
|
+
content: {
|
|
29
|
+
type: "text";
|
|
30
|
+
text: string;
|
|
31
|
+
}[];
|
|
32
|
+
};
|
|
33
|
+
export declare function successResult(data: Record<string, unknown>): {
|
|
34
|
+
isError?: true | undefined;
|
|
35
|
+
content: {
|
|
36
|
+
type: "text";
|
|
37
|
+
text: string;
|
|
38
|
+
}[];
|
|
39
|
+
};
|
|
40
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,oBAAY,eAAe;IACzB,aAAa,kBAAkB;IAC/B,WAAW,gBAAgB;IAC3B,eAAe,oBAAoB;IACnC,aAAa,kBAAkB;IAC/B,kBAAkB,uBAAuB;IACzC,YAAY,iBAAiB;IAC7B,UAAU,eAAe;IACzB,cAAc,mBAAmB;IACjC,aAAa,kBAAkB;IAC/B,cAAc,mBAAmB;IACjC,gBAAgB,qBAAqB;CACtC;AAED,qBAAa,WAAY,SAAQ,KAAK;IACpC,SAAgB,IAAI,EAAE,eAAe,CAAC;IACtC,SAAgB,UAAU,CAAC,EAAE,MAAM,CAAC;gBAExB,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM;CASxE;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO;;;;;;EAKzD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO;;;;;;EA8BzC;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;EAE1D"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export var BridgeErrorCode;
|
|
2
|
+
(function (BridgeErrorCode) {
|
|
3
|
+
BridgeErrorCode["CLI_NOT_FOUND"] = "CLI_NOT_FOUND";
|
|
4
|
+
BridgeErrorCode["CLI_TIMEOUT"] = "CLI_TIMEOUT";
|
|
5
|
+
BridgeErrorCode["CLI_EXEC_FAILED"] = "CLI_EXEC_FAILED";
|
|
6
|
+
BridgeErrorCode["STATE_CORRUPT"] = "STATE_CORRUPT";
|
|
7
|
+
BridgeErrorCode["STATE_WRITE_FAILED"] = "STATE_WRITE_FAILED";
|
|
8
|
+
BridgeErrorCode["LOCK_TIMEOUT"] = "LOCK_TIMEOUT";
|
|
9
|
+
BridgeErrorCode["LOCK_STALE"] = "LOCK_STALE";
|
|
10
|
+
BridgeErrorCode["PEER_NOT_FOUND"] = "PEER_NOT_FOUND";
|
|
11
|
+
BridgeErrorCode["INVALID_INPUT"] = "INVALID_INPUT";
|
|
12
|
+
BridgeErrorCode["STARTUP_FAILED"] = "STARTUP_FAILED";
|
|
13
|
+
BridgeErrorCode["DIR_NOT_WRITABLE"] = "DIR_NOT_WRITABLE";
|
|
14
|
+
})(BridgeErrorCode || (BridgeErrorCode = {}));
|
|
15
|
+
export class BridgeError extends Error {
|
|
16
|
+
code;
|
|
17
|
+
suggestion;
|
|
18
|
+
constructor(code, message, suggestion) {
|
|
19
|
+
const fullMessage = suggestion
|
|
20
|
+
? `${code}: ${message}. ${suggestion}`
|
|
21
|
+
: `${code}: ${message}`;
|
|
22
|
+
super(fullMessage);
|
|
23
|
+
this.name = "BridgeError";
|
|
24
|
+
this.code = code;
|
|
25
|
+
this.suggestion = suggestion;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export function toolResult(text, isError) {
|
|
29
|
+
return {
|
|
30
|
+
content: [{ type: "text", text }],
|
|
31
|
+
...(isError ? { isError: true } : {}),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export function errorResult(error) {
|
|
35
|
+
if (error instanceof BridgeError) {
|
|
36
|
+
return toolResult(JSON.stringify({
|
|
37
|
+
success: false,
|
|
38
|
+
error: error.code,
|
|
39
|
+
message: error.message,
|
|
40
|
+
suggestion: error.suggestion,
|
|
41
|
+
}, null, 2), true);
|
|
42
|
+
}
|
|
43
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
44
|
+
return toolResult(JSON.stringify({
|
|
45
|
+
success: false,
|
|
46
|
+
error: "INTERNAL_ERROR",
|
|
47
|
+
message,
|
|
48
|
+
}, null, 2), true);
|
|
49
|
+
}
|
|
50
|
+
export function successResult(data) {
|
|
51
|
+
return toolResult(JSON.stringify(data, null, 2), false);
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,eAYX;AAZD,WAAY,eAAe;IACzB,kDAA+B,CAAA;IAC/B,8CAA2B,CAAA;IAC3B,sDAAmC,CAAA;IACnC,kDAA+B,CAAA;IAC/B,4DAAyC,CAAA;IACzC,gDAA6B,CAAA;IAC7B,4CAAyB,CAAA;IACzB,oDAAiC,CAAA;IACjC,kDAA+B,CAAA;IAC/B,oDAAiC,CAAA;IACjC,wDAAqC,CAAA;AACvC,CAAC,EAZW,eAAe,KAAf,eAAe,QAY1B;AAED,MAAM,OAAO,WAAY,SAAQ,KAAK;IACpB,IAAI,CAAkB;IACtB,UAAU,CAAU;IAEpC,YAAY,IAAqB,EAAE,OAAe,EAAE,UAAmB;QACrE,MAAM,WAAW,GAAG,UAAU;YAC5B,CAAC,CAAC,GAAG,IAAI,KAAK,OAAO,KAAK,UAAU,EAAE;YACtC,CAAC,CAAC,GAAG,IAAI,KAAK,OAAO,EAAE,CAAC;QAC1B,KAAK,CAAC,WAAW,CAAC,CAAC;QACnB,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;QAC1B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;CACF;AAED,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,OAAiB;IACxD,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC;QAC1C,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC/C,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,IAAI,KAAK,YAAY,WAAW,EAAE,CAAC;QACjC,OAAO,UAAU,CACf,IAAI,CAAC,SAAS,CACZ;YACE,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,KAAK,CAAC,IAAI;YACjB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,UAAU,EAAE,KAAK,CAAC,UAAU;SAC7B,EACD,IAAI,EACJ,CAAC,CACF,EACD,IAAI,CACL,CAAC;IACJ,CAAC;IACD,MAAM,OAAO,GACX,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACzD,OAAO,UAAU,CACf,IAAI,CAAC,SAAS,CACZ;QACE,OAAO,EAAE,KAAK;QACd,KAAK,EAAE,gBAAgB;QACvB,OAAO;KACR,EACD,IAAI,EACJ,CAAC,CACF,EACD,IAAI,CACL,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAA6B;IACzD,OAAO,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AAC1D,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { SERVER_NAME, SERVER_VERSION } from "./constants.js";
|
|
4
|
+
import { runStartup } from "./startup.js";
|
|
5
|
+
import { logger } from "./logger.js";
|
|
6
|
+
import { registerRegisterPeerTool } from "./tools/register-peer.js";
|
|
7
|
+
import { registerSendMessageTool } from "./tools/send-message.js";
|
|
8
|
+
import { registerListPeersTool } from "./tools/list-peers.js";
|
|
9
|
+
import { registerGetHistoryTool } from "./tools/get-history.js";
|
|
10
|
+
import { registerDeregisterPeerTool } from "./tools/deregister-peer.js";
|
|
11
|
+
import { registerHealthCheckTool } from "./tools/health-check.js";
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// Global error handlers -- registered FIRST before anything else
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
process.on("uncaughtException", (err) => {
|
|
16
|
+
logger.error(`Uncaught exception: ${err.message}`, { stack: err.stack });
|
|
17
|
+
// Do NOT exit -- MCP server should try to continue
|
|
18
|
+
});
|
|
19
|
+
process.on("unhandledRejection", (reason) => {
|
|
20
|
+
const msg = reason instanceof Error ? reason.message : String(reason);
|
|
21
|
+
logger.error(`Unhandled rejection: ${msg}`);
|
|
22
|
+
});
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// Graceful shutdown handlers
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
process.on("SIGTERM", () => {
|
|
27
|
+
logger.info("SIGTERM received, shutting down");
|
|
28
|
+
logger.close();
|
|
29
|
+
process.exit(0);
|
|
30
|
+
});
|
|
31
|
+
process.on("SIGINT", () => {
|
|
32
|
+
logger.info("SIGINT received, shutting down");
|
|
33
|
+
logger.close();
|
|
34
|
+
process.exit(0);
|
|
35
|
+
});
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
// Main entry point
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
async function main() {
|
|
40
|
+
// Startup MUST complete before MCP transport starts
|
|
41
|
+
// (handles first-run prompt, config loading, logger init, validation)
|
|
42
|
+
await runStartup();
|
|
43
|
+
const server = new McpServer({ name: SERVER_NAME, version: SERVER_VERSION });
|
|
44
|
+
// Register all 6 tools
|
|
45
|
+
registerRegisterPeerTool(server);
|
|
46
|
+
registerDeregisterPeerTool(server);
|
|
47
|
+
registerSendMessageTool(server);
|
|
48
|
+
registerListPeersTool(server);
|
|
49
|
+
registerGetHistoryTool(server);
|
|
50
|
+
registerHealthCheckTool(server);
|
|
51
|
+
// Connect stdio transport
|
|
52
|
+
const transport = new StdioServerTransport();
|
|
53
|
+
await server.connect(transport);
|
|
54
|
+
// Startup banner: always prints regardless of log level
|
|
55
|
+
process.stderr.write(`${SERVER_NAME} v${SERVER_VERSION} running on stdio\n`);
|
|
56
|
+
logger.info("Server ready. Tools: cc_register_peer, cc_deregister_peer, cc_send_message, cc_list_peers, cc_get_history, cc_health_check");
|
|
57
|
+
}
|
|
58
|
+
main().catch((err) => {
|
|
59
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
60
|
+
logger.error(`Fatal startup error: ${msg}`);
|
|
61
|
+
// Fallback to stderr in case logger failed
|
|
62
|
+
process.stderr.write(`Fatal error: ${msg}\n`);
|
|
63
|
+
logger.close();
|
|
64
|
+
process.exit(1);
|
|
65
|
+
});
|
|
66
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type LogLevel = "debug" | "info" | "warn" | "error";
|
|
2
|
+
export declare class Logger {
|
|
3
|
+
private readonly threshold;
|
|
4
|
+
private textStream;
|
|
5
|
+
private jsonStream;
|
|
6
|
+
constructor(level: LogLevel, logDir?: string);
|
|
7
|
+
private log;
|
|
8
|
+
debug(message: string, data?: unknown): void;
|
|
9
|
+
info(message: string, data?: unknown): void;
|
|
10
|
+
warn(message: string, data?: unknown): void;
|
|
11
|
+
error(message: string, data?: unknown): void;
|
|
12
|
+
close(): void;
|
|
13
|
+
}
|
|
14
|
+
export declare function createLogger(level: LogLevel, logDir?: string): Logger;
|
|
15
|
+
/** Pre-config logger: stderr-only at info level. Replaced after startup. */
|
|
16
|
+
export declare let logger: Logger;
|
|
17
|
+
/**
|
|
18
|
+
* Initialize the fully-configured logger with file outputs.
|
|
19
|
+
* Replaces the module-level `logger` export.
|
|
20
|
+
*/
|
|
21
|
+
export declare function initLogger(level: LogLevel, logDir?: string): void;
|
|
22
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAS3D,qBAAa,MAAM;IACjB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,UAAU,CAA+B;IACjD,OAAO,CAAC,UAAU,CAA+B;gBAErC,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,MAAM;IAsB5C,OAAO,CAAC,GAAG;IAgBX,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI;IAI5C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI;IAI3C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI;IAI3C,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI;IAI5C,KAAK,IAAI,IAAI;CAId;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAErE;AAED,4EAA4E;AAC5E,eAAO,IAAI,MAAM,EAAE,MAA2B,CAAC;AAE/C;;;GAGG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAGjE"}
|