@rvry/mcp 0.1.0 → 0.1.2

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 CHANGED
@@ -6,27 +6,36 @@ RVRY is a structural constraint system that forces Large Language Models past th
6
6
 
7
7
  ## Quick Start
8
8
 
9
- The setup wizard handles everything -- token configuration, Claude Code registration, and slash command installation:
10
-
11
9
  ```bash
12
10
  npx @rvry/mcp setup
13
11
  ```
14
12
 
15
13
  The wizard will:
16
- 1. Prompt for your RVRY token (hidden input) -- or open rvry.ai/dashboard to generate one
17
- 2. Register RVRY as an MCP server in Claude Code (`-s user` scope)
18
- 3. Install slash commands (`/deepthink`, `/problem-solve`) to `.claude/commands/`
14
+ 1. Open your browser to sign in (or prompt for a token)
15
+ 2. Auto-detect Claude Code and Claude Desktop on your machine
16
+ 3. Configure both clients automatically
17
+ 4. Install slash commands (`/deepthink`, `/problem-solve`)
18
+
19
+ That's it. Restart Claude Desktop if it was running, and RVRY is ready.
20
+
21
+ ### Options
22
+
23
+ ```bash
24
+ npx @rvry/mcp setup --token rvry_abc123 # Skip browser auth, use token directly
25
+ npx @rvry/mcp setup --client code # Only configure Claude Code
26
+ npx @rvry/mcp setup --client desktop # Only configure Claude Desktop
27
+ ```
19
28
 
20
29
  ### Manual Installation
21
30
 
22
- If you prefer to configure manually, or the `claude` CLI is not available:
31
+ If you prefer to configure manually:
23
32
 
33
+ **Claude Code:**
24
34
  ```bash
25
35
  claude mcp add -e RVRY_TOKEN=rvry_your_token -s user rvry -- npx @rvry/mcp
26
36
  ```
27
37
 
28
- Or add the following to your Claude Desktop `claude_desktop_config.json`:
29
-
38
+ **Claude Desktop** (`claude_desktop_config.json`):
30
39
  ```json
31
40
  {
32
41
  "mcpServers": {
@@ -41,12 +50,10 @@ Or add the following to your Claude Desktop `claude_desktop_config.json`:
41
50
  }
42
51
  ```
43
52
 
