borgmcp 0.2.0-beta.1
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 +250 -0
- package/dist/auth.d.ts +24 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +223 -0
- package/dist/auth.js.map +1 -0
- package/dist/config-utils.d.ts +17 -0
- package/dist/config-utils.d.ts.map +1 -0
- package/dist/config-utils.js +54 -0
- package/dist/config-utils.js.map +1 -0
- package/dist/config.d.ts +33 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +65 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +157 -0
- package/dist/index.js.map +1 -0
- package/dist/postinstall.d.ts +9 -0
- package/dist/postinstall.d.ts.map +1 -0
- package/dist/postinstall.js +19 -0
- package/dist/postinstall.js.map +1 -0
- package/dist/remote-client.d.ts +27 -0
- package/dist/remote-client.d.ts.map +1 -0
- package/dist/remote-client.js +165 -0
- package/dist/remote-client.js.map +1 -0
- package/dist/setup.d.ts +11 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +196 -0
- package/dist/setup.js.map +1 -0
- package/dist/sync.d.ts +57 -0
- package/dist/sync.d.ts.map +1 -0
- package/dist/sync.js +196 -0
- package/dist/sync.js.map +1 -0
- package/dist/types.d.ts +37 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +62 -0
package/README.md
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
# Borg MCP Client
|
|
2
|
+
|
|
3
|
+
Local MCP client that syncs your `~/.claude/CLAUDE.md` file to the Borg MCP cloud service.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Automatic Sync**: Watches `~/.claude/CLAUDE.md` and auto-syncs changes to cloud
|
|
8
|
+
- **Conflict Detection**: Never lose data - conflicts are detected and backed up for manual resolution
|
|
9
|
+
- **Secure Storage**: OAuth tokens stored in OS keychain (macOS Keychain, Windows Credential Manager, Linux Secret Service)
|
|
10
|
+
- **Offline Support**: Exponential backoff retry logic handles network failures gracefully
|
|
11
|
+
- **Google OAuth**: Secure authentication via Google OAuth 2.0 device code flow
|
|
12
|
+
|
|
13
|
+
## Prerequisites
|
|
14
|
+
|
|
15
|
+
1. **Node.js 18+** with npm
|
|
16
|
+
2. **Google OAuth Credentials** (required for authentication)
|
|
17
|
+
- Client ID
|
|
18
|
+
- Client Secret
|
|
19
|
+
3. **Borg MCP Subscription** ($2/month with 7-day trial)
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
### 1. Install Dependencies
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
cd client
|
|
27
|
+
npm install
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### 2. Build the Client
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm run build
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### 3. Set Up Environment Variables
|
|
37
|
+
|
|
38
|
+
Create a `.env` file or export these variables:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
export GOOGLE_CLIENT_ID="your-client-id.apps.googleusercontent.com"
|
|
42
|
+
export GOOGLE_CLIENT_SECRET="your-client-secret"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 4. Configure Claude Code MCP Settings
|
|
46
|
+
|
|
47
|
+
Add the client to your Claude Code MCP configuration file at `~/.config/claude/mcp_config.json`:
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"mcpServers": {
|
|
52
|
+
"borg-mcp": {
|
|
53
|
+
"command": "node",
|
|
54
|
+
"args": [
|
|
55
|
+
"/absolute/path/to/mcp-claude-md-storage/client/dist/index.js"
|
|
56
|
+
],
|
|
57
|
+
"env": {
|
|
58
|
+
"GOOGLE_CLIENT_ID": "your-client-id.apps.googleusercontent.com",
|
|
59
|
+
"GOOGLE_CLIENT_SECRET": "your-client-secret"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Important**: Replace `/absolute/path/to/` with the actual path to your project directory.
|
|
67
|
+
|
|
68
|
+
## First-Time Setup
|
|
69
|
+
|
|
70
|
+
### Authentication Flow
|
|
71
|
+
|
|
72
|
+
On first run, the client will prompt you to authenticate:
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
🔐 Borg MCP Authentication
|
|
76
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
77
|
+
|
|
78
|
+
📱 Please visit: https://www.google.com/device
|
|
79
|
+
🔑 And enter code: XXXX-XXXX
|
|
80
|
+
|
|
81
|
+
Waiting for authorization...
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
1. Visit the URL shown
|
|
85
|
+
2. Enter the device code
|
|
86
|
+
3. Authorize with your Google account
|
|
87
|
+
4. Tokens are securely stored in your OS keychain
|
|
88
|
+
|
|
89
|
+
### Subscription
|
|
90
|
+
|
|
91
|
+
After authentication, create a subscription:
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
Tools available:
|
|
95
|
+
- subscribe: Create Stripe checkout session ($2/month, 7-day trial)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Use the `subscribe` tool in Claude Code to get a checkout URL and complete payment.
|
|
99
|
+
|
|
100
|
+
## How It Works
|
|
101
|
+
|
|
102
|
+
### Initial Sync
|
|
103
|
+
|
|
104
|
+
On startup, the client performs an initial sync:
|
|
105
|
+
|
|
106
|
+
- If remote has content and local is empty → **pulls from cloud**
|
|
107
|
+
- If local has content and remote is empty → **pushes to cloud**
|
|
108
|
+
- If both exist and match → **no sync needed**
|
|
109
|
+
- If both exist and differ → **conflict detection**
|
|
110
|
+
|
|
111
|
+
### Automatic File Watching
|
|
112
|
+
|
|
113
|
+
The client watches `~/.claude/CLAUDE.md` for changes:
|
|
114
|
+
|
|
115
|
+
- **Debouncing**: 1 second delay to batch rapid edits
|
|
116
|
+
- **Content Hashing**: Only syncs when content actually changes (ignores temp saves)
|
|
117
|
+
- **Real-time Upload**: Changes auto-sync to cloud within seconds
|
|
118
|
+
|
|
119
|
+
### Conflict Resolution
|
|
120
|
+
|
|
121
|
+
If both local and remote files have been modified since last sync:
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
⚠️ SYNC CONFLICT DETECTED
|
|
125
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
126
|
+
|
|
127
|
+
Both local and remote CLAUDE.md have been modified.
|
|
128
|
+
Local file: ~/.claude/CLAUDE.md
|
|
129
|
+
Remote backup: ~/.claude/CLAUDE.md.conflict
|
|
130
|
+
|
|
131
|
+
Please resolve manually by choosing one version or merging them.
|
|
132
|
+
Delete the .conflict file once resolved.
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**Resolution Steps**:
|
|
136
|
+
1. Compare `~/.claude/CLAUDE.md` (local) with `~/.claude/CLAUDE.md.conflict` (remote)
|
|
137
|
+
2. Manually merge or choose one version
|
|
138
|
+
3. Delete `.conflict` file when done
|
|
139
|
+
|
|
140
|
+
## Available Tools
|
|
141
|
+
|
|
142
|
+
Once configured, these tools are available in Claude Code:
|
|
143
|
+
|
|
144
|
+
- **subscribe**: Create Stripe checkout session for $2/month (7-day free trial)
|
|
145
|
+
- **get_claude_md**: Manually fetch CLAUDE.md from cloud
|
|
146
|
+
- **set_claude_md**: Manually upload CLAUDE.md to cloud
|
|
147
|
+
- **delete_claude_md**: Delete CLAUDE.md from cloud
|
|
148
|
+
- **subscription_status**: Check your current subscription status
|
|
149
|
+
- **export_data**: Export all your data (GDPR compliance)
|
|
150
|
+
- **sync_now**: Force immediate sync with cloud
|
|
151
|
+
|
|
152
|
+
## Troubleshooting
|
|
153
|
+
|
|
154
|
+
### "Authentication required" Error
|
|
155
|
+
|
|
156
|
+
Your OAuth token has expired. Re-run the client and follow the authentication flow again.
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
# Manually trigger re-auth by clearing tokens
|
|
160
|
+
node dist/index.js
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Sync Conflicts Not Resolving
|
|
164
|
+
|
|
165
|
+
1. Check that `.conflict` file exists at `~/.claude/CLAUDE.md.conflict`
|
|
166
|
+
2. Manually merge changes between local and conflict file
|
|
167
|
+
3. Delete `.conflict` file to clear the conflict state
|
|
168
|
+
|
|
169
|
+
### File Watcher Not Detecting Changes
|
|
170
|
+
|
|
171
|
+
- Verify `~/.claude/CLAUDE.md` path exists
|
|
172
|
+
- Check file permissions (must be readable/writable)
|
|
173
|
+
- Some editors use atomic writes (rename temp file) which may delay detection
|
|
174
|
+
|
|
175
|
+
### Network Failures
|
|
176
|
+
|
|
177
|
+
The client automatically retries with exponential backoff:
|
|
178
|
+
- Retry 1: 1 second delay
|
|
179
|
+
- Retry 2: 2 second delay
|
|
180
|
+
- Retry 3: 4 second delay
|
|
181
|
+
- Max retries: 3
|
|
182
|
+
|
|
183
|
+
If network is down, edits are queued and will sync once connection is restored.
|
|
184
|
+
|
|
185
|
+
## Security
|
|
186
|
+
|
|
187
|
+
### Token Storage
|
|
188
|
+
|
|
189
|
+
OAuth tokens are stored using platform-specific secure credential managers:
|
|
190
|
+
|
|
191
|
+
- **macOS**: Keychain Access
|
|
192
|
+
- **Windows**: Credential Manager
|
|
193
|
+
- **Linux**: Secret Service API (libsecret)
|
|
194
|
+
|
|
195
|
+
Tokens are **never** written to disk in plain text.
|
|
196
|
+
|
|
197
|
+
### Authentication
|
|
198
|
+
|
|
199
|
+
- Uses Google OAuth 2.0 device code flow (designed for CLI apps)
|
|
200
|
+
- ID tokens are automatically refreshed when expired
|
|
201
|
+
- Auth tokens are automatically injected into all remote API calls
|
|
202
|
+
|
|
203
|
+
## Development
|
|
204
|
+
|
|
205
|
+
### Running from Source
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
npm run dev
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Building
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
npm run build
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Testing
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
npm test
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## Architecture
|
|
224
|
+
|
|
225
|
+
```
|
|
226
|
+
┌─────────────────┐
|
|
227
|
+
│ Claude Code │
|
|
228
|
+
└────────┬────────┘
|
|
229
|
+
│ stdio MCP
|
|
230
|
+
│
|
|
231
|
+
┌────────▼────────┐
|
|
232
|
+
│ Borg MCP │◄──┐
|
|
233
|
+
│ Client │ │ File Watcher
|
|
234
|
+
└────────┬────────┘ │ (chokidar)
|
|
235
|
+
│ │
|
|
236
|
+
│ ┌──▼──────────────┐
|
|
237
|
+
│ │ ~/.claude/ │
|
|
238
|
+
│ │ CLAUDE.md │
|
|
239
|
+
│ └─────────────────┘
|
|
240
|
+
│ HTTPS + Auth
|
|
241
|
+
│
|
|
242
|
+
┌────────▼────────┐
|
|
243
|
+
│ api.borgmcp.ai │
|
|
244
|
+
│ (Remote Server) │
|
|
245
|
+
└─────────────────┘
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## License
|
|
249
|
+
|
|
250
|
+
MIT
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google OAuth 2.0 Authorization Code Flow with PKCE
|
|
3
|
+
* For Desktop/CLI applications
|
|
4
|
+
*
|
|
5
|
+
* Flow:
|
|
6
|
+
* 1. Generate PKCE code_verifier and code_challenge
|
|
7
|
+
* 2. Start local HTTP server for callback
|
|
8
|
+
* 3. Open browser to Google authorization URL
|
|
9
|
+
* 4. User authorizes in browser
|
|
10
|
+
* 5. Receive authorization code via localhost callback
|
|
11
|
+
* 6. Exchange code for tokens
|
|
12
|
+
* 7. Store tokens securely in OS keychain
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Perform complete OAuth authorization code flow with PKCE
|
|
16
|
+
* Opens browser for user authorization
|
|
17
|
+
* Stores tokens in OS keychain on success
|
|
18
|
+
*/
|
|
19
|
+
export declare function authenticateWithGoogle(): Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* Refresh ID token using refresh token
|
|
22
|
+
*/
|
|
23
|
+
export declare function refreshIdToken(refreshToken: string): Promise<void>;
|
|
24
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAsLH;;;;GAIG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC,CA+C5D;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CAsBf"}
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google OAuth 2.0 Authorization Code Flow with PKCE
|
|
3
|
+
* For Desktop/CLI applications
|
|
4
|
+
*
|
|
5
|
+
* Flow:
|
|
6
|
+
* 1. Generate PKCE code_verifier and code_challenge
|
|
7
|
+
* 2. Start local HTTP server for callback
|
|
8
|
+
* 3. Open browser to Google authorization URL
|
|
9
|
+
* 4. User authorizes in browser
|
|
10
|
+
* 5. Receive authorization code via localhost callback
|
|
11
|
+
* 6. Exchange code for tokens
|
|
12
|
+
* 7. Store tokens securely in OS keychain
|
|
13
|
+
*/
|
|
14
|
+
import { createServer } from 'http';
|
|
15
|
+
import { URL } from 'url';
|
|
16
|
+
import crypto from 'crypto';
|
|
17
|
+
import open from 'open';
|
|
18
|
+
import { storeIdToken, storeRefreshToken } from './config.js';
|
|
19
|
+
// Google OAuth Client credentials for Borg MCP CLI (Desktop app)
|
|
20
|
+
// Per Google's documentation: "the client secret is obviously not treated as a secret"
|
|
21
|
+
// for installed/desktop applications. This follows industry standard (AWS CLI, gcloud, GitHub CLI)
|
|
22
|
+
const GOOGLE_CLIENT_ID = '675073910799-41pbe12rfhqemidh64h09s4q3e0udpgp.apps.googleusercontent.com';
|
|
23
|
+
const GOOGLE_CLIENT_SECRET = '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';
|
|
24
|
+
const GOOGLE_AUTHORIZE_URL = 'https://accounts.google.com/o/oauth2/v2/auth';
|
|
25
|
+
const GOOGLE_TOKEN_URL = 'https://oauth2.googleapis.com/token';
|
|
26
|
+
const SCOPES = ['openid', 'email', 'profile'];
|
|
27
|
+
// Port range for dynamic port selection (8000-9000)
|
|
28
|
+
const PORT_RANGE_START = 8000;
|
|
29
|
+
const PORT_RANGE_END = 9000;
|
|
30
|
+
/**
|
|
31
|
+
* Generate PKCE code_verifier and code_challenge
|
|
32
|
+
* Uses SHA256 hashing per OAuth 2.0 PKCE spec (RFC 7636)
|
|
33
|
+
*/
|
|
34
|
+
function generatePKCE() {
|
|
35
|
+
// Generate random code_verifier (43-128 characters)
|
|
36
|
+
const verifier = crypto.randomBytes(32).toString('base64url');
|
|
37
|
+
// Generate code_challenge = BASE64URL(SHA256(code_verifier))
|
|
38
|
+
const challenge = crypto
|
|
39
|
+
.createHash('sha256')
|
|
40
|
+
.update(verifier)
|
|
41
|
+
.digest('base64url');
|
|
42
|
+
return { verifier, challenge };
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Find an available port in the specified range
|
|
46
|
+
*/
|
|
47
|
+
async function findAvailablePort() {
|
|
48
|
+
return new Promise((resolve, reject) => {
|
|
49
|
+
// Try to bind to port 0 to let the OS assign a free port
|
|
50
|
+
const testServer = createServer();
|
|
51
|
+
testServer.listen(0, () => {
|
|
52
|
+
const address = testServer.address();
|
|
53
|
+
if (address && typeof address === 'object') {
|
|
54
|
+
const port = address.port;
|
|
55
|
+
testServer.close(() => resolve(port));
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
testServer.close(() => reject(new Error('Failed to get assigned port')));
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
testServer.on('error', reject);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Start local HTTP server to receive OAuth callback
|
|
66
|
+
* Returns { server, port, codePromise }
|
|
67
|
+
*/
|
|
68
|
+
async function startCallbackServer() {
|
|
69
|
+
// Find available port first
|
|
70
|
+
const port = await findAvailablePort();
|
|
71
|
+
const codePromise = new Promise((resolve, reject) => {
|
|
72
|
+
const server = createServer((req, res) => {
|
|
73
|
+
const url = new URL(req.url, `http://localhost:${port}`);
|
|
74
|
+
if (url.pathname === '/callback') {
|
|
75
|
+
const code = url.searchParams.get('code');
|
|
76
|
+
const error = url.searchParams.get('error');
|
|
77
|
+
if (error) {
|
|
78
|
+
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
79
|
+
res.end(`
|
|
80
|
+
<html>
|
|
81
|
+
<body>
|
|
82
|
+
<h1>❌ Authentication Failed</h1>
|
|
83
|
+
<p>Error: ${error}</p>
|
|
84
|
+
<p>You can close this window.</p>
|
|
85
|
+
</body>
|
|
86
|
+
</html>
|
|
87
|
+
`);
|
|
88
|
+
server.close();
|
|
89
|
+
reject(new Error(`OAuth error: ${error}`));
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (code) {
|
|
93
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
94
|
+
res.end(`
|
|
95
|
+
<html>
|
|
96
|
+
<body>
|
|
97
|
+
<h1>✅ Authentication Successful!</h1>
|
|
98
|
+
<p>You can close this window and return to your terminal.</p>
|
|
99
|
+
</body>
|
|
100
|
+
</html>
|
|
101
|
+
`);
|
|
102
|
+
server.close();
|
|
103
|
+
resolve(code);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
107
|
+
res.end(`
|
|
108
|
+
<html>
|
|
109
|
+
<body>
|
|
110
|
+
<h1>❌ Invalid Request</h1>
|
|
111
|
+
<p>Missing authorization code.</p>
|
|
112
|
+
</body>
|
|
113
|
+
</html>
|
|
114
|
+
`);
|
|
115
|
+
server.close();
|
|
116
|
+
reject(new Error('Missing authorization code'));
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
server.listen(port, () => {
|
|
120
|
+
console.error(`Callback server listening on http://localhost:${port}`);
|
|
121
|
+
});
|
|
122
|
+
// Timeout after 5 minutes
|
|
123
|
+
setTimeout(() => {
|
|
124
|
+
server.close();
|
|
125
|
+
reject(new Error('Authentication timeout - no response received'));
|
|
126
|
+
}, 5 * 60 * 1000);
|
|
127
|
+
});
|
|
128
|
+
return { port, codePromise };
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Exchange authorization code for tokens
|
|
132
|
+
*/
|
|
133
|
+
async function exchangeCodeForTokens(code, codeVerifier, port) {
|
|
134
|
+
const redirectUri = `http://localhost:${port}/callback`;
|
|
135
|
+
const response = await fetch(GOOGLE_TOKEN_URL, {
|
|
136
|
+
method: 'POST',
|
|
137
|
+
headers: {
|
|
138
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
139
|
+
},
|
|
140
|
+
body: new URLSearchParams({
|
|
141
|
+
client_id: GOOGLE_CLIENT_ID,
|
|
142
|
+
client_secret: GOOGLE_CLIENT_SECRET,
|
|
143
|
+
code,
|
|
144
|
+
code_verifier: codeVerifier,
|
|
145
|
+
grant_type: 'authorization_code',
|
|
146
|
+
redirect_uri: redirectUri,
|
|
147
|
+
}),
|
|
148
|
+
});
|
|
149
|
+
if (!response.ok) {
|
|
150
|
+
const error = await response.text();
|
|
151
|
+
throw new Error(`Failed to exchange code for tokens: ${error}`);
|
|
152
|
+
}
|
|
153
|
+
return (await response.json());
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Perform complete OAuth authorization code flow with PKCE
|
|
157
|
+
* Opens browser for user authorization
|
|
158
|
+
* Stores tokens in OS keychain on success
|
|
159
|
+
*/
|
|
160
|
+
export async function authenticateWithGoogle() {
|
|
161
|
+
console.error('\\n🔐 Borg MCP Authentication');
|
|
162
|
+
console.error('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n');
|
|
163
|
+
// Step 1: Generate PKCE pair
|
|
164
|
+
console.error('Generating PKCE challenge...');
|
|
165
|
+
const pkce = generatePKCE();
|
|
166
|
+
// Step 2: Start local callback server (gets dynamic port)
|
|
167
|
+
console.error('Starting local callback server...');
|
|
168
|
+
const { port, codePromise } = await startCallbackServer();
|
|
169
|
+
// Step 3: Build authorization URL with dynamic redirect URI
|
|
170
|
+
const redirectUri = `http://localhost:${port}/callback`;
|
|
171
|
+
const authUrl = new URL(GOOGLE_AUTHORIZE_URL);
|
|
172
|
+
authUrl.searchParams.set('client_id', GOOGLE_CLIENT_ID);
|
|
173
|
+
authUrl.searchParams.set('redirect_uri', redirectUri);
|
|
174
|
+
authUrl.searchParams.set('response_type', 'code');
|
|
175
|
+
authUrl.searchParams.set('scope', SCOPES.join(' '));
|
|
176
|
+
authUrl.searchParams.set('code_challenge', pkce.challenge);
|
|
177
|
+
authUrl.searchParams.set('code_challenge_method', 'S256');
|
|
178
|
+
authUrl.searchParams.set('access_type', 'offline'); // Request refresh token
|
|
179
|
+
authUrl.searchParams.set('prompt', 'consent'); // Force consent to get refresh token
|
|
180
|
+
// Step 4: Open browser
|
|
181
|
+
console.error('\\n📱 Opening browser for authorization...');
|
|
182
|
+
console.error('If browser does not open, visit:');
|
|
183
|
+
console.error(`${authUrl.toString()}\\n`);
|
|
184
|
+
await open(authUrl.toString());
|
|
185
|
+
// Step 5: Wait for authorization code
|
|
186
|
+
console.error('Waiting for authorization...');
|
|
187
|
+
const code = await codePromise;
|
|
188
|
+
// Step 6: Exchange code for tokens
|
|
189
|
+
console.error('Exchanging authorization code for tokens...');
|
|
190
|
+
const tokenData = await exchangeCodeForTokens(code, pkce.verifier, port);
|
|
191
|
+
// Step 7: Store tokens securely
|
|
192
|
+
const expiresAt = Date.now() + tokenData.expires_in * 1000;
|
|
193
|
+
await storeIdToken(tokenData.id_token, expiresAt);
|
|
194
|
+
if (tokenData.refresh_token) {
|
|
195
|
+
await storeRefreshToken(tokenData.refresh_token);
|
|
196
|
+
}
|
|
197
|
+
console.error('\\n✅ Authentication successful!\\n');
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Refresh ID token using refresh token
|
|
201
|
+
*/
|
|
202
|
+
export async function refreshIdToken(refreshToken) {
|
|
203
|
+
const response = await fetch(GOOGLE_TOKEN_URL, {
|
|
204
|
+
method: 'POST',
|
|
205
|
+
headers: {
|
|
206
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
207
|
+
},
|
|
208
|
+
body: new URLSearchParams({
|
|
209
|
+
client_id: GOOGLE_CLIENT_ID,
|
|
210
|
+
client_secret: GOOGLE_CLIENT_SECRET,
|
|
211
|
+
refresh_token: refreshToken,
|
|
212
|
+
grant_type: 'refresh_token',
|
|
213
|
+
}),
|
|
214
|
+
});
|
|
215
|
+
if (!response.ok) {
|
|
216
|
+
const error = await response.text();
|
|
217
|
+
throw new Error(`Failed to refresh token: ${error}`);
|
|
218
|
+
}
|
|
219
|
+
const data = (await response.json());
|
|
220
|
+
const expiresAt = Date.now() + data.expires_in * 1000;
|
|
221
|
+
await storeIdToken(data.id_token, expiresAt);
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Settings Configuration Utilities
|
|
3
|
+
*
|
|
4
|
+
* Handles adding borg-mcp to Claude Code via the claude CLI
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Get absolute path to borgmcp index.js
|
|
8
|
+
* Returns the actual index.js file, not the npm symlink
|
|
9
|
+
*/
|
|
10
|
+
export declare function getBinaryPath(): string;
|
|
11
|
+
/**
|
|
12
|
+
* Add borgmcp MCP server to Claude Code using claude CLI
|
|
13
|
+
* First removes any existing borgmcp configuration, then adds fresh one
|
|
14
|
+
* Runs: claude mcp remove --scope user borgmcp && claude mcp add --scope user borgmcp node "<path-to-index.js>"
|
|
15
|
+
*/
|
|
16
|
+
export declare function addMcpServer(): void;
|
|
17
|
+
//# sourceMappingURL=config-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-utils.d.ts","sourceRoot":"","sources":["../src/config-utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAWH;;;GAGG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAItC;AAED;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,IAAI,CA2BnC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Settings Configuration Utilities
|
|
3
|
+
*
|
|
4
|
+
* Handles adding borg-mcp to Claude Code via the claude CLI
|
|
5
|
+
*/
|
|
6
|
+
import { execSync } from 'child_process';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import { fileURLToPath } from 'url';
|
|
9
|
+
import { dirname } from 'path';
|
|
10
|
+
// Get __dirname equivalent in ESM
|
|
11
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
12
|
+
const __dirname = dirname(__filename);
|
|
13
|
+
/**
|
|
14
|
+
* Get absolute path to borgmcp index.js
|
|
15
|
+
* Returns the actual index.js file, not the npm symlink
|
|
16
|
+
*/
|
|
17
|
+
export function getBinaryPath() {
|
|
18
|
+
// In production: dist/index.js is in the same directory as this file
|
|
19
|
+
// In development: same
|
|
20
|
+
return path.join(__dirname, 'index.js');
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Add borgmcp MCP server to Claude Code using claude CLI
|
|
24
|
+
* First removes any existing borgmcp configuration, then adds fresh one
|
|
25
|
+
* Runs: claude mcp remove --scope user borgmcp && claude mcp add --scope user borgmcp node "<path-to-index.js>"
|
|
26
|
+
*/
|
|
27
|
+
export function addMcpServer() {
|
|
28
|
+
const indexPath = getBinaryPath();
|
|
29
|
+
try {
|
|
30
|
+
// First, remove any existing borgmcp configuration (ignore errors if not found)
|
|
31
|
+
try {
|
|
32
|
+
execSync('claude mcp remove --scope user borgmcp', { stdio: 'ignore' });
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// Ignore - server might not exist yet
|
|
36
|
+
}
|
|
37
|
+
// Run claude mcp add command
|
|
38
|
+
const command = `claude mcp add --scope user borgmcp node "${indexPath}"`;
|
|
39
|
+
execSync(command, {
|
|
40
|
+
stdio: 'inherit', // Show output to user
|
|
41
|
+
env: {
|
|
42
|
+
...process.env,
|
|
43
|
+
BORG_API_URL: process.env.BORG_API_URL || 'https://api.borgmcp.ai'
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
if (error.message?.includes('command not found')) {
|
|
49
|
+
throw new Error('Claude CLI not found. Please install Claude Code first.');
|
|
50
|
+
}
|
|
51
|
+
throw new Error(`Failed to add MCP server: ${error.message}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=config-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-utils.js","sourceRoot":"","sources":["../src/config-utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAE/B,kCAAkC;AAClC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC;;;GAGG;AACH,MAAM,UAAU,aAAa;IAC3B,qEAAqE;IACrE,uBAAuB;IACvB,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;AAC1C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY;IAC1B,MAAM,SAAS,GAAG,aAAa,EAAE,CAAC;IAElC,IAAI,CAAC;QACH,gFAAgF;QAChF,IAAI,CAAC;YACH,QAAQ,CAAC,wCAAwC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC1E,CAAC;QAAC,MAAM,CAAC;YACP,sCAAsC;QACxC,CAAC;QAED,6BAA6B;QAC7B,MAAM,OAAO,GAAG,6CAA6C,SAAS,GAAG,CAAC;QAE1E,QAAQ,CAAC,OAAO,EAAE;YAChB,KAAK,EAAE,SAAS,EAAE,sBAAsB;YACxC,GAAG,EAAE;gBACH,GAAG,OAAO,CAAC,GAAG;gBACd,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,wBAAwB;aACnE;SACF,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,IAAI,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;YACjD,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;QAC7E,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,6BAA6B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IAChE,CAAC;AACH,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secure token storage using OS keychain
|
|
3
|
+
* Uses Keytar for cross-platform credential management
|
|
4
|
+
*
|
|
5
|
+
* Addresses consensus finding: Machine-specific encryption is insecure
|
|
6
|
+
* Solution: Use OS native keychains (macOS Keychain, Windows Credential Manager, Linux Secret Service)
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Store Google OAuth ID token securely in OS keychain
|
|
10
|
+
*/
|
|
11
|
+
export declare function storeIdToken(idToken: string, expiresAt: number): Promise<void>;
|
|
12
|
+
/**
|
|
13
|
+
* Store Google OAuth refresh token securely in OS keychain
|
|
14
|
+
*/
|
|
15
|
+
export declare function storeRefreshToken(refreshToken: string): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Retrieve Google OAuth ID token from OS keychain
|
|
18
|
+
* Returns null if not found or expired
|
|
19
|
+
*/
|
|
20
|
+
export declare function getIdToken(): Promise<string | null>;
|
|
21
|
+
/**
|
|
22
|
+
* Retrieve Google OAuth refresh token from OS keychain
|
|
23
|
+
*/
|
|
24
|
+
export declare function getRefreshToken(): Promise<string | null>;
|
|
25
|
+
/**
|
|
26
|
+
* Clear all stored tokens from OS keychain
|
|
27
|
+
*/
|
|
28
|
+
export declare function clearTokens(): Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* Check if user has valid authentication
|
|
31
|
+
*/
|
|
32
|
+
export declare function isAuthenticated(): Promise<boolean>;
|
|
33
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAUH;;GAEG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGpF;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE3E;AAED;;;GAGG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiBzD;AAED;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAE9D;AAED;;GAEG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAIjD;AAED;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC,CAGxD"}
|