@line-harness/mcp-server 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -0
- package/dist/client.d.ts +2 -0
- package/dist/client.js +22 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/resources/index.d.ts +2 -0
- package/dist/resources/index.js +48 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/tools/account-summary.d.ts +2 -0
- package/dist/tools/account-summary.js +47 -0
- package/dist/tools/account-summary.js.map +1 -0
- package/dist/tools/broadcast.d.ts +2 -0
- package/dist/tools/broadcast.js +80 -0
- package/dist/tools/broadcast.js.map +1 -0
- package/dist/tools/create-form.d.ts +2 -0
- package/dist/tools/create-form.js +32 -0
- package/dist/tools/create-form.js.map +1 -0
- package/dist/tools/create-rich-menu.d.ts +2 -0
- package/dist/tools/create-rich-menu.js +36 -0
- package/dist/tools/create-rich-menu.js.map +1 -0
- package/dist/tools/create-scenario.d.ts +2 -0
- package/dist/tools/create-scenario.js +78 -0
- package/dist/tools/create-scenario.js.map +1 -0
- package/dist/tools/create-tracked-link.d.ts +2 -0
- package/dist/tools/create-tracked-link.js +22 -0
- package/dist/tools/create-tracked-link.js.map +1 -0
- package/dist/tools/enroll-scenario.d.ts +2 -0
- package/dist/tools/enroll-scenario.js +23 -0
- package/dist/tools/enroll-scenario.js.map +1 -0
- package/dist/tools/get-form-submissions.d.ts +2 -0
- package/dist/tools/get-form-submissions.js +19 -0
- package/dist/tools/get-form-submissions.js.map +1 -0
- package/dist/tools/get-friend-detail.d.ts +2 -0
- package/dist/tools/get-friend-detail.js +19 -0
- package/dist/tools/get-friend-detail.js.map +1 -0
- package/dist/tools/get-link-clicks.d.ts +2 -0
- package/dist/tools/get-link-clicks.js +19 -0
- package/dist/tools/get-link-clicks.js.map +1 -0
- package/dist/tools/index.d.ts +2 -0
- package/dist/tools/index.js +31 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/list-crm-objects.d.ts +2 -0
- package/dist/tools/list-crm-objects.js +40 -0
- package/dist/tools/list-crm-objects.js.map +1 -0
- package/dist/tools/list-friends.d.ts +2 -0
- package/dist/tools/list-friends.js +30 -0
- package/dist/tools/list-friends.js.map +1 -0
- package/dist/tools/manage-tags.d.ts +2 -0
- package/dist/tools/manage-tags.js +44 -0
- package/dist/tools/manage-tags.js.map +1 -0
- package/dist/tools/send-message.d.ts +2 -0
- package/dist/tools/send-message.js +24 -0
- package/dist/tools/send-message.js.map +1 -0
- package/package.json +33 -0
package/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# @line-harness/mcp-server
|
|
2
|
+
|
|
3
|
+
MCP Server for LINE Harness — operate LINE official accounts from Claude Code, Cursor, or any MCP-compatible AI tool via natural language.
|
|
4
|
+
|
|
5
|
+
## Quick Setup
|
|
6
|
+
|
|
7
|
+
Add to your MCP config (`claude_desktop_config.json` for Claude Code, `mcp.json` for Cursor):
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"mcpServers": {
|
|
12
|
+
"line-harness": {
|
|
13
|
+
"command": "npx",
|
|
14
|
+
"args": ["-y", "@line-harness/mcp-server"],
|
|
15
|
+
"env": {
|
|
16
|
+
"LINE_HARNESS_API_URL": "https://your-worker.your-subdomain.workers.dev",
|
|
17
|
+
"LINE_HARNESS_API_KEY": "your_api_key"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Restart your AI tool. The 14 LINE Harness tools will appear automatically.
|
|
25
|
+
|
|
26
|
+
## Available Tools
|
|
27
|
+
|
|
28
|
+
| Tool | Description |
|
|
29
|
+
|---|---|
|
|
30
|
+
| `account_summary` | High-level overview: friend count, active scenarios, recent broadcasts, tags |
|
|
31
|
+
| `list_friends` | List friends with optional tag filtering and pagination |
|
|
32
|
+
| `get_friend_detail` | Detailed profile, tags, and metadata for a specific friend |
|
|
33
|
+
| `send_message` | Send text or flex message to a specific friend |
|
|
34
|
+
| `broadcast` | Send broadcast to all friends, a tag group, or a filtered segment |
|
|
35
|
+
| `manage_tags` | Create tags, add/remove tags on friends (supports batch) |
|
|
36
|
+
| `create_scenario` | Create a step-delivery scenario with delays and triggers |
|
|
37
|
+
| `enroll_in_scenario` | Enroll a friend into a scenario manually |
|
|
38
|
+
| `create_form` | Create a response-collection form with auto-tag on submit |
|
|
39
|
+
| `get_form_submissions` | Retrieve all submissions for a form |
|
|
40
|
+
| `create_tracked_link` | Create a click-tracking link with auto-tag on click |
|
|
41
|
+
| `get_link_clicks` | Click analytics for a tracked link |
|
|
42
|
+
| `create_rich_menu` | Create a LINE rich menu (persistent bottom menu) |
|
|
43
|
+
| `list_crm_objects` | List scenarios, forms, tags, rich menus, tracked links, or broadcasts |
|
|
44
|
+
|
|
45
|
+
## Environment Variables
|
|
46
|
+
|
|
47
|
+
| Variable | Description |
|
|
48
|
+
|---|---|
|
|
49
|
+
| `LINE_HARNESS_API_URL` | URL of your deployed Cloudflare Worker (e.g. `https://my-worker.workers.dev`) |
|
|
50
|
+
| `LINE_HARNESS_API_KEY` | API key set as `API_KEY` secret on your Worker |
|
|
51
|
+
|
|
52
|
+
## Requirements
|
|
53
|
+
|
|
54
|
+
- Node.js 20+
|
|
55
|
+
- A running LINE Harness Worker ([deploy guide](https://github.com/Shudesu/line-harness-oss#quick-start))
|
|
56
|
+
|
|
57
|
+
## Main Repository
|
|
58
|
+
|
|
59
|
+
[github.com/Shudesu/line-harness-oss](https://github.com/Shudesu/line-harness-oss)
|
|
60
|
+
|
|
61
|
+
## License
|
|
62
|
+
|
|
63
|
+
MIT
|
package/dist/client.d.ts
ADDED
package/dist/client.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { LineHarness } from "@line-harness/sdk";
|
|
2
|
+
let clientInstance = null;
|
|
3
|
+
export function getClient() {
|
|
4
|
+
if (clientInstance)
|
|
5
|
+
return clientInstance;
|
|
6
|
+
const apiUrl = process.env.LINE_HARNESS_API_URL;
|
|
7
|
+
const apiKey = process.env.LINE_HARNESS_API_KEY;
|
|
8
|
+
const accountId = process.env.LINE_HARNESS_ACCOUNT_ID;
|
|
9
|
+
if (!apiUrl) {
|
|
10
|
+
throw new Error("LINE_HARNESS_API_URL environment variable is required");
|
|
11
|
+
}
|
|
12
|
+
if (!apiKey) {
|
|
13
|
+
throw new Error("LINE_HARNESS_API_KEY environment variable is required");
|
|
14
|
+
}
|
|
15
|
+
clientInstance = new LineHarness({
|
|
16
|
+
apiUrl,
|
|
17
|
+
apiKey,
|
|
18
|
+
lineAccountId: accountId,
|
|
19
|
+
});
|
|
20
|
+
return clientInstance;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,IAAI,cAAc,GAAuB,IAAI,CAAC;AAE9C,MAAM,UAAU,SAAS;IACvB,IAAI,cAAc;QAAE,OAAO,cAAc,CAAC;IAE1C,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;IAChD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;IAChD,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC;IAEtD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;IAC3E,CAAC;IACD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;IAC3E,CAAC;IAED,cAAc,GAAG,IAAI,WAAW,CAAC;QAC/B,MAAM;QACN,MAAM;QACN,aAAa,EAAE,SAAS;KACzB,CAAC,CAAC;IAEH,OAAO,cAAc,CAAC;AACxB,CAAC"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { registerAllTools } from "./tools/index.js";
|
|
5
|
+
import { registerAllResources } from "./resources/index.js";
|
|
6
|
+
const server = new McpServer({
|
|
7
|
+
name: "line-harness",
|
|
8
|
+
version: "0.1.0",
|
|
9
|
+
});
|
|
10
|
+
registerAllTools(server);
|
|
11
|
+
registerAllResources(server);
|
|
12
|
+
async function main() {
|
|
13
|
+
const transport = new StdioServerTransport();
|
|
14
|
+
await server.connect(transport);
|
|
15
|
+
console.error("LINE Harness MCP Server running on stdio");
|
|
16
|
+
}
|
|
17
|
+
main().catch((error) => {
|
|
18
|
+
console.error("Fatal error:", error);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
});
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAE5D,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,cAAc;IACpB,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,gBAAgB,CAAC,MAAM,CAAC,CAAC;AACzB,oBAAoB,CAAC,MAAM,CAAC,CAAC;AAE7B,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;AAC5D,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { getClient } from "../client.js";
|
|
2
|
+
export function registerAllResources(server) {
|
|
3
|
+
server.resource("Account Summary", "line-harness://account/summary", async (uri) => {
|
|
4
|
+
const client = getClient();
|
|
5
|
+
const [friendCount, scenarios, tags] = await Promise.all([
|
|
6
|
+
client.friends.count(),
|
|
7
|
+
client.scenarios.list(),
|
|
8
|
+
client.tags.list(),
|
|
9
|
+
]);
|
|
10
|
+
const summary = {
|
|
11
|
+
friends: friendCount,
|
|
12
|
+
activeScenarios: scenarios.filter((s) => s.isActive).length,
|
|
13
|
+
totalScenarios: scenarios.length,
|
|
14
|
+
tags: tags.map((t) => ({ id: t.id, name: t.name })),
|
|
15
|
+
};
|
|
16
|
+
return {
|
|
17
|
+
contents: [{
|
|
18
|
+
uri: "line-harness://account/summary",
|
|
19
|
+
mimeType: "application/json",
|
|
20
|
+
text: JSON.stringify(summary, null, 2),
|
|
21
|
+
}],
|
|
22
|
+
};
|
|
23
|
+
});
|
|
24
|
+
server.resource("Active Scenarios", "line-harness://scenarios/active", async (uri) => {
|
|
25
|
+
const client = getClient();
|
|
26
|
+
const scenarios = await client.scenarios.list();
|
|
27
|
+
const active = scenarios.filter((s) => s.isActive);
|
|
28
|
+
return {
|
|
29
|
+
contents: [{
|
|
30
|
+
uri: "line-harness://scenarios/active",
|
|
31
|
+
mimeType: "application/json",
|
|
32
|
+
text: JSON.stringify(active, null, 2),
|
|
33
|
+
}],
|
|
34
|
+
};
|
|
35
|
+
});
|
|
36
|
+
server.resource("Tags List", "line-harness://tags/list", async (uri) => {
|
|
37
|
+
const client = getClient();
|
|
38
|
+
const tags = await client.tags.list();
|
|
39
|
+
return {
|
|
40
|
+
contents: [{
|
|
41
|
+
uri: "line-harness://tags/list",
|
|
42
|
+
mimeType: "application/json",
|
|
43
|
+
text: JSON.stringify(tags, null, 2),
|
|
44
|
+
}],
|
|
45
|
+
};
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,MAAM,UAAU,oBAAoB,CAAC,MAAiB;IACpD,MAAM,CAAC,QAAQ,CACb,iBAAiB,EACjB,gCAAgC,EAChC,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,CAAC,WAAW,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YACvD,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE;YACtB,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE;YACvB,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE;SACnB,CAAC,CAAC;QAEH,MAAM,OAAO,GAAG;YACd,OAAO,EAAE,WAAW;YACpB,eAAe,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM;YAChE,cAAc,EAAE,SAAS,CAAC,MAAM;YAChC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;SACzD,CAAC;QAEF,OAAO;YACL,QAAQ,EAAE,CAAC;oBACT,GAAG,EAAE,gCAAgC;oBACrC,QAAQ,EAAE,kBAAkB;oBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;iBACvC,CAAC;SACH,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,QAAQ,CACb,kBAAkB,EAClB,iCAAiC,EACjC,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;QAChD,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QACxD,OAAO;YACL,QAAQ,EAAE,CAAC;oBACT,GAAG,EAAE,iCAAiC;oBACtC,QAAQ,EAAE,kBAAkB;oBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;iBACtC,CAAC;SACH,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,QAAQ,CACb,WAAW,EACX,0BAA0B,EAC1B,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACtC,OAAO;YACL,QAAQ,EAAE,CAAC;oBACT,GAAG,EAAE,0BAA0B;oBAC/B,QAAQ,EAAE,kBAAkB;oBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;iBACpC,CAAC;SACH,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getClient } from "../client.js";
|
|
3
|
+
export function registerAccountSummary(server) {
|
|
4
|
+
server.tool("account_summary", "Get a high-level summary of the LINE account: friend count, active scenarios, recent broadcasts, tags, and forms. Use this to understand the current state before making changes.", {
|
|
5
|
+
accountId: z.string().optional().describe("LINE account ID (uses default if omitted)"),
|
|
6
|
+
}, async ({ accountId }) => {
|
|
7
|
+
try {
|
|
8
|
+
const client = getClient();
|
|
9
|
+
const [friendCount, scenarios, broadcasts, tags, forms] = await Promise.all([
|
|
10
|
+
client.friends.count({ accountId }),
|
|
11
|
+
client.scenarios.list({ accountId }),
|
|
12
|
+
client.broadcasts.list({ accountId }),
|
|
13
|
+
client.tags.list(),
|
|
14
|
+
client.forms.list(),
|
|
15
|
+
]);
|
|
16
|
+
const activeScenarios = scenarios.filter((s) => s.isActive);
|
|
17
|
+
const recentBroadcasts = broadcasts.slice(0, 5);
|
|
18
|
+
const summary = {
|
|
19
|
+
friends: { total: friendCount },
|
|
20
|
+
scenarios: {
|
|
21
|
+
total: scenarios.length,
|
|
22
|
+
active: activeScenarios.length,
|
|
23
|
+
activeList: activeScenarios.map((s) => ({ id: s.id, name: s.name, triggerType: s.triggerType })),
|
|
24
|
+
},
|
|
25
|
+
broadcasts: {
|
|
26
|
+
total: broadcasts.length,
|
|
27
|
+
recent: recentBroadcasts.map((b) => ({ id: b.id, title: b.title, status: b.status, sentAt: b.sentAt })),
|
|
28
|
+
},
|
|
29
|
+
tags: {
|
|
30
|
+
total: tags.length,
|
|
31
|
+
list: tags.map((t) => ({ id: t.id, name: t.name })),
|
|
32
|
+
},
|
|
33
|
+
forms: {
|
|
34
|
+
total: forms.length,
|
|
35
|
+
list: forms.map((f) => ({ id: f.id, name: f.name })),
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
return {
|
|
39
|
+
content: [{ type: "text", text: JSON.stringify(summary, null, 2) }],
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
return { content: [{ type: "text", text: JSON.stringify({ success: false, error: String(error) }, null, 2) }], isError: true };
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=account-summary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account-summary.js","sourceRoot":"","sources":["../../src/tools/account-summary.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,MAAM,UAAU,sBAAsB,CAAC,MAAiB;IACtD,MAAM,CAAC,IAAI,CACT,iBAAiB,EACjB,mLAAmL,EACnL;QACE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2CAA2C,CAAC;KACvF,EACD,KAAK,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE;QACtB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;YAE3B,MAAM,CAAC,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;gBAC1E,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC;gBACnC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,CAAC;gBACpC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,CAAC;gBACrC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE;gBAClB,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE;aACpB,CAAC,CAAC;YAEH,MAAM,eAAe,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;YACjE,MAAM,gBAAgB,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YAEhD,MAAM,OAAO,GAAG;gBACd,OAAO,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE;gBAC/B,SAAS,EAAE;oBACT,KAAK,EAAE,SAAS,CAAC,MAAM;oBACvB,MAAM,EAAE,eAAe,CAAC,MAAM;oBAC9B,UAAU,EAAE,eAAe,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;iBACtG;gBACD,UAAU,EAAE;oBACV,KAAK,EAAE,UAAU,CAAC,MAAM;oBACxB,MAAM,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;iBAC7G;gBACD,IAAI,EAAE;oBACJ,KAAK,EAAE,IAAI,CAAC,MAAM;oBAClB,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;iBACzD;gBACD,KAAK,EAAE;oBACL,KAAK,EAAE,KAAK,CAAC,MAAM;oBACnB,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;iBAC1D;aACF,CAAC;YAEF,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aACpE,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACjI,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getClient } from "../client.js";
|
|
3
|
+
export function registerBroadcast(server) {
|
|
4
|
+
server.tool("broadcast", "Send a broadcast message to all friends, a specific tag group, or a filtered segment. Creates and immediately sends the broadcast.", {
|
|
5
|
+
title: z.string().describe("Internal title for this broadcast (not shown to users)"),
|
|
6
|
+
messageType: z.enum(["text", "flex"]).describe("Message type"),
|
|
7
|
+
messageContent: z.string().describe("Message content. For text: plain string. For flex: JSON string."),
|
|
8
|
+
targetType: z.enum(["all", "tag", "segment"]).default("all").describe("Target audience: 'all' for everyone, 'tag' for a tag group, 'segment' for filtered conditions"),
|
|
9
|
+
targetTagId: z.string().optional().describe("Tag ID when targetType is 'tag'"),
|
|
10
|
+
segmentConditions: z.string().optional().describe("JSON string of segment conditions when targetType is 'segment'. Format: { operator: 'AND'|'OR', rules: [{ type: 'tag_exists'|'tag_not_exists'|'metadata_equals'|'metadata_not_equals'|'ref_code'|'is_following', value: string|boolean|{key,value} }] }"),
|
|
11
|
+
scheduledAt: z.string().optional().describe("ISO 8601 datetime to schedule. Omit to send immediately."),
|
|
12
|
+
accountId: z.string().optional().describe("LINE account ID (uses default if omitted)"),
|
|
13
|
+
}, async ({ title, messageType, messageContent, targetType, targetTagId, segmentConditions, scheduledAt, accountId }) => {
|
|
14
|
+
try {
|
|
15
|
+
const client = getClient();
|
|
16
|
+
// Validate segment broadcasts require segmentConditions
|
|
17
|
+
if (targetType === "segment" && !segmentConditions) {
|
|
18
|
+
return {
|
|
19
|
+
content: [{ type: "text", text: JSON.stringify({ success: false, error: "segmentConditions is required when targetType is 'segment'" }, null, 2) }],
|
|
20
|
+
isError: true,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
// Block scheduled segment broadcasts — the worker scheduler cannot apply segment filters after persistence
|
|
24
|
+
if (targetType === "segment" && scheduledAt) {
|
|
25
|
+
return {
|
|
26
|
+
content: [{ type: "text", text: JSON.stringify({ success: false, error: "Scheduled segment broadcasts are not supported. Use scheduledAt only with targetType 'all' or 'tag'." }, null, 2) }],
|
|
27
|
+
isError: true,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
// Segment broadcasts: validate JSON first, then create and sendToSegment
|
|
31
|
+
if (targetType === "segment" && segmentConditions) {
|
|
32
|
+
let parsedConditions;
|
|
33
|
+
try {
|
|
34
|
+
parsedConditions = JSON.parse(segmentConditions);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return {
|
|
38
|
+
content: [{ type: "text", text: JSON.stringify({ success: false, error: "segmentConditions must be valid JSON" }, null, 2) }],
|
|
39
|
+
isError: true,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
// Segment broadcasts are stored with targetType "all" because the DB schema
|
|
43
|
+
// does not have a segment type. Prefix the title so the audit trail clearly
|
|
44
|
+
// identifies them as segment sends, not all-audience blasts.
|
|
45
|
+
const broadcast = await client.broadcasts.create({
|
|
46
|
+
title: `[SEGMENT] ${title}`,
|
|
47
|
+
messageType,
|
|
48
|
+
messageContent,
|
|
49
|
+
targetType: "all",
|
|
50
|
+
lineAccountId: accountId,
|
|
51
|
+
});
|
|
52
|
+
try {
|
|
53
|
+
const result = await client.broadcasts.sendToSegment(broadcast.id, parsedConditions);
|
|
54
|
+
return { content: [{ type: "text", text: JSON.stringify({ success: true, broadcast: result }, null, 2) }] };
|
|
55
|
+
}
|
|
56
|
+
catch (sendError) {
|
|
57
|
+
// Clean up the draft broadcast so it cannot be accidentally sent later
|
|
58
|
+
await client.broadcasts.delete(broadcast.id).catch(() => { });
|
|
59
|
+
throw sendError;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Tag and all-audience broadcasts
|
|
63
|
+
const broadcast = await client.broadcasts.create({
|
|
64
|
+
title,
|
|
65
|
+
messageType,
|
|
66
|
+
messageContent,
|
|
67
|
+
targetType: targetType,
|
|
68
|
+
targetTagId,
|
|
69
|
+
scheduledAt,
|
|
70
|
+
lineAccountId: accountId,
|
|
71
|
+
});
|
|
72
|
+
const result = scheduledAt ? broadcast : await client.broadcasts.send(broadcast.id);
|
|
73
|
+
return { content: [{ type: "text", text: JSON.stringify({ success: true, broadcast: result }, null, 2) }] };
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
return { content: [{ type: "text", text: JSON.stringify({ success: false, error: String(error) }, null, 2) }], isError: true };
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=broadcast.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"broadcast.js","sourceRoot":"","sources":["../../src/tools/broadcast.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getClient } from "../client.js";
|
|
3
|
+
export function registerCreateForm(server) {
|
|
4
|
+
server.tool("create_form", "Create a form for collecting user responses. Can auto-tag responders and enroll them in scenarios.", {
|
|
5
|
+
name: z.string().describe("Form name"),
|
|
6
|
+
description: z.string().optional().describe("Form description shown to users"),
|
|
7
|
+
fields: z.string().describe("JSON string of form fields. Format: [{ name: string, label: string, type: 'text'|'email'|'tel'|'number'|'textarea'|'select'|'radio'|'checkbox'|'date', required?: boolean, options?: string[], placeholder?: string }]"),
|
|
8
|
+
onSubmitTagId: z.string().optional().describe("Tag ID to auto-apply when form is submitted"),
|
|
9
|
+
onSubmitScenarioId: z.string().optional().describe("Scenario ID to auto-enroll when form is submitted"),
|
|
10
|
+
saveToMetadata: z.boolean().default(true).describe("Save form responses to friend metadata"),
|
|
11
|
+
accountId: z.string().optional().describe("LINE account ID (uses default if omitted)"),
|
|
12
|
+
}, async ({ name, description, fields, onSubmitTagId, onSubmitScenarioId, saveToMetadata, accountId }) => {
|
|
13
|
+
try {
|
|
14
|
+
const client = getClient();
|
|
15
|
+
const form = await client.forms.create({
|
|
16
|
+
name,
|
|
17
|
+
description,
|
|
18
|
+
fields: JSON.parse(fields),
|
|
19
|
+
onSubmitTagId,
|
|
20
|
+
onSubmitScenarioId,
|
|
21
|
+
saveToMetadata,
|
|
22
|
+
});
|
|
23
|
+
return {
|
|
24
|
+
content: [{ type: "text", text: JSON.stringify({ success: true, form }, null, 2) }],
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
return { content: [{ type: "text", text: JSON.stringify({ success: false, error: String(error) }, null, 2) }], isError: true };
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=create-form.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-form.js","sourceRoot":"","sources":["../../src/tools/create-form.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,MAAM,UAAU,kBAAkB,CAAC,MAAiB;IAClD,MAAM,CAAC,IAAI,CACT,aAAa,EACb,oGAAoG,EACpG;QACE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;QACtC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,iCAAiC,CAAC;QAC9E,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wNAAwN,CAAC;QACrP,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6CAA6C,CAAC;QAC5F,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mDAAmD,CAAC;QACvG,cAAc,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,wCAAwC,CAAC;QAC5F,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2CAA2C,CAAC;KACvF,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,kBAAkB,EAAE,cAAc,EAAE,SAAS,EAAE,EAAE,EAAE;QACpG,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;YAC3B,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;gBACrC,IAAI;gBACJ,WAAW;gBACX,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;gBAC1B,aAAa;gBACb,kBAAkB;gBAClB,cAAc;aACf,CAAC,CAAC;YACH,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aACpF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACjI,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getClient } from "../client.js";
|
|
3
|
+
export function registerCreateRichMenu(server) {
|
|
4
|
+
server.tool("create_rich_menu", "Create a LINE rich menu (the persistent menu at the bottom of the chat). Image must be uploaded separately via LINE Developers Console. This creates the menu structure and button areas.", {
|
|
5
|
+
name: z.string().describe("Rich menu name"),
|
|
6
|
+
chatBarText: z.string().default("メニュー").describe("Text shown on the chat bar button"),
|
|
7
|
+
size: z.object({
|
|
8
|
+
width: z.number().default(2500).describe("Menu width in pixels (2500 for full-width)"),
|
|
9
|
+
height: z.number().default(1686).describe("Menu height: 1686 for full, 843 for half"),
|
|
10
|
+
}).default({ width: 2500, height: 1686 }).describe("Menu size in pixels"),
|
|
11
|
+
selected: z.boolean().default(false).describe("Whether the rich menu is displayed by default"),
|
|
12
|
+
areas: z.string().describe("JSON string of menu button areas. Format: [{ bounds: { x, y, width, height }, action: { type: 'uri'|'message'|'postback', uri?, text?, data? } }]"),
|
|
13
|
+
setAsDefault: z.boolean().default(false).describe("Set this as the default rich menu for all friends"),
|
|
14
|
+
}, async ({ name, chatBarText, size, selected, areas, setAsDefault }) => {
|
|
15
|
+
try {
|
|
16
|
+
const client = getClient();
|
|
17
|
+
const menu = await client.richMenus.create({
|
|
18
|
+
name,
|
|
19
|
+
chatBarText,
|
|
20
|
+
size,
|
|
21
|
+
selected,
|
|
22
|
+
areas: JSON.parse(areas),
|
|
23
|
+
});
|
|
24
|
+
if (setAsDefault) {
|
|
25
|
+
await client.richMenus.setDefault(menu.richMenuId);
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
content: [{ type: "text", text: JSON.stringify({ success: true, richMenuId: menu.richMenuId, isDefault: setAsDefault }, null, 2) }],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
return { content: [{ type: "text", text: JSON.stringify({ success: false, error: String(error) }, null, 2) }], isError: true };
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=create-rich-menu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-rich-menu.js","sourceRoot":"","sources":["../../src/tools/create-rich-menu.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,MAAM,UAAU,sBAAsB,CAAC,MAAiB;IACtD,MAAM,CAAC,IAAI,CACT,kBAAkB,EAClB,2LAA2L,EAC3L;QACE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC;QAC3C,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,mCAAmC,CAAC;QACrF,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;YACb,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,4CAA4C,CAAC;YACtF,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,0CAA0C,CAAC;SACtF,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,qBAAqB,CAAC;QACzE,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,+CAA+C,CAAC;QAC9F,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,mJAAmJ,CAAC;QAC/K,YAAY,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,mDAAmD,CAAC;KACvG,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,EAAE;QACnE,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;YAC3B,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC;gBACzC,IAAI;gBACJ,WAAW;gBACX,IAAI;gBACJ,QAAQ;gBACR,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;aACzB,CAAC,CAAC;YACH,IAAI,YAAY,EAAE,CAAC;gBACjB,MAAM,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACrD,CAAC;YACD,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aACpI,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACjI,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getClient } from "../client.js";
|
|
3
|
+
import { parseDelay } from "@line-harness/sdk";
|
|
4
|
+
export function registerCreateScenario(server) {
|
|
5
|
+
server.tool("create_scenario", "Create a step delivery scenario with multiple message steps. Each step has a delay and message content. Scenarios auto-trigger on friend_add, tag_added, or manual enrollment.", {
|
|
6
|
+
name: z.string().describe("Scenario name"),
|
|
7
|
+
triggerType: z.enum(["friend_add", "tag_added", "manual"]).describe("When to start: 'friend_add' on new friends, 'tag_added' when a tag is applied, 'manual' for explicit enrollment"),
|
|
8
|
+
triggerTagId: z.string().optional().describe("Required when triggerType is 'tag_added': the tag ID that triggers this scenario"),
|
|
9
|
+
steps: z.array(z.object({
|
|
10
|
+
delay: z.string().describe("Delay before sending. Format: '0m' for immediate, '30m' for 30 minutes, '24h' for 24 hours"),
|
|
11
|
+
type: z.enum(["text", "flex"]).describe("Message type"),
|
|
12
|
+
content: z.string().describe("Message content"),
|
|
13
|
+
})).describe("Ordered list of message steps"),
|
|
14
|
+
accountId: z.string().optional().describe("LINE account ID (uses default if omitted)"),
|
|
15
|
+
}, async ({ name, triggerType, triggerTagId, steps, accountId }) => {
|
|
16
|
+
try {
|
|
17
|
+
// Enforce triggerTagId when triggerType is tag_added
|
|
18
|
+
if (triggerType === "tag_added" && !triggerTagId) {
|
|
19
|
+
return {
|
|
20
|
+
content: [{ type: "text", text: JSON.stringify({ success: false, error: "triggerTagId is required when triggerType is 'tag_added'" }, null, 2) }],
|
|
21
|
+
isError: true,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
// Pre-validate all step delays before creating any resources
|
|
25
|
+
const parsedSteps = [];
|
|
26
|
+
for (let i = 0; i < steps.length; i++) {
|
|
27
|
+
const step = steps[i];
|
|
28
|
+
let delayMinutes;
|
|
29
|
+
try {
|
|
30
|
+
delayMinutes = parseDelay(step.delay);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return {
|
|
34
|
+
content: [{ type: "text", text: JSON.stringify({ success: false, error: `Invalid delay format at step ${i + 1}: "${step.delay}". Use formats like '0m', '30m', '24h'.` }, null, 2) }],
|
|
35
|
+
isError: true,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
parsedSteps.push({ delayMinutes, type: step.type, content: step.content });
|
|
39
|
+
}
|
|
40
|
+
const client = getClient();
|
|
41
|
+
// Create the scenario
|
|
42
|
+
const scenario = await client.scenarios.create({
|
|
43
|
+
name,
|
|
44
|
+
triggerType,
|
|
45
|
+
triggerTagId,
|
|
46
|
+
lineAccountId: accountId,
|
|
47
|
+
});
|
|
48
|
+
// Add all steps — if any fail, clean up the scenario to avoid partial automation
|
|
49
|
+
try {
|
|
50
|
+
for (let i = 0; i < parsedSteps.length; i++) {
|
|
51
|
+
const step = parsedSteps[i];
|
|
52
|
+
await client.scenarios.addStep(scenario.id, {
|
|
53
|
+
stepOrder: i + 1,
|
|
54
|
+
delayMinutes: step.delayMinutes,
|
|
55
|
+
messageType: step.type,
|
|
56
|
+
messageContent: step.content,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
catch (stepError) {
|
|
61
|
+
// Delete the partially-created scenario to prevent incomplete automations from running
|
|
62
|
+
await client.scenarios.delete(scenario.id).catch(() => { });
|
|
63
|
+
throw stepError;
|
|
64
|
+
}
|
|
65
|
+
const scenarioWithSteps = await client.scenarios.get(scenario.id);
|
|
66
|
+
return {
|
|
67
|
+
content: [{
|
|
68
|
+
type: "text",
|
|
69
|
+
text: JSON.stringify({ success: true, scenario: scenarioWithSteps }, null, 2),
|
|
70
|
+
}],
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
return { content: [{ type: "text", text: JSON.stringify({ success: false, error: String(error) }, null, 2) }], isError: true };
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=create-scenario.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-scenario.js","sourceRoot":"","sources":["../../src/tools/create-scenario.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getClient } from "../client.js";
|
|
3
|
+
export function registerCreateTrackedLink(server) {
|
|
4
|
+
server.tool("create_tracked_link", "Create a click-tracking link. When clicked, can auto-tag the user and enroll them in a scenario.", {
|
|
5
|
+
name: z.string().describe("Link name (internal label)"),
|
|
6
|
+
originalUrl: z.string().describe("The destination URL to redirect to"),
|
|
7
|
+
tagId: z.string().optional().describe("Tag ID to auto-apply on click"),
|
|
8
|
+
scenarioId: z.string().optional().describe("Scenario ID to auto-enroll on click"),
|
|
9
|
+
}, async ({ name, originalUrl, tagId, scenarioId }) => {
|
|
10
|
+
try {
|
|
11
|
+
const client = getClient();
|
|
12
|
+
const link = await client.trackedLinks.create({ name, originalUrl, tagId, scenarioId });
|
|
13
|
+
return {
|
|
14
|
+
content: [{ type: "text", text: JSON.stringify({ success: true, link }, null, 2) }],
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
return { content: [{ type: "text", text: JSON.stringify({ success: false, error: String(error) }, null, 2) }], isError: true };
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=create-tracked-link.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-tracked-link.js","sourceRoot":"","sources":["../../src/tools/create-tracked-link.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,MAAM,UAAU,yBAAyB,CAAC,MAAiB;IACzD,MAAM,CAAC,IAAI,CACT,qBAAqB,EACrB,kGAAkG,EAClG;QACE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,4BAA4B,CAAC;QACvD,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,oCAAoC,CAAC;QACtE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;QACtE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qCAAqC,CAAC;KAClF,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE;QACjD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;YAC3B,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC;YACxF,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aACpF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACjI,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getClient } from "../client.js";
|
|
3
|
+
export function registerEnrollScenario(server) {
|
|
4
|
+
server.tool("enroll_in_scenario", "Enroll a friend into a scenario. The friend will start receiving the scenario's step messages from step 1.", {
|
|
5
|
+
scenarioId: z.string().describe("The scenario ID to enroll the friend in"),
|
|
6
|
+
friendId: z.string().describe("The friend's ID to enroll"),
|
|
7
|
+
}, async ({ scenarioId, friendId }) => {
|
|
8
|
+
try {
|
|
9
|
+
const client = getClient();
|
|
10
|
+
const enrollment = await client.scenarios.enroll(scenarioId, friendId);
|
|
11
|
+
return {
|
|
12
|
+
content: [{
|
|
13
|
+
type: "text",
|
|
14
|
+
text: JSON.stringify({ success: true, enrollment }, null, 2),
|
|
15
|
+
}],
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
return { content: [{ type: "text", text: JSON.stringify({ success: false, error: String(error) }, null, 2) }], isError: true };
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=enroll-scenario.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enroll-scenario.js","sourceRoot":"","sources":["../../src/tools/enroll-scenario.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,MAAM,UAAU,sBAAsB,CAAC,MAAiB;IACtD,MAAM,CAAC,IAAI,CACT,oBAAoB,EACpB,4GAA4G,EAC5G;QACE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,yCAAyC,CAAC;QAC1E,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2BAA2B,CAAC;KAC3D,EACD,KAAK,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,EAAE;QACjC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;YAC3B,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;YACvE,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;qBAC7D,CAAC;aACH,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACjI,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getClient } from "../client.js";
|
|
3
|
+
export function registerGetFormSubmissions(server) {
|
|
4
|
+
server.tool("get_form_submissions", "Get all submissions for a specific form. Returns response data with timestamps and friend IDs.", {
|
|
5
|
+
formId: z.string().describe("The form ID to get submissions for"),
|
|
6
|
+
}, async ({ formId }) => {
|
|
7
|
+
try {
|
|
8
|
+
const client = getClient();
|
|
9
|
+
const submissions = await client.forms.getSubmissions(formId);
|
|
10
|
+
return {
|
|
11
|
+
content: [{ type: "text", text: JSON.stringify({ success: true, submissions }, null, 2) }],
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
return { content: [{ type: "text", text: JSON.stringify({ success: false, error: String(error) }, null, 2) }], isError: true };
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=get-form-submissions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-form-submissions.js","sourceRoot":"","sources":["../../src/tools/get-form-submissions.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,MAAM,UAAU,0BAA0B,CAAC,MAAiB;IAC1D,MAAM,CAAC,IAAI,CACT,sBAAsB,EACtB,gGAAgG,EAChG;QACE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,oCAAoC,CAAC;KAClE,EACD,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;QACnB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;YAC3B,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;YAC9D,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aAC3F,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACjI,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getClient } from "../client.js";
|
|
3
|
+
export function registerGetFriendDetail(server) {
|
|
4
|
+
server.tool("get_friend_detail", "Get detailed information about a specific friend including tags, metadata, and profile.", {
|
|
5
|
+
friendId: z.string().describe("The friend's ID"),
|
|
6
|
+
}, async ({ friendId }) => {
|
|
7
|
+
try {
|
|
8
|
+
const client = getClient();
|
|
9
|
+
const friend = await client.friends.get(friendId);
|
|
10
|
+
return {
|
|
11
|
+
content: [{ type: "text", text: JSON.stringify({ success: true, friend }, null, 2) }],
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
return { content: [{ type: "text", text: JSON.stringify({ success: false, error: String(error) }, null, 2) }], isError: true };
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=get-friend-detail.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-friend-detail.js","sourceRoot":"","sources":["../../src/tools/get-friend-detail.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,MAAM,UAAU,uBAAuB,CAAC,MAAiB;IACvD,MAAM,CAAC,IAAI,CACT,mBAAmB,EACnB,yFAAyF,EACzF;QACE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iBAAiB,CAAC;KACjD,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;QACrB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;YAC3B,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAClD,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aACtF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACjI,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getClient } from "../client.js";
|
|
3
|
+
export function registerGetLinkClicks(server) {
|
|
4
|
+
server.tool("get_link_clicks", "Get click analytics for a tracked link including total clicks and per-friend click history.", {
|
|
5
|
+
linkId: z.string().describe("The tracked link ID"),
|
|
6
|
+
}, async ({ linkId }) => {
|
|
7
|
+
try {
|
|
8
|
+
const client = getClient();
|
|
9
|
+
const link = await client.trackedLinks.get(linkId);
|
|
10
|
+
return {
|
|
11
|
+
content: [{ type: "text", text: JSON.stringify({ success: true, link }, null, 2) }],
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
return { content: [{ type: "text", text: JSON.stringify({ success: false, error: String(error) }, null, 2) }], isError: true };
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=get-link-clicks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-link-clicks.js","sourceRoot":"","sources":["../../src/tools/get-link-clicks.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,MAAM,UAAU,qBAAqB,CAAC,MAAiB;IACrD,MAAM,CAAC,IAAI,CACT,iBAAiB,EACjB,6FAA6F,EAC7F;QACE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,qBAAqB,CAAC;KACnD,EACD,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;QACnB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;YAC3B,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACnD,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aACpF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACjI,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { registerSendMessage } from "./send-message.js";
|
|
2
|
+
import { registerBroadcast } from "./broadcast.js";
|
|
3
|
+
import { registerCreateScenario } from "./create-scenario.js";
|
|
4
|
+
import { registerEnrollScenario } from "./enroll-scenario.js";
|
|
5
|
+
import { registerManageTags } from "./manage-tags.js";
|
|
6
|
+
import { registerCreateForm } from "./create-form.js";
|
|
7
|
+
import { registerCreateTrackedLink } from "./create-tracked-link.js";
|
|
8
|
+
import { registerCreateRichMenu } from "./create-rich-menu.js";
|
|
9
|
+
import { registerListFriends } from "./list-friends.js";
|
|
10
|
+
import { registerGetFriendDetail } from "./get-friend-detail.js";
|
|
11
|
+
import { registerGetFormSubmissions } from "./get-form-submissions.js";
|
|
12
|
+
import { registerGetLinkClicks } from "./get-link-clicks.js";
|
|
13
|
+
import { registerAccountSummary } from "./account-summary.js";
|
|
14
|
+
import { registerListCrmObjects } from "./list-crm-objects.js";
|
|
15
|
+
export function registerAllTools(server) {
|
|
16
|
+
registerSendMessage(server);
|
|
17
|
+
registerBroadcast(server);
|
|
18
|
+
registerCreateScenario(server);
|
|
19
|
+
registerEnrollScenario(server);
|
|
20
|
+
registerManageTags(server);
|
|
21
|
+
registerCreateForm(server);
|
|
22
|
+
registerCreateTrackedLink(server);
|
|
23
|
+
registerCreateRichMenu(server);
|
|
24
|
+
registerListFriends(server);
|
|
25
|
+
registerGetFriendDetail(server);
|
|
26
|
+
registerGetFormSubmissions(server);
|
|
27
|
+
registerGetLinkClicks(server);
|
|
28
|
+
registerAccountSummary(server);
|
|
29
|
+
registerListCrmObjects(server);
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAE/D,MAAM,UAAU,gBAAgB,CAAC,MAAiB;IAChD,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAC5B,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC1B,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC/B,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC/B,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAC3B,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAC3B,yBAAyB,CAAC,MAAM,CAAC,CAAC;IAClC,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC/B,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAC5B,uBAAuB,CAAC,MAAM,CAAC,CAAC;IAChC,0BAA0B,CAAC,MAAM,CAAC,CAAC;IACnC,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAC9B,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC/B,sBAAsB,CAAC,MAAM,CAAC,CAAC;AACjC,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getClient } from "../client.js";
|
|
3
|
+
export function registerListCrmObjects(server) {
|
|
4
|
+
server.tool("list_crm_objects", "List all CRM objects of a specific type: scenarios, forms, tags, rich menus, tracked links, or broadcasts.", {
|
|
5
|
+
objectType: z.enum(["scenarios", "forms", "tags", "rich_menus", "tracked_links", "broadcasts"]).describe("Type of CRM object to list"),
|
|
6
|
+
accountId: z.string().optional().describe("LINE account ID (uses default if omitted)"),
|
|
7
|
+
}, async ({ objectType, accountId }) => {
|
|
8
|
+
try {
|
|
9
|
+
const client = getClient();
|
|
10
|
+
let items;
|
|
11
|
+
switch (objectType) {
|
|
12
|
+
case "scenarios":
|
|
13
|
+
items = await client.scenarios.list({ accountId });
|
|
14
|
+
break;
|
|
15
|
+
case "forms":
|
|
16
|
+
items = await client.forms.list();
|
|
17
|
+
break;
|
|
18
|
+
case "tags":
|
|
19
|
+
items = await client.tags.list();
|
|
20
|
+
break;
|
|
21
|
+
case "rich_menus":
|
|
22
|
+
items = await client.richMenus.list();
|
|
23
|
+
break;
|
|
24
|
+
case "tracked_links":
|
|
25
|
+
items = await client.trackedLinks.list();
|
|
26
|
+
break;
|
|
27
|
+
case "broadcasts":
|
|
28
|
+
items = await client.broadcasts.list({ accountId });
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
content: [{ type: "text", text: JSON.stringify({ success: true, objectType, items }, null, 2) }],
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
return { content: [{ type: "text", text: JSON.stringify({ success: false, error: String(error) }, null, 2) }], isError: true };
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=list-crm-objects.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-crm-objects.js","sourceRoot":"","sources":["../../src/tools/list-crm-objects.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,MAAM,UAAU,sBAAsB,CAAC,MAAiB;IACtD,MAAM,CAAC,IAAI,CACT,kBAAkB,EAClB,4GAA4G,EAC5G;QACE,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,eAAe,EAAE,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,4BAA4B,CAAC;QACtI,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2CAA2C,CAAC;KACvF,EACD,KAAK,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,EAAE,EAAE;QAClC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;YAE3B,IAAI,KAAK,CAAC;YACV,QAAQ,UAAU,EAAE,CAAC;gBACnB,KAAK,WAAW;oBACd,KAAK,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC;oBACnD,MAAM;gBACR,KAAK,OAAO;oBACV,KAAK,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;oBAClC,MAAM;gBACR,KAAK,MAAM;oBACT,KAAK,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;oBACjC,MAAM;gBACR,KAAK,YAAY;oBACf,KAAK,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;oBACtC,MAAM;gBACR,KAAK,eAAe;oBAClB,KAAK,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;oBACzC,MAAM;gBACR,KAAK,YAAY;oBACf,KAAK,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC;oBACpD,MAAM;YACV,CAAC;YAED,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aACjG,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACjI,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getClient } from "../client.js";
|
|
3
|
+
export function registerListFriends(server) {
|
|
4
|
+
server.tool("list_friends", "List friends with optional filtering by tag. Returns paginated results with friend details.", {
|
|
5
|
+
tagId: z.string().optional().describe("Filter by tag ID"),
|
|
6
|
+
limit: z.number().default(20).describe("Number of friends to return (max 100)"),
|
|
7
|
+
offset: z.number().default(0).describe("Offset for pagination"),
|
|
8
|
+
accountId: z.string().optional().describe("LINE account ID (uses default if omitted)"),
|
|
9
|
+
}, async ({ tagId, limit, offset, accountId }) => {
|
|
10
|
+
try {
|
|
11
|
+
const client = getClient();
|
|
12
|
+
const result = await client.friends.list({ tagId, limit, offset, accountId });
|
|
13
|
+
return {
|
|
14
|
+
content: [{
|
|
15
|
+
type: "text",
|
|
16
|
+
text: JSON.stringify({
|
|
17
|
+
success: true,
|
|
18
|
+
total: result.total,
|
|
19
|
+
hasNextPage: result.hasNextPage,
|
|
20
|
+
friends: result.items,
|
|
21
|
+
}, null, 2),
|
|
22
|
+
}],
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
return { content: [{ type: "text", text: JSON.stringify({ success: false, error: String(error) }, null, 2) }], isError: true };
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=list-friends.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-friends.js","sourceRoot":"","sources":["../../src/tools/list-friends.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,MAAM,UAAU,mBAAmB,CAAC,MAAiB;IACnD,MAAM,CAAC,IAAI,CACT,cAAc,EACd,6FAA6F,EAC7F;QACE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kBAAkB,CAAC;QACzD,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,uCAAuC,CAAC;QAC/E,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,uBAAuB,CAAC;QAC/D,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2CAA2C,CAAC;KACvF,EACD,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE;QAC5C,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;YAC3B,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;YAC9E,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;4BACnB,OAAO,EAAE,IAAI;4BACb,KAAK,EAAE,MAAM,CAAC,KAAK;4BACnB,WAAW,EAAE,MAAM,CAAC,WAAW;4BAC/B,OAAO,EAAE,MAAM,CAAC,KAAK;yBACtB,EAAE,IAAI,EAAE,CAAC,CAAC;qBACZ,CAAC;aACH,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACjI,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getClient } from "../client.js";
|
|
3
|
+
export function registerManageTags(server) {
|
|
4
|
+
server.tool("manage_tags", "Create tags, add tags to friends, or remove tags from friends. Supports batch operations on multiple friends.", {
|
|
5
|
+
action: z.enum(["create", "add", "remove"]).describe("Action to perform"),
|
|
6
|
+
tagName: z.string().optional().describe("Tag name (for 'create' action)"),
|
|
7
|
+
tagColor: z.string().optional().describe("Tag color hex code (for 'create' action, e.g. '#FF0000')"),
|
|
8
|
+
tagId: z.string().optional().describe("Tag ID (for 'add' or 'remove' actions)"),
|
|
9
|
+
friendIds: z.array(z.string()).optional().describe("Friend IDs to add/remove the tag from (for 'add' or 'remove' actions)"),
|
|
10
|
+
}, async ({ action, tagName, tagColor, tagId, friendIds }) => {
|
|
11
|
+
try {
|
|
12
|
+
const client = getClient();
|
|
13
|
+
if (action === "create") {
|
|
14
|
+
if (!tagName)
|
|
15
|
+
throw new Error("tagName is required for create action");
|
|
16
|
+
const tag = await client.tags.create({ name: tagName, color: tagColor });
|
|
17
|
+
return {
|
|
18
|
+
content: [{ type: "text", text: JSON.stringify({ success: true, tag }, null, 2) }],
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
if (!tagId)
|
|
22
|
+
throw new Error("tagId is required for add/remove actions");
|
|
23
|
+
if (!friendIds?.length)
|
|
24
|
+
throw new Error("friendIds is required for add/remove actions");
|
|
25
|
+
const results = [];
|
|
26
|
+
for (const friendId of friendIds) {
|
|
27
|
+
if (action === "add") {
|
|
28
|
+
await client.friends.addTag(friendId, tagId);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
await client.friends.removeTag(friendId, tagId);
|
|
32
|
+
}
|
|
33
|
+
results.push({ friendId, status: "ok" });
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
content: [{ type: "text", text: JSON.stringify({ success: true, results }, null, 2) }],
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
return { content: [{ type: "text", text: JSON.stringify({ success: false, error: String(error) }, null, 2) }], isError: true };
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=manage-tags.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manage-tags.js","sourceRoot":"","sources":["../../src/tools/manage-tags.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getClient } from "../client.js";
|
|
3
|
+
export function registerSendMessage(server) {
|
|
4
|
+
server.tool("send_message", "Send a text or flex message to a specific friend. Use messageType 'flex' for rich card layouts.", {
|
|
5
|
+
friendId: z.string().describe("The friend's ID to send the message to"),
|
|
6
|
+
content: z.string().describe("Message content. For text: plain string. For flex: JSON string of LINE Flex Message."),
|
|
7
|
+
messageType: z.enum(["text", "flex"]).default("text").describe("Message type: 'text' for plain text, 'flex' for Flex Message JSON"),
|
|
8
|
+
}, async ({ friendId, content, messageType }) => {
|
|
9
|
+
try {
|
|
10
|
+
const client = getClient();
|
|
11
|
+
const result = await client.friends.sendMessage(friendId, content, messageType);
|
|
12
|
+
return {
|
|
13
|
+
content: [{
|
|
14
|
+
type: "text",
|
|
15
|
+
text: JSON.stringify({ success: true, messageId: result.messageId }, null, 2),
|
|
16
|
+
}],
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
return { content: [{ type: "text", text: JSON.stringify({ success: false, error: String(error) }, null, 2) }], isError: true };
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=send-message.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"send-message.js","sourceRoot":"","sources":["../../src/tools/send-message.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,MAAM,UAAU,mBAAmB,CAAC,MAAiB;IACnD,MAAM,CAAC,IAAI,CACT,cAAc,EACd,iGAAiG,EACjG;QACE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wCAAwC,CAAC;QACvE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sFAAsF,CAAC;QACpH,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,mEAAmE,CAAC;KACpI,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE;QAC3C,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;YAC3B,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,QAAQ,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;YAChF,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;qBAC9E,CAAC;aACH,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACjI,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@line-harness/mcp-server",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP Server for LINE Harness — operate LINE official accounts from any AI tool",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"line-harness-mcp": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc && chmod 755 dist/index.js",
|
|
12
|
+
"dev": "tsc --watch",
|
|
13
|
+
"start": "node dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"keywords": ["mcp", "line", "crm", "ai"],
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist",
|
|
22
|
+
"README.md"
|
|
23
|
+
],
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
26
|
+
"@line-harness/sdk": "workspace:*",
|
|
27
|
+
"zod": "^3.23.0"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"typescript": "^5.5.0",
|
|
31
|
+
"@types/node": "^20.0.0"
|
|
32
|
+
}
|
|
33
|
+
}
|