push_gemini_text
Generate AI text responses using Gemini models and deliver them directly to LINE users as messages through the LINE Messaging API.
Instructions
Generate text with Gemini and push it to a LINE user as a text message.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| model | No | Gemini model name, e.g., gemini-1.5-flash | gemini-1.5-flash |
| prompt | Yes | Prompt to send to Gemini | |
| userId | No | The user ID to receive a message. Defaults to DESTINATION_USER_ID. | U1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p |
Implementation Reference
- src/tools/pushGeminiText.ts:53-153 (handler)The core handler function for the 'push_gemini_text' tool. It checks for userId and API key, calls the Gemini API with fallback logic for models ('gemini-1.5-flash' etc.) and API versions (v1/v1beta), extracts the generated text, truncates to 2000 characters (LINE limit), and pushes it as a text message to the specified LINE user using the messaging client.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}`, ); } },
- src/tools/pushGeminiText.ts:31-52 (schema)Zod input schemas for the tool parameters: userId (string, default destinationId), model (string, default 'gemini-1.5-flash'), prompt (non-empty string). Used in server.tool call.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, },
- src/index.ts:24-71 (registration)Imports the PushGeminiText class and instantiates it with the LINE messaging client and destination ID, then calls .register(server) to register all tools including 'push_gemini_text' with the MCP server.import PushGeminiText from "./tools/pushGeminiText.js"; import CancelRichMenuDefault from "./tools/cancelRichMenuDefault.js"; import PushTextMessage from "./tools/pushTextMessage.js"; import PushFlexMessage from "./tools/pushFlexMessage.js"; import BroadcastTextMessage from "./tools/broadcastTextMessage.js"; import BroadcastFlexMessage from "./tools/broadcastFlexMessage.js"; import GetProfile from "./tools/getProfile.js"; import GetMessageQuota from "./tools/getMessageQuota.js"; import GetRichMenuList from "./tools/getRichMenuList.js"; import DeleteRichMenu from "./tools/deleteRichMenu.js"; import SetRichMenuDefault from "./tools/setRichMenuDefault.js"; import PushGeminiFlex from "./tools/pushGeminiFlex.js"; import GeminiCommand from "./tools/geminiCommand.js"; import PushMessages from "./tools/pushMessages.js"; import BroadcastMessages from "./tools/broadcastMessages.js"; import QueryMssql from "./tools/queryMssql.js"; import ExportMssqlKnowledge from "./tools/exportMssqlKnowledge.js"; import AiQueryMssql from "./tools/aiQueryMssql.js"; // Load environment variables from .env if present (no external deps) loadEnvFromDotenv(); const server = new McpServer({ name: "line-bot", version: LINE_BOT_MCP_SERVER_VERSION, }); const channelAccessToken = process.env.CHANNEL_ACCESS_TOKEN || ""; const destinationId = process.env.DESTINATION_USER_ID || ""; const messagingApiClient = new line.messagingApi.MessagingApiClient({ channelAccessToken: channelAccessToken, defaultHeaders: { "User-Agent": USER_AGENT, }, }); new PushTextMessage(messagingApiClient, destinationId).register(server); new PushFlexMessage(messagingApiClient, destinationId).register(server); new BroadcastTextMessage(messagingApiClient).register(server); new BroadcastFlexMessage(messagingApiClient).register(server); new GetProfile(messagingApiClient, destinationId).register(server); new GetMessageQuota(messagingApiClient).register(server); new GetRichMenuList(messagingApiClient).register(server); new DeleteRichMenu(messagingApiClient).register(server); new SetRichMenuDefault(messagingApiClient).register(server); new CancelRichMenuDefault(messagingApiClient).register(server); new PushGeminiText(messagingApiClient, destinationId).register(server);
- src/tools/pushGeminiText.ts:45-154 (registration)Inside the PushGeminiText class's register method, calls server.tool to register the 'push_gemini_text' tool with its name, description, input schema, and handler function.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}`, ); } }, );