Skip to main content
Glama
wasintoh

line-oa-mcp-ultimate

by wasintoh

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
LINE_CHANNEL_ACCESS_TOKENYesThe channel access token for your LINE Messaging API channel.

Capabilities

Features and capabilities supported by this server

CapabilityDetails
tools
{
  "listChanged": true
}
prompts
{
  "listChanged": true
}
resources
{
  "listChanged": true
}

Tools

Functions exposed to the LLM to take actions

NameDescription
line_send_messageA

Send any LINE message to any target. Picks the right LINE API automatically (reply / push / multicast / narrowcast / broadcast) based on the shape of target.

Three modes (parameter mode):

  • send_now (default): Send immediately. Pre-flight validation + Quota Guardian + quiet-hours check are applied.

  • draft: DO NOT SEND. Return a "handoff package" with audience id, Flex JSON, a LINE OA Manager broadcast URL, and 6 click-through steps. Use this when the user wants to SCHEDULE — LINE OA Manager UI has native scheduling that Messaging API lacks.

  • dry_run: Validate + estimate cost only. Useful before confirm flows.

Target shapes (pick one):

  • { reply_to: "webhookEventId" } — reply (1 user, free, 30s window)

  • { user_id: "U..." } — push to one

  • { user_ids: ["U...", "U..."] } — multicast (auto-chunked to 500/call)

  • { audience: "name-or-id" } — narrowcast by audience group

  • { filter: { ages, genders, areas, ... } } — narrowcast by demographic

  • { everyone: true } — broadcast (requires confirm: true)

Message shapes (pick one):

  • { text: "..." } — plain text (≤5000 chars)

  • { template: "voucher", data: {...} } — pre-built Thai-localized Flex template

  • { flex_json: {...}, alt_text: "..." } — raw Flex JSON (advanced)

  • { sticker: { package_id, sticker_id } } — LINE sticker

  • { coupon_id: "01..." , delivery_tag? } — native LINE coupon (from line_manage_coupon)

Auto-applied safety:

  • Pre-flight validation via LINE /validate (catches JSON errors before consuming quota)

  • Quota Guardian: blocks if projected cost > 95% of remaining quota unless confirm=true

  • Quiet-hours warning (22:00–08:00 BKK) unless force=true

  • Reply-token TTL handling: falls back to push if token is expired (with a warning)

  • Auto-generated X-Line-Retry-Key for safe retries

Returns (varies by mode): send_now → { success, transport, request_id?, recipient_count_estimated, quota, warnings[], next_steps? } draft → { draft: true, oa_manager_url, audience_summary, flex_json_pretty, flex_preview_url, copy_paste_steps[], notes } dry_run → { dry_run: true, transport, validated, projected_recipients, projected_cost_messages, quota, warnings[] }

Examples:

  • "ส่งข้อความให้คุณ A" → { target: { user_id: "U..." }, message: { text: "..." } }

  • "ออกแบบโปรวันแม่ + เตรียม schedule" → { target: { audience: "moms" }, message: { template: "promo_simple", data: {...} }, mode: "draft" }

  • "ส่งโปรให้ผู้หญิง 25-44 กรุงเทพ" → { target: { filter: { genders: ["female"], ages: ["age_25", "age_30"], areas: ["bangkok"] } }, message: {...} }

Errors:

  • QUOTA_OVER → Reduce audience or wait for monthly reset

  • QUIET_HOURS → Pass force=true or use mode=draft to schedule

  • INVALID_MESSAGE → Pre-validation caught a JSON error; check details

  • AUDIENCE_NOT_READY → Wait ~10 minutes after audience creation

line_find_stickerA

Find LINE stickers from a curated catalog by mood or keyword. Both Thai and English search terms are supported.

LINE only allows bots to send stickers from a limited official list. This tool lets agents pick stickers by intent ("celebration", "ขอบคุณ", "sorry") rather than guessing IDs.

Args:

  • query: Mood or keyword. Examples: "ขอบคุณ", "celebration", "sorry", "love".

  • limit: Number of suggestions (1-20). Default 5.

  • response_format: 'markdown' (default) | 'json'.

Returns: { query, count, stickers: [{ package_id, sticker_id, moods, keywords_th, keywords_en, description }] }

Pass the chosen package_id + sticker_id to line_send_message: { message: { sticker: { package_id, sticker_id } } }

Examples:

  • "หา sticker ขอบคุณ" → { query: "ขอบคุณ" }

  • "celebration sticker" → { query: "celebration" }

line_build_rich_menuA

