palette-mcp 1.1.1 → 1.2.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.
@@ -1,9 +1,92 @@
1
+ import { ComponentSyncService } from '../sync/index.js';
1
2
  export class DesignSystemService {
2
3
  reactComponents = [];
3
4
  vueComponents = [];
4
- constructor() {
5
+ syncService;
6
+ syncConfig;
7
+ initialized = false;
8
+ lastSyncResult = null;
9
+ constructor(syncConfig = {}) {
10
+ this.syncConfig = {
11
+ autoSync: syncConfig.autoSync ?? true,
12
+ verbose: syncConfig.verbose ?? false,
13
+ };
14
+ this.syncService = new ComponentSyncService();
15
+ // 하드코딩된 기본 컴포넌트 초기화 (폴백용)
5
16
  this.initializeComponents();
6
17
  }
18
+ /**
19
+ * 서비스 초기화 (비동기)
20
+ * 서버 시작 시 호출하여 GitHub에서 최신 컴포넌트 동기화
21
+ */
22
+ async initialize() {
23
+ if (this.initialized) {
24
+ return;
25
+ }
26
+ if (this.syncConfig.autoSync) {
27
+ try {
28
+ console.log('[DesignSystem] 컴포넌트 동기화 시작...');
29
+ const result = await this.syncService.sync({
30
+ verbose: this.syncConfig.verbose,
31
+ });
32
+ this.lastSyncResult = result;
33
+ if (result.success) {
34
+ if (result.reactComponents.length > 0) {
35
+ this.reactComponents = result.reactComponents;
36
+ }
37
+ if (result.vueComponents.length > 0) {
38
+ this.vueComponents = result.vueComponents;
39
+ }
40
+ console.log(`[DesignSystem] 동기화 완료: React ${this.reactComponents.length}개, Vue ${this.vueComponents.length}개` +
41
+ (result.fromCache ? ' (캐시에서 로드)' : ' (GitHub에서 동기화)'));
42
+ }
43
+ else {
44
+ console.warn('[DesignSystem] 동기화 실패, 하드코딩된 데이터 사용:', result.error);
45
+ }
46
+ }
47
+ catch (error) {
48
+ console.warn('[DesignSystem] 동기화 중 오류, 하드코딩된 데이터 사용:', error);
49
+ }
50
+ }
51
+ this.initialized = true;
52
+ }
53
+ /**
54
+ * 수동 동기화 실행
55
+ */
56
+ async syncComponents(force = false) {
57
+ const result = await this.syncService.sync({
58
+ force,
59
+ verbose: this.syncConfig.verbose,
60
+ });
61
+ this.lastSyncResult = result;
62
+ if (result.success) {
63
+ if (result.reactComponents.length > 0) {
64
+ this.reactComponents = result.reactComponents;
65
+ }
66
+ if (result.vueComponents.length > 0) {
67
+ this.vueComponents = result.vueComponents;
68
+ }
69
+ }
70
+ return result;
71
+ }
72
+ /**
73
+ * 마지막 동기화 결과 조회
74
+ */
75
+ getLastSyncResult() {
76
+ return this.lastSyncResult;
77
+ }
78
+ /**
79
+ * 캐시 상태 조회
80
+ */
81
+ async getCacheStatus() {
82
+ return this.syncService.getCacheStatus();
83
+ }
84
+ /**
85
+ * 캐시 삭제
86
+ */
87
+ async clearCache() {
88
+ await this.syncService.clearCache();
89
+ }
7
90
  /**
8
91
  * 디자인 시스템(React, Vue) 컴포넌트 메타데이터 제공 필요.
9
92
  * 1. 메타데이터 구조 정의
@@ -2,49 +2,74 @@
2
2
  * Palette MCP Server - Smithery Remote 배포용
3
3
  *
4
4
  * Smithery.ai에서 호스팅될 때 사용됩니다.
5
- * Smithery가 파일을 로드하고 createServer 함수를 호출합니다.
5
+ * @smithery/sdk를 사용하여 HTTP 서버로 실행됩니다.
6
6
  */
7
7
  import { z } from 'zod';
8
- import { tools } from './server.js';
8
+ /**
9
+ * Smithery 설정 스키마 정의
10
+ *
11
+ * Palette MCP Server Configuration
12
+ * Figma 디자인을 Design System 컴포넌트로 변환하기 위한 설정
13
+ *
14
+ * 모든 필드는 optional로 설정하여 Smithery Optional config 점수 획득
15
+ */
9
16
  export declare const configSchema: z.ZodObject<{
10
- FIGMA_ACCESS_TOKEN: z.ZodString;
11
- GITHUB_TOKEN: z.ZodString;
12
- FIGMA_MCP_SERVER_URL: z.ZodDefault<z.ZodString>;
17
+ FIGMA_ACCESS_TOKEN: z.ZodOptional<z.ZodString>;
18
+ GITHUB_TOKEN: z.ZodOptional<z.ZodString>;
19
+ FIGMA_MCP_SERVER_URL: z.ZodDefault<z.ZodOptional<z.ZodString>>;
13
20
  }, "strip", z.ZodTypeAny, {
14
- FIGMA_ACCESS_TOKEN: string;
15
21
  FIGMA_MCP_SERVER_URL: string;
16
- GITHUB_TOKEN: string;
22
+ FIGMA_ACCESS_TOKEN?: string | undefined;
23
+ GITHUB_TOKEN?: string | undefined;
17
24
  }, {
18
- FIGMA_ACCESS_TOKEN: string;
19
- GITHUB_TOKEN: string;
25
+ FIGMA_ACCESS_TOKEN?: string | undefined;
20
26
  FIGMA_MCP_SERVER_URL?: string | undefined;
27
+ GITHUB_TOKEN?: string | undefined;
21
28
  }>;
22
29
  type SmitheryConfig = z.infer<typeof configSchema>;
23
30
  /**
24
- * Smithery에서 호출하는 서버 생성 함수
25
- *
26
- * @param config - Smithery에서 전달받은 사용자 설정
27
- * @returns MCP 서버 인스턴스
31
+ * MCP 서버 생성 함수 - Smithery가 호출
28
32
  */
29
- export default function createServer({ config }: {
30
- config: SmitheryConfig;
31
- }): import("@modelcontextprotocol/sdk/server/index.js").Server<{
33
+ export default function createMcpServer({ config }?: {
34
+ config?: SmitheryConfig;
35
+ }): import("@modelcontextprotocol/sdk/server").Server<{
32
36
  method: string;
33
- params?: z.objectOutputType<{
34
- _meta: z.ZodOptional<z.ZodObject<{
35
- progressToken: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
36
- }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
37
- progressToken: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
38
- }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
39
- progressToken: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
40
- }, z.ZodTypeAny, "passthrough">>>;
41
- }, z.ZodTypeAny, "passthrough"> | undefined;
37
+ params?: {
38
+ [x: string]: unknown;
39
+ task?: {
40
+ [x: string]: unknown;
41
+ ttl?: number | null | undefined;
42
+ pollInterval?: number | undefined;
43
+ } | undefined;
44
+ _meta?: {
45
+ [x: string]: unknown;
46
+ progressToken?: string | number | undefined;
47
+ "io.modelcontextprotocol/related-task"?: {
48
+ [x: string]: unknown;
49
+ taskId: string;
50
+ } | undefined;
51
+ } | undefined;
52
+ } | undefined;
42
53
  }, {
43
54
  method: string;
44
- params?: z.objectOutputType<{
45
- _meta: z.ZodOptional<z.ZodObject<{}, "passthrough", z.ZodTypeAny, z.objectOutputType<{}, z.ZodTypeAny, "passthrough">, z.objectInputType<{}, z.ZodTypeAny, "passthrough">>>;
46
- }, z.ZodTypeAny, "passthrough"> | undefined;
47
- }, z.objectOutputType<{
48
- _meta: z.ZodOptional<z.ZodObject<{}, "passthrough", z.ZodTypeAny, z.objectOutputType<{}, z.ZodTypeAny, "passthrough">, z.objectInputType<{}, z.ZodTypeAny, "passthrough">>>;
49
- }, z.ZodTypeAny, "passthrough">>;
50
- export { tools };
55
+ params?: {
56
+ [x: string]: unknown;
57
+ _meta?: {
58
+ [x: string]: unknown;
59
+ "io.modelcontextprotocol/related-task"?: {
60
+ [x: string]: unknown;
61
+ taskId: string;
62
+ } | undefined;
63
+ } | undefined;
64
+ } | undefined;
65
+ }, {
66
+ [x: string]: unknown;
67
+ _meta?: {
68
+ [x: string]: unknown;
69
+ "io.modelcontextprotocol/related-task"?: {
70
+ [x: string]: unknown;
71
+ taskId: string;
72
+ } | undefined;
73
+ } | undefined;
74
+ }>;
75
+ export {};
package/dist/smithery.js CHANGED
@@ -2,43 +2,79 @@
2
2
  * Palette MCP Server - Smithery Remote 배포용
