gemini-design-mcp 3.8.0 → 3.9.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.
package/build/index.js CHANGED
@@ -11,7 +11,7 @@ import { generateVibesSchema, generateVibes } from "./tools/generate-vibes.js";
11
11
  // Create MCP server
12
12
  const server = new McpServer({
13
13
  name: "gemini-design-mcp",
14
- version: "3.8.0",
14
+ version: "3.9.0",
15
15
  });
16
16
  // =============================================================================
17
17
  // TOOL 1: CREATE_FRONTEND
@@ -304,7 +304,7 @@ async function main() {
304
304
  res.json({
305
305
  status: "ok",
306
306
  service: "gemini-design-mcp",
307
- version: "3.8.0",
307
+ version: "3.9.0",
308
308
  transport: "sse",
309
309
  timestamp: Date.now(),
310
310
  });
@@ -315,9 +315,12 @@ async function main() {
315
315
  const authHeader = req.headers.authorization;
316
316
  const apiKey = authHeader?.replace("Bearer ", "");
317
317
 
318
- if (!apiKey || !apiKey.startsWith("gd_")) {
318
+ // Accept both platform keys (gd_) and Google API keys (AIza)
319
+ const isValidKey = apiKey && (apiKey.startsWith("gd_") || apiKey.startsWith("AIza"));
320
+ if (!isValidKey) {
319
321
  return res.status(401).json({
320
- error: "Missing or invalid API key. Use Authorization: Bearer gd_xxx",
322
+ error: "Missing or invalid API key. Use Authorization: Bearer <key>. " +
323
+ "Accepted formats: gd_xxx (platform) or AIza... (Google API key)",
321
324
  });
322
325
  }
323
326
 
@@ -354,7 +357,7 @@ async function main() {
354
357
 
355
358
  const port = parseInt(process.env.PORT || "3000", 10);
356
359
  app.listen(port, "0.0.0.0", () => {
357
- console.log(`gemini-design-mcp v3.8.0 running on SSE transport`);
360
+ console.log(`gemini-design-mcp v3.9.0 running on SSE transport`);
358
361
  console.log(` SSE endpoint: http://0.0.0.0:${port}/sse`);
359
362
  console.log(` Messages endpoint: http://0.0.0.0:${port}/messages`);
360
363
  console.log(` Health check: http://0.0.0.0:${port}/health`);
@@ -363,7 +366,7 @@ async function main() {
363
366
  // Stdio mode (default, for local IDE usage)
364
367
  const transport = new StdioServerTransport();
365
368
  await server.connect(transport);
366
- console.error("gemini-design-mcp v3.8.0 running on stdio");
369
+ console.error("gemini-design-mcp v3.9.0 running on stdio");
367
370
  }
368
371
  }
369
372
  main().catch((error) => {
@@ -2,71 +2,105 @@
2
2
  const PROXY_URL = "https://dashing-alpaca-785.convex.site/v1/generate";
3
3
  // Default model - Gemini 3 Flash Preview
4
4
  export const DEFAULT_MODEL = "gemini-3-flash-preview";
5
- // Get and validate API key
5
+ // Import Google Generative AI SDK for BYOK (Bring Your Own Key)
6
+ import { GoogleGenAI } from "@google/genai";
7
+ // Get and validate API key - supports both platform keys (gd_) and Google API keys (AIza)
6
8
  function getApiKey() {
7
9
  const apiKey = process.env.API_KEY;
8
10
  if (!apiKey) {
9
11
  throw new Error("Missing API_KEY environment variable. " +
10
- "Get your API key at https://gemini-design-mcp.com/dashboard/api-keys");
12
+ "Use either a platform key (gd_xxx) from https://gemini-design-mcp.com/dashboard/api-keys " +
13
+ "or a Google API key (AIza...) from https://aistudio.google.com/apikey");
11
14
  }
12
- if (!apiKey.startsWith("gd_")) {
13
- throw new Error("Invalid API key format. API keys must start with 'gd_'. " +
14
- "Get your API key at https://gemini-design-mcp.com/dashboard/api-keys");
15
+ // Accept both platform keys (gd_) and Google API keys (AIza)
16
+ if (!apiKey.startsWith("gd_") && !apiKey.startsWith("AIza")) {
17
+ throw new Error("Invalid API key format. Use either:\n" +
18
+ "- Platform key starting with 'gd_' from https://gemini-design-mcp.com/dashboard/api-keys\n" +
19
+ "- Google API key starting with 'AIza' from https://aistudio.google.com/apikey");
15
20
  }
16
21
  return apiKey;
17
22
  }
23
+ // Generate via platform proxy (for gd_ keys)
24
+ async function generateViaProxy(apiKey, systemPrompt, userPrompt, model, thinkingMode, endpoint) {
25
+ const response = await fetch(PROXY_URL, {
26
+ method: "POST",
27
+ headers: {
28
+ "Content-Type": "application/json",
29
+ "Authorization": `Bearer ${apiKey}`,
30
+ },
31
+ body: JSON.stringify({
32
+ model,
33
+ endpoint,
34
+ contents: [
35
+ {
36
+ role: "user",
37
+ parts: [{ text: userPrompt }],
38
+ },
39
+ ],
40
+ systemInstruction: {
41
+ parts: [{ text: systemPrompt }],
42
+ },
43
+ generationConfig: {
44
+ temperature: 1,
45
+ },
46
+ // Pass thinking mode for billing/logging purposes
47
+ thinkingMode,
48
+ }),
49
+ });
50
+ const result = await response.json();
51
+ if (!response.ok) {
52
+ const errorMsg = result.error || `API error: ${response.status}`;
53
+ // Check for credit/quota related errors
54
+ if (errorMsg.toLowerCase().includes('credit') ||
55
+ errorMsg.toLowerCase().includes('quota') ||
56
+ errorMsg.toLowerCase().includes('insufficient') ||
57
+ errorMsg.toLowerCase().includes('limit') ||
58
+ response.status === 402 ||
59
+ response.status === 429) {
60
+ throw new Error(`${errorMsg}\n\n Top up your credits here: https://gemini-design-mcp.com/settings/billing`);
61
+ }
62
+ throw new Error(errorMsg);
63
+ }
64
+ // Extract text from Gemini response format
65
+ const text = result.candidates?.[0]?.content?.parts?.[0]?.text;
66
+ if (!text) {
67
+ throw new Error("No content in response");
68
+ }
69
+ return text;
70
+ }
71
+ // Generate via direct Google API (for AIza keys - BYOK)
72
+ async function generateViaDirect(apiKey, systemPrompt, userPrompt, model) {
73
+ const ai = new GoogleGenAI({ apiKey });
74
+ const response = await ai.models.generateContent({
75
+ model,
76
+ contents: userPrompt,
77
+ config: {
78
+ systemInstruction: systemPrompt,
79
+ temperature: 1,
80
+ },
81
+ });
82
+ const text = response.text;
83
+ if (!text) {
84
+ throw new Error("No content in response from Google API");
85
+ }
86
+ return text;
87
+ }
18
88
  export async function generateWithGemini(systemPrompt, userPrompt, model = DEFAULT_MODEL, thinkingMode = "minimal", endpoint = "generate") {
19
89
  const apiKey = getApiKey();
90
+ const isGoogleKey = apiKey.startsWith("AIza");
20
91
  try {
21
- const response = await fetch(PROXY_URL, {
22
- method: "POST",
23
- headers: {
24
- "Content-Type": "application/json",
25
- "Authorization": `Bearer ${apiKey}`,
26
- },
27
- body: JSON.stringify({
28
- model,
29
- endpoint,
30
- contents: [
31
- {
32
- role: "user",
33
- parts: [{ text: userPrompt }],
34
- },
35
- ],
36
- systemInstruction: {
37
- parts: [{ text: systemPrompt }],
38
- },
39
- generationConfig: {
40
- temperature: 1,
41
- },
42
- // Pass thinking mode for billing/logging purposes
43
- thinkingMode,
44
- }),
45
- });
46
- const result = await response.json();
47
- if (!response.ok) {
48
- const errorMsg = result.error || `API error: ${response.status}`;
49
- // Check for credit/quota related errors
50
- if (errorMsg.toLowerCase().includes('credit') ||
51
- errorMsg.toLowerCase().includes('quota') ||
52
- errorMsg.toLowerCase().includes('insufficient') ||
53
- errorMsg.toLowerCase().includes('limit') ||
54
- response.status === 402 ||
55
- response.status === 429) {
56
- throw new Error(`${errorMsg}\n\nšŸ’³ Top up your credits here: https://gemini-design-mcp.com/settings/billing`);
57
- }
58
- throw new Error(errorMsg);
59
- }
60
- // Extract text from Gemini response format
61
- const text = result.candidates?.[0]?.content?.parts?.[0]?.text;
62
- if (!text) {
63
- throw new Error("No content in response");
92
+ if (isGoogleKey) {
93
+ // BYOK: Direct call to Google API
94
+ return await generateViaDirect(apiKey, systemPrompt, userPrompt, model);
95
+ } else {
96
+ // Platform key: Use proxy
97
+ return await generateViaProxy(apiKey, systemPrompt, userPrompt, model, thinkingMode, endpoint);
64
98
  }
65
- return text;
66
99
  }
67
100
  catch (error) {
68
101
  const errorMessage = error instanceof Error ? error.message : "Unknown error";
69
- console.error("Gemini Design API error:", errorMessage);
70
- throw new Error(`Gemini Design API error: ${errorMessage}`);
102
+ const source = isGoogleKey ? "Google Gemini API" : "Gemini Design API";
103
+ console.error(`${source} error:`, errorMessage);
104
+ throw new Error(`${source} error: ${errorMessage}`);
71
105
  }
72
106
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gemini-design-mcp",
3
- "version": "3.8.0",
3
+ "version": "3.9.0",
4
4
  "description": "MCP server that uses Gemini 3 Pro for frontend/design code generation",
5
5
  "main": "build/index.js",
6
6
  "bin": {