44
- ## Configuration
45
-
46
- RVRY requires an API token to communicate with the reasoning engine.
47
-
48
- 1. Generate a token at [rvry.ai/dashboard](https://rvry.ai/dashboard).
49
- 2. The setup wizard sets `RVRY_TOKEN` automatically. For manual setup, set it in your MCP config.
53
+ Config file locations:
54
+ - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
55
+ - Windows: `%APPDATA%\Claude\claude_desktop_config.json`
56
+ - Linux: `~/.config/Claude/claude_desktop_config.json`
50
57
 
51
58
  ## Tools Provided
52
59
 
package/dist/setup.d.ts CHANGED
@@ -1,7 +1,12 @@
1
1
  /**
2
2
  * @rvry/mcp setup wizard
3
3
  *
4
- * Interactive setup: token input, Claude Code MCP registration, slash command installation.
4
+ * Interactive setup: device auth flow (browser-based) or manual token paste.
5
+ * Auto-detects Claude Code CLI and Claude Desktop, configures both.
6
+ *
5
7
  * Usage: npx @rvry/mcp setup
8
+ * npx @rvry/mcp setup --token <value>
9
+ * npx @rvry/mcp setup --client code (Claude Code only)
10
+ * npx @rvry/mcp setup --client desktop (Claude Desktop only)
6
11
  */
7
12
  export declare function runSetup(): Promise<void>;
package/dist/setup.js CHANGED
@@ -1,19 +1,36 @@
1
1
  /**
2
2
  * @rvry/mcp setup wizard
3
3
  *
4
- * Interactive setup: token input, Claude Code MCP registration, slash command installation.
4
+ * Interactive setup: device auth flow (browser-based) or manual token paste.
5
+ * Auto-detects Claude Code CLI and Claude Desktop, configures both.
6
+ *
5
7
  * Usage: npx @rvry/mcp setup
8
+ * npx @rvry/mcp setup --token <value>
9
+ * npx @rvry/mcp setup --client code (Claude Code only)
10
+ * npx @rvry/mcp setup --client desktop (Claude Desktop only)
6
11
  */
7
12
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
8
13
  import { join, dirname } from 'path';
14
+ import { homedir } from 'os';
9
15
  import { createInterface } from 'readline';
10
16
  import { execSync } from 'child_process';
11
17
  import { platform } from 'os';
18
+ const ENGINE_URL = 'https://engine.rvry.ai';
12
19
  const COMMAND_FILES = [
13
20
  'deepthink.md',
14
21
  'problem-solve.md',
15
22
  ];
16
23
  const TOKEN_REGEX = /^rvry_[0-9a-f]{32,}$/;
24
+ /** Polling interval for device auth: 3 seconds */
25
+ const POLL_INTERVAL_MS = 3000;
26
+ /** Max polling duration: 10 minutes */
27
+ const POLL_TIMEOUT_MS = 10 * 60 * 1000;
28
+ /** RVRY MCP server config block (reused across Desktop + manual output) */
29
+ const RVRY_SERVER_ENTRY = (token) => ({
30
+ command: 'npx',
31
+ args: ['@rvry/mcp'],
32
+ env: { RVRY_TOKEN: token },
33
+ });
17
34
  // ── Utility functions ──────────────────────────────────────────────
18
35
  /**
19
36
  * Find the commands directory shipped with this package.
@@ -140,6 +157,7 @@ function maskToken(token) {
140
157
  }
141
158
  /**
142
159
  * Open a URL in the default browser, platform-aware.
160
+ * Returns true if the browser was opened successfully, false otherwise.
143
161
  */
144
162
  function openBrowser(url) {
145
163
  const plat = platform();
@@ -153,11 +171,10 @@ function openBrowser(url) {
153
171
  else {
154
172
  execSync(`xdg-open "${url}"`, { stdio: 'pipe' });
155
173
  }
174
+ return true;
156
175
  }
157
176
  catch {
158
- // Non-fatal: browser open failed
159
- console.log(' Could not open browser automatically.');
160
- console.log(` Visit: ${url}`);
177
+ return false;
161
178
  }
162
179
  }
163
180
  /**
@@ -173,11 +190,83 @@ function isClaudeCLIAvailable() {
173
190
  return false;
174
191
  }
175
192
  }
193
+ /**
194
+ * Get the platform-specific Claude Desktop config file path.
195
+ */
196
+ function getDesktopConfigPath() {
197
+ const plat = platform();
198
+ if (plat === 'darwin') {
199
+ return join(homedir(), 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
200
+ }
201
+ else if (plat === 'win32') {
202
+ return join(process.env.APPDATA ?? join(homedir(), 'AppData', 'Roaming'), 'Claude', 'claude_desktop_config.json');
203
+ }
204
+ return join(homedir(), '.config', 'Claude', 'claude_desktop_config.json');
205
+ }
206
+ /**
207
+ * Check if Claude Desktop config directory exists (app is installed).
208
+ */
209
+ function isClaudeDesktopInstalled() {
210
+ const configPath = getDesktopConfigPath();
211
+ const configDir = dirname(configPath);
212
+ return existsSync(configDir);
213
+ }
214
+ /**
215
+ * Configure Claude Desktop by merging RVRY into the existing config.
216
+ * Creates the config file if it doesn't exist. Preserves other MCP servers.
217
+ * Returns 'created' | 'updated' | 'unchanged' | 'error'.
218
+ */
219
+ function configureDesktop(token) {
220
+ const configPath = getDesktopConfigPath();
221
+ try {
222
+ let config = {};
223
+ if (existsSync(configPath)) {
224
+ const raw = readFileSync(configPath, 'utf-8');
225
+ try {
226
+ config = JSON.parse(raw);
227
+ }
228
+ catch {
229
+ console.log(` Warning: ${configPath} contains invalid JSON.`);
230
+ console.log(' Creating a backup and writing fresh config.');
231
+ writeFileSync(configPath + '.backup', raw, 'utf-8');
232
+ config = {};
233
+ }
234
+ }
235
+ // Ensure mcpServers object exists
236
+ if (!config.mcpServers || typeof config.mcpServers !== 'object') {
237
+ config.mcpServers = {};
238
+ }
239
+ const servers = config.mcpServers;
240
+ const newEntry = RVRY_SERVER_ENTRY(token);
241
+ // Check if RVRY is already configured with the same token
242
+ const existing = servers.RVRY;
243
+ if (existing) {
244
+ const existingEnv = existing.env;
245
+ if (existingEnv?.RVRY_TOKEN === token) {
246
+ return 'unchanged';
247
+ }
248
+ }
249
+ const wasNew = !existing;
250
+ servers.RVRY = newEntry;
251
+ // Write config with clean formatting
252
+ const configDir = dirname(configPath);
253
+ if (!existsSync(configDir)) {
254
+ mkdirSync(configDir, { recursive: true });
255
+ }
256
+ writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
257
+ return wasNew ? 'created' : 'updated';
258
+ }
259
+ catch (err) {
260
+ const msg = err instanceof Error ? err.message : String(err);
261
+ console.log(` Error writing Desktop config: ${msg}`);
262
+ return 'error';
263
+ }
264
+ }
176
265
  /**
177
266
  * Register RVRY as an MCP server in Claude Code.
178
267
  * Removes existing registration first for idempotency.
179
268
  */
180
- function registerMCP(token) {
269
+ function registerClaudeCode(token) {
181
270
  try {
182
271
  // Remove existing (ignore error if not registered)
183
272
  try {
@@ -195,40 +284,124 @@ function registerMCP(token) {
195
284
  }
196
285
  }
197
286
  /**
198
- * Print manual JSON config block for users without the Claude CLI.
287
+ * Verify token by hitting the engine /api/usage endpoint.
288
+ * Returns tier info on success, null on failure.
199
289
  */
200
- function printManualConfig(token) {
201
- const config = {
202
- mcpServers: {
203
- RVRY: {
204
- command: 'npx',
205
- args: ['@rvry/mcp'],
206
- env: {
207
- RVRY_TOKEN: token,
208
- },
209
- },
290
+ async function verifyToken(token) {
291
+ try {
292
+ const res = await fetch(`${ENGINE_URL}/api/usage`, {
293
+ headers: { 'Authorization': `Bearer ${token}` },
294
+ });
295
+ if (!res.ok)
296
+ return null;
297
+ const data = await res.json();
298
+ return { tier: data.tier, used: data.monthlyUsage ?? 0, limit: data.limit };
299
+ }
300
+ catch {
301
+ return null;
302
+ }
303
+ }
304
+ /**
305
+ * Sleep for a given number of milliseconds.
306
+ */
307
+ function sleep(ms) {
308
+ return new Promise((resolve) => setTimeout(resolve, ms));
309
+ }
310
+ // ── Spinner animation ──────────────────────────────────────────────
311
+ const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
312
+ /**
313
+ * Create a spinner that animates in the terminal.
314
+ * Returns start/stop controls.
315
+ */
316
+ function createSpinner(message) {
317
+ let frameIndex = 0;
318
+ let timer = null;
319
+ return {
320
+ start() {
321
+ process.stdout.write(` ${SPINNER_FRAMES[0]} ${message}`);
322
+ timer = setInterval(() => {
323
+ frameIndex = (frameIndex + 1) % SPINNER_FRAMES.length;
324
+ process.stdout.write(`\r ${SPINNER_FRAMES[frameIndex]} ${message}`);
325
+ }, 80);
326
+ },
327
+ stop(finalMessage) {
328
+ if (timer) {
329
+ clearInterval(timer);
330
+ timer = null;
331
+ }
332
+ process.stdout.write('\r' + ' '.repeat(message.length + 10) + '\r');
333
+ if (finalMessage) {
334
+ console.log(` ${finalMessage}`);
335
+ }
210
336
  },
211
337
  };
212
- console.log('');
213
- console.log(' Claude CLI not found. Add this to your MCP config manually:');
214
- console.log('');
215
- console.log(JSON.stringify(config, null, 2));
216
- console.log('');
217
- const plat = platform();
218
- if (plat === 'darwin') {
219
- console.log(' Claude Desktop config location:');
220
- console.log(' ~/Library/Application Support/Claude/claude_desktop_config.json');
338
+ }
339
+ // ── Device auth flow ───────────────────────────────────────────────
340
+ /**
341
+ * Device authorization flow: open browser, poll for token.
342
+ * Returns the token on success, or null on failure/timeout.
343
+ */
344
+ async function deviceAuthFlow() {
345
+ // Step 1: Request a device code from the engine
346
+ let deviceCode;
347
+ let verificationUrl;
348
+ try {
349
+ const res = await fetch(`${ENGINE_URL}/api/device/start`, { method: 'POST' });
350
+ if (!res.ok) {
351
+ const body = await res.json().catch(() => ({ error: 'Unknown error' }));
352
+ console.log(` Could not start device auth: ${body.error ?? res.statusText}`);
353
+ return null;
354
+ }
355
+ const data = await res.json();
356
+ deviceCode = data.device_code;
357
+ verificationUrl = data.verification_url;
221
358
  }
222
- else if (plat === 'win32') {
223
- console.log(' Claude Desktop config location:');
224
- console.log(' %APPDATA%\\Claude\\claude_desktop_config.json');
359
+ catch (err) {
360
+ console.log(' Could not connect to RVRY engine. Is engine.rvry.ai reachable?');
361
+ return null;
362
+ }
363
+ // Step 2: Open browser
364
+ console.log('');
365
+ const browserOpened = openBrowser(verificationUrl);
366
+ if (browserOpened) {
367
+ console.log(' Browser opened. Complete sign-in to continue.');
225
368
  }
226
369
  else {
227
- console.log(' Claude Desktop config location:');
228
- console.log(' ~/.config/Claude/claude_desktop_config.json');
370
+ console.log(' Could not open browser automatically.');
371
+ console.log(` Visit: ${verificationUrl}`);
372
+ }
373
+ console.log('');
374
+ // Step 3: Poll for token
375
+ const spinner = createSpinner('Waiting for login in browser...');
376
+ spinner.start();
377
+ const startTime = Date.now();
378
+ while (Date.now() - startTime < POLL_TIMEOUT_MS) {
379
+ await sleep(POLL_INTERVAL_MS);
380
+ try {
381
+ const res = await fetch(`${ENGINE_URL}/api/device/${deviceCode}/token`);
382
+ if (!res.ok) {
383
+ spinner.stop('Polling error. Falling back to manual token entry.');
384
+ return null;
385
+ }
386
+ const data = await res.json();
387
+ if (data.status === 'complete' && data.token) {
388
+ spinner.stop('Login successful!');
389
+ return { token: data.token, warning: data.warning };
390
+ }
391
+ if (data.status === 'expired') {
392
+ spinner.stop('Device code expired.');
393
+ return null;
394
+ }
395
+ // status === 'pending' — keep polling
396
+ }
397
+ catch {
398
+ // Network error during poll — keep trying
399
+ }
229
400
  }
401
+ spinner.stop('Timed out waiting for login.');
402
+ return null;
230
403
  }
231
- // ── Token input flow ───────────────────────────────────────────────
404
+ // ── Manual token input flow ────────────────────────────────────────
232
405
  async function getToken() {
233
406
  while (true) {
234
407
  const token = (await readHiddenInput(' Enter your RVRY token: ')).trim();
@@ -281,57 +454,208 @@ async function installCommands() {
281
454
  }
282
455
  // ── Main setup flow ────────────────────────────────────────────────
283
456
  const BANNER = `
284
- ░█████████ ░██ ░██ ░█████████ ░██ ░██
285
- ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██
286
- ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██
287
- ░█████████ ░██ ░██ ░█████████ ░████
288
- ░██ ░██ ░██ ░██ ░██ ░██ ░██
289
- ░██ ░██ ░██░██ ░██ ░██ ░██
290
- ░██ ░██ ░███ ░██ ░██ ░██
457
+ _____ __ __ _____ __ __
458
+ | __ \\\\ \\\\ / /| __ \\\\ \\\\ / /
459
+ | |__) |\\\\ \\\\ / / | |__) |\\\\ \\\\_/ /
460
+ | _ / \\\\ \\\\/ / | _ / \\\\ /
461
+ | | \\\\ \\\\ \\\\ / | | \\\\ \\\\ | |
462
+ |_| \\\\_\\\\ \\\\/ |_| \\\\_\\\\ |_|
291
463
  `;
292
464
  export async function runSetup() {
293
465
  console.log(BANNER);
294
466
  console.log('Setup');
295
467
  console.log('');
296
- // Step 1: Token input
297
- console.log('[1/3] Token');
298
- const token = await getToken();
299
- console.log('');
300
- // Step 2: Claude Code MCP registration
301
- console.log('[2/3] Claude Code MCP Registration');
302
- let claudeConfigured = false;
303
- if (isClaudeCLIAvailable()) {
304
- const success = registerMCP(token);
305
- if (success) {
306
- claudeConfigured = true;
307
- console.log(' Registered RVRY in Claude Code (user scope).');
468
+ // Parse flags
469
+ const tokenFlagIndex = process.argv.indexOf('--token');
470
+ const clientFlagIndex = process.argv.indexOf('--client');
471
+ const clientFilter = clientFlagIndex !== -1 ? process.argv[clientFlagIndex + 1] : null;
472
+ // ── Step 1: Authentication ──────────────────────────────────────
473
+ let token = null;
474
+ let warning;
475
+ if (tokenFlagIndex !== -1 && process.argv[tokenFlagIndex + 1]) {
476
+ const flagValue = process.argv[tokenFlagIndex + 1];
477
+ if (!isValidToken(flagValue)) {
478
+ console.log(' Invalid token format. Expected: rvry_ followed by 32+ hex characters.');
479
+ process.exit(1);
480
+ }
481
+ token = flagValue;
482
+ console.log('[1/4] Authentication (from --token flag)');
483
+ console.log(` Token: ${maskToken(token)}`);
484
+ }
485
+ else {
486
+ console.log('[1/4] Authentication');
487
+ console.log(' Opening browser for sign-in...');
488
+ const result = await deviceAuthFlow();
489
+ if (result) {
490
+ token = result.token;
491
+ warning = result.warning;
492
+ console.log(` Token: ${maskToken(token)}`);
493
+ if (warning) {
494
+ console.log(` Warning: ${warning}`);
495
+ }
308
496
  }
309
497
  else {
310
- console.log(' Failed to register with Claude CLI.');
311
- printManualConfig(token);
498
+ console.log('');
499
+ console.log(' Falling back to manual token entry.');
500
+ console.log(' Generate a token at https://rvry.ai/dashboard');
501
+ console.log('');
502
+ token = await getToken();
312
503
  }
313
504
  }
505
+ // Verify token against engine
506
+ const spinner = createSpinner('Verifying token...');
507
+ spinner.start();
508
+ const usage = await verifyToken(token);
509
+ if (usage) {
510
+ const usageText = usage.limit < 0
511
+ ? `${usage.used ?? 0} sessions used (unlimited)`
512
+ : `${usage.used ?? 0}/${usage.limit} sessions used`;
513
+ spinner.stop(`Verified. Plan: ${usage.tier} (${usageText})`);
514
+ }
314
515
  else {
315
- printManualConfig(token);
516
+ spinner.stop('Could not verify token (engine may be unreachable). Continuing anyway.');
517
+ }
518
+ console.log('');
519
+ // ── Step 2: Detect clients ──────────────────────────────────────
520
+ console.log('[2/4] Detecting Claude clients');
521
+ const hasClaudeCode = isClaudeCLIAvailable();
522
+ const hasDesktop = isClaudeDesktopInstalled();
523
+ const desktopConfigPath = getDesktopConfigPath();
524
+ const wantCode = !clientFilter || clientFilter === 'code';
525
+ const wantDesktop = !clientFilter || clientFilter === 'desktop';
526
+ if (hasClaudeCode && wantCode) {
527
+ console.log(' Found: Claude Code (claude CLI)');
528
+ }
529
+ if (hasDesktop && wantDesktop) {
530
+ console.log(` Found: Claude Desktop (${desktopConfigPath})`);
531
+ }
532
+ if (!hasClaudeCode && !hasDesktop) {
533
+ console.log(' No Claude clients detected.');
316
534
  }
317
535
  console.log('');
318
- // Step 3: Slash command installation
319
- console.log('[3/3] Slash Commands');
536
+ // ── Step 3: Configure clients ───────────────────────────────────
537
+ console.log('[3/4] Client Configuration');
538
+ let codeConfigured = false;
539
+ let desktopConfigured = 'skipped';
540
+ let neitherConfigured = true;
541
+ // Claude Code
542
+ if (hasClaudeCode && wantCode) {
543
+ const rl = createRL();
544
+ const answer = await ask(rl, ' Install for Claude Code? [Y/n] ');
545
+ rl.close();
546
+ if (answer.toLowerCase() !== 'n') {
547
+ const success = registerClaudeCode(token);
548
+ if (success) {
549
+ codeConfigured = true;
550
+ neitherConfigured = false;
551
+ console.log(' Claude Code: Registered (user scope -- works in all projects)');
552
+ }
553
+ else {
554
+ console.log(' Claude Code: Failed to register via CLI');
555
+ }
556
+ }
557
+ else {
558
+ console.log(' Claude Code: Skipped');
559
+ }
560
+ }
561
+ else if (wantCode && !hasClaudeCode) {
562
+ console.log(' Claude Code: CLI not found (install: https://docs.anthropic.com/en/docs/claude-code)');
563
+ }
564
+ // Claude Desktop / Co-Work
565
+ if (hasDesktop && wantDesktop) {
566
+ const rl = createRL();
567
+ const answer = await ask(rl, ' Install for Claude Desktop / Co-Work? [Y/n] ');
568
+ rl.close();
569
+ if (answer.toLowerCase() !== 'n') {
570
+ desktopConfigured = configureDesktop(token);
571
+ switch (desktopConfigured) {
572
+ case 'created':
573
+ neitherConfigured = false;
574
+ console.log(' Claude Desktop: Added RVRY to config');
575
+ break;
576
+ case 'updated':
577
+ neitherConfigured = false;
578
+ console.log(' Claude Desktop: Updated RVRY token in config');
579
+ break;
580
+ case 'unchanged':
581
+ neitherConfigured = false;
582
+ console.log(' Claude Desktop: Already configured with this token');
583
+ break;
584
+ case 'error':
585
+ console.log(' Claude Desktop: Failed to write config (see error above)');
586
+ break;
587
+ }
588
+ }
589
+ else {
590
+ console.log(' Claude Desktop: Skipped');
591
+ }
592
+ }
593
+ else if (wantDesktop && !hasDesktop) {
594
+ console.log(' Claude Desktop: Not installed');
595
+ }
596
+ // Fallback: print manual config if nothing was configured
597
+ if (neitherConfigured) {
598
+ console.log('');
599
+ console.log(' Manual configuration:');
600
+ console.log('');
601
+ console.log(' Option A — Claude Code (if you install it later):');
602
+ console.log(` claude mcp add -e RVRY_TOKEN="${token}" -s user rvry -- npx @rvry/mcp`);
603
+ console.log('');
604
+ console.log(' Option B — Claude Desktop config JSON:');
605
+ const manualConfig = { mcpServers: { RVRY: RVRY_SERVER_ENTRY(token) } };
606
+ console.log(` File: ${desktopConfigPath}`);
607
+ console.log('');
608
+ for (const line of JSON.stringify(manualConfig, null, 2).split('\n')) {
609
+ console.log(` ${line}`);
610
+ }
611
+ }
612
+ console.log('');
613
+ // ── Step 4: Slash commands ──────────────────────────────────────
614
+ console.log('[4/4] Slash Commands');
320
615
  const commandCount = await installCommands();
321
616
  if (commandCount > 0) {
322
- console.log(` Installed ${commandCount} commands to .claude/commands/`);
617
+ console.log(` Installed ${commandCount} command${commandCount > 1 ? 's' : ''} to .claude/commands/`);
323
618
  }
324
619
  else {
325
- console.log(' No new commands installed.');
620
+ console.log(' No new commands installed (already up to date).');
326
621
  }
327
622
  console.log('');
328
- // Summary
623
+ // ── Summary ─────────────────────────────────────────────────────
624
+ console.log('─'.repeat(50));
625
+ console.log('');
329
626
  console.log('RVRY Setup Complete');
330
627
  console.log('');
331
- console.log(` Token: ${maskToken(token)}`);
332
- console.log(` Claude Code: ${claudeConfigured ? 'Configured (user scope)' : 'Manual config required'}`);
333
- console.log(` Commands: ${commandCount} installed to .claude/commands/`);
628
+ console.log(` Token: ${maskToken(token)}${usage ? ` (${usage.tier})` : ''}`);
629
+ if (codeConfigured) {
630
+ console.log(' Claude Code: Configured');
631
+ }
632
+ if (desktopConfigured !== 'skipped' && desktopConfigured !== 'error') {
633
+ console.log(' Claude Desktop: Configured');
634
+ }
635
+ console.log(` Commands: ${commandCount} installed`);
334
636
  console.log('');
335
- console.log('Try: /deepthink "your question"');
637
+ // Client-specific next steps
638
+ console.log('Next steps:');
639
+ const desktopOk = desktopConfigured !== 'skipped' && desktopConfigured !== 'error';
640
+ let step = 1;
641
+ if (desktopOk) {
642
+ console.log(` ${step}. Restart Claude Desktop for the new MCP server to load`);
643
+ step++;
644
+ }
645
+ if (codeConfigured) {
646
+ console.log(` ${step}. In Claude Code, try:`);
647
+ console.log(' /deepthink "your question"');
648
+ console.log(' /problem-solve "your decision"');
649
+ step++;
650
+ }
651
+ if (desktopOk) {
652
+ console.log(` ${step}. In Claude Desktop, use natural language:`);
653
+ console.log(' "Use deepthink to analyze..." or "Use problem-solve for..."');
654
+ step++;
655
+ }
656
+ if (!codeConfigured && !desktopOk) {
657
+ console.log(' 1. Configure a Claude client using the manual instructions above');
658
+ console.log(' 2. Then try: /deepthink "your question"');
659
+ }
336
660
  console.log('');
337
661
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rvry/mcp",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "RVRY reasoning depth enforcement (RDE) engine client.",
5
5
  "type": "module",
6
6
  "bin": {