3
3
  *
4
4
  * Smithery.ai에서 호스팅될 때 사용됩니다.
5
- * Smithery가 파일을 로드하고 createServer 함수를 호출합니다.
5
+ * @smithery/sdk를 사용하여 HTTP 서버로 실행됩니다.
6
6
  */
7
+ import { createStatelessServer } from '@smithery/sdk/server/stateless.js';
7
8
  import { z } from 'zod';
8
- import { createPaletteServer, tools } from './server.js';
9
- // Smithery 설정 스키마 정의
9
+ import { createPaletteServer } from './server.js';
10
+ /**
11
+ * Smithery 설정 스키마 정의
12
+ *
13
+ * Palette MCP Server Configuration
14
+ * Figma 디자인을 Design System 컴포넌트로 변환하기 위한 설정
15
+ *
16
+ * 모든 필드는 optional로 설정하여 Smithery Optional config 점수 획득
17
+ */
10
18
  export const configSchema = z.object({
19
+ // Figma Access Token - Figma API 호출에 필요
11
20
  FIGMA_ACCESS_TOKEN: z
12
21
  .string()
13
- .describe('Figma Personal Access Token (https://www.figma.com/developers/api#access-tokens)'),
22
+ .min(1)
23
+ .optional()
24
+ .describe('Figma Personal Access Token. Required for accessing Figma designs. Get yours at https://www.figma.com/developers/api#access-tokens'),
25
+ // GitHub Token - 비공개 디자인 시스템 패키지 접근용
14
26
  GITHUB_TOKEN: z
15
27
  .string()
16
- .describe('GitHub Personal Access Token for design system packages'),
28
+ .min(1)
29
+ .optional()
30
+ .describe('GitHub Personal Access Token for accessing private design system packages. Required only for private repositories.'),
31
+ // Figma MCP Server URL - 로컬 개발용 (Remote 모드에서는 사용 안함)
17
32
  FIGMA_MCP_SERVER_URL: z
18
33
  .string()
34
+ .url('Must be a valid URL')
35
+ .optional()
19
36
  .default('http://127.0.0.1:3845/mcp')
20
- .describe('Figma Dev Mode MCP server URL'),
21
- });
37
+ .describe('Figma Dev Mode MCP server URL. Only needed for local development with Figma Desktop app.'),
38
+ }).describe('Configuration options for Palette MCP Server - Figma to Design System converter');
39
+ // 기본 설정
40
+ const defaultConfig = {
41
+ FIGMA_ACCESS_TOKEN: undefined,
42
+ GITHUB_TOKEN: undefined,
43
+ FIGMA_MCP_SERVER_URL: 'http://127.0.0.1:3845/mcp',
44
+ };
22
45
  /**
23
- * Smithery에서 호출하는 서버 생성 함수
24
- *
25
- * @param config - Smithery에서 전달받은 사용자 설정
26
- * @returns MCP 서버 인스턴스
46
+ * MCP 서버 생성 함수 - Smithery가 호출
27
47
  */
