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

Universal LINE sender. Auto-picks the API (reply/push/multicast/narrowcast/broadcast) from the target shape; message shape selects text/template/flex/sticker/coupon/image/video. Feed pre-built objects from line_design_imagemap/line_design_card/line_design_flex via message.message_json; native coupons from line_manage_coupon via message.coupon_id.

mode: send_now (default) sends immediately; draft returns a LINE OA Manager handoff package (URL + Flex JSON + steps) — use when the user wants to SCHEDULE, since the Messaging API can't schedule but the OA Manager UI can; dry_run validates + estimates cost without sending.

Safety: pre-flight /validate before spending quota; Quota Guardian blocks if projected cost >95% of remaining quota unless confirm=true; broadcast { everyone:true } requires confirm=true; quiet-hours 22:00–08:00 BKK warns unless force=true; quiet_push silences the recipient device; reply tokens expire ~1 min (falls back to a push hint).

Returns send_now → { success, transport, request_id?, recipient_count_estimated, quota, warnings[] }; draft and dry_run return their own shapes. Narrowcast needs ~24h before line_get_message_stats shows engagement.

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

line_find_sticker

Find LINE stickers from a curated catalog by mood or keyword (Thai or English). Bots may only send stickers from LINE's limited official list, so this picks by intent ("celebration", "ขอบคุณ", "sorry") instead of guessing IDs. Pass the chosen package_id + sticker_id to line_send_message via message.sticker.

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

line_build_rich_menuA

Create a LINE Rich Menu from an already-hosted image in one call: validate → create → upload image → set as default. Collapses 4 LINE API calls into one, incl. the api-data.line.me domain switch for image upload (the #1 cause of failed implementations). Single-panel menus only. To RENDER the image from labels instead of hosting your own, use line_design_rich_menu_image.

image_url must be public HTTPS JPEG/PNG, width 800–2500px, aspect ≥1.45, ≤1MB (validated client-side before upload). areas are tappable regions with postback/message/uri/richmenuswitch actions and must fit inside the image bounds. size 'large' (2500x1686, default) or 'compact' (2500x843). set_as_default default true. Max 1,000 rich menus per OA.

Returns { rich_menu_id, name, set_as_default, warnings[] }.

line_list_rich_menusA

List all rich menus on an OA and identify the account-wide default. OAs hold up to 1,000 rich menus — run this before line_build_rich_menu to avoid the cap, and line_delete_rich_menu to clean up.

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

line_delete_rich_menuA

Delete a rich menu by ID. Requires confirm=true (guards against prompt drift). If the menu is linked to specific users those links break silently — consider line_audit_user_menu first.

Returns { success, deleted_id }.

line_audit_user_menuA

Diagnose "why is user X seeing menu Y?" — inspects the rich-menu priority chain: a per-user link (line_link_rich_menu) overrides the account-wide default, and LINE OA Manager-built menus silently override API-built ones. Pass user_id.

Returns { user_id, visible_rich_menu_id?, source:'per_user'|'default'|'none', per_user_link?, default_id?, explanation (Thai) }.

line_link_rich_menuA

Attach (mode='link') or detach (mode='unlink') a rich menu for specific LINE users. A per-user menu overrides the account-wide default — this is how you show different menus to different segments (e.g. paying vs. free). Unlinking falls the user back to the account default. Pass user_id (single) or user_ids[] (bulk, auto-chunked at 500/batch). rich_menu_id required for link. To set the account-wide default instead, use line_set_default_rich_menu.

Returns { mode, linked_count?/unlinked_count?, rich_menu_id?, chunks? }.

Example: "ผูก rich menu R123 ให้สมาชิก 800 คน" → { mode:"link", rich_menu_id:"R123", user_ids:[...800 ids] }.

line_set_default_rich_menuA

Set or clear the OA's default rich menu — shown to every follower without a per-user menu linked (per-user links via line_link_rich_menu override it). mode 'set' (needs rich_menu_id) or 'clear'.

Returns { mode, rich_menu_id? }.

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. modes: create (bind alias_id→rich_menu_id), update (repoint), delete (removes alias, not the underlying menu), get, list. alias_id required except for list; rich_menu_id required for create/update.

Returns create/update/delete → { mode, alias_id, rich_menu_id? }; get → { richMenuAliasId, richMenuId }; list → { aliases[] }.

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

line_upload_rich_menu_imageA

Replace the image on an EXISTING rich menu without recreating it — richMenuId, tappable areas, and per-user links are preserved. Downloads from a public HTTPS URL, validates JPEG/PNG ≤1MB, then uploads to the api-data.line.me content endpoint (the domain switch that trips up most implementations). Private/internal addresses are blocked by an SSRF guard.

Returns { rich_menu_id, uploaded, bytes }.

Example: "เปลี่ยนรูป rich menu R123" → { rich_menu_id:"R123", image_url:"https://.../banner.png" }.

line_design_flex

Compose a validated Flex Message for line_send_message. Modes: template mode { template, data } (Thai-localized, recommended; templates: receipt, voucher, shipping_update, order_confirm, appointment_reminder, promo_simple, course_cert, thank_you); raw mode { flex_json, alt_text } (advanced); or { list_templates: true } to get the catalog with Thai descriptions + required fields per template. DESIGN ONLY — never calls the LINE API.

Feed the result to line_send_message via message.flex_json, or pass { template, data } straight to line_send_message (same templates). Returns { flex_json, alt_text, preview_url (Flex Simulator), size_bytes, warnings[] } (warns near the 30KB bubble limit).

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

line_design_imagemapA

Build a validated Imagemap message (LINE OA Manager calls it a "Rich Message") and return it as JSON to hand to line_send_message via message.message_json. DESIGN ONLY — never calls the LINE API.

Image hosting (critical): LINE has NO imagemap-image upload API — you must pre-host the image at a public HTTPS base_url, and LINE fetches sized variants ${base_url}/1040, /700, /460, /300, /240 (host all, or serve the right size per suffix). Canvas width is always forced to 1040; you give base_height and all area coordinates in px on that 1040-wide canvas. areas must fit inside 1040 × base_height. Optional video area supported.

Returns { message, usage_hint }.

Example: "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"}}] }.

