@fre4x/gemini 1.0.21 → 1.0.23

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.
Files changed (2) hide show
  1. package/dist/index.js +183 -146
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -55341,19 +55341,38 @@ if (!IS_MOCK && !API_KEY) {
55341
55341
  process.exit(1);
55342
55342
  }
55343
55343
  var ai = IS_MOCK ? null : new import_genai.GoogleGenAI({ apiKey: API_KEY });
55344
+ var MIME_MAP = {
55345
+ jpg: "image/jpeg",
55346
+ jpeg: "image/jpeg",
55347
+ png: "image/png",
55348
+ gif: "image/gif",
55349
+ webp: "image/webp",
55350
+ bmp: "image/bmp",
55351
+ mp4: "video/mp4",
55352
+ mov: "video/quicktime",
55353
+ avi: "video/x-msvideo",
55354
+ webm: "video/webm",
55355
+ mkv: "video/x-matroska",
55356
+ mp3: "audio/mpeg",
55357
+ wav: "audio/wav",
55358
+ ogg: "audio/ogg",
55359
+ flac: "audio/flac",
55360
+ pdf: "application/pdf"
55361
+ };
55362
+ function inferMimeType(url2) {
55363
+ const ext = url2.split("?")[0].split(".").pop()?.toLowerCase();
55364
+ return ext ? MIME_MAP[ext] ?? null : null;
55365
+ }
55344
55366
  var GENERATE_TEXT_TOOL = {
55345
55367
  name: "generate_text",
55346
55368
  description: "Generate text response from a prompt using Gemini",
55347
55369
  inputSchema: {
55348
55370
  type: "object",
55349
55371
  properties: {
55350
- prompt: {
55351
- type: "string",
55352
- description: "The text prompt to generate content from"
55353
- },
55372
+ prompt: { type: "string", description: "The text prompt to generate content from" },
55354
55373
  model: {
55355
55374
  type: "string",
55356
- description: "Gemini model (default: gemini-2.0-flash). Known models: gemini-2.5-pro-preview-03-25, gemini-2.0-flash, gemini-2.0-flash-lite, gemini-1.5-pro, gemini-1.5-flash",
55375
+ description: "Gemini model (default: gemini-2.0-flash). Use list_models to see options.",
55357
55376
  default: "gemini-2.0-flash"
55358
55377
  }
55359
55378
  },
@@ -55366,54 +55385,51 @@ var ANALYZE_MEDIA_TOOL = {
55366
55385
  inputSchema: {
55367
55386
  type: "object",
55368
55387
  properties: {
55369
- prompt: {
55370
- type: "string",
55371
- description: "Question or instruction about the media"
55372
- },
55373
- media_url: {
55374
- type: "string",
55375
- description: "URL or file:// path of the media file (image, video, or audio)"
55376
- },
55388
+ prompt: { type: "string", description: "Question or instruction about the media" },
55389
+ media_url: { type: "string", description: "URL or file:// path of the media file" },
55377
55390
  mime_type: {
55378
55391
  type: "string",
55379
- description: "MIME type of the media file"
55392
+ description: "MIME type (optional \u2014 auto-detected from URL extension if omitted)"
55380
55393
  },
55381
55394
  model: {
55382
55395
  type: "string",
55383
- description: "Gemini model (default: gemini-2.0-flash). Known models: gemini-2.5-pro-preview-03-25, gemini-2.0-flash, gemini-2.0-flash-lite, gemini-1.5-pro, gemini-1.5-flash",
55396
+ description: "Gemini model (default: gemini-2.0-flash)",
55384
55397
  default: "gemini-2.0-flash"
55385
55398
  }
55386
55399
  },
55387
- required: ["prompt", "media_url", "mime_type"]
55400
+ required: ["prompt", "media_url"]
55388
55401
  }
55389
55402
  };
55390
55403
  var LIST_MODELS_TOOL = {
55391
55404
  name: "list_models",
55392
- description: "List all available Gemini models for the current API key",
55405
+ description: "List available Gemini models grouped by capability (text, image, video)",
55393
55406
  inputSchema: {
55394
55407
  type: "object",
55395
- properties: {},
55408
+ properties: {
55409
+ capability: {
55410
+ type: "string",
55411
+ description: "Filter by capability: text, image, video, or all (default: all)",
55412
+ enum: ["all", "text", "image", "video"]
55413
+ }
55414
+ },
55396
55415
  required: []
55397
55416
  }
55398
55417
  };
55399
55418
  var GENERATE_IMAGE_TOOL = {
55400
55419
  name: "generate_image",
55401
- description: "Generate an image using Imagen 4.0",
55420
+ description: "Generate an image using Imagen and return it as base64",
55402
55421
  inputSchema: {
55403
55422
  type: "object",
55404
55423
  properties: {
55405
- prompt: {
55406
- type: "string",
55407
- description: "Description of the image to generate"
55408
- },
55424
+ prompt: { type: "string", description: "Description of the image to generate" },
55409
55425
  aspect_ratio: {
55410
55426
  type: "string",
55411
- description: "Aspect ratio of the generated image (e.g., 1:1, 16:9, 4:3, 9:16)",
55427
+ description: "Aspect ratio: 1:1, 16:9, 4:3, or 9:16 (default: 1:1)",
55412
55428
  default: "1:1"
55413
55429
  },
55414
55430
  model: {
55415
55431
  type: "string",
55416
- description: "Imagen model (default: imagen-3.0-generate-002). Known models: imagen-3.0-generate-002",
55432
+ description: "Imagen model (default: imagen-3.0-generate-002)",
55417
55433
  default: "imagen-3.0-generate-002"
55418
55434
  }
55419
55435
  },
@@ -55422,33 +55438,37 @@ var GENERATE_IMAGE_TOOL = {
55422
55438
  };
55423
55439
  var GENERATE_VIDEO_TOOL = {
55424
55440
  name: "generate_video",
55425
- description: "Generate a video using Veo",
55441
+ description: "Start async video generation using Veo. Returns an operation_name to poll with get_video_status.",
55426
55442
  inputSchema: {
55427
55443
  type: "object",
55428
55444
  properties: {
55429
- prompt: {
55430
- type: "string",
55431
- description: "Description of the video to generate"
55432
- },
55445
+ prompt: { type: "string", description: "Description of the video to generate" },
55433
55446
  model: {
55434
55447
  type: "string",
55435
- description: "Veo model (default: veo-2.0-generate-001). Known models: veo-2.0-generate-001, veo-3.0-generate-preview",
55448
+ description: "Veo model (default: veo-2.0-generate-001)",
55436
55449
  default: "veo-2.0-generate-001"
55437
55450
  }
55438
55451
  },
55439
55452
  required: ["prompt"]
55440
55453
  }
55441
55454
  };
55442
- var server = new Server(
55443
- {
55444
- name: "gemini-mcp",
55445
- version: "1.0.0"
55446
- },
55447
- {
55448
- capabilities: {
55449
- tools: {}
55450
- }
55455
+ var GET_VIDEO_STATUS_TOOL = {
55456
+ name: "get_video_status",
55457
+ description: "Poll the status of an async video generation started by generate_video. Returns done=true and video URLs when complete.",
55458
+ inputSchema: {
55459
+ type: "object",
55460
+ properties: {
55461
+ operation_name: {
55462
+ type: "string",
55463
+ description: "Operation name returned by generate_video"
55464
+ }
55465
+ },
55466
+ required: ["operation_name"]
55451
55467
  }
55468
+ };
55469
+ var server = new Server(
55470
+ { name: "gemini-mcp", version: "1.0.0" },
55471
+ { capabilities: { tools: {} } }
55452
55472
  );
55453
55473
  server.setRequestHandler(ListToolsRequestSchema, async () => ({
55454
55474
  tools: [
@@ -55456,125 +55476,107 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
55456
55476
  ANALYZE_MEDIA_TOOL,
55457
55477
  LIST_MODELS_TOOL,
55458
55478
  GENERATE_IMAGE_TOOL,
55459
- GENERATE_VIDEO_TOOL
55479
+ GENERATE_VIDEO_TOOL,
55480
+ GET_VIDEO_STATUS_TOOL
55460
55481
  ]
55461
55482
  }));
55462
55483
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
55463
55484
  const { name, arguments: args } = request.params;
55464
55485
  try {
55465
55486
  if (name === "generate_text") {
55466
- const { prompt, model = "gemini-2.0-flash" } = z2.object({
55467
- prompt: z2.string(),
55468
- model: z2.string().optional()
55469
- }).parse(args);
55487
+ const { prompt, model = "gemini-2.0-flash" } = z2.object({ prompt: z2.string(), model: z2.string().optional() }).parse(args);
55470
55488
  if (IS_MOCK) {
55471
- return {
55472
- content: [{ type: "text", text: `[Mock] Generated text for prompt: "${prompt}" using model: ${model}
55489
+ return { content: [{ type: "text", text: `[Mock] Generated text for: "${prompt}" (model: ${model})
55473
55490
 
55474
- This is a mock response. In production, Gemini would generate real content here.` }]
55475
- };
55491
+ Mock response \u2014 no API call made.` }] };
55476
55492
  }
55477
- const response = await ai.models.generateContent({
55478
- model,
55479
- contents: prompt
55480
- });
55481
- return {
55482
- content: [
55483
- {
55484
- type: "text",
55485
- text: response.text || "No response generated."
55486
- }
55487
- ]
55488
- };
55493
+ const response = await ai.models.generateContent({ model, contents: prompt });
55494
+ return { content: [{ type: "text", text: response.text || "No response generated." }] };
55489
55495
  }
55490
55496
  if (name === "analyze_media") {
55491
- const {
55492
- prompt,
55493
- media_url,
55494
- mime_type,
55495
- model = "gemini-2.0-flash"
55496
- } = z2.object({
55497
+ const { prompt, media_url, mime_type: providedMimeType, model = "gemini-2.0-flash" } = z2.object({
55497
55498
  prompt: z2.string(),
55498
55499
  media_url: z2.string(),
55499
- mime_type: z2.string(),
55500
+ mime_type: z2.string().optional(),
55500
55501
  model: z2.string().optional()
55501
55502
  }).parse(args);
55502
- if (IS_MOCK) {
55503
+ const mime_type = providedMimeType ?? inferMimeType(media_url);
55504
+ if (!mime_type) {
55503
55505
  return {
55504
- content: [{ type: "text", text: `[Mock] Analyzed media at: ${media_url} (${mime_type})
55506
+ content: [{ type: "text", text: "Error: Could not auto-detect MIME type from URL. Provide mime_type explicitly (e.g. image/jpeg, video/mp4, audio/mpeg)." }],
55507
+ isError: true
55508
+ };
55509
+ }
55510
+ if (IS_MOCK) {
55511
+ return { content: [{ type: "text", text: `[Mock] Analyzed ${media_url} (${mime_type})
55505
55512
  Prompt: "${prompt}"
55506
55513
 
55507
- This is a mock response. In production, Gemini would analyze the actual media.` }]
55508
- };
55514
+ Mock response \u2014 no API call made.` }] };
55509
55515
  }
55510
55516
  let base64Data;
55511
55517
  if (media_url.startsWith("file://")) {
55512
- const filePath = decodeURIComponent(
55513
- media_url.replace("file://", "")
55514
- );
55515
- const fileBuffer = await fs.readFile(filePath);
55516
- base64Data = fileBuffer.toString("base64");
55518
+ const filePath = decodeURIComponent(media_url.replace("file://", ""));
55519
+ base64Data = (await fs.readFile(filePath)).toString("base64");
55517
55520
  } else {
55518
- const mediaResponse = await fetch(media_url);
55519
- const mediaBuffer = await mediaResponse.arrayBuffer();
55520
- base64Data = Buffer.from(mediaBuffer).toString("base64");
55521
+ const buf = await (await fetch(media_url)).arrayBuffer();
55522
+ base64Data = Buffer.from(buf).toString("base64");
55521
55523
  }
55522
55524
  const response = await ai.models.generateContent({
55523
55525
  model,
55524
- contents: [
55525
- {
55526
- role: "user",
55527
- parts: [
55528
- { text: prompt },
55529
- {
55530
- inlineData: {
55531
- data: base64Data,
55532
- mimeType: mime_type
55533
- }
55534
- }
55535
- ]
55536
- }
55537
- ]
55526
+ contents: [{ role: "user", parts: [{ text: prompt }, { inlineData: { data: base64Data, mimeType: mime_type } }] }]
55538
55527
  });
55539
- return {
55540
- content: [
55541
- {
55542
- type: "text",
55543
- text: response.text || "No analysis generated."
55544
- }
55545
- ]
55546
- };
55528
+ return { content: [{ type: "text", text: response.text || "No analysis generated." }] };
55547
55529
  }
55548
55530
  if (name === "list_models") {
55531
+ const { capability = "all" } = z2.object({ capability: z2.string().optional() }).parse(args ?? {});
55549
55532
  if (IS_MOCK) {
55550
55533
  return {
55551
- content: [{ type: "text", text: "Available models:\nmodels/gemini-2.5-pro-preview-03-25\nmodels/gemini-2.0-flash\nmodels/gemini-2.0-flash-lite\nmodels/gemini-1.5-pro\nmodels/gemini-1.5-flash\nmodels/imagen-3.0-generate-001\nmodels/veo-2.0-generate-001" }]
55534
+ content: [{ type: "text", text: [
55535
+ "## Available Gemini Models\n",
55536
+ "### \u{1F4DD} Text Generation",
55537
+ "- gemini-2.5-pro-preview-03-25 (latest, most capable)",
55538
+ "- gemini-2.0-flash (fast, recommended default)",
55539
+ "- gemini-2.0-flash-lite (lightweight)",
55540
+ "- gemini-1.5-pro (stable)",
55541
+ "- gemini-1.5-flash (stable, fast)",
55542
+ "\n### \u{1F5BC}\uFE0F Image Generation (use with generate_image)",
55543
+ "- imagen-3.0-generate-002",
55544
+ "\n### \u{1F3AC} Video Generation (use with generate_video + get_video_status)",
55545
+ "- veo-2.0-generate-001"
55546
+ ].join("\n") }]
55552
55547
  };
55553
55548
  }
55554
55549
  const resp = await fetch(
55555
55550
  `https://generativelanguage.googleapis.com/v1beta/models?key=${API_KEY}&pageSize=200`
55556
55551
  );
55557
- if (!resp.ok) {
55558
- throw new Error(`Failed to list models: ${resp.status} ${resp.statusText}`);
55559
- }
55552
+ if (!resp.ok) throw new Error(`Failed to list models: ${resp.status} ${resp.statusText}`);
55560
55553
  const data = await resp.json();
55561
- const modelList = (data.models ?? []).map((m) => m.name);
55562
- return {
55563
- content: [
55564
- {
55565
- type: "text",
55566
- text: modelList.length > 0 ? `Available models:
55567
- ${modelList.join("\n")}` : "No models found."
55568
- }
55569
- ]
55570
- };
55554
+ const models = (data.models ?? []).map((m) => ({
55555
+ name: m.name.replace("models/", ""),
55556
+ methods: m.supportedGenerationMethods ?? []
55557
+ }));
55558
+ const textModels = models.filter((m) => m.methods.includes("generateContent"));
55559
+ const imageModels = models.filter((m) => m.methods.includes("predict"));
55560
+ const videoModels = models.filter((m) => m.name.startsWith("veo"));
55561
+ const lines = ["## Available Gemini Models\n"];
55562
+ if (capability === "all" || capability === "text") {
55563
+ lines.push("### \u{1F4DD} Text Generation");
55564
+ for (const m of textModels) lines.push(`- ${m.name}`);
55565
+ lines.push("");
55566
+ }
55567
+ if (capability === "all" || capability === "image") {
55568
+ lines.push("### \u{1F5BC}\uFE0F Image Generation (use with generate_image)");
55569
+ for (const m of imageModels) lines.push(`- ${m.name}`);
55570
+ lines.push("");
55571
+ }
55572
+ if (capability === "all" || capability === "video") {
55573
+ lines.push("### \u{1F3AC} Video Generation (use with generate_video + get_video_status)");
55574
+ for (const m of videoModels) lines.push(`- ${m.name}`);
55575
+ }
55576
+ return { content: [{ type: "text", text: lines.join("\n").trim() || "No models found." }] };
55571
55577
  }
55572
55578
  if (name === "generate_image") {
55573
- const {
55574
- prompt,
55575
- aspect_ratio = "1:1",
55576
- model = "imagen-3.0-generate-002"
55577
- } = z2.object({
55579
+ const { prompt, aspect_ratio = "1:1", model = "imagen-3.0-generate-002" } = z2.object({
55578
55580
  prompt: z2.string(),
55579
55581
  aspect_ratio: z2.string().optional(),
55580
55582
  model: z2.string().optional()
@@ -55587,49 +55589,84 @@ ${modelList.join("\n")}` : "No models found."
55587
55589
  const response = await ai.models.generateImages({
55588
55590
  model,
55589
55591
  prompt,
55590
- config: {
55591
- aspectRatio: aspect_ratio
55592
- }
55592
+ config: { aspectRatio: aspect_ratio }
55593
55593
  });
55594
- const images = response.generatedImages.map((img) => ({
55594
+ const images = (response.generatedImages ?? []).map((img) => ({
55595
55595
  type: "image",
55596
55596
  data: img.image.imageBytes,
55597
55597
  mimeType: "image/png"
55598
55598
  }));
55599
+ if (images.length === 0) {
55600
+ return {
55601
+ content: [{ type: "text", text: `Image generation returned no results. Possible reasons:
55602
+ - Content policy violation in prompt
55603
+ - Model unavailable (${model}) in your region/API tier
55604
+ - Prompt unsupported or aspect ratio invalid (${aspect_ratio})
55605
+
55606
+ Check Imagen access at https://ai.google.dev/` }],
55607
+ isError: true
55608
+ };
55609
+ }
55610
+ return { content: images };
55611
+ }
55612
+ if (name === "generate_video") {
55613
+ const { prompt, model = "veo-2.0-generate-001" } = z2.object({ prompt: z2.string(), model: z2.string().optional() }).parse(args);
55614
+ if (IS_MOCK) {
55615
+ return { content: [{ type: "text", text: `[Mock] Video generation started.
55616
+ Operation name: mock-operations/123456
55617
+
55618
+ Call get_video_status with operation_name="mock-operations/123456" to check progress.` }] };
55619
+ }
55620
+ const operation = await ai.models.generateVideos({ model, prompt });
55621
+ const opName = operation.name ?? "unknown";
55599
55622
  return {
55600
- content: images
55623
+ content: [{ type: "text", text: `Video generation started (async \u2014 typically takes 2\u20135 minutes).
55624
+
55625
+ Operation name: ${opName}
55626
+
55627
+ Call get_video_status with:
55628
+ operation_name="${opName}"
55629
+
55630
+ Poll every ~30 seconds until done=true.` }]
55601
55631
  };
55602
55632
  }
55603
- if (name === "generate_video") {
55604
- const { prompt, model = "veo-2.0-generate-001" } = z2.object({
55605
- prompt: z2.string(),
55606
- model: z2.string().optional()
55607
- }).parse(args);
55633
+ if (name === "get_video_status") {
55634
+ const { operation_name } = z2.object({ operation_name: z2.string() }).parse(args);
55608
55635
  if (IS_MOCK) {
55636
+ return { content: [{ type: "text", text: `[Mock] Operation: ${operation_name}
55637
+ done: true
55638
+ Video URL: https://example.com/mock-video.mp4` }] };
55639
+ }
55640
+ const resp = await fetch(
55641
+ `https://generativelanguage.googleapis.com/v1beta/${operation_name}?key=${API_KEY}`
55642
+ );
55643
+ if (!resp.ok) throw new Error(`Failed to get operation: ${resp.status} ${resp.statusText}`);
55644
+ const op = await resp.json();
55645
+ if (!op.done) {
55646
+ return { content: [{ type: "text", text: `Operation ${operation_name} is still in progress. Check back in ~30 seconds.` }] };
55647
+ }
55648
+ if (op.error) {
55609
55649
  return {
55610
- content: [{ type: "text", text: `[Mock] Video generation started for prompt: "${prompt}" using model: ${model}
55611
- Operation ID: mock-op-12345. Note: Video generation is asynchronous and may take some time.` }]
55650
+ content: [{ type: "text", text: `Video generation failed: ${op.error.message ?? JSON.stringify(op.error)}` }],
55651
+ isError: true
55612
55652
  };
55613
55653
  }
55614
- const operation = await ai.models.generateVideos({
55615
- model,
55616
- prompt
55617
- });
55654
+ const videos = (op.response?.generatedVideos ?? []).map((v) => v.video?.uri ?? "").filter(Boolean);
55618
55655
  return {
55619
- content: [
55620
- {
55621
- type: "text",
55622
- text: `Video generation started. Operation ID: ${operation.name}. Note: Video generation is asynchronous and may take some time.`
55623
- }
55624
- ]
55656
+ content: [{
55657
+ type: "text",
55658
+ text: videos.length > 0 ? `Video generation complete!
55659
+
55660
+ Download URLs:
55661
+ ${videos.join("\n")}` : `Complete but no video URLs found:
55662
+ ${JSON.stringify(op.response, null, 2)}`
55663
+ }]
55625
55664
  };
55626
55665
  }
55627
55666
  throw new Error(`Tool not found: ${name}`);
55628
55667
  } catch (error48) {
55629
55668
  if (error48 instanceof z2.ZodError) {
55630
- throw new Error(
55631
- `Invalid arguments: ${error48.issues.map((e) => `${e.path.join(".")}: ${e.message}`).join(", ")}`
55632
- );
55669
+ throw new Error(`Invalid arguments: ${error48.issues.map((e) => `${e.path.join(".")}: ${e.message}`).join(", ")}`);
55633
55670
  }
55634
55671
  throw error48;
55635
55672
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fre4x/gemini",
3
- "version": "1.0.21",
3
+ "version": "1.0.23",
4
4
  "description": "A Gemini MCP server providing text completion, multimodal analysis, and image/video generation.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",