28
- export default function createServer({ config }) {
29
- // 환경변수 설정
30
- process.env.FIGMA_ACCESS_TOKEN = config.FIGMA_ACCESS_TOKEN;
31
- process.env.GITHUB_TOKEN = config.GITHUB_TOKEN;
32
- process.env.FIGMA_MCP_SERVER_URL = config.FIGMA_MCP_SERVER_URL;
48
+ export default function createMcpServer({ config } = {}) {
49
+ // config가 없거나 불완전해도 서버 초기화 가능하도록 방어적 처리
50
+ const safeConfig = { ...defaultConfig, ...config };
51
+ // 환경변수 설정 (값이 있는 경우에만)
52
+ if (safeConfig.FIGMA_ACCESS_TOKEN) {
53
+ process.env.FIGMA_ACCESS_TOKEN = safeConfig.FIGMA_ACCESS_TOKEN;
54
+ }
55
+ if (safeConfig.GITHUB_TOKEN) {
56
+ process.env.GITHUB_TOKEN = safeConfig.GITHUB_TOKEN;
57
+ }
58
+ if (safeConfig.FIGMA_MCP_SERVER_URL) {
59
+ process.env.FIGMA_MCP_SERVER_URL = safeConfig.FIGMA_MCP_SERVER_URL;
60
+ }
33
61
  // 공통 서버 생성 로직 사용
62
+ // Remote 모드에서는 Figma Desktop MCP 클라이언트를 사용하지 않음 (로컬호스트 접근 불가)
34
63
  const server = createPaletteServer({
35
- figmaAccessToken: config.FIGMA_ACCESS_TOKEN,
36
- githubToken: config.GITHUB_TOKEN,
37
- figmaMcpServerUrl: config.FIGMA_MCP_SERVER_URL,
64
+ figmaAccessToken: safeConfig.FIGMA_ACCESS_TOKEN,
65
+ githubToken: safeConfig.GITHUB_TOKEN,
66
+ figmaMcpServerUrl: safeConfig.FIGMA_MCP_SERVER_URL,
67
+ useFigmaMcp: false, // Remote 모드에서는 Figma REST API만 사용
38
68
  });
39
- console.error('Palette server created for Smithery (Remote mode)');
40
- // Smithery가 기대하는 형식으로 반환
69
+ console.error('Palette MCP server created for Smithery (Remote mode)');
41
70
  return server;
42
71
  }
43
- // Tools 정보도 export (Smithery capabilities 탐지에 사용할 수 있음)
44
- export { tools };
72
+ // 직접 실행 시에만 서버 시작 (Smithery에서 import할 때는 실행 안됨)
73
+ // Smithery는 createStatelessServer를 내부적으로 호출함
74
+ if (process.env.SMITHERY_STANDALONE === 'true') {
75
+ const { app } = createStatelessServer(createMcpServer);
76
+ const port = process.env.PORT || 3000;
77
+ app.listen(port, () => {
78
+ console.error(`Palette MCP server listening on port ${port}`);
79
+ });
80
+ }
@@ -3,8 +3,17 @@ import { existsSync } from 'fs';
3
3
  import { join } from 'path';
4
4
  import { fileURLToPath } from 'url';
5
5
  import { dirname } from 'path';
6
- const __filename = fileURLToPath(import.meta.url);
7
- const __dirname = dirname(__filename);
6
+ // ESM과 CJS 모두 호환되는 __dirname 구현
7
+ let __dirname_resolved;
8
+ try {
9
+ // ESM 환경
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ __dirname_resolved = dirname(__filename);
12
+ }
13
+ catch {
14
+ // CJS 환경 또는 번들러 환경 - process.cwd() 사용
15
+ __dirname_resolved = process.cwd();
16
+ }
8
17
  /**
9
18
  * 요청 ID 생성 (타임스탬프 + 랜덤 문자열)
10
19
  */
@@ -17,7 +26,7 @@ export function generateRequestId() {
17
26
  * 요청별 폴더 경로 생성
18
27
  */
19
28
  export function getRequestFolderPath(requestId) {
20
- const projectRoot = join(__dirname, '..', '..');
29
+ const projectRoot = join(__dirname_resolved, '..', '..');
21
30
  return join(projectRoot, 'dist', 'requests', requestId);
22
31
  }
23
32
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "palette-mcp",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "MCP server for converting Figma designs to React/Vue components using design system",
5
5
  "main": "dist/index.js",
6
6
  "module": "src/smithery.ts",
@@ -35,6 +35,7 @@
35
35
  "test:services": "tsx src/test.ts",
36
36
  "test:figma-tools": "tsx src/test-figma-tools.ts",
37
37
  "test:mcp-servers": "tsx src/test-mcp-servers.ts",
38
+ "sync:ds": "tsx src/scripts/sync-design-system.ts",
38
39
  "mcp": "node dist/index.js",
39
40
  "mcp:dev": "tsx src/index.ts",
40
41
  "prepublishOnly": "npm run build"
@@ -69,10 +70,14 @@
69
70
  "node": ">=18.0.0"
70
71
  },
71
72
  "dependencies": {
72
- "@modelcontextprotocol/sdk": "^0.4.0",
73
+ "@modelcontextprotocol/sdk": "^1.20.0",
74
+ "@octokit/rest": "^21.0.0",
75
+ "@smithery/sdk": "^2.1.0",
73
76
  "axios": "^1.6.0",
77
+ "cors": "^2.8.5",
74
78
  "dotenv": "^17.2.3",
75
- "puppeteer": "^21.0.0",
79
+ "express": "^5.2.1",
80
+ "typescript": "^5.0.0",
76
81
  "zod": "^3.22.0"
77
82
  },
78
83
  "peerDependencies": {
@@ -88,13 +93,15 @@
88
93
  }
89
94
  },