line_design_cardA

Build a validated LINE Template message (LINE OA Manager calls it a "Card Message") and return it as JSON to hand to line_send_message via message.message_json. DESIGN ONLY — never calls the LINE API.

kind (required) picks the subtype and enforces LINE limits:

  • buttons → title?, text, thumbnail_image_url?, actions (1..4 buttons; text ≤60 chars with title/thumb, else ≤160)

  • confirm → text + exactly 2 buttons (e.g. ตกลง / ยกเลิก)

  • carousel → columns (≤10, each ≤3 buttons); EVERY column must have the SAME number of buttons (LINE rule)

  • image_carousel → columns of { image_url (HTTPS), action } (≤10) Actions: uri | message | postback; label ≤20 chars. alt_text (1..400) required.

Returns { message, usage_hint }.

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

line_build_audience_from_csvA

Create a LINE audience by uploading user IDs (or IFAs) — the "CSV from Google Sheets → retargeting audience" flow most Thai SMBs need. LINE indexes for ~5-10 min after creation (line_list_audiences shows IN_PROGRESS then READY). user_ids max 10,000/call; is_ifa true for IFA values instead of LINE user IDs. Region-gated to JP/TW/TH OAs (+premium).

Returns { audience_group_id, name, type, created_unix_ms }.

Example: "สร้าง 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 — retarget without a CRM. source_request_id is the request_id returned by a prior line_send_message; type 'clicks' (default, optional click_url filter) or 'opens'. The source message must be ≥24h old before the audience is reliable, needs ~50+ users to be usable in narrowcast, and is region-gated to JP/TW/TH (+premium). Feed the resulting audience back into line_send_message target.audience.

Returns { audience_group_id, name, type }.

line_list_audiencesA

List audience groups on the OA — including ones created in LINE OA Manager UI (chat-tag, friend-path, web-traffic) that CANNOT be created via Messaging API. status: READY (usable in narrowcast now) | IN_PROGRESS (indexing, wait ~10 min) | FAILED | EXPIRED (both need recreate). Filter with status_filter (default 'all') and name_contains (case-insensitive); paginate with limit/page (default 20).

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

line_delete_audienceA

Delete an audience group. Irreversible — requires confirm=true. audience_group_id (numeric) from line_list_audiences.

Returns { success, deleted_id }.

line_update_audienceA

Mutate an existing LINE audience group. modes: add_users (append user_ids) | rename (set description). audience_group_id from line_list_audiences. Only Messaging-API-created (upload) audiences accept mutation — audiences built in LINE OA Manager UI (chat-tag, friend-path, web-traffic) are read-only and LINE will reject changes.

