polydev-ai 1.8.63 → 1.8.71

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
@@ -24,6 +24,26 @@ Get insights from GPT 5.2, Claude Opus 4.5, Gemini 3, and Grok 4.1 — all throu
24
24
 
25
25
  ---
26
26
 
27
+ ## 🔑 Key Advantage: Use Your Existing Subscriptions
28
+
29
+ **Already paying for ChatGPT Plus, Claude Pro, or Gemini Advanced?** Use those subscriptions directly through your CLI tools — no API keys needed.
30
+
31
+ | Subscription | CLI Tool | How to Use |
32
+ |--------------|----------|------------|
33
+ | Claude Pro ($20/mo) | Claude Code | `claude login` with your Anthropic account |
34
+ | ChatGPT Plus ($20/mo) | Codex CLI | `codex login` with your OpenAI account |
35
+ | Gemini Advanced ($20/mo) | Gemini CLI | `gemini login` with your Google account |
36
+
37
+ **How it works:**
38
+ 1. Login to your CLI tool with your subscription account (no API keys!)
39
+ 2. Add Polydev as an MCP server to your CLI
40
+ 3. Polydev queries models through your authenticated CLI sessions
41
+ 4. Your subscription quota is used — no extra costs
42
+
43
+ **No API keys. No double-paying.** Your existing subscriptions just work.
44
+
45
+ ---
46
+
27
47
  ## Quick Start
28
48
 
29
49
  ### 1. Get your free API token
package/mcp/manifest.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polydev-perspectives",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Multi-model AI perspectives - query GPT 5.2, Claude Opus 4.5, Gemini 3, and Grok 4.1 simultaneously. Get diverse perspectives when stuck or need enhanced reasoning. Achieved 74.6% on SWE-bench Verified.",
5
5
  "author": "Polydev AI",
6
6
  "license": "MIT",
@@ -12,6 +12,138 @@
12
12
  "prompts": false
13
13
  },