Create a LINE Rich Menu in one call: validate → create → upload image → set as default. Collapses what is normally 4 LINE API calls into one tool, including the api-data.line.me domain switch for image upload (the #1 cause of failed implementations).

This V1 supports single-panel rich menus. The "tab-pair" (Tab A ↔ Tab B switching design) shipped widely by Thai agencies will be added in V1.1 alongside richmenu alias support.

Args:

  • name: Internal admin name (≤300 chars).

  • chat_bar_text: Label on the chat-bar button (≤14 chars). Show in user's LINE UI.

  • size: 'compact' (2500x843) or 'large' (2500x1686, default).

  • image_url: Public HTTPS URL of the rich menu image. JPEG/PNG, aspect ≥1.45, ≤1MB.

  • areas: Tappable regions with action objects (postback / message / uri / richmenuswitch).

  • set_as_default: Set as account-wide default after creation. Default true.

  • selected: Whether the menu auto-opens. Default true.

  • oa: Optional OA id.

Returns: { rich_menu_id: string, name: string, set_as_default: boolean, warnings: string[] }

Image requirements (validated client-side before upload):

  • Width: 800-2500px

  • Aspect ratio: ≥1.45

  • File size: ≤1MB

  • Format: JPEG or PNG

Examples:

  • "Rich Menu โปรวันแม่ 2 ปุ่ม" → params with 2 areas, large size, set_as_default: true

Errors:

  • INVALID_AREA → Coordinates exceed image bounds

  • IMAGE_TOO_LARGE → ≥1MB; resize and retry

  • QUOTA_EXCEEDED → 1,000 rich menus max per OA

line_list_rich_menusA

List all rich menus on an OA + identify which one is the account-wide default. OAs can hold up to 1,000 rich menus — use line_delete_rich_menu to clean up.

Args:

  • oa: optional OA id.

  • response_format: 'markdown' (default) | 'json'.

Returns: { total: number, default_id?: string, rich_menus: [{ rich_menu_id, name, chat_bar_text?, size?, is_default, is_selected }] }

Use this before line_build_rich_menu to avoid hitting the 1,000-menu cap.

line_delete_rich_menuA

Delete a rich menu by ID. If the menu is currently linked to specific users, those links break silently — consider running line_audit_user_menu first.

Requires confirm=true to prevent accidental deletion via prompt drift.

Args:

  • rich_menu_id: The richMenuId (starts with 'richmenu-').

  • confirm: Must be true to proceed.

  • oa: optional OA id.

Returns: { success: true, deleted_id }

line_audit_user_menuA

Why is user X seeing menu Y? This tool inspects the rich-menu priority chain for a user:

  1. Per-user link (line_link_rich_menu_to_user) — overrides everything

  2. Account-wide default

  3. (LINE OA Manager built menus override API-built ones — silent gotcha!)

Args:

  • user_id: LINE user ID.

  • oa: optional OA id.

Returns: { user_id, visible_rich_menu_id?: string, source: 'per_user' | 'default' | 'none', per_user_link?: string, default_id?: string, explanation: string // Thai-language explanation }

line_link_rich_menuA

Attach or detach a rich menu for specific LINE users. A per-user menu overrides the account-wide default, so this is the way to show different menus to different segments (e.g. paying members vs. free users).

Pass a single user_id (per-user endpoint) or a list of user_ids (bulk endpoint, auto-chunked into batches of 500). Unlinking a user makes them fall back to the account default menu (if any).

Args:

  • mode: 'link' (attach) | 'unlink' (detach).

  • rich_menu_id: Required for mode='link'; ignored for unlink.

  • user_id: A single LINE user ID, OR

  • user_ids: A list of LINE user IDs (bulk, auto-chunked at 500/batch).

  • oa: Optional OA id.

Returns: { mode: "link" | "unlink", linked_count?: number, // present when mode='link' unlinked_count?: number, // present when mode='unlink' rich_menu_id?: string, // present when mode='link' chunks?: number // number of bulk batches sent (bulk path only) }

Examples:

  • "ผูก rich menu R123 ให้ user U1" → { mode: "link", rich_menu_id: "R123", user_id: "U1" }

  • "ผูก rich menu R123 ให้สมาชิก 800 คน" → { mode: "link", rich_menu_id: "R123", user_ids: [...800 ids] } (sent as 2 chunks)

  • "ถอด rich menu ของ user U1" → { mode: "unlink", user_id: "U1" }

Errors:

  • mode='link' without rich_menu_id → returns input error

  • neither user_id nor user_ids → returns input error

  • 404 → user has no rich menu linked (unlink), or rich_menu_id not found (link)

line_set_default_rich_menuA

Set or clear the OA's default rich menu. The default menu shows to every follower who does not have a per-user menu linked (per-user links override the default).

Args:

  • mode: 'set' (assign a default) | 'clear' (remove the default).

  • rich_menu_id: Required for mode='set'; ignored for clear.

  • oa: Optional OA id.

Returns: { mode: "set" | "clear", rich_menu_id?: string // present when mode='set' }

Examples:

  • "ตั้ง rich menu R123 เป็น default" → { mode: "set", rich_menu_id: "R123" }

  • "ลบ default rich menu" → { mode: "clear" }

Errors:

  • mode='set' without rich_menu_id → returns input error

  • 404 → rich_menu_id not found (set), or no default set (clear)

line_manage_rich_menu_aliasA

Rich menu alias CRUD. Aliases power tab-switching rich menus: a 'richmenuswitch' action references a richMenuAliasId, and repointing that alias at a different rich menu swaps the displayed panel instantly — no per-user re-linking. Five modes:

  • create: Bind a new alias_id to a rich_menu_id.

  • update: Repoint an existing alias to a different rich_menu_id.

  • delete: Remove an alias (does not delete the underlying rich menu).

  • get: Fetch a single alias by alias_id.

  • list: List all aliases on the OA.

Args:

  • mode: 'create' | 'update' | 'delete' | 'get' | 'list'.

  • alias_id: Required for all modes except 'list'.

  • rich_menu_id: Required for 'create' and 'update'.

  • oa: Optional OA id.

Returns:

  • create/update/delete → { mode, alias_id, rich_menu_id? }

  • get → { richMenuAliasId, richMenuId }

  • list → { aliases: { richMenuAliasId, richMenuId }[] }

Examples:

  • "สร้าง alias tab-a ชี้ไป R123" → { mode: "create", alias_id: "tab-a", rich_menu_id: "R123" }

  • "เปลี่ยน alias tab-a ไปที่ R456" → { mode: "update", alias_id: "tab-a", rich_menu_id: "R456" }

  • "ดู alias ทั้งหมด" → { mode: "list" }

  • "ลบ alias tab-a" → { mode: "delete", alias_id: "tab-a" }

Errors:

  • missing alias_id (non-list modes) / missing rich_menu_id (create/update) → returns input error

  • 400 → alias_id already exists (create)

  • 404 → alias not found (update/delete/get)

line_upload_rich_menu_imageA

Replace the image on an EXISTING rich menu without recreating it — the richMenuId, tappable areas, and any per-user links are preserved. Downloads the image from a public HTTPS URL, validates format + size, then uploads to the api-data.line.me content endpoint (the domain switch that trips up most implementations).

Args:

  • rich_menu_id: ID of the existing rich menu to update.

  • image_url: Public HTTPS URL of the new image. JPEG/PNG, ≤1MB.

  • oa: Optional OA id.

Returns: { rich_menu_id: string, uploaded: true, bytes: number // size of the uploaded image }

Image requirements (validated client-side before upload):

  • Format: JPEG or PNG

  • File size: ≤1MB

Examples:

  • "เปลี่ยนรูป rich menu R123 เป็นแบนเนอร์ใหม่" → { rich_menu_id: "R123", image_url: "https://.../banner.png" }

Errors:

  • image_url not reachable → returns download error

  • unsupported format → returns format error

  • IMAGE_TOO_LARGE → ≥1MB; compress and retry

  • 404 → rich_menu_id not found

line_design_flexA

Compose a validated Flex Message ready for line_send_message. Two input modes:

  1. Template mode (recommended for Thai use cases): { template: "voucher", data: { title, code, discount, valid_until } } Available templates: receipt, voucher, shipping_update, order_confirm, appointment_reminder, promo_simple, course_cert, thank_you

  2. Raw mode (advanced): { flex_json: {...bubble or carousel JSON...}, alt_text: "..." }

  3. Discovery: { list_templates: true } returns the catalog with descriptions in Thai and required fields per template.

Returns: { template?: string, flex_json: { ...Flex contents... }, alt_text: string, preview_url: string, // LINE Flex Simulator deep link size_bytes: number, warnings: string[] // e.g., if approaching the 30KB bubble limit }

Composability:

  • Use line_design_flex first → grab flex_json → pass to line_send_message as { message: { flex_json, alt_text } }

  • Or pass { message: { template, data } } directly to line_send_message — the same templates are reused.

Examples:

  • "ออกแบบคูปอง 20% หมดวันที่ 31 ส.ค." → { template: "voucher", data: { title: "ส่วนลดวันแม่", code: "MOM20", discount: "ส่วนลด 20%", valid_until: "31 ส.ค. 2026" } }

  • "ดูว่ามี template อะไรบ้าง" → { list_templates: true }

line_design_imagemapA

Build a validated Imagemap message (LINE OA Manager calls this a "Rich Message") and return it as JSON, ready to hand to line_send_message. DESIGN ONLY — this never calls the LINE API; it just builds + validates the message object.

Image hosting (read carefully):

  • LINE has NO imagemap-image upload API. You MUST pre-host the image yourself at a public HTTPS base_url.

  • At send time LINE fetches sized variants: ${base_url}/1040, /700, /460, /300, /240. Host all of them (or a server that serves the right size per suffix).

  • baseSize.width is always forced to 1040. You only provide base_height (the image height when width = 1040). All area coordinates are px on that 1040-wide canvas.

Args:

  • base_url: HTTPS base URL of the hosted image set (≤1000 chars).

  • alt_text: Fallback text (1..400 chars).

  • base_height: Integer image height at width 1040.

  • areas: ≥1 tappable area, each { bounds: { x, y, width, height (ints) }, action: { type:"uri", uri, label? } | { type:"message", text, label? } }. Areas must fit inside 1040 × base_height.

  • video: optional { original_content_url, preview_image_url, area, external_link? }.

Returns: { message: , usage_hint: string }

Composability:

  • Build here → grab message → send via line_send_message (raw message passthrough).

Examples:

  • "Rich Message โปรโมชั่น ครึ่งบน-ครึ่งล่าง กดไปคนละลิงก์" → { base_url: "https://cdn.example.com/promo", alt_text: "โปรโมชั่นเดือนนี้", base_height: 1040, areas: [ { bounds: { x: 0, y: 0, width: 1040, height: 520 }, action: { type: "uri", uri: "https://shop.example.com/a" } }, { bounds: { x: 0, y: 520, width: 1040, height: 520 }, action: { type: "uri", uri: "https://shop.example.com/b" } } ] }

Errors:

  • base_url ต้องเป็น HTTPS → fix the URL scheme

  • พื้นที่เกินขอบรูป → an area's x+width or y+height exceeds 1040 × base_height

line_design_cardA

Build a validated Template message (LINE OA Manager calls this a "Card Message") and return it as JSON, ready to hand to line_send_message. DESIGN ONLY — this never calls the LINE API; it just builds + validates the message object. Supports all four LINE template subtypes.

Subtypes (set via kind) and their LINE limits:

  • buttons → { title?, text, thumbnail_image_url?, actions } — 1..4 buttons. text ≤60 chars with title/thumb, else ≤160.

  • confirm → { text, actions } — exactly 2 buttons (e.g. ตกลง / ยกเลิก).

  • carousel → { columns } — ≤10 columns, each ≤3 buttons. EVERY column must have the SAME number of buttons (LINE rule). Each column: { title?, text, thumbnail_image_url?, default_action?, actions }.

  • image_carousel → { columns } — ≤10 columns, each { image_url (HTTPS), action }.

Action shape (used in actions / default_action / image_carousel action): { type:"uri", label, uri } | { type:"message", label, text } | { type:"postback", label, data, displayText? } label ≤20 chars. uri accepts http/https/tel/line.

Args:

  • kind: one of buttons | confirm | carousel | image_carousel (required).

  • alt_text: fallback text (1..400 chars, required).

  • title?, text?, thumbnail_image_url?, actions? — used by buttons/confirm.

  • columns? — used by carousel/image_carousel.

Returns: { message: , usage_hint: string }

Composability:

  • Build here → grab message → send via line_send_message (raw message passthrough).

Examples:

  • "การ์ดยืนยันการจอง ตกลง/ยกเลิก" → { kind: "confirm", alt_text: "ยืนยันการจอง", text: "ยืนยันการจองคิวเวลา 14:00 ไหม?", actions: [ { type: "postback", label: "ตกลง", data: "confirm=1" }, { type: "message", label: "ยกเลิก", text: "ยกเลิก" } ] }

  • "การ์ดเมนู 3 ปุ่ม มีรูป" → { kind: "buttons", alt_text: "เมนูร้าน", title: "ร้านกาแฟ", text: "เลือกเมนูที่สนใจ", thumbnail_image_url: "https://cdn.example.com/cover.jpg", actions: [ { type: "uri", label: "ดูเมนู", uri: "https://shop.example.com/menu" }, { type: "message", label: "โปรวันนี้", text: "โปรวันนี้" } ] }

Errors:

  • "buttons: ต้องมี actions อย่างน้อย 1 ปุ่ม" → supply actions for kind=buttons

  • "confirm: ต้องมี 2 ปุ่มเป๊ะ" → confirm needs exactly two

  • "carousel: ทุก column ต้องมีจำนวน action เท่ากัน" → equalize button counts across columns

  • "action.label ยาวเกิน 20 ตัวอักษร" → shorten the label

line_build_audience_from_csvA

Create a new LINE audience by uploading user IDs (or IFAs). After creation LINE indexes the audience for ~5-10 minutes — line_list_audiences will report status=IN_PROGRESS during that window, then READY.

This is the "CSV from Google Sheets → retargeting audience" flow most Thai SMBs need.

Args:

  • name: Audience name (≤120 chars).

  • user_ids: Array of LINE user IDs (max 10,000 per call).

  • is_ifa: True for IFA values instead of LINE user IDs (default false).

  • oa: optional OA id.

Returns: { audience_group_id, name, type, created_unix_ms }

Region note: Audience Management API is gated to JP / TW / TH OAs (+ premium).

Examples:

  • "สร้าง audience ลูกค้าเดือนก่อน" → { name: "buyers_last_month", user_ids: [...] }

line_build_audience_from_engagementA

Create a LINE audience from people who clicked or opened a previous broadcast / narrowcast. The killer "retarget without a CRM" tool.

Args:

  • name: New audience name.

  • source_request_id: request_id from a previous line_send_message call (saved in its return value).

  • type: 'clicks' (default) or 'opens'.

  • click_url: optional — limit to a specific clicked URL (for 'clicks' only).

  • oa: optional OA id.

Returns: { audience_group_id, name, type }

Notes:

  • LINE requires the source message to be ≥24 hours old before the engagement audience is reliable.

  • Minimum ~50 users for the audience to be usable in narrowcast.

  • Region-gated to JP / TW / TH (+ premium).

Example workflow:

  1. line_send_message(..., target: narrowcast) → save request_id

  2. Wait 24h

  3. line_build_audience_from_engagement({ source_request_id, type: 'clicks' })

  4. line_send_message(..., target: { audience: 'new-engagement-audience' })

line_list_audiencesA

List audience groups on the OA. Audiences created via LINE OA Manager UI (e.g. chat-tag audiences, friend-path audiences, web-traffic audiences) also appear here — even though those types cannot be CREATED via Messaging API.

Status meanings:

  • READY: usable in narrowcast immediately

  • IN_PROGRESS: still indexing — wait ~10 minutes

  • FAILED: creation failed; recreate

  • EXPIRED: aged out; recreate

Args:

  • status_filter: 'all' (default) | 'READY' | 'IN_PROGRESS' | 'FAILED' | 'EXPIRED'.

  • name_contains: optional substring filter (case-insensitive).

  • limit, page: pagination (default 20/page).

  • oa: optional OA id.

Returns: { total: number, count: number, page: number, audiences: [{ audience_group_id, name, status, audience_count?, created, type? }], has_more: boolean }

Examples:

  • "ดู audience ที่พร้อมส่ง" → { status_filter: "READY" }

  • "หา audience ชื่อ vip" → { name_contains: "vip" }

line_delete_audienceA

Delete an audience group. Irreversible — requires confirm=true.

Args:

  • audience_group_id: numeric ID (from line_list_audiences).

  • confirm: must be true to proceed.

  • oa: optional OA id.

Returns: { success: true, deleted_id }

line_update_audienceA

Mutate an existing LINE audience group (upload type). Two modes.

Only Messaging-API-created (upload) audiences accept add_users. Audiences built in LINE OA Manager UI (chat-tag, friend-path, web-traffic) are read-only here and LINE will reject mutation.

Args:

  • mode ('add_users' | 'rename'): what to change.

  • audience_group_id (number): target audience id (from line_list_audiences).

  • user_ids (string[], add_users only): LINE user IDs to append.

  • description (string, rename only): the new audience name.

  • oa (string, optional): OA id. Default = active OA.

Returns:

  • add_users → { mode, audience_group_id, added_count }

  • rename → { mode, audience_group_id, new_description }

Examples:

  • "เพิ่ม 3 คนเข้า audience 12345" → { mode: "add_users", audience_group_id: 12345, user_ids: ["U1...", "U2...", "U3..."] }

  • "เปลี่ยนชื่อ audience 12345 เป็น VIP มิ.ย." → { mode: "rename", audience_group_id: 12345, description: "VIP มิ.ย." }

Errors:

  • Missing user_ids for add_users / missing description for rename → inline input error.

  • LINE rejects mutation on non-upload audiences (e.g. chat-tag) → LineApiError surfaced.

line_get_oa_reportA

Generate a digest of LINE OA performance over a date range. Bundles 8+ Insight API calls into a single Thai-friendly markdown report.

Args:

  • range: One of 'today' | 'yesterday' | 'this-week' | 'last-week' | 'this-month' | 'last-month', or { from: "YYYY-MM-DD", to: "YYYY-MM-DD" }. Default 'last-week'.

  • oa: optional OA id.

  • response_format: 'markdown' (default) | 'json'.

Returns (structured): { oa_id, range: { from, to, preset? }, delivery: { total, daily: [{ date, broadcast, multicast, push, reply, total }] }, followers: { latest_count?, follow?, unfollow?, net_gain? }, demographic_available: boolean, quota: { used, total, percentage_used }, notes: string[] // T-2 data lag note, privacy-floor note, etc. }

Notes:

  • LINE insight data has a T-2 lag (yesterday is the latest reliable date).

  • Insight is masked below the ~20-user privacy floor; report surfaces this.

  • Demographic only populated when the OA has enough consented friends.

Examples:

  • "สรุปสัปดาห์ที่แล้ว" → range: 'last-week'

  • "ดูข้อมูลเดือนนี้" → range: 'this-month'

  • "วิเคราะห์ 1-15 พ.ค." → range: { from: '2026-05-01', to: '2026-05-15' }

line_get_message_statsA

Fetch per-broadcast engagement stats for a specific request_id: impressions, opens, clicks, CTR, and per-URL click breakdown.

Args:

  • request_id: From a prior line_send_message return value.

  • oa: optional OA id.

  • response_format: 'markdown' (default) | 'json'.

Returns (structured): { request_id, delivered?: number, unique_impression?: number, // null if below ~20-user privacy floor unique_click?: number, ctr_percent?: number, per_url_clicks: [{ url, click, unique_click }], notes: string[] // T-1 lag note, privacy-floor note }

Important caveats (surfaced in notes):

  • 24-hour data lag — stats stabilize ~T+1 after send.

  • Below ~20 unique users, LINE returns null for privacy.

  • Available only for narrowcast / multicast / broadcast (not reply / push to single user).

line_get_oa_statusA

Quick health check of a LINE Official Account: friend count, monthly quota usage, webhook status, and current default rich menu. Aggregates 4 LINE API calls into one card.

Use this as the first call of a session — every other tool decision (whether to send, schedule, switch OA, etc.) benefits from knowing current quota and webhook state.

Args:

  • oa (string, optional): OA id from multi-OA config. Default = active OA.

  • response_format ('markdown' | 'json'): Output format. Default 'markdown'.

Returns: Structured object: { oa: { id, display_name, picture_url? }, friends?: number, // omitted if not retrievable quota: { used, total, remaining, percentage_used }, webhook: { active, url? }, default_rich_menu?: { id, name? }, region?: string, health: 'OK' | 'WARNING' | 'ERROR', warnings: string[] }

Examples:

  • "ดูสถานะ OA หน่อย" → call with no args

  • "Status ของ Client A" → { oa: "client_a" }

line_estimate_send_costA

Estimate how many quota messages a planned send will consume — without actually sending. Useful before user confirmation, especially for narrowcast / broadcast.

Args:

  • target: Same shapes as line_send_message ({ user_id } | { user_ids } | { audience } | { filter } | { everyone: true }).

  • message_count: How many message objects in the send (1-5, default 1). LINE charges per message * recipients.

  • oa: optional OA id.

Returns: { estimated_recipients?: number, // known exactly for user_id(s); approximate for audience; unknown for filter/everyone estimated_cost_messages?: number, // recipients * message_count quota: { used, total, remaining, percentage_used }, cost_share_percent?: number, // estimated_cost / remaining notes: string[] }

Notes:

  • For target.audience: we look up audience_count via line_list_audiences first.

  • For target.filter or target.everyone: exact estimation isn't possible from API alone — we surface "unknown" and recommend a dry_run via line_send_message instead.

line_get_narrowcast_progressA

Poll the delivery progress of an async narrowcast send (GET /v2/bot/message/progress/narrowcast). Narrowcast runs in the background — the send returns a request_id, and this tool reports how far it has gotten.

Args:

  • request_id (string): the id returned by a prior narrowcast send.

  • oa (string, optional): OA id. Default = active OA.

Returns: { request_id, phase, // waiting | sending | succeeded | failed status_text, // Thai-readable status line success_count?, failure_count?, target_count?, failed_description?, error_code?, accepted_time?, completed_time? }

Examples:

  • "narrowcast เสร็จยัง" → { request_id: "" }

Errors:

  • Unknown / expired request_id → LineApiError surfaced.

line_test_webhookA

Ping the OA's webhook URL from LINE servers and report HTTP status + latency. LINE checks that the endpoint returns 200 within their timeout AND that signature verification works (when secret is configured).

Args:

  • override_endpoint: optional public HTTPS URL to test instead of the configured one.

  • oa: optional OA id.

Returns: { success: boolean, status_code: number, latency_ms?: number, reason: string, // LINE's human-readable result detail?: string, configured_endpoint?: string, tested_endpoint: string }

Common failure modes (LINE returns them via 'reason'):

  • INVALID_REPLY: webhook responded but the response shape is unexpected

  • UNAUTHORIZED: signature verification failed (your code uses wrong channel_secret)

  • SERVER_ERROR: webhook returned 5xx

  • TIMEOUT: webhook took >10s

  • SSL_ERROR: HTTPS cert problem

Use this whenever a bot stops responding before debugging anything else.

line_set_webhook_endpointA

Read or write the LINE OA's webhook URL (PUT/GET /v2/bot/channel/webhook/endpoint). Complements line_test_webhook — set the URL here, then ping it with line_test_webhook.

Args:

  • mode ('set' | 'get'): write or read.

  • endpoint (string, set only): public HTTPS URL (https:// required, ≤500 chars).

  • oa (string, optional): OA id. Default = active OA.

Returns: { endpoint: string, active: boolean } // re-read after a 'set' to confirm

Examples:

Errors:

  • Non-HTTPS or >500 char URL → inline input error (LINE requires HTTPS).

  • mode='set' without endpoint → inline input error.

  • LINE rejects the URL → LineApiError surfaced.

line_manage_liff_appA

LIFF lifecycle CRUD. Four modes:

  • create: New LIFF app. Requires config.view (type + url).

  • list: List all LIFF apps on the channel.

  • update: Modify an existing LIFF app. Requires liff_id + partial config.

  • delete: Remove a LIFF app. Requires liff_id + confirm=true.

Args:

  • mode: 'create' | 'list' | 'update' | 'delete'.

  • liff_id: required for update / delete.

  • config: full for create, partial for update.

  • confirm: required true for delete.

  • oa: optional OA id.

Auth note: LIFF Server API uses LINE Login channel tokens — V1 uses the same Messaging API token for simplicity. For separate-channel setups, see docs.

Examples:

  • "สร้าง LIFF tall https://my.app" → { mode: "create", config: { view: { type: "tall", url: "https://my.app" } } }

  • "ดู LIFF apps ทั้งหมด" → { mode: "list" }

line_check_tokenA

Verify the active OA's configured channel access token (GET /oauth2/v2.1/verify). Reports the bound client_id, remaining lifetime, and granted scope. Run before a campaign — a token expiring mid-send fails silently.

Args:

  • oa (string, optional): OA id whose configured token to verify. Default = active OA.

Returns: { valid: true, client_id: string, expires_in_seconds: number, expires_in_days: number, scope?: string, warning?: string // set (Thai) when < 7 days remain }

Examples:

  • "token ยังใช้ได้ไหม" → call with no args

  • "เช็ค token ของ client_a" → { oa: "client_a" }

Errors:

  • Invalid / expired token → LineApiError (401) surfaced (no { valid: false } shape — an error is returned instead).

line_get_user_profileA

Fetch a LINE user's profile (display name, picture, status message, language) by user ID.

Note: Only works if the user has added the bot as a friend AND has not blocked it AND has consented to share profile (per LINE TOS). Returns 404 ambiguously if any of these conditions fail — we surface a clear Thai-language explanation.

Args:

  • user_id: LINE user ID (typically starts with 'U').

  • oa: optional OA id.

  • response_format: 'markdown' (default) | 'json'.

Returns: { user_id, display_name, picture_url?, status_message?, language? }

line_list_followersA

Page through every user that has added the OA as a friend.

⚠️ Region-gated: only TH / JP / TW OAs with premium tier can use this endpoint. Other OAs will get LINE 403.

Args:

  • page_size: 1-1000 (default 300).

  • continuation_token: token from previous call (cursor pagination).

  • oa: optional OA id.

Returns: { user_ids: string[], count: number, has_more: boolean, next_continuation_token?: string }

For very large OAs (50k+), prefer creating an engagement audience via line_build_audience_from_engagement rather than pulling all IDs.

line_list_oasA

List all LINE Official Accounts available to this MCP instance, from the multi-OA config file (or single-OA env mode). Useful before line_use_oa to discover the OA IDs.

Args:

  • response_format: 'markdown' (default) | 'json'.

Returns: { active_oa: string, oas: [{ id, display_name?, region?, is_premium?, is_active }] }

line_use_oaA

Switch which OA all subsequent tool calls default to (until changed or process restarts). In-memory only — does not edit ~/.line-mcp/config.json.

Args:

  • oa_id: OA id from the multi-OA config (use line_list_oas to discover).

Returns: { active_oa, display_name }

line_run_on_many_oasA

Agency feature — run any read-only line_* tool across many OAs in parallel. Errors on individual OAs are isolated (one bad token doesn't break the whole run).

Supported tools (read-only only for V1 safety):

  • line_get_oa_status

  • line_get_oa_report

  • line_list_audiences

  • line_list_rich_menus

  • line_test_webhook

Args:

  • tool: One of the supported tool names.

  • oa_ids: Array of OA ids, or 'all' (default).

  • parallel: Max concurrency 1-10 (default 5).

  • response_format: 'markdown' (default) | 'json'.

Returns: { tool, count_ok, count_failed, results: [{ oa_id, oa_name, success, summary }], errors: [{ oa_id, error }] }

Examples:

  • "เช็คสถานะทุก OA" → { tool: "line_get_oa_status", oa_ids: "all" }

  • "ทดสอบ webhook ทุก client" → { tool: "line_test_webhook" }

line_manage_couponA

Coupon CRUD on a LINE OA (POST /v2/bot/coupon). Four modes:

  • create: Make a new coupon. Maps friendly inputs to LINE's required schema (reward, acquisitionCondition, startTimestamp/endTimestamp in UNIX seconds, timezone, visibility, maxUseCountPerTicket).

  • list: List all coupons.

  • get: Fetch a specific coupon by coupon_id.

  • discontinue: End a live coupon (irreversible — requires confirm=true).

Rate limit: shared bucket 200 req/sec with multicast.

create data fields:

  • title (required, ≤60)

  • discount_type: 'percentage' (default) | 'fixed' | 'explicit'

  • discount_value: % (percentage) or amount (fixed)

  • price_before / price_after: for discount_type='explicit'

  • valid_from / valid_to (required): UNIX seconds | 'YYYY-MM-DD' | ISO datetime

  • timezone: default 'ASIA_BANGKOK'

  • visibility: 'PUBLIC' | 'UNLISTED' (default UNLISTED)

  • max_use_per_ticket: 1 (default) | -1 (unlimited)

  • acquisition_type: 'normal' (default) | 'lottery' (+lottery_probability)

  • description, image_url, coupon_code, barcode_image_url (optional)

Examples:

  • "Early Bird ลด 20% 1–8 มิ.ย." → { mode: "create", data: { title: "Early Bird คอร์สจารโต", discount_type: "percentage", discount_value: 20, valid_from: "2026-06-01", valid_to: "2026-06-08", coupon_code: "EARLYBIRD" } }

  • "คูปองลด 100 บาท" → { mode: "create", data: { title: "ลด 100", discount_type: "fixed", discount_value: 100, valid_from: "2026-06-01", valid_to: "2026-06-30" } }

  • "ดู coupons ทั้งหมด" → { mode: "list" }

  • "ปิด coupon C123" → { mode: "discontinue", coupon_id: "C123", confirm: true }

line_get_coupon_statsA

Read available stats for a LINE coupon. We combine multiple signals because LINE's Coupon API does not (yet) expose a dedicated redemption-events endpoint:

  1. Raw coupon detail (LINE GET /v2/bot/coupon/{id}) — some accounts include usage fields inline.

  2. Click-audience size (if you pass click_audience_id) — proxies "users who clicked through".

Args:

  • coupon_id: ID of the coupon (from line_manage_coupon mode='list' or mode='create').

  • click_audience_id: optional numeric audience id to enrich the report.

  • oa: optional OA id.

  • response_format: 'markdown' (default) | 'json'.

Returns (structured): { coupon_id, raw: {...whatever LINE returned about the coupon...}, click_audience?: { id, name, audience_count, status }, estimated_redemptions?: number, notes: string[] // explains data sources clearly }

Notes:

  • For an accurate redemption count, build your coupon Flex with a postback action and listen for postback events via a webhook server (V2 webhook-server companion).

  • Click audience size approximates "clickthroughs", not actual redemptions — surface this caveat to the user.

Prompts

Interactive templates invoked by user choice

NameDescription
daily-oa-reportGenerate a Thai-language summary of today's / last week's LINE OA performance.
build-campaignWizard for designing a broadcast: audience → Flex → schedule via OA Manager.
schedule-broadcast-howtoExplain 3 patterns to schedule a LINE broadcast: OA Manager UI, Cowork Scheduled Tasks, system cron.
diagnose-rich-menu"ทำไม user ไม่เห็นเมนู?" troubleshooter
coupon-campaignCreate coupon → broadcast → audience from clicks → measure
migrate-from-line-notifyHelp user migrate LINE Notify (dead 2025-03-31) to Messaging API push.
webhook-setup-guideWalk through setting up a LINE webhook handler — signature verification, ngrok/cloudflared, common pitfalls.

Resources

Contextual data attached and managed by the client

NameDescription
flex-templatesThai-localized Flex Message templates with required fields.
stickers-catalogBundled curated catalog of bot-safe LINE stickers with mood/keyword tags.
thai-holidaysThai public, royal, Buddhist, and cultural holidays with marketing promo patterns.

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/wasintoh/line-oa-mcp-ultimate'

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