Returns add_users → { mode, audience_group_id, added_count }; rename → { mode, audience_group_id, new_description }.

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

line_get_oa_reportA

Digest of LINE OA performance over a date range — bundles 8+ Insight API calls into one Thai-friendly markdown report. range: a preset ('today'|'yesterday'|'this-week'|'last-week'|'this-month'|'last-month', default 'last-week') or { from, to } as YYYY-MM-DD. LINE insight data lags T-2 (yesterday is the latest reliable date) and is masked below the ~20-user privacy floor; demographics populate only with enough consented friends (report surfaces these in notes).

Returns { oa_id, range, delivery{total,daily[]}, followers, demographic_available, quota, notes[] }.

line_get_message_statsA

Fetch per-broadcast engagement for a request_id (from a prior line_send_message): impressions, opens, clicks, CTR, and per-URL click breakdown. Caveats (in notes): ~24h data lag (stats stabilize ~T+1); below ~20 unique users LINE returns null for privacy; available only for narrowcast/multicast/broadcast, not reply or push-to-single-user.

Returns { request_id, delivered?, unique_impression?, unique_click?, ctr_percent?, per_url_clicks[], notes[] }.

line_get_oa_statusA

Quick health check of a LINE OA — friend count, monthly quota usage, webhook status, and current default rich menu, aggregating 4 LINE API calls into one card. Good as the first call of a session: current quota and webhook state inform every later decision (send, schedule, switch OA).

Returns { oa, friends?, quota, webhook, default_rich_menu?, region?, health:'OK'|'WARNING'|'ERROR', warnings[] }.

line_estimate_send_cost

Estimate how many quota messages a planned send will consume, without sending. Useful before confirmation, especially for narrowcast/broadcast. target uses the same shapes as line_send_message; message_count (1-5, default 1) — LINE charges message_count × recipients. Recipients are exact for user_id(s), looked up for a numeric audience, and unknown for filter/everyone (recommends a line_send_message dry_run instead).

Returns { estimated_recipients?, estimated_cost_messages?, quota, cost_share_percent?, notes[] }.

line_get_narrowcast_progressA

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

Returns { request_id, phase (waiting|sending|succeeded|failed), status_text, success_count?, failure_count?, target_count?, error_code?, accepted_time?, completed_time? }.

line_test_webhookA

Ping the OA's webhook URL from LINE servers and report HTTP status + latency; LINE checks it returns 200 within timeout and that signature verification works. Use this FIRST whenever a bot stops responding, before debugging anything else. Pass override_endpoint to test a URL other than the configured one. reason surfaces LINE's result: INVALID_REPLY | UNAUTHORIZED (bad channel_secret signature) | SERVER_ERROR (5xx) | TIMEOUT (>10s) | SSL_ERROR.

Returns { success, status_code, latency_ms?, reason, configured_endpoint?, tested_endpoint }.

line_set_webhook_endpointA

Read or write the LINE OA's webhook URL (PUT/GET /v2/bot/channel/webhook/endpoint). mode 'set' (needs endpoint: public HTTPS, ≤500 chars) or 'get'. Complements line_test_webhook — set here, then ping with line_test_webhook.

Returns { endpoint, active } (re-read after a 'set' to confirm).

line_manage_liff_app

LIFF app lifecycle CRUD. modes: create (needs config.view {type,url}), list, update (liff_id + partial config), delete (liff_id + confirm=true). Auth note: LIFF Server API uses LINE Login channel tokens; this uses the same Messaging API token — for separate-channel setups see docs.

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

line_check_tokenA

Verify the active OA's channel access token (GET /oauth2/v2.1/verify) — reports bound client_id, remaining lifetime, and granted scope; warns (Thai) when <7 days remain. Run before a campaign: a token expiring mid-send fails silently. An invalid/expired token surfaces a 401 error (no { valid:false } shape).

Returns { valid, client_id, expires_in_seconds, expires_in_days, scope?, warning? }.

line_get_user_profileA

Fetch a LINE user's profile (display name, picture, status message, language) by user_id. Only works if the user has added the bot, has not blocked it, and consented to share profile — any failure returns an ambiguous 404, surfaced as a clear Thai explanation.

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 on premium tier — others get LINE 403. page_size 1-1000 (default 300); continuation_token for cursor pagination. For very large OAs (50k+), prefer an engagement audience via line_build_audience_from_engagement over pulling all IDs.

