@framingui/mcp-server 0.6.26 → 0.6.28
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 +4 -3
- package/dist/__tests__/react-native-contract.test.d.ts +2 -0
- package/dist/__tests__/react-native-contract.test.d.ts.map +1 -0
- package/dist/__tests__/react-native-contract.test.js +50 -0
- package/dist/__tests__/react-native-contract.test.js.map +1 -0
- package/dist/auth/state.d.ts +16 -0
- package/dist/auth/state.d.ts.map +1 -1
- package/dist/auth/state.js +54 -15
- package/dist/auth/state.js.map +1 -1
- package/dist/auth/verify.d.ts +9 -0
- package/dist/auth/verify.d.ts.map +1 -1
- package/dist/auth/verify.js.map +1 -1
- package/dist/billing/quota-policy.d.ts +13 -0
- package/dist/billing/quota-policy.d.ts.map +1 -0
- package/dist/billing/quota-policy.js +32 -0
- package/dist/billing/quota-policy.js.map +1 -0
- package/dist/billing/tool-metering.d.ts +10 -0
- package/dist/billing/tool-metering.d.ts.map +1 -0
- package/dist/billing/tool-metering.js +126 -0
- package/dist/billing/tool-metering.js.map +1 -0
- package/dist/billing/usage-ledger.d.ts +61 -0
- package/dist/billing/usage-ledger.d.ts.map +1 -0
- package/dist/billing/usage-ledger.js +102 -0
- package/dist/billing/usage-ledger.js.map +1 -0
- package/dist/billing/usage-sync.d.ts +3 -0
- package/dist/billing/usage-sync.d.ts.map +1 -0
- package/dist/billing/usage-sync.js +40 -0
- package/dist/billing/usage-sync.js.map +1 -0
- package/dist/cli/agent-md-templates.d.ts.map +1 -1
- package/dist/cli/agent-md-templates.js +58 -38
- package/dist/cli/agent-md-templates.js.map +1 -1
- package/dist/cli/commands.d.ts +2 -0
- package/dist/cli/commands.d.ts.map +1 -0
- package/dist/cli/commands.js +20 -0
- package/dist/cli/commands.js.map +1 -0
- package/dist/cli/guide-template.d.ts.map +1 -1
- package/dist/cli/guide-template.js +20 -36
- package/dist/cli/guide-template.js.map +1 -1
- package/dist/cli/help.d.ts +5 -0
- package/dist/cli/help.d.ts.map +1 -0
- package/dist/cli/help.js +59 -0
- package/dist/cli/help.js.map +1 -0
- package/dist/cli/init.d.ts +2 -3
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +33 -48
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/package-manager.d.ts +5 -0
- package/dist/cli/package-manager.d.ts.map +1 -0
- package/dist/cli/package-manager.js +34 -0
- package/dist/cli/package-manager.js.map +1 -0
- package/dist/cli/update.d.ts +8 -0
- package/dist/cli/update.d.ts.map +1 -0
- package/dist/cli/update.js +53 -0
- package/dist/cli/update.js.map +1 -0
- package/dist/commands/slash-command-adapters.d.ts +9 -0
- package/dist/commands/slash-command-adapters.d.ts.map +1 -0
- package/dist/commands/slash-command-adapters.js +116 -0
- package/dist/commands/slash-command-adapters.js.map +1 -0
- package/dist/data/component-fallback-catalog.d.ts +26 -0
- package/dist/data/component-fallback-catalog.d.ts.map +1 -0
- package/dist/data/component-fallback-catalog.js +149 -0
- package/dist/data/component-fallback-catalog.js.map +1 -0
- package/dist/data/component-props.d.ts +30 -0
- package/dist/data/component-props.d.ts.map +1 -0
- package/dist/data/component-props.js +537 -0
- package/dist/data/component-props.js.map +1 -0
- package/dist/data/component-registry.d.ts +30 -0
- package/dist/data/component-registry.d.ts.map +1 -0
- package/dist/data/component-registry.js +320 -0
- package/dist/data/component-registry.js.map +1 -0
- package/dist/data/examples/screen-examples.d.ts +38 -0
- package/dist/data/examples/screen-examples.d.ts.map +1 -0
- package/dist/data/examples/screen-examples.js +500 -0
- package/dist/data/examples/screen-examples.js.map +1 -0
- package/dist/data/react-native-runtime-catalog.d.ts +24 -0
- package/dist/data/react-native-runtime-catalog.d.ts.map +1 -0
- package/dist/data/react-native-runtime-catalog.js +265 -0
- package/dist/data/react-native-runtime-catalog.js.map +1 -0
- package/dist/index.js +225 -205
- package/dist/index.js.map +1 -1
- package/dist/platform-support.d.ts +22 -0
- package/dist/platform-support.d.ts.map +1 -0
- package/dist/platform-support.js +148 -0
- package/dist/platform-support.js.map +1 -0
- package/dist/project-context-resolution.d.ts +7 -0
- package/dist/project-context-resolution.d.ts.map +1 -0
- package/dist/project-context-resolution.js +21 -0
- package/dist/project-context-resolution.js.map +1 -0
- package/dist/project-context-state.d.ts +12 -0
- package/dist/project-context-state.d.ts.map +1 -0
- package/dist/project-context-state.js +14 -0
- package/dist/project-context-state.js.map +1 -0
- package/dist/project-context.d.ts +15 -0
- package/dist/project-context.d.ts.map +1 -0
- package/dist/project-context.js +78 -0
- package/dist/project-context.js.map +1 -0
- package/dist/prompts/doctor-workflow.js +1 -1
- package/dist/prompts/getting-started.d.ts.map +1 -1
- package/dist/prompts/getting-started.js +36 -15
- package/dist/prompts/getting-started.js.map +1 -1
- package/dist/prompts/screen-workflow.d.ts.map +1 -1
- package/dist/prompts/screen-workflow.js +54 -3
- package/dist/prompts/screen-workflow.js.map +1 -1
- package/dist/schemas/mcp-schemas.d.ts +954 -309
- package/dist/schemas/mcp-schemas.d.ts.map +1 -1
- package/dist/schemas/mcp-schemas.js +130 -1
- package/dist/schemas/mcp-schemas.js.map +1 -1
- package/dist/tools/detect-project-context.d.ts +5 -0
- package/dist/tools/detect-project-context.d.ts.map +1 -0
- package/dist/tools/detect-project-context.js +36 -0
- package/dist/tools/detect-project-context.js.map +1 -0
- package/dist/tools/get-screen-generation-context.d.ts +3 -1
- package/dist/tools/get-screen-generation-context.d.ts.map +1 -1
- package/dist/tools/get-screen-generation-context.js +120 -20
- package/dist/tools/get-screen-generation-context.js.map +1 -1
- package/dist/tools/list-components.d.ts.map +1 -1
- package/dist/tools/list-components.js +42 -3
- package/dist/tools/list-components.js.map +1 -1
- package/dist/tools/list-screen-templates.d.ts +3 -1
- package/dist/tools/list-screen-templates.d.ts.map +1 -1
- package/dist/tools/list-screen-templates.js +3 -3
- package/dist/tools/list-screen-templates.js.map +1 -1
- package/dist/tools/preview-component.d.ts.map +1 -1
- package/dist/tools/preview-component.js +57 -7
- package/dist/tools/preview-component.js.map +1 -1
- package/dist/tools/preview-theme.d.ts +3 -1
- package/dist/tools/preview-theme.d.ts.map +1 -1
- package/dist/tools/preview-theme.js +48 -21
- package/dist/tools/preview-theme.js.map +1 -1
- package/dist/tools/theme-authority.js +1 -1
- package/dist/tools/theme-authority.js.map +1 -1
- package/dist/tools/validate-environment.d.ts +3 -1
- package/dist/tools/validate-environment.d.ts.map +1 -1
- package/dist/tools/validate-environment.js +102 -9
- package/dist/tools/validate-environment.js.map +1 -1
- package/dist/tools/validate-screen-definition.d.ts.map +1 -1
- package/dist/tools/validate-screen-definition.js +41 -7
- package/dist/tools/validate-screen-definition.js.map +1 -1
- package/dist/tools/whoami.d.ts.map +1 -1
- package/dist/tools/whoami.js +27 -17
- package/dist/tools/whoami.js.map +1 -1
- package/dist/utils/style-contract-reader.d.ts +10 -0
- package/dist/utils/style-contract-reader.d.ts.map +1 -0
- package/dist/utils/style-contract-reader.js +67 -0
- package/dist/utils/style-contract-reader.js.map +1 -0
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -24,10 +24,65 @@ import { previewScreenTemplateTool } from './tools/preview-screen-template.js';
|
|
|
24
24
|
import { getScreenGenerationContextTool } from './tools/get-screen-generation-context.js';
|
|
25
25
|
import { validateScreenDefinitionTool } from './tools/validate-screen-definition.js';
|
|
26
26
|
import { validateEnvironmentTool } from './tools/validate-environment.js';
|
|
27
|
+
import { detectProjectContextTool } from './tools/detect-project-context.js';
|
|
27
28
|
import { whoamiTool } from './tools/whoami.js';
|
|
28
29
|
import { readPackageJson } from './utils/package-json-reader.js';
|
|
29
30
|
import { getPromptDefinition, listPromptDefinitions } from './prompts/prompt-catalog.js';
|
|
30
|
-
import {
|
|
31
|
+
import { getAuthData } from './auth/state.js';
|
|
32
|
+
import { recordToolUsage, getUsageQuotaSnapshot, } from './billing/usage-ledger.js';
|
|
33
|
+
import { evaluateQuotaPolicy } from './billing/quota-policy.js';
|
|
34
|
+
import { syncUsageEvent } from './billing/usage-sync.js';
|
|
35
|
+
import { WhoamiInputSchema, GenerateBlueprintInputSchema, PreviewThemeInputSchema, ListThemesInputSchema, ExportScreenInputSchema, ValidateScreenInputSchema, ListTokensInputSchema, ListIconLibrariesInputSchema, PreviewIconLibraryInputSchema, ListComponentsInputSchema, PreviewComponentInputSchema, ListScreenTemplatesInputSchema, PreviewScreenTemplateInputSchema, GetScreenGenerationContextInputSchema, ValidateScreenDefinitionInputSchema, GenerateScreenInputSchema, ValidateEnvironmentInputSchema, DetectProjectContextInputSchema, } from './schemas/mcp-schemas.js';
|
|
36
|
+
function buildToolResponse(result) {
|
|
37
|
+
return {
|
|
38
|
+
content: [
|
|
39
|
+
{
|
|
40
|
+
type: 'text',
|
|
41
|
+
text: JSON.stringify(result, null, 2),
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function inferUsageOutcome(result) {
|
|
47
|
+
if (typeof result === 'object' &&
|
|
48
|
+
result !== null &&
|
|
49
|
+
'success' in result &&
|
|
50
|
+
result.success === false) {
|
|
51
|
+
return 'tool_error';
|
|
52
|
+
}
|
|
53
|
+
return 'success';
|
|
54
|
+
}
|
|
55
|
+
function meterToolCall(name, outcome) {
|
|
56
|
+
const authData = getAuthData();
|
|
57
|
+
const entry = recordToolUsage({
|
|
58
|
+
toolName: name,
|
|
59
|
+
outcome,
|
|
60
|
+
userId: authData?.user?.id ?? null,
|
|
61
|
+
plan: authData?.user?.plan ?? null,
|
|
62
|
+
});
|
|
63
|
+
void syncUsageEvent(entry);
|
|
64
|
+
}
|
|
65
|
+
function getQuotaPolicyDecision(name) {
|
|
66
|
+
const authData = getAuthData();
|
|
67
|
+
const snapshot = getUsageQuotaSnapshot({
|
|
68
|
+
userId: authData?.user?.id ?? null,
|
|
69
|
+
plan: authData?.user?.plan ?? null,
|
|
70
|
+
paidQuotaEntitlement: authData?.quotaEntitlement ?? null,
|
|
71
|
+
});
|
|
72
|
+
return evaluateQuotaPolicy({
|
|
73
|
+
toolName: name,
|
|
74
|
+
snapshot,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
function attachQuotaWarning(result, warning) {
|
|
78
|
+
if (!warning || typeof result !== 'object' || result === null || Array.isArray(result)) {
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
...result,
|
|
83
|
+
quotaWarning: warning,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
31
86
|
const packageJsonResult = readPackageJson(fileURLToPath(new URL('../package.json', import.meta.url)));
|
|
32
87
|
const serverVersion = packageJsonResult.success
|
|
33
88
|
? packageJsonResult.packageJson?.version || '0.6.5'
|
|
@@ -397,21 +452,24 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
397
452
|
},
|
|
398
453
|
{
|
|
399
454
|
name: 'get-screen-generation-context',
|
|
400
|
-
description: '[WORKFLOW STEP 1/3] Get complete context for AI agents to generate
|
|
455
|
+
description: '[WORKFLOW STEP 1/3] Get complete context for AI agents to generate screens from natural language for web or React Native direct-write workflows.\n\n' +
|
|
401
456
|
'THIS IS THE FIRST STEP in the screen generation workflow:\n' +
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
'3.
|
|
405
|
-
'
|
|
406
|
-
'
|
|
457
|
+
'1. If project path is known, call detect-project-context once to set defaults\n' +
|
|
458
|
+
"2. Call THIS TOOL with user's description and optional platform override (Step 1/3)\n" +
|
|
459
|
+
'3. For web: write Screen Definition JSON, then validate with validate-screen-definition (Step 2/3)\n' +
|
|
460
|
+
'4. For React Native: write code directly from the returned direct-write contract\n' +
|
|
461
|
+
'5. Call validate-environment if path known (final step)\n\n' +
|
|
462
|
+
'IMPORTANT: Web uses the validated Screen Definition path. React Native uses the direct-write contract path.\n\n' +
|
|
407
463
|
'WHEN TO CALL:\n' +
|
|
408
464
|
'- When user requests a new screen/page/component\n' +
|
|
409
465
|
'- Before attempting to generate a Screen Definition JSON\n' +
|
|
466
|
+
'- Before writing Expo / React Native screens directly\n' +
|
|
410
467
|
'- When you need to know available components, templates, or layout tokens\n\n' +
|
|
411
468
|
'RETURNS:\n' +
|
|
412
469
|
'- Template matches based on description\n' +
|
|
413
|
-
'- Available components with
|
|
414
|
-
'- JSON schema for Screen Definition\n' +
|
|
470
|
+
'- Available components with platform-aware guidance\n' +
|
|
471
|
+
'- JSON schema for Screen Definition (web path)\n' +
|
|
472
|
+
'- Direct-write runtime guidance (React Native path)\n' +
|
|
415
473
|
'- Example definitions for reference\n' +
|
|
416
474
|
'- Theme recipes and contextual hints',
|
|
417
475
|
inputSchema: {
|
|
@@ -432,6 +490,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
432
490
|
type: 'boolean',
|
|
433
491
|
description: 'Include example screen definitions (default: true)',
|
|
434
492
|
},
|
|
493
|
+
platform: {
|
|
494
|
+
type: 'string',
|
|
495
|
+
enum: ['web', 'react-native'],
|
|
496
|
+
description: 'Optional explicit platform override. If omitted, the session default or legacy web fallback is used.',
|
|
497
|
+
},
|
|
435
498
|
},
|
|
436
499
|
required: ['description'],
|
|
437
500
|
},
|
|
@@ -519,30 +582,64 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
519
582
|
required: ['screenDefinition', 'outputFormat'],
|
|
520
583
|
},
|
|
521
584
|
},
|
|
585
|
+
{
|
|
586
|
+
name: 'detect-project-context',
|
|
587
|
+
description: 'Detect the active project context from a filesystem path and optionally set it as the session default.\n\n' +
|
|
588
|
+
'WHEN TO CALL:\n' +
|
|
589
|
+
'- As the first step when the user has provided a project path\n' +
|
|
590
|
+
'- Before using React Native direct-write workflow without repeating platform flags\n' +
|
|
591
|
+
'- To determine whether the target project is web, Expo, or bare React Native\n\n' +
|
|
592
|
+
'RETURNS:\n' +
|
|
593
|
+
'- platform: web or react-native\n' +
|
|
594
|
+
'- environment: runtime and package manager\n' +
|
|
595
|
+
'- recommendations: default workflow recommendation for the detected project\n' +
|
|
596
|
+
'- sessionDefaultApplied: whether the detected context was stored for later tool calls',
|
|
597
|
+
inputSchema: {
|
|
598
|
+
type: 'object',
|
|
599
|
+
properties: {
|
|
600
|
+
projectPath: {
|
|
601
|
+
type: 'string',
|
|
602
|
+
description: 'Path to package.json or project root directory',
|
|
603
|
+
},
|
|
604
|
+
setAsDefault: {
|
|
605
|
+
type: 'boolean',
|
|
606
|
+
description: 'Store the detected project context as the active session default',
|
|
607
|
+
},
|
|
608
|
+
},
|
|
609
|
+
required: ['projectPath'],
|
|
610
|
+
},
|
|
611
|
+
},
|
|
522
612
|
{
|
|
523
613
|
name: 'validate-environment',
|
|
524
|
-
description: '[WORKFLOW STEP 3/3 - Optional] Validate user environment
|
|
614
|
+
description: '[WORKFLOW STEP 3/3 - Optional] Validate user environment for web or React Native direct-write delivery.\n\n' +
|
|
525
615
|
'WHEN TO CALL:\n' +
|
|
526
|
-
'- After writing React code, to verify required packages are installed\n' +
|
|
616
|
+
'- After writing React or React Native code, to verify required packages are installed\n' +
|
|
527
617
|
'- When user wants to check if their project has required packages\n' +
|
|
528
618
|
'- Before running generated code to ensure all dependencies are available\n' +
|
|
529
|
-
'- To verify Tailwind CSS is configured correctly for @framingui/ui components\n
|
|
619
|
+
'- To verify Tailwind CSS is configured correctly for @framingui/ui components on web\n' +
|
|
620
|
+
'- To audit React Native source files for hardcoded values or web-only patterns\n\n' +
|
|
530
621
|
'RETURNS:\n' +
|
|
531
622
|
'- installed: Packages already in package.json with versions\n' +
|
|
532
623
|
'- missing: Packages that need to be installed\n' +
|
|
533
624
|
'- installCommands: Ready-to-use install commands for npm/yarn/pnpm/bun\n' +
|
|
534
|
-
'-
|
|
625
|
+
'- environment: detected runtime and package manager\n' +
|
|
626
|
+
'- tailwind: Tailwind CSS config validation (web path)\n' +
|
|
627
|
+
'- sourceAudit: source-file QC findings for React Native direct-write paths\n\n' +
|
|
535
628
|
'TAILWIND VALIDATION (checkTailwind=true by default):\n' +
|
|
536
|
-
'- Checks if tailwind.config.{ts,js,mjs,cjs} exists
|
|
537
|
-
'- Verifies @framingui/ui content paths are included
|
|
538
|
-
'- Verifies tailwindcss-animate is
|
|
629
|
+
'- Checks if tailwind.config.{ts,js,mjs,cjs} exists\n' +
|
|
630
|
+
'- Verifies @framingui/ui content paths are included (prevents missing styles)\n' +
|
|
631
|
+
'- Verifies tailwindcss-animate plugin is configured (required for Dialog, Popover animations)\n' +
|
|
539
632
|
'- Returns actionable issues[] and fixes[] for each problem found\n\n' +
|
|
633
|
+
'REACT NATIVE VALIDATION:\n' +
|
|
634
|
+
'- Detects Expo vs bare React Native projects\n' +
|
|
635
|
+
'- Skips Tailwind by default when platform=react-native\n' +
|
|
636
|
+
'- Audits sourceFiles for raw color/spacing/radius literals and web-only patterns such as className\n\n' +
|
|
540
637
|
'EXAMPLE WORKFLOW:\n' +
|
|
541
638
|
'1. get-screen-generation-context → get component info and context\n' +
|
|
542
|
-
'2. validate-screen-definition → validate Screen Definition JSON\n' +
|
|
543
|
-
'3. Write
|
|
639
|
+
'2. For web: validate-screen-definition → validate Screen Definition JSON\n' +
|
|
640
|
+
'3. Write code using the returned contract path\n' +
|
|
544
641
|
'4. Call THIS TOOL with projectPath + requiredPackages\n' +
|
|
545
|
-
'5. Show user missing packages, install commands,
|
|
642
|
+
'5. Show user missing packages, install commands, and any Tailwind or source-audit issues',
|
|
546
643
|
inputSchema: {
|
|
547
644
|
type: 'object',
|
|
548
645
|
properties: {
|
|
@@ -555,10 +652,20 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
555
652
|
description: 'Array of package names to validate (e.g., ["framer-motion", "@radix-ui/react-slot"])',
|
|
556
653
|
items: { type: 'string' },
|
|
557
654
|
},
|
|
655
|
+
platform: {
|
|
656
|
+
type: 'string',
|
|
657
|
+
enum: ['web', 'react-native'],
|
|
658
|
+
description: 'Target platform for environment validation (default: web)',
|
|
659
|
+
},
|
|
558
660
|
checkTailwind: {
|
|
559
661
|
type: 'boolean',
|
|
560
662
|
description: 'Also validate Tailwind CSS configuration for @framingui/ui compatibility (default: true)',
|
|
561
663
|
},
|
|
664
|
+
sourceFiles: {
|
|
665
|
+
type: 'array',
|
|
666
|
+
description: 'Optional source files to audit for direct-write QC (recommended for React Native)',
|
|
667
|
+
items: { type: 'string' },
|
|
668
|
+
},
|
|
562
669
|
},
|
|
563
670
|
required: ['projectPath', 'requiredPackages'],
|
|
564
671
|
},
|
|
@@ -572,22 +679,43 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
572
679
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
573
680
|
const { name, arguments: args } = request.params;
|
|
574
681
|
info(`CallTool request: ${name}`);
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
682
|
+
if (name !== 'detect-project-context') {
|
|
683
|
+
// 모든 원격/카탈로그 도구 호출 전에 인증 가드 실행
|
|
684
|
+
try {
|
|
685
|
+
requireAuth();
|
|
686
|
+
}
|
|
687
|
+
catch (e) {
|
|
688
|
+
if (e instanceof AuthRequiredError) {
|
|
689
|
+
meterToolCall(name, 'auth_error');
|
|
690
|
+
return {
|
|
691
|
+
content: [
|
|
692
|
+
{
|
|
693
|
+
type: 'text',
|
|
694
|
+
text: JSON.stringify({
|
|
695
|
+
success: false,
|
|
696
|
+
code: 'AUTH_REQUIRED',
|
|
697
|
+
error: 'Authentication required to use FramingUI MCP tools.',
|
|
698
|
+
nextAction: 'Run `framingui-mcp login` or set FRAMINGUI_API_KEY, then retry the same tool call.',
|
|
699
|
+
signupUrl: 'https://framingui.com/auth/signup?utm_source=mcp&utm_medium=cli&utm_campaign=auth_prompt',
|
|
700
|
+
retryable: true,
|
|
701
|
+
}),
|
|
702
|
+
},
|
|
703
|
+
],
|
|
704
|
+
isError: true,
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
// 예상치 못한 예외는 로깅 후 에러 반환 (silent swallow 방지)
|
|
708
|
+
logError(`Unexpected error in requireAuth: ${e}`);
|
|
709
|
+
meterToolCall(name, 'auth_error');
|
|
581
710
|
return {
|
|
582
711
|
content: [
|
|
583
712
|
{
|
|
584
713
|
type: 'text',
|
|
585
714
|
text: JSON.stringify({
|
|
586
715
|
success: false,
|
|
587
|
-
code: '
|
|
588
|
-
error: 'Authentication
|
|
589
|
-
|
|
590
|
-
signupUrl: 'https://framingui.com/auth/signup?utm_source=mcp&utm_medium=cli&utm_campaign=auth_prompt',
|
|
716
|
+
code: 'AUTH_CHECK_FAILED',
|
|
717
|
+
error: 'Authentication check failed unexpectedly.',
|
|
718
|
+
detail: e instanceof Error ? e.message : String(e),
|
|
591
719
|
retryable: true,
|
|
592
720
|
}),
|
|
593
721
|
},
|
|
@@ -595,18 +723,20 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
595
723
|
isError: true,
|
|
596
724
|
};
|
|
597
725
|
}
|
|
598
|
-
|
|
599
|
-
|
|
726
|
+
}
|
|
727
|
+
const quotaDecision = getQuotaPolicyDecision(name);
|
|
728
|
+
if (!quotaDecision.allowed) {
|
|
729
|
+
meterToolCall(name, 'validation_error');
|
|
600
730
|
return {
|
|
601
731
|
content: [
|
|
602
732
|
{
|
|
603
733
|
type: 'text',
|
|
604
734
|
text: JSON.stringify({
|
|
605
735
|
success: false,
|
|
606
|
-
code: '
|
|
607
|
-
error:
|
|
608
|
-
|
|
609
|
-
retryable:
|
|
736
|
+
code: 'QUOTA_EXCEEDED',
|
|
737
|
+
error: quotaDecision.warning ??
|
|
738
|
+
'This tool call would exceed the included quota while hard cap mode is enabled.',
|
|
739
|
+
retryable: false,
|
|
610
740
|
}),
|
|
611
741
|
},
|
|
612
742
|
],
|
|
@@ -617,223 +747,111 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
617
747
|
switch (name) {
|
|
618
748
|
case 'whoami': {
|
|
619
749
|
WhoamiInputSchema.parse(args);
|
|
620
|
-
const result = await whoamiTool();
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
{
|
|
624
|
-
type: 'text',
|
|
625
|
-
text: JSON.stringify(result, null, 2),
|
|
626
|
-
},
|
|
627
|
-
],
|
|
628
|
-
};
|
|
750
|
+
const result = attachQuotaWarning(await whoamiTool(), quotaDecision.warning);
|
|
751
|
+
meterToolCall(name, inferUsageOutcome(result));
|
|
752
|
+
return buildToolResponse(result);
|
|
629
753
|
}
|
|
630
754
|
case 'generate-blueprint': {
|
|
631
|
-
// Validate input
|
|
632
755
|
const validatedInput = GenerateBlueprintInputSchema.parse(args);
|
|
633
|
-
const result = await generateBlueprintTool(validatedInput);
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
{
|
|
637
|
-
type: 'text',
|
|
638
|
-
text: JSON.stringify(result, null, 2),
|
|
639
|
-
},
|
|
640
|
-
],
|
|
641
|
-
};
|
|
756
|
+
const result = attachQuotaWarning(await generateBlueprintTool(validatedInput), quotaDecision.warning);
|
|
757
|
+
meterToolCall(name, inferUsageOutcome(result));
|
|
758
|
+
return buildToolResponse(result);
|
|
642
759
|
}
|
|
643
760
|
case 'list-icon-libraries': {
|
|
644
|
-
// Validate input (no required fields)
|
|
645
761
|
ListIconLibrariesInputSchema.parse(args);
|
|
646
|
-
const result = await listIconLibrariesTool();
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
{
|
|
650
|
-
type: 'text',
|
|
651
|
-
text: JSON.stringify(result, null, 2),
|
|
652
|
-
},
|
|
653
|
-
],
|
|
654
|
-
};
|
|
762
|
+
const result = attachQuotaWarning(await listIconLibrariesTool(), quotaDecision.warning);
|
|
763
|
+
meterToolCall(name, inferUsageOutcome(result));
|
|
764
|
+
return buildToolResponse(result);
|
|
655
765
|
}
|
|
656
766
|
case 'preview-icon-library': {
|
|
657
|
-
// Validate input
|
|
658
767
|
const validatedInput = PreviewIconLibraryInputSchema.parse(args);
|
|
659
|
-
const result = await previewIconLibraryTool(validatedInput);
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
{
|
|
663
|
-
type: 'text',
|
|
664
|
-
text: JSON.stringify(result, null, 2),
|
|
665
|
-
},
|
|
666
|
-
],
|
|
667
|
-
};
|
|
768
|
+
const result = attachQuotaWarning(await previewIconLibraryTool(validatedInput), quotaDecision.warning);
|
|
769
|
+
meterToolCall(name, inferUsageOutcome(result));
|
|
770
|
+
return buildToolResponse(result);
|
|
668
771
|
}
|
|
669
772
|
case 'list-themes': {
|
|
670
|
-
// Validate input (no required fields)
|
|
671
773
|
ListThemesInputSchema.parse(args);
|
|
672
|
-
const result = await listThemesTool();
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
{
|
|
676
|
-
type: 'text',
|
|
677
|
-
text: JSON.stringify(result, null, 2),
|
|
678
|
-
},
|
|
679
|
-
],
|
|
680
|
-
};
|
|
774
|
+
const result = attachQuotaWarning(await listThemesTool(), quotaDecision.warning);
|
|
775
|
+
meterToolCall(name, inferUsageOutcome(result));
|
|
776
|
+
return buildToolResponse(result);
|
|
681
777
|
}
|
|
682
778
|
case 'preview-theme': {
|
|
683
|
-
// Validate input
|
|
684
779
|
const validatedInput = PreviewThemeInputSchema.parse(args);
|
|
685
|
-
const result = await previewThemeTool(validatedInput);
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
{
|
|
689
|
-
type: 'text',
|
|
690
|
-
text: JSON.stringify(result, null, 2),
|
|
691
|
-
},
|
|
692
|
-
],
|
|
693
|
-
};
|
|
780
|
+
const result = attachQuotaWarning(await previewThemeTool(validatedInput), quotaDecision.warning);
|
|
781
|
+
meterToolCall(name, inferUsageOutcome(result));
|
|
782
|
+
return buildToolResponse(result);
|
|
694
783
|
}
|
|
695
784
|
case 'export-screen': {
|
|
696
|
-
// Validate input
|
|
697
785
|
const validatedInput = ExportScreenInputSchema.parse(args);
|
|
698
|
-
const result = await exportScreenTool(validatedInput);
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
{
|
|
702
|
-
type: 'text',
|
|
703
|
-
text: JSON.stringify(result, null, 2),
|
|
704
|
-
},
|
|
705
|
-
],
|
|
706
|
-
};
|
|
786
|
+
const result = attachQuotaWarning(await exportScreenTool(validatedInput), quotaDecision.warning);
|
|
787
|
+
meterToolCall(name, inferUsageOutcome(result));
|
|
788
|
+
return buildToolResponse(result);
|
|
707
789
|
}
|
|
708
790
|
case 'validate_screen': {
|
|
709
|
-
// Validate input
|
|
710
791
|
const validatedInput = ValidateScreenInputSchema.parse(args);
|
|
711
|
-
const result = await validateScreenTool(validatedInput);
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
{
|
|
715
|
-
type: 'text',
|
|
716
|
-
text: JSON.stringify(result, null, 2),
|
|
717
|
-
},
|
|
718
|
-
],
|
|
719
|
-
};
|
|
792
|
+
const result = attachQuotaWarning(await validateScreenTool(validatedInput), quotaDecision.warning);
|
|
793
|
+
meterToolCall(name, inferUsageOutcome(result));
|
|
794
|
+
return buildToolResponse(result);
|
|
720
795
|
}
|
|
721
796
|
case 'list_tokens': {
|
|
722
|
-
// Validate input
|
|
723
797
|
const validatedInput = ListTokensInputSchema.parse(args);
|
|
724
|
-
const result = await listTokensTool(validatedInput);
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
{
|
|
728
|
-
type: 'text',
|
|
729
|
-
text: JSON.stringify(result, null, 2),
|
|
730
|
-
},
|
|
731
|
-
],
|
|
732
|
-
};
|
|
798
|
+
const result = attachQuotaWarning(await listTokensTool(validatedInput), quotaDecision.warning);
|
|
799
|
+
meterToolCall(name, inferUsageOutcome(result));
|
|
800
|
+
return buildToolResponse(result);
|
|
733
801
|
}
|
|
734
802
|
case 'list-components': {
|
|
735
|
-
// Validate input
|
|
736
803
|
const validatedInput = ListComponentsInputSchema.parse(args);
|
|
737
|
-
const result = await listComponentsTool(validatedInput);
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
{
|
|
741
|
-
type: 'text',
|
|
742
|
-
text: JSON.stringify(result, null, 2),
|
|
743
|
-
},
|
|
744
|
-
],
|
|
745
|
-
};
|
|
804
|
+
const result = attachQuotaWarning(await listComponentsTool(validatedInput), quotaDecision.warning);
|
|
805
|
+
meterToolCall(name, inferUsageOutcome(result));
|
|
806
|
+
return buildToolResponse(result);
|
|
746
807
|
}
|
|
747
808
|
case 'preview-component': {
|
|
748
|
-
// Validate input
|
|
749
809
|
const validatedInput = PreviewComponentInputSchema.parse(args);
|
|
750
|
-
const result = await previewComponentTool(validatedInput);
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
{
|
|
754
|
-
type: 'text',
|
|
755
|
-
text: JSON.stringify(result, null, 2),
|
|
756
|
-
},
|
|
757
|
-
],
|
|
758
|
-
};
|
|
810
|
+
const result = attachQuotaWarning(await previewComponentTool(validatedInput), quotaDecision.warning);
|
|
811
|
+
meterToolCall(name, inferUsageOutcome(result));
|
|
812
|
+
return buildToolResponse(result);
|
|
759
813
|
}
|
|
760
814
|
case 'list-screen-templates': {
|
|
761
|
-
// Validate input
|
|
762
815
|
const validatedInput = ListScreenTemplatesInputSchema.parse(args);
|
|
763
|
-
const result = await listScreenTemplatesTool(validatedInput);
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
{
|
|
767
|
-
type: 'text',
|
|
768
|
-
text: JSON.stringify(result, null, 2),
|
|
769
|
-
},
|
|
770
|
-
],
|
|
771
|
-
};
|
|
816
|
+
const result = attachQuotaWarning(await listScreenTemplatesTool(validatedInput), quotaDecision.warning);
|
|
817
|
+
meterToolCall(name, inferUsageOutcome(result));
|
|
818
|
+
return buildToolResponse(result);
|
|
772
819
|
}
|
|
773
820
|
case 'preview-screen-template': {
|
|
774
|
-
// Validate input
|
|
775
821
|
const validatedInput = PreviewScreenTemplateInputSchema.parse(args);
|
|
776
|
-
const result = await previewScreenTemplateTool(validatedInput);
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
{
|
|
780
|
-
type: 'text',
|
|
781
|
-
text: JSON.stringify(result, null, 2),
|
|
782
|
-
},
|
|
783
|
-
],
|
|
784
|
-
};
|
|
822
|
+
const result = attachQuotaWarning(await previewScreenTemplateTool(validatedInput), quotaDecision.warning);
|
|
823
|
+
meterToolCall(name, inferUsageOutcome(result));
|
|
824
|
+
return buildToolResponse(result);
|
|
785
825
|
}
|
|
786
826
|
case 'get-screen-generation-context': {
|
|
787
|
-
// Validate input
|
|
788
827
|
const validatedInput = GetScreenGenerationContextInputSchema.parse(args);
|
|
789
|
-
const result = await getScreenGenerationContextTool(validatedInput);
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
{
|
|
793
|
-
type: 'text',
|
|
794
|
-
text: JSON.stringify(result, null, 2),
|
|
795
|
-
},
|
|
796
|
-
],
|
|
797
|
-
};
|
|
828
|
+
const result = attachQuotaWarning(await getScreenGenerationContextTool(validatedInput), quotaDecision.warning);
|
|
829
|
+
meterToolCall(name, inferUsageOutcome(result));
|
|
830
|
+
return buildToolResponse(result);
|
|
798
831
|
}
|
|
799
832
|
case 'validate-screen-definition': {
|
|
800
|
-
// Validate input
|
|
801
833
|
const validatedInput = ValidateScreenDefinitionInputSchema.parse(args);
|
|
802
|
-
const result = await validateScreenDefinitionTool(validatedInput);
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
{
|
|
806
|
-
type: 'text',
|
|
807
|
-
text: JSON.stringify(result, null, 2),
|
|
808
|
-
},
|
|
809
|
-
],
|
|
810
|
-
};
|
|
834
|
+
const result = attachQuotaWarning(await validateScreenDefinitionTool(validatedInput), quotaDecision.warning);
|
|
835
|
+
meterToolCall(name, inferUsageOutcome(result));
|
|
836
|
+
return buildToolResponse(result);
|
|
811
837
|
}
|
|
812
838
|
case 'generate_screen': {
|
|
813
|
-
// Validate input
|
|
814
839
|
const validatedInput = GenerateScreenInputSchema.parse(args);
|
|
815
|
-
const result = await generateScreenTool(validatedInput);
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
{
|
|
819
|
-
type: 'text',
|
|
820
|
-
text: JSON.stringify(result, null, 2),
|
|
821
|
-
},
|
|
822
|
-
],
|
|
823
|
-
};
|
|
840
|
+
const result = attachQuotaWarning(await generateScreenTool(validatedInput), quotaDecision.warning);
|
|
841
|
+
meterToolCall(name, inferUsageOutcome(result));
|
|
842
|
+
return buildToolResponse(result);
|
|
824
843
|
}
|
|
825
844
|
case 'validate-environment': {
|
|
826
|
-
// Validate input
|
|
827
845
|
const validatedInput = ValidateEnvironmentInputSchema.parse(args);
|
|
828
|
-
const result = await validateEnvironmentTool(validatedInput);
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
846
|
+
const result = attachQuotaWarning(await validateEnvironmentTool(validatedInput), quotaDecision.warning);
|
|
847
|
+
meterToolCall(name, inferUsageOutcome(result));
|
|
848
|
+
return buildToolResponse(result);
|
|
849
|
+
}
|
|
850
|
+
case 'detect-project-context': {
|
|
851
|
+
const validatedInput = DetectProjectContextInputSchema.parse(args);
|
|
852
|
+
const result = await detectProjectContextTool(validatedInput);
|
|
853
|
+
meterToolCall(name, inferUsageOutcome(result));
|
|
854
|
+
return buildToolResponse(result);
|
|
837
855
|
}
|
|
838
856
|
default:
|
|
839
857
|
throw new Error(`Unknown tool: ${name}`);
|
|
@@ -841,6 +859,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
841
859
|
}
|
|
842
860
|
catch (error) {
|
|
843
861
|
logError(`Tool execution error: ${error}`);
|
|
862
|
+
const outcome = error instanceof Error && error.name === 'ZodError' ? 'validation_error' : 'runtime_error';
|
|
863
|
+
meterToolCall(name, outcome);
|
|
844
864
|
return {
|
|
845
865
|
content: [
|
|
846
866
|
{
|
|
@@ -921,5 +941,5 @@ catch (err) {
|
|
|
921
941
|
logError(`Failed to connect to stdio transport: ${errorMessage}`);
|
|
922
942
|
process.exit(1);
|
|
923
943
|
}
|
|
924
|
-
info('
|
|
944
|
+
info('18 MCP tools registered: whoami, generate-blueprint, list-themes, preview-theme, list-icon-libraries, preview-icon-library, export-screen, validate_screen, list_tokens, list-components, preview-component, list-screen-templates, preview-screen-template, get-screen-generation-context, validate-screen-definition, generate_screen, validate-environment, detect-project-context');
|
|
925
945
|
//# sourceMappingURL=index.js.map
|