Skip to content

create rich menu operation #121

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 32 commits into
base: main
Choose a base branch
from
Open

Conversation

4geru
Copy link
Contributor

@4geru 4geru commented Jun 8, 2025

Hello Maintainers! 👋

Thank you for maintaining this excellent LINE Bot MCP Server project. I'm excited to contribute a new feature that adds dynamic rich menu creation capabilities. I hope this enhancement will be valuable for the community.

Background

The LINE Bot MCP Server needed functionality to create rich menus dynamically. Previously, users had to manually create rich menu images and configure them individually. There was a need for a flexible, text-based approach to generate rich menus programmatically.

Todo

1. Implemented Rich Menu Creation Feature

  • Added new create_rich_menu tool
  • Implemented automatic rich menu generation that accepts chat bar text and action arrays

2. Built Template System

  • Created 6 rich menu templates (Markdown format) supporting 1-6 items
  • Placed templates in richmenu-templates/ directory
  • Added example images in richmenu-examples/ for reference

3. Implemented Image Generation Pipeline

  • Used Marp to convert Markdown templates to HTML
  • Used Puppeteer to convert HTML to PNG images with specified dimensions (1600x910px)
  • Uploaded generated images to LINE Messaging API

4. Defined LINE Bot Action Schema

  • Created src/common/schema/actionSchema.ts with schemas for 9 action types (postback, message, uri, datetimepicker, camera, cameraRoll, location, richmenuswitch, clipboard)
  • Implemented type-safe validation using Zod

5. Added Dependencies

  • @marp-team/marp-core: For Markdown to slide generation
  • @marp-team/marp-cli: Marp command-line tools

Verified

Functionality

  • All templates (1-6 items) work correctly
  • Placeholders (item01 ' ~ ' item06) in Markdown templates are properly replaced with action labels
  • Generated images comply with LINE specifications (1600x910px)
  • Complete workflow from rich menu creation, image upload, to default setting works

Error Handling

  • Proper error responses for invalid action counts (< 1 or > 6)
  • Error catching at each stage: Marp conversion, Puppeteer execution, LINE API calls
  • Proper cleanup of temporary files

Technical Aspects

  • Proper management and deletion of temporary files (HTML, PNG)
  • Proper cleanup of Puppeteer browser instances
  • Correct usage of both LINE Messaging API Client and Blob Client

Result

This implementation enables automatic generation of visually appealing rich menus using only text-based configuration, significantly improving the developer experience for LINE Bot creators.

Usage

https://x.com/_4geru/status/1933793286285898071
https://x.com/_4geru/status/1933890824808632560

@eucyt
Copy link
Contributor

eucyt commented Jun 9, 2025

@4geru
(just in case)
We refactored dir struction to avoid conflict. So check this development flow for detail please 🙇
https://github.com/line/line-bot-mcp-server/blob/ee1196bc33c1d9ca40c75e67fa044734a8d8602b/CONTRIBUTING.md#add-a-new-tool

@4geru
Copy link
Contributor Author

4geru commented Jun 10, 2025

@eucyt Hello Euchi-san. I updated to separate the tools file.
Also, I can generate and upload the rich menu.

However, it cannot open in my app. LINE app stands up many times, and restarts...
Could you support me...? 🙇 🙇

スクリーンショット 2025-06-11 7 58 20

@4geru
Copy link
Contributor Author

4geru commented Jun 10, 2025

Memo

prompt

LINE MCP を使って リッチメニューをなので作成してください
[1] カメラのアクションを設定してください
[2] テンプレートは7です
[3] ボタンは「ポッチっとな」です

result

{
  "richMenuId": "richmenu-6ba77c74ccaf8a1153045f627cc972c3",
  "setImageResponse": {},
  "richMenuImagePath": "/tmp/slide-07-1749597029244.png",
  "params": {
    "name": "ポッチっとな",
    "chatBarText": "ポッチっとな",
    "selected": false,
    "size": {
      "width": 1600,
      "height": 910
    },
    "areas": [
      {
        "bounds": {
          "x": 0,
          "y": 0,
          "width": 1600,
          "height": 900
        },
        "action": {
          "type": "camera",
          "label": "ポッチっとな"
        }
      }
    ]
  }
}

@4geru
Copy link
Contributor Author

4geru commented Jun 11, 2025

I checked image requirements. 👌
https://developers.line.biz/ja/reference/messaging-api/#upload-rich-menu-image-requirements
スクリーンショット 2025-06-11 13 46 16

@4geru 4geru marked this pull request as ready for review June 15, 2025 01:01
Comment on lines +39 to +40
"@marp-team/marp-cli": "^4.1.2",
"@marp-team/marp-core": "^4.1.0",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

packages for generating slides/images

Comment on lines 7 to 36
section {
padding: 0 !important;
background-color: orange;
height: 100% !important;
margin-top: 0 !important;
margin-bottom: 0 !important;
}
.columns-container {
display: flex;
flex-wrap: wrap;
width: 100%;
height: 100%;
}
.column-item {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background-color: white;
box-sizing: border-box;
overflow: hidden;
}
.column-item h3 {
font-weight: bold;
width: 100%;
text-align: center;
font-size: clamp(16px, 6vw, 50px);
white-space: normal;
word-break: break-all;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to put them all in a common file, but it isn't easy, so I write them by hand in each file.

});