14
14
  "tools": [
15
+ {
16
+ "name": "get_auth_status",
17
+ "description": "Check Polydev authentication status and get setup instructions. Use this first to verify your token is valid or get help setting up Polydev. Works in all IDEs (Claude Desktop, Cursor, Continue, Windsurf, VSCode, etc.).",
18
+ "inputSchema": {
19
+ "type": "object",
20
+ "properties": {
21
+ "user_token": {
22
+ "type": "string",
23
+ "description": "Polydev user authentication token (optional - checks if provided, shows setup instructions if not)"
24
+ }
25
+ }
26
+ },
27
+ "outputSchema": {
28
+ "type": "object",
29
+ "properties": {
30
+ "authenticated": {
31
+ "type": "boolean",
32
+ "description": "Whether the user is authenticated"
33
+ },
34
+ "user_email": {
35
+ "type": "string",
36
+ "description": "User email if authenticated"
37
+ },
38
+ "credits_remaining": {
39
+ "type": "integer",
40
+ "description": "Credits remaining if authenticated"
41
+ },
42
+ "subscription_tier": {
43
+ "type": "string",
44
+ "description": "Current subscription tier"
45
+ },
46
+ "setup_instructions": {
47
+ "type": "object",
48
+ "description": "Setup instructions if not authenticated"
49
+ },
50
+ "message": {
51
+ "type": "string",
52
+ "description": "Human-readable status message"
53
+ }
54
+ }
55
+ },
56
+ "examples": [
57
+ {
58
+ "description": "Check auth status without token",
59
+ "input": {},
60
+ "output": {
61
+ "authenticated": false,
62
+ "setup_instructions": {
63
+ "step_1": "Visit https://polydev.ai to create your free account",
64
+ "step_2": "Go to https://polydev.ai/dashboard/mcp-tools",
65
+ "step_3": "Generate your MCP access token",
66
+ "step_4": "Add the token to your IDE configuration"
67
+ },
68
+ "message": "Welcome to Polydev! Get started in 2 minutes."
69
+ }
70
+ },
71
+ {
72
+ "description": "Check auth status with valid token",
73
+ "input": { "user_token": "polydev_abc123..." },
74
+ "output": {
75
+ "authenticated": true,
76
+ "user_email": "user@example.com",
77
+ "credits_remaining": 9500,
78
+ "subscription_tier": "Premium",
79
+ "message": "Ready to use Polydev! You have 9,500 credits remaining."
80
+ }
81
+ }
82
+ ]
83
+ },
84
+ {
85
+ "name": "login",
86
+ "description": "Authenticate with Polydev by opening your browser. Automatically configures your MCP token after successful login. Use this for a seamless signup/login experience - no manual token copying required.",
87
+ "inputSchema": {
88
+ "type": "object",
89
+ "properties": {
90
+ "open_browser": {
91
+ "type": "boolean",
92
+ "description": "Whether to automatically open the browser (default: true)",
93
+ "default": true
94
+ },
95
+ "timeout_seconds": {
96
+ "type": "integer",
97
+ "description": "How long to wait for authentication (default: 300 = 5 minutes)",
98
+ "minimum": 30,
99
+ "maximum": 600,
100
+ "default": 300
101
+ }
102
+ }
103
+ },
104
+ "outputSchema": {
105
+ "type": "object",
106
+ "properties": {
107
+ "success": {
108
+ "type": "boolean",
109
+ "description": "Whether authentication was successful"
110
+ },
111
+ "user_email": {
112
+ "type": "string",
113
+ "description": "Authenticated user's email"
114
+ },
115
+ "token": {
116
+ "type": "string",
117
+ "description": "MCP access token (save this for future use)"
118
+ },
119
+ "credits_remaining": {
120
+ "type": "integer",
121
+ "description": "Available credits"
122
+ },
123
+ "message": {
124
+ "type": "string",
125
+ "description": "Human-readable status message"
126
+ },
127
+ "auth_url": {
128
+ "type": "string",
129
+ "description": "URL to open if browser didn't open automatically"
130
+ }
131
+ }
132
+ },
133
+ "examples": [
134
+ {
135
+ "description": "Login with browser auto-open",
136
+ "input": {},
137
+ "output": {
138
+ "success": true,
139
+ "user_email": "user@example.com",
140
+ "token": "polydev_abc123...",
141
+ "credits_remaining": 500,
142
+ "message": "Successfully authenticated! Token has been saved."
143
+ }
144
+ }
145
+ ]
146
+ },
15
147
  {
16
148
  "name": "get_perspectives",
17
149
  "description": "When stuck in agentic workflows, get diverse perspectives from multiple LLMs to overcome roadblocks. All models use Polydev-managed API keys - just configure once in dashboard.",
package/mcp/server.js CHANGED
@@ -145,6 +145,14 @@ class MCPServer {
145
145
  let result;
146
146
 
147
147
  switch (name) {
148
+ case 'get_auth_status':
149
+ result = await this.getAuthStatus(args);
150
+ break;
151
+
152
+ case 'login':
153
+ result = await this.login(args);
154
+ break;
155
+
148
156
  case 'get_perspectives':
149
157
  result = await this.callPerspectivesAPI(args);
150
158
  break;
@@ -262,10 +270,31 @@ class MCPServer {
262
270
  console.error(`[Polydev MCP] Debug - final userToken: ${userToken ? 'present' : 'missing'}`);
263
271
 
264
272
  if (!userToken || typeof userToken !== 'string') {
265
- throw new Error('user_token is required. Either:\n' +
266
- '1. Pass user_token parameter, or\n' +
267
- '2. Set POLYDEV_USER_TOKEN environment variable\n' +
268
- 'Generate token at: https://polydev.ai/dashboard/mcp-tokens');
273
+ // Return helpful setup instructions instead of just throwing an error
274
+ const detectedIDE = this.detectIDE();
275
+ const setupInstructions = this.getSetupInstructions(detectedIDE);
276
+
277
+ throw new Error(
278
+ '═══════════════════════════════════════════════════════════════\n' +
279
+ ' POLYDEV SETUP REQUIRED\n' +
280
+ '═══════════════════════════════════════════════════════════════\n\n' +
281
+ 'To use Polydev, you need an authentication token.\n\n' +
282
+ 'QUICK SETUP (2 minutes):\n' +
283
+ '1. Create free account: https://polydev.ai/signup\n' +
284
+ '2. Get your token: https://polydev.ai/dashboard/mcp-tools\n' +
285
+ '3. Add token to your MCP configuration\n\n' +
286
+ 'FREE TIER INCLUDES:\n' +
287
+ '• 500 credits/month (no credit card needed)\n' +
288
+ '• Access to GLM-4.7, Gemini 3 Flash, Grok 4.1, GPT-5 Mini\n' +
289
+ '• 1 credit per request (all models)\n\n' +
290
+ 'CONFIGURATION:\n' +
291
+ 'Set POLYDEV_USER_TOKEN in your MCP server env, or\n' +
292
+ 'Pass user_token parameter with each request.\n\n' +
293
+ 'NEED HELP?\n' +
294
+ '• Setup guide: https://polydev.ai/docs/mcp-integration\n' +
295
+ '• Use get_auth_status tool for personalized instructions\n' +
296
+ '═══════════════════════════════════════════════════════════════'
297
+ );
269
298
  }
270
299
 
271
300
  console.error(`[Polydev MCP] Getting perspectives for: "${args.prompt.substring(0, 60)}${args.prompt.length > 60 ? '...' : ''}"`);
@@ -307,7 +336,24 @@ class MCPServer {
307
336
  }
308
337
 
309
338
  if (response.status === 401) {
310
- throw new Error(`Authentication failed: ${errorMessage}. Generate a new token at https://polydev.ai/dashboard/mcp-tools`);
339
+ throw new Error(
340
+ '═══════════════════════════════════════════════════════════════\n' +
341
+ ' AUTHENTICATION FAILED\n' +
342
+ '═══════════════════════════════════════════════════════════════\n\n' +
343
+ `Error: ${errorMessage}\n\n` +
344
+ 'YOUR TOKEN MAY BE:\n' +
345
+ '• Expired (tokens last 30 days)\n' +
346
+ '• Invalid or mistyped\n' +
347
+ '• From a different account\n\n' +
348
+ 'TO FIX:\n' +
349
+ '1. Go to: https://polydev.ai/dashboard/mcp-tools\n' +
350
+ '2. Generate a new token\n' +
351
+ '3. Update your MCP configuration\n\n' +
352
+ 'QUICK CHECK:\n' +
353
+ '• Use get_auth_status tool to verify your setup\n' +
354
+ '• Token should start with "polydev_"\n' +
355
+ '═══════════════════════════════════════════════════════════════'
356
+ );
311
357
  }
312
358
 
313
359
  throw new Error(`Polydev API error: ${errorMessage}`);
@@ -328,8 +374,551 @@ class MCPServer {
328
374
  return result;
329
375
  }
330
376
 
377
+ /**
378
+ * Get authentication status and setup instructions
379
+ * Works universally across all IDEs (Claude Desktop, Cursor, Continue, Windsurf, VSCode, etc.)
380
+ */
381
+ async getAuthStatus(args) {
382
+ const serverUrl = 'https://www.polydev.ai/api/mcp/auth-status';
383
+ const userToken = args.user_token || process.env.POLYDEV_USER_TOKEN;
384
+
385
+ console.error('[Polydev MCP] Checking authentication status...');
386
+
387
+ // Detect IDE from environment
388
+ const detectedIDE = this.detectIDE();
389
+
390
+ // If no token provided, return setup instructions
391
+ if (!userToken) {
392
+ return {
393
+ authenticated: false,
394
+ detected_ide: detectedIDE,
395
+ setup_instructions: this.getSetupInstructions(detectedIDE),
396
+ quick_links: {
397
+ signup: 'https://polydev.ai/signup',
398
+ login: 'https://polydev.ai/login',
399
+ dashboard: 'https://polydev.ai/dashboard',
400
+ mcp_tools: 'https://polydev.ai/dashboard/mcp-tools',
401
+ documentation: 'https://polydev.ai/docs/mcp-integration'
402
+ },
403
+ available_models: ['GLM-4.7', 'Gemini 3 Flash', 'Grok 4.1 Fast Reasoning', 'GPT-5 Mini'],
404
+ pricing: {
405
+ free_tier: '500 credits/month (no credit card required)',
406
+ premium_tier: '$10/month for 10,000 credits',
407
+ credit_cost: '1 credit per request (all models)'
408
+ },
409
+ message: 'Welcome to Polydev! Create your free account to get started.',
410
+ timestamp: new Date().toISOString()
411
+ };
412
+ }
413
+
414
+ // Validate token with the server
415
+ try {
416
+ const response = await fetch(serverUrl, {
417
+ method: 'POST',
418
+ headers: {
419
+ 'Content-Type': 'application/json',
420
+ 'Authorization': `Bearer ${userToken}`,
421
+ 'User-Agent': 'polydev-mcp/1.4.0'
422
+ },
423
+ body: JSON.stringify({ action: 'check_status' })
424
+ });
425
+
426
+ if (response.ok) {
427
+ const data = await response.json();
428
+ return {
429
+ authenticated: true,
430
+ user_email: data.email,
431
+ credits_remaining: data.credits_remaining,
432
+ credits_used_today: data.credits_used_today || 0,
433
+ subscription_tier: data.subscription_tier || 'Free',
434
+ token_expires_at: data.token_expires_at,
435
+ enabled_models: data.enabled_models || ['GLM-4.7', 'Gemini 3 Flash', 'Grok 4.1 Fast Reasoning', 'GPT-5 Mini'],
436
+ cli_subscriptions: data.cli_subscriptions || [],
437
+ quick_links: {
438
+ dashboard: 'https://polydev.ai/dashboard',
439
+ usage: 'https://polydev.ai/dashboard/usage',
440
+ settings: 'https://polydev.ai/dashboard/settings',
441
+ upgrade: 'https://polydev.ai/dashboard/subscription'
442
+ },
443
+ message: `Ready to use Polydev! You have ${data.credits_remaining?.toLocaleString() || 0} credits remaining.`,
444
+ timestamp: new Date().toISOString()
445
+ };
446
+ } else if (response.status === 401) {
447
+ return {
448
+ authenticated: false,
449
+ error: 'invalid_token',
450
+ detected_ide: detectedIDE,
451
+ setup_instructions: this.getSetupInstructions(detectedIDE),
452
+ quick_links: {
453
+ regenerate_token: 'https://polydev.ai/dashboard/mcp-tools',
454
+ login: 'https://polydev.ai/login'
455
+ },
456
+ message: 'Your token is invalid or expired. Please generate a new one.',
457
+ timestamp: new Date().toISOString()
458
+ };
459
+ } else {
460
+ const errorText = await response.text();
461
+ return {
462
+ authenticated: false,
463
+ error: 'server_error',
464
+ error_details: errorText,
465
+ message: 'Unable to verify authentication. Please try again.',
466
+ timestamp: new Date().toISOString()
467
+ };
468
+ }
469
+ } catch (error) {
470
+ console.error('[Polydev MCP] Auth status check error:', error);
471
+ return {
472
+ authenticated: false,
473
+ error: 'connection_error',
474
+ error_details: error.message,
475
+ offline_mode: true,
476
+ message: 'Unable to connect to Polydev servers. Check your internet connection.',
477
+ timestamp: new Date().toISOString()
478
+ };
479
+ }
480
+ }
481
+
482
+ /**
483
+ * Detect the IDE/MCP client from environment
484
+ */
485
+ detectIDE() {
486
+ // Check common environment variables and process info
487
+ const env = process.env;
488
+
489
+ if (env.CURSOR_CHANNEL || env.CURSOR_VERSION) return 'cursor';
490
+ if (env.CONTINUE_EXTENSION_ID) return 'continue';
491
+ if (env.VSCODE_PID || env.VSCODE_CWD) return 'vscode';
492
+ if (env.CLAUDE_DESKTOP) return 'claude-desktop';
493
+ if (env.WINDSURF_VERSION) return 'windsurf';
494
+ if (env.CLINE_VERSION) return 'cline';
495
+
496
+ // Check process title/args for hints
497
+ const processTitle = process.title || '';
498
+ const args = process.argv.join(' ').toLowerCase();
499
+
500
+ if (args.includes('cursor') || processTitle.includes('cursor')) return 'cursor';
501
+ if (args.includes('claude') || processTitle.includes('claude')) return 'claude-desktop';
502
+ if (args.includes('continue')) return 'continue';
503
+ if (args.includes('windsurf')) return 'windsurf';
504
+
505
+ return 'unknown';
506
+ }
507
+
508
+ /**
509
+ * Get IDE-specific setup instructions
510
+ */
511
+ getSetupInstructions(ide) {
512
+ const baseSteps = {
513
+ step_1: 'Create your free Polydev account at https://polydev.ai/signup',
514
+ step_2: 'Go to https://polydev.ai/dashboard/mcp-tools',
515
+ step_3: 'Click "Generate Token" to create your MCP access token',
516
+ step_4: 'Copy the token (it starts with "polydev_")'
517
+ };
518
+
519
+ const ideConfigs = {
520
+ 'cursor': {
521
+ ...baseSteps,
522
+ step_5: 'Open Cursor Settings (Cmd/Ctrl + ,)',
523
+ step_6: 'Search for "MCP" in settings',
524
+ step_7: 'Add Polydev server with your token',
525
+ config_example: `{
526
+ "mcpServers": {
527
+ "polydev": {
528
+ "command": "npx",
529
+ "args": ["-y", "polydev-mcp"],
530
+ "env": { "POLYDEV_USER_TOKEN": "polydev_your_token_here" }
531
+ }
532
+ }
533
+ }`
534
+ },
535
+ 'claude-desktop': {
536
+ ...baseSteps,
537
+ step_5: 'Open Claude Desktop settings',
538
+ step_6: 'Navigate to Developer > MCP Servers',
539
+ step_7: 'Add the Polydev server configuration',
540
+ config_example: `{
541
+ "mcpServers": {
542
+ "polydev": {
543
+ "command": "npx",
544
+ "args": ["-y", "polydev-mcp"],
545
+ "env": { "POLYDEV_USER_TOKEN": "polydev_your_token_here" }
546
+ }
547
+ }
548
+ }`
549
+ },
550
+ 'continue': {
551
+ ...baseSteps,
552
+ step_5: 'Open Continue extension settings in VSCode',
553
+ step_6: 'Add Polydev to your config.json',
554
+ config_example: `{
555
+ "mcpServers": [{
556
+ "name": "polydev",
557
+ "command": "npx",
558
+ "args": ["-y", "polydev-mcp"],
559
+ "env": { "POLYDEV_USER_TOKEN": "polydev_your_token_here" }
560
+ }]
561
+ }`
562
+ },
563
+ 'windsurf': {
564
+ ...baseSteps,
565
+ step_5: 'Open Windsurf Settings',
566
+ step_6: 'Navigate to MCP Configuration',
567
+ step_7: 'Add Polydev server with your token',
568
+ config_example: `{
569
+ "mcp": {
570
+ "servers": {
571
+ "polydev": {
572
+ "command": "npx",
573
+ "args": ["-y", "polydev-mcp"],
574
+ "env": { "POLYDEV_USER_TOKEN": "polydev_your_token_here" }
575
+ }
576
+ }
577
+ }
578
+ }`
579
+ },
580
+ 'vscode': {
581
+ ...baseSteps,
582
+ step_5: 'Install an MCP-compatible extension (Continue, Cline, etc.)',
583
+ step_6: 'Configure the extension with Polydev',
584
+ step_7: 'Add your token to the configuration'
585
+ },
586
+ 'unknown': {
587
+ ...baseSteps,
588
+ step_5: 'Configure your MCP client with the Polydev server',
589
+ step_6: 'Set POLYDEV_USER_TOKEN environment variable with your token',
590
+ note: 'Visit https://polydev.ai/docs/mcp-integration for detailed setup guides'
591
+ }
592
+ };
593
+
594
+ return ideConfigs[ide] || ideConfigs['unknown'];
595
+ }
596
+
597
+ /**
598
+ * Format authentication status response for beautiful output
599
+ */
600
+ formatAuthStatusResponse(result) {
601
+ let formatted = '';
602
+
603
+ if (result.authenticated) {
604
+ formatted += `# Polydev Authentication Status\n\n`;
605
+ formatted += `## Account\n`;
606
+ formatted += `Email: ${result.user_email}\n`;
607
+ formatted += `Tier: ${result.subscription_tier}\n\n`;
608
+
609
+ formatted += `## Credits\n`;
610
+ formatted += `Remaining: ${result.credits_remaining?.toLocaleString() || 0}\n`;
611
+ if (result.credits_used_today !== undefined) {
612
+ formatted += `Used Today: ${result.credits_used_today}\n`;
613
+ }
614
+ formatted += `\n`;
615
+
616
+ formatted += `## Available Models (1 credit each)\n`;
617
+ if (result.enabled_models && result.enabled_models.length > 0) {
618
+ result.enabled_models.forEach(model => {
619
+ formatted += `- ${model}\n`;
620
+ });
621
+ }
622
+ formatted += `\n`;
623
+
624
+ if (result.cli_subscriptions && result.cli_subscriptions.length > 0) {
625
+ formatted += `## Connected CLI Subscriptions (no credit cost)\n`;
626
+ result.cli_subscriptions.forEach(cli => {
627
+ formatted += `- ${cli}\n`;
628
+ });
629
+ formatted += `\n`;
630
+ }
631
+
632
+ formatted += `## Quick Links\n`;
633
+ formatted += `- Dashboard: ${result.quick_links.dashboard}\n`;
634
+ formatted += `- Usage History: ${result.quick_links.usage}\n`;
635
+ formatted += `- Settings: ${result.quick_links.settings}\n`;
636
+
637
+ if (result.subscription_tier === 'Free') {
638
+ formatted += `\n## Upgrade to Premium\n`;
639
+ formatted += `Get 10,000 credits/month for $10: ${result.quick_links.upgrade}\n`;
640
+ }
641
+ } else {
642
+ formatted += `# Welcome to Polydev\n\n`;
643
+ formatted += `Multi-model AI that helps when you're stuck. Query GPT-5, Claude, Gemini, and Grok simultaneously.\n\n`;
644
+
645
+ if (result.error === 'invalid_token') {
646
+ formatted += `## Token Issue\n`;
647
+ formatted += `Your token is invalid or expired.\n`;
648
+ formatted += `Generate a new one: ${result.quick_links.regenerate_token}\n\n`;
649
+ }
650
+
651
+ formatted += `## Get Started (Free)\n\n`;
652
+
653
+ if (result.setup_instructions) {
654
+ Object.entries(result.setup_instructions).forEach(([key, value]) => {
655
+ if (key.startsWith('step_')) {
656
+ const stepNum = key.replace('step_', '');
657
+ formatted += `${stepNum}. ${value}\n`;
658
+ }
659
+ });
660
+
661
+ if (result.setup_instructions.config_example) {
662
+ formatted += `\n## Configuration Example\n`;
663
+ formatted += `\`\`\`json\n${result.setup_instructions.config_example}\n\`\`\`\n`;
664
+ }
665
+
666
+ if (result.setup_instructions.note) {
667
+ formatted += `\nNote: ${result.setup_instructions.note}\n`;
668
+ }
669
+ }
670
+
671
+ formatted += `\n## Pricing\n`;
672
+ if (result.pricing) {
673
+ formatted += `- Free Tier: ${result.pricing.free_tier}\n`;
674
+ formatted += `- Premium: ${result.pricing.premium_tier}\n`;
675
+ formatted += `- Cost: ${result.pricing.credit_cost}\n`;
676
+ }
677
+
678
+ formatted += `\n## Available Models\n`;
679
+ if (result.available_models) {
680
+ result.available_models.forEach(model => {
681
+ formatted += `- ${model}\n`;
682
+ });
683
+ }
684
+
685
+ if (result.detected_ide && result.detected_ide !== 'unknown') {
686
+ formatted += `\n## Detected IDE\n`;
687
+ formatted += `${result.detected_ide.charAt(0).toUpperCase() + result.detected_ide.slice(1)}\n`;
688
+ }
689
+ }
690
+
691
+ return formatted;
692
+ }
693
+
694
+ /**
695
+ * Browser-based login with automatic token retrieval
696
+ * Implements OAuth Device Authorization Grant (RFC 8628)
697
+ */
698
+ async login(args) {
699
+ const { open_browser = true, timeout_seconds = 300 } = args;
700
+ const deviceAuthUrl = 'https://www.polydev.ai/api/mcp/device-auth';
701
+
702
+ console.error('[Polydev MCP] Initiating browser-based login...');
703
+
704
+ try {
705
+ // Step 1: Request device code from server
706
+ const initResponse = await fetch(deviceAuthUrl, {
707
+ method: 'POST',
708
+ headers: {
709
+ 'Content-Type': 'application/json',
710
+ 'User-Agent': 'polydev-mcp/1.4.0'
711
+ },
712
+ body: JSON.stringify({ action: 'init' })
713
+ });
714
+
715
+ if (!initResponse.ok) {
716
+ const errorText = await initResponse.text();
717
+ throw new Error(`Failed to initiate login: ${errorText}`);
718
+ }
719
+
720
+ const deviceData = await initResponse.json();
721
+ const { device_code, user_code, verification_url, expires_in, interval } = deviceData;
722
+
723
+ console.error(`[Polydev MCP] Device code obtained. User code: ${user_code}`);
724
+ console.error(`[Polydev MCP] Verification URL: ${verification_url}`);
725
+
726
+ // Step 2: Open browser if requested
727
+ if (open_browser) {
728
+ const browserOpened = await this.openBrowser(verification_url);
729
+ if (!browserOpened) {
730
+ console.error('[Polydev MCP] Could not open browser automatically');
731
+ }
732
+ }
733
+
734
+ // Step 3: Poll for token
735
+ const pollInterval = (interval || 5) * 1000; // Convert to ms
736
+ const maxPollTime = Math.min(timeout_seconds, expires_in || 300) * 1000;
737
+ const startTime = Date.now();
738
+
739
+ console.error(`[Polydev MCP] Polling for token (timeout: ${maxPollTime / 1000}s)...`);
740
+
741
+ while (Date.now() - startTime < maxPollTime) {
742
+ await this.sleep(pollInterval);
743
+
744
+ const pollResponse = await fetch(deviceAuthUrl, {
745
+ method: 'POST',
746
+ headers: {
747
+ 'Content-Type': 'application/json',
748
+ 'User-Agent': 'polydev-mcp/1.4.0'
749
+ },
750
+ body: JSON.stringify({
751
+ action: 'poll',
752
+ device_code
753
+ })
754
+ });
755
+
756
+ if (pollResponse.ok) {
757
+ const pollData = await pollResponse.json();
758
+
759
+ if (pollData.status === 'completed' && pollData.token) {
760
+ console.error('[Polydev MCP] Authentication successful!');
761
+
762
+ // Store token in environment for this session
763
+ process.env.POLYDEV_USER_TOKEN = pollData.token;
764
+
765
+ return {
766
+ success: true,
767
+ user_email: pollData.email,
768
+ token: pollData.token,
769
+ credits_remaining: pollData.credits_remaining || 500,
770
+ subscription_tier: pollData.subscription_tier || 'Free',
771
+ message: 'Successfully authenticated! Your token has been configured for this session.',
772
+ next_steps: [
773
+ 'Your token is now active for this session',
774
+ 'Add POLYDEV_USER_TOKEN to your MCP config for persistent access',
775
+ 'Use get_perspectives to query multiple AI models'
776
+ ],
777
+ timestamp: new Date().toISOString()
778
+ };
779
+ }
780
+
781
+ if (pollData.status === 'pending') {
782
+ console.error('[Polydev MCP] Waiting for user to complete authentication...');
783
+ continue;
784
+ }
785
+
786
+ if (pollData.status === 'expired') {
787
+ throw new Error('Login session expired. Please try again.');
788
+ }
789
+
790
+ if (pollData.error) {
791
+ throw new Error(pollData.error);
792
+ }
793
+ }
794
+ }
795
+
796
+ // Timeout reached
797
+ return {
798
+ success: false,
799
+ error: 'timeout',
800
+ message: `Login timed out after ${timeout_seconds} seconds. Please try again.`,
801
+ auth_url: verification_url,
802
+ user_code: user_code,
803
+ instructions: 'Open the URL above and enter the user code to complete authentication.',
804
+ timestamp: new Date().toISOString()
805
+ };
806
+
807
+ } catch (error) {
808
+ console.error('[Polydev MCP] Login error:', error);
809
+ return {
810
+ success: false,
811
+ error: error.message,
812
+ message: 'Login failed. Please try again or use manual token setup.',
813
+ manual_setup_url: 'https://polydev.ai/dashboard/mcp-tools',
814
+ timestamp: new Date().toISOString()
815
+ };
816
+ }
817
+ }
818
+
819
+ /**
820
+ * Open browser to a URL (cross-platform)
821
+ */
822
+ async openBrowser(url) {
823
+ const { exec } = require('child_process');
824
+ const platform = process.platform;
825
+
826
+ let command;
827
+ if (platform === 'darwin') {
828
+ command = `open "${url}"`;
829
+ } else if (platform === 'win32') {
830
+ command = `start "" "${url}"`;
831
+ } else {
832
+ // Linux and others
833
+ command = `xdg-open "${url}" || sensible-browser "${url}" || x-www-browser "${url}"`;
834
+ }
835
+
836
+ return new Promise((resolve) => {
837
+ exec(command, (error) => {
838
+ if (error) {
839
+ console.error('[Polydev MCP] Browser open error:', error.message);
840
+ resolve(false);
841
+ } else {
842
+ console.error('[Polydev MCP] Browser opened successfully');
843
+ resolve(true);
844
+ }
845
+ });
846
+ });
847
+ }
848
+
849
+ /**
850
+ * Sleep utility for polling
851
+ */
852
+ sleep(ms) {
853
+ return new Promise(resolve => setTimeout(resolve, ms));
854
+ }
855
+
856
+ /**
857
+ * Format login response for beautiful output
858
+ */
859
+ formatLoginResponse(result) {
860
+ let formatted = '';
861
+
862
+ if (result.success) {
863
+ formatted += `# Polydev Login Successful\n\n`;
864
+ formatted += `## Account\n`;
865
+ formatted += `Email: ${result.user_email}\n`;
866
+ formatted += `Tier: ${result.subscription_tier}\n`;
867
+ formatted += `Credits: ${result.credits_remaining?.toLocaleString() || 'N/A'}\n\n`;
868
+
869
+ formatted += `## Token\n`;
870
+ formatted += `\`\`\`\n${result.token}\n\`\`\`\n\n`;
871
+
872
+ formatted += `## Next Steps\n`;
873
+ if (result.next_steps) {
874
+ result.next_steps.forEach((step, i) => {
875
+ formatted += `${i + 1}. ${step}\n`;
876
+ });
877
+ }
878
+
879
+ formatted += `\n## Save Token for Persistent Access\n`;
880
+ formatted += `Add this to your MCP configuration:\n`;
881
+ formatted += `\`\`\`json\n`;
882
+ formatted += `{\n`;
883
+ formatted += ` "env": { "POLYDEV_USER_TOKEN": "${result.token}" }\n`;
884
+ formatted += `}\n`;
885
+ formatted += `\`\`\`\n`;
886
+ } else {
887
+ formatted += `# Polydev Login\n\n`;
888
+
889
+ if (result.error === 'timeout') {
890
+ formatted += `## Timeout\n`;
891
+ formatted += `${result.message}\n\n`;
892
+
893
+ if (result.auth_url) {
894
+ formatted += `## Complete Manually\n`;
895
+ formatted += `1. Open: ${result.auth_url}\n`;
896
+ formatted += `2. Enter code: **${result.user_code}**\n`;
897
+ formatted += `3. Run login again after completing\n`;
898
+ }
899
+ } else {
900
+ formatted += `## Error\n`;
901
+ formatted += `${result.message}\n\n`;
902
+
903
+ if (result.manual_setup_url) {
904
+ formatted += `## Manual Setup\n`;
905
+ formatted += `Visit: ${result.manual_setup_url}\n`;
906
+ formatted += `Generate a token and add it to your MCP configuration.\n`;
907
+ }
908
+ }
909
+ }
910
+
911
+ return formatted;
912
+ }
913
+
331
914
  formatResponse(toolName, result) {
332
915
  switch (toolName) {
916
+ case 'get_auth_status':
917
+ return this.formatAuthStatusResponse(result);
918
+
919
+ case 'login':
920
+ return this.formatLoginResponse(result);
921
+
333
922
  case 'get_perspectives':
334
923
  return this.formatPerspectivesResponse(result);
335
924
 
@@ -1712,25 +1712,65 @@ if (require.main === module) {
1712
1712
  * This allows Smithery to discover tools/resources without real credentials
1713
1713
  */
1714
1714
  function createSandboxServer() {
1715
- // Return a minimal server that exposes our tool definitions for scanning
1716
- // No real API calls will be made - this is just for capability discovery
1717
- const fs = require('fs');
1718
- const path = require('path');
1719
-
1720
- const manifestPath = path.join(__dirname, 'manifest.json');
1721
- const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
1722
-
1715
+ // Embed manifest directly to work with Smithery bundling
1716
+ // (file paths don't resolve in bundled context)
1723
1717
  return {
1724
1718
  serverInfo: {
1725
- name: manifest.name,
1726
- version: manifest.version
1719
+ name: 'polydev-perspectives',
1720
+ version: '1.8.70'
1727
1721
  },
1728
1722
  capabilities: { tools: {} },
1729
- tools: manifest.tools.map(tool => ({
1730
- name: tool.name,
1731
- description: tool.description,
1732
- inputSchema: tool.inputSchema
1733
- }))
1723
+ tools: [
1724
+ {
1725
+ name: 'get_perspectives',
1726
+ description: 'Query GPT 5.2, Claude Opus 4.5, Gemini 3, and Grok 4.1 simultaneously for diverse AI perspectives when debugging, making architecture decisions, or reviewing code.',
1727
+ inputSchema: {
1728
+ type: 'object',
1729
+ properties: {
1730
+ prompt: {
1731
+ type: 'string',
1732
+ description: 'The prompt to get perspectives on'
1733
+ },
1734
+ user_token: {
1735
+ type: 'string',
1736
+ description: 'Polydev user authentication token'
1737
+ }
1738
+ },
1739
+ required: ['prompt']
1740
+ }
1741
+ },
1742
+ {
1743
+ name: 'get_cli_status',
1744
+ description: 'Check status of local CLI tools (Claude Code, Codex CLI, Gemini CLI)',
1745
+ inputSchema: {
1746
+ type: 'object',
1747
+ properties: {
1748
+ provider_id: {
1749
+ type: 'string',
1750
+ description: 'Optional specific provider to check'
1751
+ }
1752
+ }
1753
+ }
1754
+ },
1755
+ {
1756
+ name: 'force_cli_detection',
1757
+ description: 'Force re-detection of installed local CLI tools',
1758
+ inputSchema: { type: 'object', properties: {} }
1759
+ },
1760
+ {
1761
+ name: 'send_cli_prompt',
1762
+ description: 'Send prompt to local CLI with perspectives fallback',
1763
+ inputSchema: {
1764
+ type: 'object',
1765
+ properties: {
1766
+ provider_id: { type: 'string', description: 'CLI provider ID' },
1767
+ prompt: { type: 'string', description: 'Prompt to send' },
1768
+ mode: { type: 'string', enum: ['args', 'stdin'], default: 'args' }
1769
+ },
1770
+ required: ['provider_id', 'prompt']
1771
+ }
1772
+ }
1773
+ ]
1734
1774
  };
1735
1775
  }
1736
1776
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polydev-ai",
3
- "version": "1.8.63",
3
+ "version": "1.8.71",
4
4
  "engines": {
5
5
  "node": ">=20.x <=22.x"
6
6
  },
@@ -22,7 +22,8 @@
22
22
  "private": false,
23
23
  "main": "mcp/stdio-wrapper.js",
24
24
  "bin": {
25
- "polydev-stdio": "mcp/stdio-wrapper.js"
25
+ "polydev-stdio": "mcp/stdio-wrapper.js",
26
+ "polydev-ai": "mcp/stdio-wrapper.js"
26
27
  },
27
28
  "files": [
28
29
  "mcp/",