featurely-mcp 1.0.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.
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Featurely MCP Server
4
+ * Gives AI assistants (Claude, Cursor, Windsurf, etc.) complete knowledge
5
+ * of all four Featurely SDK packages:
6
+ * - featurely-error-tracker
7
+ * - featurely-feature-reporter
8
+ * - featurely-site-manager
9
+ * - featurely-i18n
10
+ */
11
+ export {};
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;GAQG"}
package/dist/index.js ADDED
@@ -0,0 +1,886 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Featurely MCP Server
4
+ * Gives AI assistants (Claude, Cursor, Windsurf, etc.) complete knowledge
5
+ * of all four Featurely SDK packages:
6
+ * - featurely-error-tracker
7
+ * - featurely-feature-reporter
8
+ * - featurely-site-manager
9
+ * - featurely-i18n
10
+ */
11
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
12
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
13
+ import { z } from "zod";
14
+ // ─── Documentation corpus ────────────────────────────────────────────────────
15
+ const DOCS = {
16
+ "error-tracker": {
17
+ overview: `featurely-error-tracker — Advanced Error Tracking SDK
18
+
19
+ Track errors in your applications with automatic breadcrumbs, device info,
20
+ toast notifications, performance monitoring, and complete context for reproduction.
21
+
22
+ NPM: https://www.npmjs.com/package/featurely-error-tracker
23
+ Install: npm install featurely-error-tracker
24
+ Required API key permission: errors:write`,
25
+ installation: `# Installation
26
+
27
+ npm install featurely-error-tracker
28
+
29
+ ## Quick Start
30
+ 1. Get your API key from the Featurely dashboard → Settings → API Keys
31
+ 2. Create a key with \`errors:write\` permission
32
+ 3. Initialize the tracker in your app entry point:
33
+
34
+ \`\`\`ts
35
+ import { ErrorTracker } from 'featurely-error-tracker';
36
+
37
+ const tracker = new ErrorTracker({
38
+ apiKey: 'ft_live_your_api_key_here',
39
+ environment: 'production',
40
+ appVersion: '1.0.0',
41
+ });
42
+
43
+ tracker.install(); // Registers global error/unhandledrejection handlers
44
+ tracker.setUser(user.id, user.email); // Call after login
45
+ \`\`\``,
46
+ apiReference: `# ErrorTracker — Full API Reference
47
+
48
+ ## Constructor
49
+
50
+ \`\`\`ts
51
+ new ErrorTracker(config: ErrorTrackerConfig)
52
+ \`\`\`
53
+
54
+ ### ErrorTrackerConfig
55
+
56
+ | Field | Type | Required | Description |
57
+ |-------|------|----------|-------------|
58
+ | apiKey | string | ✅ | API key with errors:write permission |
59
+ | environment | string | ✅ | 'development' | 'staging' | 'production' |
60
+ | appVersion | string | ✅ | Semantic version of your app |
61
+ | toast | ToastConfig | ❌ | Visual error alerts (see below) |
62
+ | performance | PerformanceConfig | ❌ | Web Vitals tracking |
63
+ | offline | OfflineConfig | ❌ | Queue errors when offline |
64
+ | privacy | PrivacyConfig | ❌ | PII scrubbing |
65
+
66
+ ### ToastConfig
67
+ \`\`\`ts
68
+ {
69
+ enabled: boolean; // Show toast on errors
70
+ position: 'top-left' | 'top-center' | 'top-right'
71
+ | 'bottom-left' | 'bottom-center' | 'bottom-right';
72
+ duration: number; // ms; 0 = no auto-dismiss
73
+ showOnAutoCapture: boolean; // Show for automatically caught errors
74
+ }
75
+ \`\`\`
76
+
77
+ ### PerformanceConfig
78
+ \`\`\`ts
79
+ {
80
+ enabled: boolean; // Enable performance monitoring
81
+ trackWebVitals: boolean;// Track LCP, FCP automatically
82
+ sendWithErrors: boolean;// Attach perf data to error reports
83
+ }
84
+ \`\`\`
85
+
86
+ ### OfflineConfig
87
+ \`\`\`ts
88
+ {
89
+ enabled: boolean;
90
+ maxQueueSize: number; // Max errors to queue (default: 50)
91
+ storage: 'localStorage' | 'memory';
92
+ }
93
+ \`\`\`
94
+
95
+ ### PrivacyConfig
96
+ \`\`\`ts
97
+ {
98
+ scrubPII: boolean; // Auto-remove emails, cards, SSNs, phones
99
+ scrubQueryParams: string[]; // URL params to remove (e.g. ['token','apiKey'])
100
+ customPatterns: RegExp[]; // Additional regex patterns to scrub
101
+ }
102
+ \`\`\`
103
+
104
+ ## Methods
105
+
106
+ ### tracker.install()
107
+ Registers global handlers for \`window.onerror\` and \`unhandledrejection\`.
108
+ Call once in your app entry point.
109
+
110
+ ### tracker.setUser(userId: string, email?: string)
111
+ Associate subsequent error reports with a user.
112
+
113
+ ### tracker.reportError(error: Error, severity: Severity, context?: object): Promise<void>
114
+ Manually report an error.
115
+ - severity: 'low' | 'medium' | 'high' | 'critical'
116
+
117
+ ### tracker.showToast(options: ToastOptions): void
118
+ Show a manual toast notification.
119
+ \`\`\`ts
120
+ tracker.showToast({
121
+ message: 'Data saved!',
122
+ style: 'success', // 'error' | 'warning' | 'success' | 'info'
123
+ position: 'top-right',
124
+ duration: 3000,
125
+ closable: true,
126
+ });
127
+ \`\`\`
128
+
129
+ ### tracker.trackPerformance(label: string, startTime: number): void
130
+ Track a custom performance metric.
131
+
132
+ ### tracker.destroy(): void
133
+ Remove global handlers and clean up.`,
134
+ examples: `# Code Examples
135
+
136
+ ## Basic Setup (Vanilla JS / TypeScript)
137
+ \`\`\`ts
138
+ import { ErrorTracker } from 'featurely-error-tracker';
139
+
140
+ const tracker = new ErrorTracker({
141
+ apiKey: 'ft_live_your_api_key_here',
142
+ environment: 'production',
143
+ appVersion: '1.0.0',
144
+ });
145
+ tracker.install();
146
+ \`\`\`
147
+
148
+ ## Manual Error Reporting
149
+ \`\`\`ts
150
+ try {
151
+ await riskyOperation();
152
+ } catch (error) {
153
+ await tracker.reportError(error, 'high', {
154
+ userId: user.id,
155
+ action: 'risky_operation',
156
+ });
157
+ }
158
+ \`\`\`
159
+
160
+ ## With Toast Notifications
161
+ \`\`\`ts
162
+ const tracker = new ErrorTracker({
163
+ apiKey: 'ft_live_your_api_key_here',
164
+ environment: 'production',
165
+ appVersion: '1.0.0',
166
+ toast: {
167
+ enabled: true,
168
+ position: 'top-right',
169
+ duration: 5000,
170
+ showOnAutoCapture: true,
171
+ },
172
+ });
173
+ tracker.install();
174
+ \`\`\`
175
+
176
+ ## With All Advanced Features
177
+ \`\`\`ts
178
+ const tracker = new ErrorTracker({
179
+ apiKey: 'ft_live_your_api_key_here',
180
+ environment: 'production',
181
+ appVersion: '1.0.0',
182
+ performance: {
183
+ enabled: true,
184
+ trackWebVitals: true,
185
+ sendWithErrors: true,
186
+ },
187
+ offline: {
188
+ enabled: true,
189
+ maxQueueSize: 50,
190
+ storage: 'localStorage',
191
+ },
192
+ privacy: {
193
+ scrubPII: true,
194
+ scrubQueryParams: ['token', 'apiKey', 'password', 'secret'],
195
+ customPatterns: [/api[_-]?key/gi],
196
+ },
197
+ });
198
+ tracker.install();
199
+ \`\`\`
200
+
201
+ ## React Integration
202
+ \`\`\`tsx
203
+ 'use client';
204
+ import { useEffect } from 'react';
205
+ import { ErrorTracker } from 'featurely-error-tracker';
206
+
207
+ let tracker: ErrorTracker | null = null;
208
+
209
+ export function ErrorTrackerProvider({ children, user }) {
210
+ useEffect(() => {
211
+ if (!tracker) {
212
+ tracker = new ErrorTracker({
213
+ apiKey: process.env.NEXT_PUBLIC_FEATURELY_API_KEY!,
214
+ environment: process.env.NODE_ENV,
215
+ appVersion: process.env.NEXT_PUBLIC_APP_VERSION ?? '1.0.0',
216
+ });
217
+ tracker.install();
218
+ }
219
+ if (user) tracker.setUser(user.id, user.email);
220
+ return () => { tracker?.destroy(); tracker = null; };
221
+ }, [user]);
222
+
223
+ return <>{children}</>;
224
+ }
225
+ \`\`\``,
226
+ },
227
+ "feature-reporter": {
228
+ overview: `featurely-feature-reporter — Embeddable Feedback Widget
229
+
230
+ Embeddable widget for collecting user feature requests and bug reports.
231
+ Beautiful UI, screenshot capture, customizable colors, seamless Featurely dashboard integration.
232
+
233
+ NPM: https://www.npmjs.com/package/featurely-feature-reporter
234
+ Install: npm install featurely-feature-reporter
235
+ Required API key permission: features:write`,
236
+ installation: `# Installation
237
+
238
+ npm install featurely-feature-reporter
239
+
240
+ ## Quick Start
241
+ 1. Get your API key from the Featurely dashboard → Settings → API Keys
242
+ 2. Create a key with \`features:write\` permission
243
+ 3. Find your project ID in the Featurely dashboard URL
244
+ 4. Initialize the widget:
245
+
246
+ \`\`\`ts
247
+ import { FeatureReporter } from 'featurely-feature-reporter';
248
+
249
+ const reporter = new FeatureReporter({
250
+ apiKey: 'ft_live_your_api_key_here',
251
+ projectId: 'your-project-id',
252
+ position: 'bottom-right',
253
+ color: 'blue',
254
+ });
255
+ reporter.init();
256
+ \`\`\``,
257
+ apiReference: `# FeatureReporter — Full API Reference
258
+
259
+ ## Constructor
260
+
261
+ \`\`\`ts
262
+ new FeatureReporter(config: FeatureReporterConfig)
263
+ \`\`\`
264
+
265
+ ### FeatureReporterConfig
266
+
267
+ | Field | Type | Required | Description |
268
+ |-------|------|----------|-------------|
269
+ | apiKey | string | ✅ | API key with features:write permission |
270
+ | projectId | string | ✅ | Your Featurely project ID |
271
+ | position | Position | ❌ | Widget placement (default: 'bottom-right') |
272
+ | color | Color | ❌ | Widget color theme (default: 'blue') |
273
+ | icon | Icon | ❌ | Widget button icon (default: 'comment') |
274
+ | draggable | boolean | ❌ | Allow users to drag widget |
275
+ | enableFeatureRequests | boolean | ❌ | Show feature request form (default: true) |
276
+ | enableBugReports | boolean | ❌ | Show bug report form (default: true) |
277
+ | showDashboardLink | boolean | ❌ | Show link to public board (default: false) |
278
+ | labels | LabelsConfig | ❌ | Custom text overrides |
279
+ | onSubmit | function | ❌ | Callback on submission |
280
+ | onError | function | ❌ | Callback on error |
281
+
282
+ ### Position options
283
+ 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left' | 'right-center' | 'left-center'
284
+
285
+ ### Color options
286
+ 'blue' | 'green' | 'purple' | 'red' | 'orange' | 'pink'
287
+
288
+ ### Icon options
289
+ 'comment' | 'lightbulb' | 'bug' | 'message' | 'plus' | 'star'
290
+
291
+ ### LabelsConfig
292
+ \`\`\`ts
293
+ {
294
+ widgetTooltip?: string; // Default: 'Feedback'
295
+ featureRequestTitle?: string; // Default: 'Request a Feature'
296
+ bugReportTitle?: string; // Default: 'Report a Bug'
297
+ submitButton?: string; // Default: 'Send'
298
+ cancelButton?: string; // Default: 'Cancel'
299
+ }
300
+ \`\`\`
301
+
302
+ ## Methods
303
+
304
+ ### reporter.init(): void
305
+ Mount and render the widget on the page. Call once.
306
+
307
+ ### reporter.setUser(userId: string, email?: string, name?: string): void
308
+ Associate submissions with a user. Call after login.
309
+
310
+ ### reporter.show(): void
311
+ Programmatically show the widget button.
312
+
313
+ ### reporter.hide(): void
314
+ Programmatically hide the widget button.
315
+
316
+ ### reporter.destroy(): void
317
+ Remove the widget from the DOM. Call before unmounting.`,
318
+ examples: `# Code Examples
319
+
320
+ ## Basic Setup
321
+ \`\`\`ts
322
+ import { FeatureReporter } from 'featurely-feature-reporter';
323
+
324
+ const reporter = new FeatureReporter({
325
+ apiKey: 'ft_live_your_api_key_here',
326
+ projectId: 'your-project-id',
327
+ position: 'bottom-right',
328
+ color: 'blue',
329
+ });
330
+ reporter.init();
331
+ reporter.setUser(user.id, user.email, user.name);
332
+ \`\`\`
333
+
334
+ ## Fully Customised
335
+ \`\`\`ts
336
+ const reporter = new FeatureReporter({
337
+ apiKey: 'ft_live_your_api_key_here',
338
+ projectId: 'your-project-id',
339
+ position: 'bottom-right',
340
+ color: 'purple',
341
+ icon: 'lightbulb',
342
+ draggable: true,
343
+ enableFeatureRequests: true,
344
+ enableBugReports: true,
345
+ labels: {
346
+ widgetTooltip: 'Feedback',
347
+ featureRequestTitle: 'Suggest a Feature',
348
+ bugReportTitle: 'Report a Problem',
349
+ submitButton: 'Send Feedback',
350
+ },
351
+ onSubmit: (type, data) => {
352
+ console.log(\`\${type} submitted\`, data);
353
+ },
354
+ });
355
+ reporter.init();
356
+ \`\`\`
357
+
358
+ ## React Integration (Next.js App Router)
359
+ \`\`\`tsx
360
+ 'use client';
361
+ import { useEffect } from 'react';
362
+ import { FeatureReporter } from 'featurely-feature-reporter';
363
+
364
+ let reporter: FeatureReporter | null = null;
365
+
366
+ export function FeedbackWidget({ user }) {
367
+ useEffect(() => {
368
+ if (!reporter) {
369
+ reporter = new FeatureReporter({
370
+ apiKey: process.env.NEXT_PUBLIC_FEATURELY_API_KEY!,
371
+ projectId: process.env.NEXT_PUBLIC_PROJECT_ID!,
372
+ position: 'bottom-right',
373
+ color: 'blue',
374
+ });
375
+ reporter.init();
376
+ }
377
+ if (user) reporter.setUser(user.id, user.email, user.name);
378
+ return () => { reporter?.destroy(); reporter = null; };
379
+ }, [user]);
380
+
381
+ return null; // Widget renders itself into document.body
382
+ }
383
+ \`\`\``,
384
+ },
385
+ "site-manager": {
386
+ overview: `featurely-site-manager — Comprehensive Site Management SDK
387
+
388
+ Maintenance mode, status messages, feature flags, A/B testing, version management,
389
+ and analytics. Control your app's features and communicate with users from the Featurely dashboard.
390
+
391
+ NPM: https://www.npmjs.com/package/featurely-site-manager
392
+ Install: npm install featurely-site-manager
393
+ Required API key permission: public:read
394
+ Bundle size: ESM 25.53 KB`,
395
+ installation: `# Installation
396
+
397
+ npm install featurely-site-manager
398
+
399
+ ## Quick Start
400
+ 1. Get your API key from the Featurely dashboard → Settings → API Keys
401
+ 2. Create a key with \`public:read\` permission
402
+ 3. Configure maintenance/flags/messages in Settings → Site Management
403
+ 4. Initialize the manager:
404
+
405
+ \`\`\`ts
406
+ import { SiteManager } from 'featurely-site-manager';
407
+
408
+ const manager = new SiteManager({
409
+ apiKey: 'ft_live_your_api_key_here',
410
+ projectId: 'your-project-id',
411
+ pollInterval: 60000, // Check every 60s
412
+ });
413
+ await manager.init();
414
+ \`\`\``,
415
+ apiReference: `# SiteManager — Full API Reference
416
+
417
+ ## Constructor
418
+
419
+ \`\`\`ts
420
+ new SiteManager(config: SiteManagerConfig)
421
+ \`\`\`
422
+
423
+ ### SiteManagerConfig
424
+
425
+ | Field | Type | Required | Description |
426
+ |-------|------|----------|-------------|
427
+ | apiKey | string | ✅ | API key with public:read permission |
428
+ | projectId | string | ✅ | Your Featurely project ID |
429
+ | apiUrl | string | ❌ | Custom API base URL |
430
+ | pollInterval | number | ❌ | Update check interval ms (default: 60000) |
431
+ | userEmail | string | ❌ | For maintenance whitelist check |
432
+ | userId | string | ❌ | For feature flag bucketing & analytics |
433
+ | enableAnalytics | boolean | ❌ | Track events (default: true) |
434
+ | analyticsFlushInterval | number | ❌ | Send events interval ms (default: 60000) |
435
+ | appVersion | string | ❌ | Current version for version-check |
436
+ | enableVersionCheck | boolean | ❌ | Enable version polling (default: false) |
437
+ | versionCheckInterval | number | ❌ | Version check interval ms (default: 3600000) |
438
+ | bypassCheck | () => boolean | ❌ | Custom maintenance bypass logic |
439
+ | onMaintenanceEnabled | (config) => void | ❌ | Callback when maintenance starts |
440
+ | onMaintenanceDisabled | () => void | ❌ | Callback when maintenance ends |
441
+ | onMessageReceived | (message) => void | ❌ | Callback for new status messages |
442
+ | onMessageDismissed | (id) => void | ❌ | Callback when message dismissed |
443
+ | onFeatureFlagsUpdated | (flags) => void | ❌ | Callback when flags change |
444
+ | onUpdateAvailable | (info) => void | ❌ | Callback when newer version available |
445
+ | onUpdateRequired | (info) => void | ❌ | Callback when update is mandatory |
446
+ | onError | (error) => void | ❌ | Global error callback |
447
+
448
+ ## Methods
449
+
450
+ ### manager.init(): Promise<void>
451
+ Initialize and start polling. Must be awaited.
452
+
453
+ ### manager.isInMaintenanceMode(): boolean
454
+ Returns true if maintenance mode is currently active.
455
+
456
+ ### manager.getActiveMessages(): StatusMessage[]
457
+ Returns all currently active status messages.
458
+ - StatusMessage: { id, type: 'info'|'warning'|'error'|'success', content, position: 'top'|'bottom', style: 'banner'|'toast', priority }
459
+
460
+ ### manager.isFeatureEnabled(flagKey: string): boolean
461
+ Returns true if the feature flag is enabled for the current user/session.
462
+
463
+ ### manager.getFeatureVariant(flagKey: string): string | null
464
+ Returns the A/B variant string for the flag, or null if not in experiment.
465
+
466
+ ### manager.getAllFeatureFlags(): FeatureFlag[]
467
+ Returns all feature flags (enabled and disabled).
468
+
469
+ ### manager.getEnabledFeatures(): string[]
470
+ Returns array of enabled flag keys.
471
+
472
+ ### manager.trackEvent(name: string, properties?: Record<string, unknown>): void
473
+ Track a custom analytics event. Batched and sent on flush interval.
474
+
475
+ ### manager.refresh(): Promise<void>
476
+ Manually trigger a configuration poll immediately.
477
+
478
+ ### manager.destroy(): void
479
+ Stop polling and flush pending analytics. Call before unmounting.`,
480
+ examples: `# Code Examples
481
+
482
+ ## Basic Setup
483
+ \`\`\`ts
484
+ import { SiteManager } from 'featurely-site-manager';
485
+
486
+ const manager = new SiteManager({
487
+ apiKey: 'ft_live_your_api_key_here',
488
+ projectId: 'your-project-id',
489
+ userEmail: user?.email,
490
+ userId: user?.id,
491
+ });
492
+ await manager.init();
493
+ \`\`\`
494
+
495
+ ## Feature Flags
496
+ \`\`\`ts
497
+ // Check if feature is enabled
498
+ if (manager.isFeatureEnabled('new-checkout')) {
499
+ renderNewCheckout();
500
+ }
501
+
502
+ // A/B testing
503
+ const variant = manager.getFeatureVariant('checkout-flow');
504
+ if (variant === 'variant-a') {
505
+ renderVariantA();
506
+ } else {
507
+ renderVariantB();
508
+ }
509
+
510
+ // Get all enabled flags
511
+ const enabled = manager.getEnabledFeatures();
512
+ console.log('Active features:', enabled);
513
+ \`\`\`
514
+
515
+ ## Maintenance Mode
516
+ \`\`\`ts
517
+ const manager = new SiteManager({
518
+ apiKey: 'ft_live_your_api_key_here',
519
+ projectId: 'your-project-id',
520
+ userEmail: user?.email,
521
+ onMaintenanceEnabled: (config) => {
522
+ router.push('/maintenance');
523
+ },
524
+ onMaintenanceDisabled: () => {
525
+ router.push('/');
526
+ },
527
+ });
528
+ await manager.init();
529
+
530
+ const isMaintenance = manager.isInMaintenanceMode();
531
+ \`\`\`
532
+
533
+ ## Status Messages
534
+ \`\`\`ts
535
+ const manager = new SiteManager({
536
+ apiKey: 'ft_live_your_api_key_here',
537
+ projectId: 'your-project-id',
538
+ onMessageReceived: (message) => {
539
+ showBanner(message.content, message.type);
540
+ },
541
+ });
542
+ await manager.init();
543
+
544
+ const messages = manager.getActiveMessages();
545
+ \`\`\`
546
+
547
+ ## Analytics
548
+ \`\`\`ts
549
+ // Track custom events
550
+ manager.trackEvent('checkout_started', { cartValue: 99.99 });
551
+ manager.trackEvent('button_clicked', { button: 'signup', page: '/home' });
552
+ \`\`\`
553
+
554
+ ## Version Checking
555
+ \`\`\`ts
556
+ const manager = new SiteManager({
557
+ apiKey: 'ft_live_your_api_key_here',
558
+ projectId: 'your-project-id',
559
+ appVersion: '1.2.3',
560
+ enableVersionCheck: true,
561
+ onUpdateRequired: (info) => {
562
+ alert(\`Update required! Please upgrade to \${info.latestVersion.version}\`);
563
+ },
564
+ onUpdateAvailable: (info) => {
565
+ console.log('New version available:', info.latestVersion.version);
566
+ },
567
+ });
568
+ await manager.init();
569
+ \`\`\`
570
+
571
+ ## React Integration (Next.js)
572
+ \`\`\`tsx
573
+ 'use client';
574
+ import { useEffect } from 'react';
575
+ import { SiteManager } from 'featurely-site-manager';
576
+
577
+ let manager: SiteManager | null = null;
578
+
579
+ export function SiteManagerProvider({ children, user }) {
580
+ useEffect(() => {
581
+ if (!manager) {
582
+ manager = new SiteManager({
583
+ apiKey: process.env.NEXT_PUBLIC_FEATURELY_API_KEY!,
584
+ projectId: process.env.NEXT_PUBLIC_PROJECT_ID!,
585
+ userEmail: user?.email,
586
+ userId: user?.id,
587
+ });
588
+ manager.init();
589
+ }
590
+ return () => { manager?.destroy(); manager = null; };
591
+ }, [user]);
592
+
593
+ return <>{children}</>;
594
+ }
595
+ \`\`\``,
596
+ },
597
+ "i18n": {
598
+ overview: `featurely-i18n — Lightweight i18n Client
599
+
600
+ Fetch and cache translation keys from your Featurely project.
601
+ Manage all translations in the dashboard, serve via public API with ETag-based caching.
602
+
603
+ NPM: https://www.npmjs.com/package/featurely-i18n
604
+ Install: npm install featurely-i18n
605
+ Required API key permission: public:read`,
606
+ installation: `# Installation
607
+
608
+ npm install featurely-i18n
609
+
610
+ ## Quick Start
611
+ 1. Add translation keys in Featurely dashboard → Translations
612
+ 2. Get your API key from Settings → API Keys with \`public:read\` permission
613
+ 3. Initialize and load:
614
+
615
+ \`\`\`ts
616
+ import { FeaturelyI18n } from 'featurely-i18n';
617
+
618
+ const i18n = new FeaturelyI18n({
619
+ apiKey: 'ft_live_your_api_key_here',
620
+ locale: 'en',
621
+ fallbackLocale: 'en',
622
+ });
623
+ await i18n.load();
624
+
625
+ const label = i18n.t('button.submit'); // "Submit"
626
+ const msg = i18n.t('greeting', { name: 'Ada' }); // "Hello, Ada!"
627
+ \`\`\``,
628
+ apiReference: `# FeaturelyI18n — Full API Reference
629
+
630
+ ## Constructor
631
+
632
+ \`\`\`ts
633
+ new FeaturelyI18n(config: FeaturelyI18nConfig)
634
+ \`\`\`
635
+
636
+ ### FeaturelyI18nConfig
637
+
638
+ | Field | Type | Required | Description |
639
+ |-------|------|----------|-------------|
640
+ | apiKey | string | ✅ | API key with public:read permission |
641
+ | locale | string | ✅ | Active locale (e.g. 'en', 'nb', 'de') |
642
+ | fallbackLocale | string | ❌ | Used when a key is missing in active locale |
643
+
644
+ ## Properties
645
+
646
+ ### i18n.locale: string
647
+ The currently active locale.
648
+
649
+ ### i18n.translations: Record<string, string>
650
+ All loaded translation key-value pairs for the active locale.
651
+
652
+ ## Methods
653
+
654
+ ### i18n.load(): Promise<void>
655
+ Fetch translations from the API. Respects ETag — returns immediately if nothing changed.
656
+ Always call this before using \`t()\`.
657
+
658
+ ### i18n.t(key: string, variables?: Record<string, string | number>): string
659
+ Translate a key. Supports \`{variable}\` interpolation.
660
+ Falls back to fallbackLocale if key is missing. Returns the key itself if not found anywhere.
661
+
662
+ ### i18n.setLocale(locale: string): Promise<void>
663
+ Switch locale and automatically reload translations.
664
+
665
+ ## Direct REST API
666
+
667
+ \`\`\`
668
+ GET /api/public/v1/translations?locale={locale}
669
+ Headers: X-API-Key: ft_live_...
670
+ \`\`\`
671
+
672
+ Response: \`{ translations: Record<string, string>, hash: string, locale: string }\`
673
+
674
+ Use \`hash\` as \`If-None-Match\` header on subsequent requests.
675
+ Returns \`304 Not Modified\` when nothing has changed (no body).`,
676
+ examples: `# Code Examples
677
+
678
+ ## Basic Usage
679
+ \`\`\`ts
680
+ import { FeaturelyI18n } from 'featurely-i18n';
681
+
682
+ const i18n = new FeaturelyI18n({
683
+ apiKey: 'ft_live_your_api_key_here',
684
+ locale: 'en',
685
+ fallbackLocale: 'en',
686
+ });
687
+ await i18n.load();
688
+
689
+ i18n.t('button.submit'); // "Submit"
690
+ i18n.t('greeting', { name: 'Ada' }); // "Hello, Ada!"
691
+ i18n.t('items.count', { count: 5 }); // "5 items"
692
+ \`\`\`
693
+
694
+ ## Locale Switching
695
+ \`\`\`ts
696
+ await i18n.setLocale('nb'); // Fetches Norwegian translations
697
+ console.log(i18n.locale); // "nb"
698
+ console.log(i18n.translations); // { "button.submit": "Send inn", ... }
699
+ \`\`\`
700
+
701
+ ## Direct API (with ETag caching)
702
+ \`\`\`ts
703
+ // First request — fetches all translations
704
+ const res = await fetch('/api/public/v1/translations?locale=en', {
705
+ headers: { 'X-API-Key': 'ft_live_your_api_key_here' },
706
+ });
707
+ const { translations, hash } = await res.json();
708
+
709
+ // Subsequent requests — 304 if nothing changed
710
+ const cached = await fetch('/api/public/v1/translations?locale=en', {
711
+ headers: {
712
+ 'X-API-Key': 'ft_live_your_api_key_here',
713
+ 'If-None-Match': hash,
714
+ },
715
+ });
716
+ // cached.status === 304 → use previously fetched translations
717
+ \`\`\`
718
+
719
+ ## React Integration
720
+ \`\`\`tsx
721
+ 'use client';
722
+ import { createContext, useContext, useEffect, useState } from 'react';
723
+ import { FeaturelyI18n } from 'featurely-i18n';
724
+
725
+ const i18n = new FeaturelyI18n({
726
+ apiKey: process.env.NEXT_PUBLIC_FEATURELY_API_KEY!,
727
+ locale: 'en',
728
+ fallbackLocale: 'en',
729
+ });
730
+
731
+ const I18nContext = createContext(i18n);
732
+
733
+ export function I18nProvider({ children, locale = 'en' }) {
734
+ const [ready, setReady] = useState(false);
735
+ useEffect(() => {
736
+ i18n.setLocale(locale).then(() => setReady(true));
737
+ }, [locale]);
738
+ if (!ready) return null;
739
+ return <I18nContext.Provider value={i18n}>{children}</I18nContext.Provider>;
740
+ }
741
+
742
+ export function useTranslation() {
743
+ const i18n = useContext(I18nContext);
744
+ return { t: i18n.t.bind(i18n), locale: i18n.locale };
745
+ }
746
+
747
+ // Usage:
748
+ // const { t } = useTranslation();
749
+ // <button>{t('button.submit')}</button>
750
+ \`\`\`
751
+
752
+ ## Next.js Server Component (SSR)
753
+ \`\`\`ts
754
+ // app/[locale]/layout.tsx
755
+ import { FeaturelyI18n } from 'featurely-i18n';
756
+
757
+ async function getTranslations(locale: string) {
758
+ const i18n = new FeaturelyI18n({
759
+ apiKey: process.env.FEATURELY_API_KEY!,
760
+ locale,
761
+ });
762
+ await i18n.load();
763
+ return i18n.translations;
764
+ }
765
+
766
+ export default async function RootLayout({ children, params }) {
767
+ const translations = await getTranslations(params.locale);
768
+ return <html><body>{children}</body></html>;
769
+ }
770
+ \`\`\``,
771
+ },
772
+ };
773
+ const PACKAGE_IDS = Object.keys(DOCS);
774
+ const PACKAGES_OVERVIEW = `# Featurely SDK Packages — Overview
775
+
776
+ Featurely provides four SDK packages for integrating with the Featurely platform:
777
+
778
+ ## 1. featurely-error-tracker
779
+ Track errors automatically with breadcrumbs, device info, performance monitoring,
780
+ PII scrubbing, and offline queuing. Toast notifications for visual alerts.
781
+ - Install: \`npm install featurely-error-tracker\`
782
+ - Permission needed: \`errors:write\`
783
+ - Main class: \`ErrorTracker\`
784
+
785
+ ## 2. featurely-feature-reporter
786
+ Embeddable feedback widget — collects feature requests and bug reports from users.
787
+ Screenshot capture, 6 positions, 6 color themes, fully customisable labels.
788
+ - Install: \`npm install featurely-feature-reporter\`
789
+ - Permission needed: \`features:write\`
790
+ - Main class: \`FeatureReporter\`
791
+
792
+ ## 3. featurely-site-manager
793
+ Control your app remotely: maintenance mode, status banners, feature flags,
794
+ A/B testing, version management, and analytics tracking. Polls for updates.
795
+ - Install: \`npm install featurely-site-manager\`
796
+ - Permission needed: \`public:read\`
797
+ - Main class: \`SiteManager\`
798
+
799
+ ## 4. featurely-i18n
800
+ Lightweight i18n client — fetch and cache translations from Featurely by locale.
801
+ ETag-based caching, variable interpolation, runtime locale switching.
802
+ - Install: \`npm install featurely-i18n\`
803
+ - Permission needed: \`public:read\`
804
+ - Main class: \`FeaturelyI18n\`
805
+
806
+ ## All packages require:
807
+ - A Featurely account and project at https://featurely.no
808
+ - An API key from Settings → API Keys in the dashboard
809
+ - Node.js ≥ 14 (≥ 18 for server-side usage)
810
+ - TypeScript support is built-in (full type definitions included)
811
+ `;
812
+ // ─── MCP Server ───────────────────────────────────────────────────────────────
813
+ const server = new McpServer({
814
+ name: "featurely",
815
+ version: "1.0.0",
816
+ });
817
+ // Resource: overview of all packages
818
+ server.resource("packages-overview", "featurely://packages", async () => ({
819
+ contents: [
820
+ {
821
+ uri: "featurely://packages",
822
+ mimeType: "text/markdown",
823
+ text: PACKAGES_OVERVIEW,
824
+ },
825
+ ],
826
+ }));
827
+ // Resource: one per package
828
+ for (const pkgId of PACKAGE_IDS) {
829
+ const pkg = DOCS[pkgId];
830
+ server.resource(`package-${pkgId}`, `featurely://${pkgId}`, async () => ({
831
+ contents: [
832
+ {
833
+ uri: `featurely://${pkgId}`,
834
+ mimeType: "text/markdown",
835
+ text: [
836
+ pkg.overview,
837
+ pkg.installation,
838
+ pkg.apiReference,
839
+ pkg.examples,
840
+ ].join("\n\n---\n\n"),
841
+ },
842
+ ],
843
+ }));
844
+ }
845
+ // Tool: list all packages
846
+ server.tool("list_packages", "List all Featurely SDK packages with a short description and install command. Use this first to discover what's available.", {}, async () => ({
847
+ content: [{ type: "text", text: PACKAGES_OVERVIEW }],
848
+ }));
849
+ // Tool: full docs for one package
850
+ server.tool("get_package_docs", "Get complete documentation for a specific Featurely SDK package, including overview, installation, full API reference, and code examples.", {
851
+ package: z
852
+ .enum(["error-tracker", "feature-reporter", "site-manager", "i18n"])
853
+ .describe("Which package: 'error-tracker' (track errors), 'feature-reporter' (feedback widget), 'site-manager' (feature flags / maintenance / messages), 'i18n' (translations)"),
854
+ }, async ({ package: pkg }) => {
855
+ const d = DOCS[pkg];
856
+ const text = [d.overview, d.installation, d.apiReference, d.examples].join("\n\n---\n\n");
857
+ return { content: [{ type: "text", text }] };
858
+ });
859
+ // Tool: installation guide only
860
+ server.tool("get_installation_guide", "Get the installation and quick-start guide for a Featurely SDK package.", {
861
+ package: z
862
+ .enum(["error-tracker", "feature-reporter", "site-manager", "i18n"])
863
+ .describe("Which package to get installation steps for."),
864
+ }, async ({ package: pkg }) => ({
865
+ content: [{ type: "text", text: DOCS[pkg].installation }],
866
+ }));
867
+ // Tool: API reference only
868
+ server.tool("get_api_reference", "Get the full API reference (constructor config, all methods, all types) for a Featurely SDK package.", {
869
+ package: z
870
+ .enum(["error-tracker", "feature-reporter", "site-manager", "i18n"])
871
+ .describe("Which package API to look up."),
872
+ }, async ({ package: pkg }) => ({
873
+ content: [{ type: "text", text: DOCS[pkg].apiReference }],
874
+ }));
875
+ // Tool: code examples
876
+ server.tool("get_code_examples", "Get runnable code examples for a Featurely SDK package. Includes basic setup, framework integrations (React, Next.js), and advanced usage patterns.", {
877
+ package: z
878
+ .enum(["error-tracker", "feature-reporter", "site-manager", "i18n"])
879
+ .describe("Which package to get examples for."),
880
+ }, async ({ package: pkg }) => ({
881
+ content: [{ type: "text", text: DOCS[pkg].examples }],
882
+ }));
883
+ // ─── Start ────────────────────────────────────────────────────────────────────
884
+ const transport = new StdioServerTransport();
885
+ await server.connect(transport);
886
+ //# 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/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "featurely-mcp",
3
+ "version": "1.0.0",
4
+ "description": "MCP server for all Featurely SDK packages — gives AI assistants full knowledge of featurely-error-tracker, featurely-feature-reporter, featurely-site-manager, and featurely-i18n",
5
+ "type": "module",
6
+ "bin": {
7
+ "featurely-mcp": "./dist/index.js"
8
+ },
9
+ "exports": {
10
+ ".": "./dist/index.js"
11
+ },
12
+ "files": [
13
+ "dist",
14
+ "README.md"
15
+ ],
16
+ "scripts": {
17
+ "build": "tsc",
18
+ "dev": "tsc --watch",
19
+ "start": "node dist/index.js",
20
+ "prepublishOnly": "npm run build"
21
+ },
22
+ "keywords": [
23
+ "mcp",
24
+ "model-context-protocol",
25
+ "featurely",
26
+ "ai",
27
+ "llm",
28
+ "claude",
29
+ "cursor",
30
+ "sdk-docs"
31
+ ],
32
+ "author": "Featurely",
33
+ "license": "MIT",
34
+ "homepage": "https://featurely.no",
35
+ "dependencies": {
36
+ "@modelcontextprotocol/sdk": "^1.12.0",
37
+ "zod": "^3.24.0"
38
+ },
39
+ "devDependencies": {
40
+ "typescript": "^5.3.0",
41
+ "@types/node": "^20.0.0"
42
+ },
43
+ "engines": {
44
+ "node": ">=18.0.0"
45
+ }
46
+ }