// actions
export const actionSchema = z.union([
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it cannot automatically compare from line-bot-sdk-nodejs

@4geru 4geru force-pushed the 4geru/generate-rich-menu branch from fffcb1d to 9c6171c Compare June 15, 2025 01:05
@4geru 4geru changed the title 4geru/generate rich menu create rich menu operation Jun 15, 2025
@4geru
Copy link
Contributor Author

4geru commented Jun 15, 2025

@eucyt Sorry for the wait. We have improved and verified the functionality, so please leave a review.

@mokuzon mokuzon requested a review from eucyt June 17, 2025 05:30
@4geru 4geru force-pushed the 4geru/generate-rich-menu branch from b77e1cd to 0b6bd3d Compare June 19, 2025 14:26
@4geru
Copy link
Contributor Author

4geru commented Jun 19, 2025

@eucyt Sorry, I committed a file...
0b6bd3d

@eucyt
Copy link
Contributor

eucyt commented Jun 30, 2025

@4geru san
Sorry to late...
I'll review this in this week 🙇

@eucyt
Copy link
Contributor

eucyt commented Jul 3, 2025

@eucyt Hello Euchi-san. I updated to separate the tools file. Also, I can generate and upload the rich menu.

However, it cannot open in my app. LINE app stands up many times, and restarts... Could you support me...? 🙇 🙇

スクリーンショット 2025-06-11 7 58 20

Is this issue still occurring? If it is still happening, could you please provide the steps to reproduce it, specifically what is happening, and what the expected behavior should be? 🙏

Copy link
Contributor

@eucyt eucyt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is awesome! Thank you for implementing this wonderful tool. This greatly expands the possibilities of line-bot-mcp-server.

register(server: McpServer) {
server.tool(
"create_rich_menu",
"Create a rich menu associated with your LINE Official Account.",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about clearly specifying the description to avoid that agent confuse tools to use?

Suggested change
"Create a rich menu associated with your LINE Official Account.",
"Create a rich menu based on the given actions. Generate and upload a rich menu image based on the given action. This rich menu will be registered as the default.",

Comment on lines +57 to +60
// 1. Validate the rich menu image
if (templeteNo < 1 || templeteNo > 6) {
return createErrorResponse("Invalid texts length");
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to specify the number of elements using Zod like this? This way, the agent could know the element count constraints in advance when executing the tool.

z
  .array(actionSchema)
  .min(1)
  .max(6)
  .describe("hoge")

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know this setting. thanks for comment :)

"create_rich_menu",
"Create a rich menu associated with your LINE Official Account.",
{
chatBarText: z.string().describe("The ID of the rich menu to create."),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this more clear?
FYI: https://developers.line.biz/en/reference/messaging-api/#rich-menu-object

Suggested change
chatBarText: z.string().describe("The ID of the rich menu to create."),
chatBarText: z.string().describe("Text displayed in the chat bar and this is also used as name of the rich menu to create"),

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly, The ID makes us confuse :(

let setImageResponse: any = null;
let setDefaultResponse: any = null;
const lineActions = actions as messagingApi.Action[];
const templeteNo = lineActions.length;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nits] typo

Suggested change
const templeteNo = lineActions.length;
const templateNo = lineActions.length;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry!!!!

Comment on lines +149 to +152
for (let index = 0; index < actions.length; index++) {
const pattern = new RegExp(`<h3>item0${index + 1}</h3>`, "g");
content = content.replace(pattern, `<h3>${actions[index].label}</h3>`);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Just Question] Do you have plans to be enable to fill specified original images in richmenu?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I haven't planned yet. Just now, we can fill in the message.
I imagine generating the mock app from LLM, and it will update the image later.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nits] templete -> template 🙏

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, if these example images are not used, I think we should remove them to avoid more maintenance.

Comment on lines +6 to +35
section {
padding: 0 !important;
background-color: orange;
height: 100% !important;
margin-top: 0 !important;
margin-bottom: 0 !important;
}
.columns-container {
display: flex;
flex-wrap: wrap;
width: 100%;
height: 100%;
}
.column-item {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background-color: white;
box-sizing: border-box;
overflow: hidden;
}
.column-item h3 {
font-weight: bold;
width: 100%;
text-align: center;
font-size: 100px;
white-space: normal;
word-break: break-all;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using @import url('hoge'), can we extract common styles into a separate CSS file for reuse?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was unable to run this tool with Docker on my local. I encountered the following error. Is it possible to make it compatible with Docker? (I'm also concerned about whether screenshots will work. However, if this tool could be used with Docker, it would be quite convenient 😄 )

{"error":{"errno":-2,"code":"ENOENT","syscall":"open","path":"/app/richmenu-templetes/templete-02.md"},"createRichMenuResponse":{"richMenuId":"richmenu-828cebe92610f4649aab4b0a8ea05d17"},"setImageResponse":null,"setDefaultResponse":null}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to try with Docker. I tried from dist/index.js.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add description to README.md and README.ja.md 🙏

@4geru
Copy link
Contributor Author

4geru commented Jul 3, 2025

This issue was not solved :). Some accounts are dead. 😃 However, this tool is updated.

#121 (comment)

@eucyt
Copy link
Contributor

eucyt commented Jul 4, 2025

This issue was not solved :). Some accounts are dead. 😃 However, this tool is updated.

#121 (comment)

@4geru san
I don't fully understand the issue you're consulting about, so could you first tell me about the problem that's occurring?

Are you saying that the LINE client application in smartphone keeps crashing? In other words, is this directly unrelated to the line-bot-mcp-server or LINE Official Account? I would appreciate if you could explain the steps that lead to this malfunction.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants