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 +9 -6
- package/build/lib/gemini.js +85 -51
- package/package.json +1 -1
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.
|
|
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.
|
|
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
|
-
|
|
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
|
|
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.
|
|
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.
|
|
369
|
+
console.error("gemini-design-mcp v3.9.0 running on stdio");
|
|
367
370
|
}
|
|
368
371
|
}
|
|
369
372
|
main().catch((error) => {
|
package/build/lib/gemini.js
CHANGED
|
@@ -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
|
-
//
|
|
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
|
-
"
|
|
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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
70
|
-
|
|
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
|
}
|