diff --git a/README.ja.md b/README.ja.md index 11f268a..0204d36 100644 --- a/README.ja.md +++ b/README.ja.md @@ -23,37 +23,49 @@ LINE公式アカウントとAI Agentを接続するために、LINE Messaging AP - `message.altText` (string): フレックスメッセージが表示できない場合に表示される代替テキスト。 - `message.contents` (any): フレックスメッセージの内容。メッセージのレイアウトとコンポーネントを定義するJSONオブジェクト。 - `message.contents.type` (enum): コンテナのタイプ。'bubble'は単一コンテナ、'carousel'は複数のスワイプ可能なバブルを示す。 -3. **broadcast_text_message** +3. **reply_text_message** + - LINEでユーザーにシンプルなテキストメッセージで返信する。書式なしのプレーンテキストメッセージの送信に使用する。 + - **入力:** + - `message.text` (string): ユーザーに返信するテキスト。 + - `replyToken` (string): 返信トークン。 +4. **reply_flex_message** + - LINEでユーザーに高度にカスタマイズ可能なフレックスメッセージで返信する。バブル(単一コンテナ)とカルーセル(複数のスワイプ可能なバブル)の両方のレイアウトをサポート。 + - **入力:** + - `message.altText` (string): フレックスメッセージが表示できない場合に表示される代替テキスト。 + - `message.contents` (any): フレックスメッセージの内容。メッセージのレイアウトとコンポーネントを定義するJSONオブジェクト。 + - `message.contents.type` (enum): コンテナのタイプ。'bubble'は単一コンテナ、'carousel'は複数のスワイプ可能なバブルを示す。 + - `replyToken` (string): 返信トークン。 +5. **broadcast_text_message** - LINE公式アカウントと友だちになっているすべてのユーザーに、LINEでシンプルなテキストメッセージを送信する。 - **入力:** - `message.text` (string): ユーザーに送信するテキスト。 -4. **broadcast_flex_message** +6. **broadcast_flex_message** - LINE公式アカウントと友だちになっているすべてのユーザーに、LINEで高度にカスタマイズ可能なフレックスメッセージを送信する。 - **入力:** - `message.altText` (string): フレックスメッセージが表示できない場合に表示される代替テキスト。 - `message.contents` (any): フレックスメッセージの内容。メッセージのレイアウトとコンポーネントを定義するJSONオブジェクト。 - `message.contents.type` (enum): コンテナのタイプ。'bubble'は単一コンテナ、'carousel'は複数のスワイプ可能なバブルを示す。 -5. **get_profile** +7. **get_profile** - LINEユーザーの詳細なプロフィール情報を取得する。表示名、プロフィール画像URL、ステータスメッセージ、言語を取得できる。 - **入力:** - `userId` (string?): プロフィールを取得したいユーザーのユーザーID。デフォルトはDESTINATION_USER_ID。`user_id`または`DESTINATION_USER_ID`のどちらか一方は必ず設定する必要があります。 -6. **get_message_quota** +8. **get_message_quota** - LINE公式アカウントのメッセージ容量と消費量を取得します。月間メッセージ制限と現在の使用量が表示されます。 - **入力:** - なし -7. **get_rich_menu_list** +9. **get_rich_menu_list** - LINE公式アカウントに登録されているリッチメニューの一覧を取得する。 - **入力:** - なし -8. **delete_rich_menu** - - LINE公式アカウントからリッチメニューを削除する。 - - **入力:** - - `richMenuId` (string): 削除するリッチメニューのID。 -9. **set_rich_menu_default** +10. **delete_rich_menu** + - LINE公式アカウントからリッチメニューを削除する。 + - **入力:** + - `richMenuId` (string): 削除するリッチメニューのID。 +11. **set_rich_menu_default** - リッチメニューをデフォルトとして設定する。 - **入力:** - `richMenuId` (string): デフォルトとして設定するリッチメニューのID。 -10. **cancel_rich_menu_default** +12. **cancel_rich_menu_default** - デフォルトのリッチメニューを解除する。 - **入力:** - なし diff --git a/README.md b/README.md index 25ecfff..102c2aa 100644 --- a/README.md +++ b/README.md @@ -25,37 +25,49 @@ - `message.altText` (string): Alternative text shown when flex message cannot be displayed. - `message.contents` (any): The contents of the flex message. This is a JSON object that defines the layout and components of the message. - `message.contents.type` (enum): Type of the container. 'bubble' for single container, 'carousel' for multiple swipeable bubbles. -3. **broadcast_text_message** +3. **reply_text_message** + - Reply with a simple text message to a user via LINE. Use this for sending plain text messages without formatting. + - **Inputs:** + - `message.text` (string): The plain text content to reply to the user. + - `replyToken` (string): Reply token. +4. **reply_flex_message** + - Reply with a highly customizable flex message to a user via LINE. Supports both bubble (single container) and carousel (multiple swipeable bubbles) layouts. + - **Inputs:** + - `message.altText` (string): Alternative text shown when flex message cannot be displayed. + - `message.contents` (any): The contents of the flex message. This is a JSON object that defines the layout and components of the message. + - `message.contents.type` (enum): Type of the container. 'bubble' for single container, 'carousel' for multiple swipeable bubbles. + - `replyToken` (string): Reply token. +5. **broadcast_text_message** - Broadcast a simple text message via LINE to all users who have followed your LINE Official Account. - **Inputs:** - `message.text` (string): The plain text content to send to the users. -4. **broadcast_flex_message** +6. **broadcast_flex_message** - Broadcast a highly customizable flex message via LINE to all users who have added your LINE Official Account. - **Inputs:** - `message.altText` (string): Alternative text shown when flex message cannot be displayed. - `message.contents` (any): The contents of the flex message. This is a JSON object that defines the layout and components of the message. - `message.contents.type` (enum): Type of the container. 'bubble' for single container, 'carousel' for multiple swipeable bubbles. -5. **get_profile** +7. **get_profile** - Get detailed profile information of a LINE user including display name, profile picture URL, status message and language. - **Inputs:** - `userId` (string?): The ID of the user whose profile you want to retrieve. Defaults to DESTINATION_USER_ID. -6. **get_message_quota** +8. **get_message_quota** - Get the message quota and consumption of the LINE Official Account. This shows the monthly message limit and current usage. - **Inputs:** - None -7. **get_rich_menu_list** +9. **get_rich_menu_list** - Get the list of rich menus associated with your LINE Official Account. - **Inputs:** - None -8. **delete_rich_menu** - - Delete a rich menu from your LINE Official Account. - - **Inputs:** - - `richMenuId` (string): The ID of the rich menu to delete. -9. **set_rich_menu_default** +10. **delete_rich_menu** + - Delete a rich menu from your LINE Official Account. + - **Inputs:** + - `richMenuId` (string): The ID of the rich menu to delete. +11. **set_rich_menu_default** - Set a rich menu as the default rich menu. - **Inputs:** - `richMenuId` (string): The ID of the rich menu to set as default. -10. **cancel_rich_menu_default** +12. **cancel_rich_menu_default** - Cancel the default rich menu. - **Inputs:** - None diff --git a/src/common/schema/constants.ts b/src/common/schema/constants.ts index 93f7066..aecc9fb 100644 --- a/src/common/schema/constants.ts +++ b/src/common/schema/constants.ts @@ -1,2 +1,5 @@ export const NO_USER_ID_ERROR = "Error: Specify the userId or set the DESTINATION_USER_ID in the environment variables of this MCP Server."; + +export const NO_REPLY_TOKEN_ERROR = + "Error: Reply token is required to send a reply message."; diff --git a/src/index.ts b/src/index.ts index edc2b61..3fc5924 100644 --- a/src/index.ts +++ b/src/index.ts @@ -23,6 +23,8 @@ import { LINE_BOT_MCP_SERVER_VERSION, USER_AGENT } from "./version.js"; import CancelRichMenuDefault from "./tools/cancelRichMenuDefault.js"; import PushTextMessage from "./tools/pushTextMessage.js"; import PushFlexMessage from "./tools/pushFlexMessage.js"; +import ReplyFlexMessage from "./tools/replyFlexMessage.js"; +import ReplyTextMessage from "./tools/replyTextMessage.js"; import BroadcastTextMessage from "./tools/broadcastTextMessage.js"; import BroadcastFlexMessage from "./tools/broadcastFlexMessage.js"; import GetProfile from "./tools/getProfile.js"; @@ -48,6 +50,8 @@ const messagingApiClient = new line.messagingApi.MessagingApiClient({ new PushTextMessage(messagingApiClient, destinationId).register(server); new PushFlexMessage(messagingApiClient, destinationId).register(server); +new ReplyTextMessage(messagingApiClient).register(server); +new ReplyFlexMessage(messagingApiClient).register(server); new BroadcastTextMessage(messagingApiClient).register(server); new BroadcastFlexMessage(messagingApiClient).register(server); new GetProfile(messagingApiClient, destinationId).register(server); diff --git a/src/tools/replyFlexMessage.ts b/src/tools/replyFlexMessage.ts new file mode 100644 index 0000000..ecc1995 --- /dev/null +++ b/src/tools/replyFlexMessage.ts @@ -0,0 +1,48 @@ +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_REPLY_TOKEN_ERROR } from "../common/schema/constants.js"; +import { flexMessageSchema } from "../common/schema/flexMessage.js"; + +export default class PushFlexMessage extends AbstractTool { + private client: messagingApi.MessagingApiClient; + + constructor(client: messagingApi.MessagingApiClient) { + super(); + this.client = client; + } + + register(server: McpServer) { + server.tool( + "reply_flex_message", + "Push a highly customizable flex message to a user via LINE. Supports both bubble (single container) and carousel " + + "(multiple swipeable bubbles) layouts.", + { + message: flexMessageSchema, + replyToken: z.string().describe("Reply token."), + }, + async ({ message, replyToken }) => { + if (!replyToken) { + return createErrorResponse(NO_REPLY_TOKEN_ERROR); + } + + try { + const response = await this.client.replyMessage({ + messages: [message as unknown as messagingApi.Message], + replyToken: replyToken, + }); + return createSuccessResponse(response); + } catch (error) { + return createErrorResponse( + `Failed to reply flex message: ${error.message}`, + ); + } + }, + ); + } +} diff --git a/src/tools/replyTextMessage.ts b/src/tools/replyTextMessage.ts new file mode 100644 index 0000000..97d94ba --- /dev/null +++ b/src/tools/replyTextMessage.ts @@ -0,0 +1,47 @@ +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_REPLY_TOKEN_ERROR } from "../common/schema/constants.js"; +import { textMessageSchema } from "../common/schema/textMessage.js"; + +export default class PushTextMessage extends AbstractTool { + private client: messagingApi.MessagingApiClient; + + constructor(client: messagingApi.MessagingApiClient) { + super(); + this.client = client; + } + + register(server: McpServer) { + server.tool( + "reply_text_message", + "Push a simple text message to a user via LINE. Use this for sending plain text messages without formatting.", + { + message: textMessageSchema, + replyToken: z.string().describe("Reply token."), + }, + async ({ message, replyToken }) => { + if (!replyToken) { + return createErrorResponse(NO_REPLY_TOKEN_ERROR); + } + + try { + const response = await this.client.replyMessage({ + messages: [message as unknown as messagingApi.Message], + replyToken: replyToken, + }); + return createSuccessResponse(response); + } catch (error) { + return createErrorResponse( + `Failed to reply message: ${error.message}`, + ); + } + }, + ); + } +}