Returns { user_ids[], count, has_more, next_continuation_token? }.

line_list_oasA

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

Returns { active_oa, 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 restart). In-memory only — does not edit config.json. oa_id from line_list_oas.

Returns { active_oa, display_name }.

line_run_on_many_oasA

Agency feature — run any read-only line_* tool across many OAs in parallel; per-OA errors are isolated (one bad token doesn't break the run). tool must be one of the supported read-only tools below; oa_ids an array or 'all' (default); parallel concurrency 1-10 (default 5).

Supported tools:

  • line_get_oa_status

  • line_get_oa_report

  • line_list_audiences

  • line_list_rich_menus

  • line_test_webhook

Returns { tool, count_ok, count_failed, results[], errors[] }.

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

line_manage_couponA

Coupon CRUD on a LINE OA (POST /v2/bot/coupon). modes: create (maps friendly inputs to LINE's schema — dates to UNIX seconds, visibility, etc.), list, get (by coupon_id), discontinue (ends a live coupon; irreversible — requires confirm=true). Deliver a created coupon via line_send_message message.coupon_id. Rate limit: shared 200 req/sec bucket with multicast.

create data: title (≤60, required); discount_type 'percentage'(default)|'fixed'|'explicit' with discount_value (or price_before/price_after for explicit); valid_from/valid_to accept UNIX seconds | 'YYYY-MM-DD' | ISO; visibility PUBLIC|UNLISTED (default UNLISTED); acquisition_type normal|lottery.

Example: "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" } }. "ปิด coupon C123" → { mode:"discontinue", coupon_id:"C123", confirm:true }.

line_get_coupon_stats

Read available stats for a LINE coupon. LINE has no dedicated redemption endpoint, so this combines signals: raw coupon detail (some accounts include usage inline) plus, if you pass click_audience_id, the click-audience size as a clickthrough proxy. coupon_id comes from line_manage_coupon. Caveat (surfaced in notes): click-audience size approximates clickthroughs, NOT actual redemptions — for real counts build the coupon Flex with a postback action and listen via webhook.

Returns { coupon_id, raw, click_audience?, estimated_redemptions?, notes[] }.

line_design_rich_menu_imageA

Design a professional LINE rich menu PNG from labels alone — pure-JS renderer with Thai typography (LINE Seed / Prompt / Noto), then optionally deploy to LINE in the same call. No design tool or headless browser.

ALWAYS preview first: mode="preview" (default) returns the PNG as an image block — LOOK at it, iterate with the user, then call again mode="deploy". mode="save" writes the PNG to disk.

Templates (cells filled in reading order; tap areas auto-derived from the same geometry, pixel-perfect):

  • grid_6 (2500x1686, 6 cells): 3×2 grid, 6 equal cells — the classic LINE OA menu

  • grid_4 (2500x1686, 4 cells): 2×2 grid, 4 large cells

  • hero_top_3 (2500x1686, 4 cells): full-width hero banner on top + 3 cells below

  • hero_left_2 (2500x1686, 3 cells): left-half hero + 2 stacked cells on the right

  • split_2 (2500x1686, 2 cells): two tall vertical halves

  • full_1 (2500x1686, 1 cells): one full-canvas cell (single campaign banner)

  • compact_3 (2500x843, 3 cells): compact 1×3 row

  • compact_2 (2500x843, 2 cells): compact 1×2 row

  • compact_1 (2500x843, 1 cells): compact single full-width cell

cells[] length MUST equal the template's cell count; per-cell action is required only for deploy. brand auto-corrects label contrast for readability. deploy needs deploy:{ name, set_default?, alias? } and auto-deletes the orphaned menu on any post-create failure; LINE caps the PNG at <1MB (gradients auto-flatten to solid once).

Returns preview → PNG image block + { width, height, bytes, template, font_used, warnings[] }; deploy → { rich_menu_id, areas_count, set_default, alias? }.

Example: "ทำเมนูร้านกาแฟ 6 ปุ่ม สีเขียว" → { template:"grid_6", brand:{primary:"#06C755"}, cells:[{label:"สั่งเลย", icon_emoji:"☕", action:{type:"uri", uri:"https://shop.line.me/@cafe"}}, ...5 more] }.

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.
design-rich-menuGuided flow: brand colors/font/purpose → template + cells → preview image → iterate → deploy with confirmation.

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