90
95
  "devDependencies": {
96
+ "@types/cors": "^2.8.19",
97
+ "@types/express": "^5.0.6",
91
98
  "@types/jest": "^29.0.0",
92
99
  "@types/node": "^20.0.0",
100
+ "@types/puppeteer": "^7.0.4",
93
101
  "@types/react": "^19.2.2",
94
102
  "@types/react-dom": "^19.2.2",
95
103
  "jest": "^29.0.0",
96
- "tsx": "^4.20.6",
97
- "typescript": "^5.0.0"
104
+ "tsx": "^4.20.6"
98
105
  },
99
106
  "publishConfig": {
100
107
  "access": "public"
package/smithery.yaml CHANGED
@@ -1,12 +1,5 @@
1
1
  # Smithery.ai MCP Server Configuration
2
2
  # https://smithery.ai/docs/build/config
3
- #
4
- # 이 서버는 두 가지 모드를 지원합니다:
5
- # - Remote: Smithery.ai에서 호스팅 (runtime: typescript)
6
- # - Local: npx palette-mcp로 직접 실행
7
3
 
8
- # TypeScript 런타임으로 Smithery 호스팅
9
- runtime: typescript
10
-
11
- # Smithery가 로드할 모듈 (src/smithery.ts)
12
- # package.json의 "module" 필드와 연동됨
4
+ # TypeScript runtime: configSchema is defined in smithery.ts using zod
5
+ runtime: "typescript"