Skip to main content
Glama
pushGeminiText.ts4.67 kB
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { messagingApi } from "@line/bot-sdk"; import { z } from "zod"; import { createErrorResponse, createSuccessResponse, } from "../common/response.js"; import { AbstractTool } from "./AbstractTool.js"; import { NO_USER_ID_ERROR } from "../common/schema/constants.js"; type GenerateContentResponse = { candidates?: Array<{ content?: { parts?: Array<{ text?: string }>; }; }>; error?: { message?: string }; }; export default class PushGeminiText extends AbstractTool { private client: messagingApi.MessagingApiClient; private destinationId: string; constructor(client: messagingApi.MessagingApiClient, destinationId: string) { super(); this.client = client; this.destinationId = destinationId; } register(server: McpServer) { const userIdSchema = z .string() .default(this.destinationId) .describe( "The user ID to receive a message. Defaults to DESTINATION_USER_ID.", ); const modelSchema = z .string() .default("gemini-1.5-flash") .describe("Gemini model name, e.g., gemini-1.5-flash"); const promptSchema = z.string().min(1).describe("Prompt to send to Gemini"); server.tool( "push_gemini_text", "Generate text with Gemini and push it to a LINE user as a text message.", { userId: userIdSchema, prompt: promptSchema, model: modelSchema, }, async ({ userId, prompt, model }) => { if (!userId) { return createErrorResponse(NO_USER_ID_ERROR); } const apiKey = process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY; if (!apiKey) { return createErrorResponse( "Please set GEMINI_API_KEY (or GOOGLE_API_KEY) in environment variables.", ); } try { async function callGeminiOnce( modelName: string, apiVersion: "v1" | "v1beta", ) { const endpoint = `https://generativelanguage.googleapis.com/${apiVersion}/models/${encodeURIComponent( modelName, )}:generateContent`; const body = { contents: [ { role: "user", parts: [{ text: prompt }], }, ], }; const res = await fetch(endpoint, { method: "POST", headers: { "Content-Type": "application/json", "X-goog-api-key": apiKey, }, body: JSON.stringify(body), }); return res; } const tryModels: string[] = [model]; if (!model.endsWith("-latest")) tryModels.push(`${model}-latest`); for (const m of [ "gemini-2.0-flash", "gemini-2.0-flash-latest", "gemini-1.5-flash-latest", ]) { if (!tryModels.includes(m)) tryModels.push(m); } let res: Response | undefined; let lastErrorText = ""; for (const m of tryModels) { for (const ver of ["v1", "v1beta"] as const) { res = await callGeminiOnce(m, ver); if (res.ok) { break; } lastErrorText = await res.text(); if (res.status !== 404) break; } if (res?.ok) break; } if (!res || !res.ok) { return createErrorResponse( `Gemini API error: HTTP ${res?.status} ${res?.statusText} - ${lastErrorText}`, ); } const data = (await res.json()) as GenerateContentResponse; const generated = data?.candidates?.[0]?.content?.parts ?.map(p => p.text || "") .join("") || ""; if (!generated) { return createErrorResponse( data?.error?.message || "Gemini returned empty content.", ); } // LINE text message limit is 2000 chars const textMessage = generated.slice(0, 2000); const response = await this.client.pushMessage({ to: userId, messages: [ { type: "text", text: textMessage, } as unknown as messagingApi.Message, ], }); return createSuccessResponse(response); } catch (error: any) { return createErrorResponse( `Failed to push Gemini text: ${error.message}`, ); } }, ); } }

Implementation Reference

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/tndfame/mcp_management'

If you have feedback or need assistance with the MCP directory API, please join our Discord server