@line-harness/mcp-server 0.6.6 → 0.7.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/dist/index.js CHANGED
@@ -529,9 +529,9 @@ import { z as z5 } from "zod";
529
529
  function registerManageTags(server2) {
530
530
  server2.tool(
531
531
  "manage_tags",
532
- "Create tags, add tags to friends, or remove tags from friends. Supports batch operations on multiple friends.",
532
+ "List, create, or delete tags, and add/remove tags to/from friends. Supports batch operations on multiple friends.",
533
533
  {
534
- action: z5.enum(["create", "add", "remove"]).describe("Action to perform"),
534
+ action: z5.enum(["list", "create", "delete", "add", "remove"]).describe("Action to perform"),
535
535
  tagName: z5.string().optional().describe("Tag name (for 'create' action)"),
536
536
  tagColor: z5.string().optional().describe("Tag color hex code (for 'create' action, e.g. '#FF0000')"),
537
537
  tagId: z5.string().optional().describe("Tag ID (for 'add' or 'remove' actions)"),
@@ -542,6 +542,19 @@ function registerManageTags(server2) {
542
542
  async ({ action, tagName, tagColor, tagId, friendIds }) => {
543
543
  try {
544
544
  const client = getClient();
545
+ if (action === "list") {
546
+ const tags = await client.tags.list();
547
+ return {
548
+ content: [{ type: "text", text: JSON.stringify({ success: true, tags }, null, 2) }]
549
+ };
550
+ }
551
+ if (action === "delete") {
552
+ if (!tagId) throw new Error("tagId is required for delete action");
553
+ await client.tags.delete(tagId);
554
+ return {
555
+ content: [{ type: "text", text: JSON.stringify({ success: true, deleted: tagId }, null, 2) }]
556
+ };
557
+ }
545
558
  if (action === "create") {
546
559
  if (!tagName) throw new Error("tagName is required for create action");
547
560
  const tag = await client.tags.create({
@@ -779,17 +792,19 @@ import { z as z9 } from "zod";
779
792
  function registerListFriends(server2) {
780
793
  server2.tool(
781
794
  "list_friends",
782
- "List friends with optional filtering by tag. Returns paginated results with friend details.",
795
+ "List friends with optional filtering by tag or name search. Returns paginated results with friend details.",
783
796
  {
797
+ search: z9.string().optional().describe("Search friends by display name (partial match)"),
784
798
  tagId: z9.string().optional().describe("Filter by tag ID"),
785
799
  limit: z9.number().default(20).describe("Number of friends to return (max 100)"),
786
800
  offset: z9.number().default(0).describe("Offset for pagination"),
787
801
  accountId: z9.string().optional().describe("LINE account ID (uses default if omitted)")
788
802
  },
789
- async ({ tagId, limit, offset, accountId }) => {
803
+ async ({ search, tagId, limit, offset, accountId }) => {
790
804
  try {
791
805
  const client = getClient();
792
806
  const result = await client.friends.list({
807
+ search,
793
808
  tagId,
794
809
  limit,
795
810
  offset,
@@ -1486,6 +1501,338 @@ function registerUploadImage(server2) {
1486
1501
  );
1487
1502
  }
1488
1503
 
1504
+ // src/tools/manage-friends.ts
1505
+ import { z as z19 } from "zod";
1506
+ function registerManageFriends(server2) {
1507
+ server2.tool(
1508
+ "manage_friends",
1509
+ "\u53CB\u3060\u3061\u306E\u7BA1\u7406\u64CD\u4F5C\u3002count: \u53CB\u3060\u3061\u6570\u53D6\u5F97\u3001set_metadata: \u30E1\u30BF\u30C7\u30FC\u30BF\u66F4\u65B0\u3001set_rich_menu: \u30EA\u30C3\u30C1\u30E1\u30CB\u30E5\u30FC\u5272\u5F53\u3001remove_rich_menu: \u30EA\u30C3\u30C1\u30E1\u30CB\u30E5\u30FC\u89E3\u9664\u3002",
1510
+ {
1511
+ action: z19.enum(["count", "set_metadata", "set_rich_menu", "remove_rich_menu"]).describe("Action to perform"),
1512
+ friendId: z19.string().optional().describe("Friend ID (required for set_metadata, set_rich_menu, remove_rich_menu)"),
1513
+ metadata: z19.string().optional().describe("JSON string of metadata fields to set (for 'set_metadata')"),
1514
+ richMenuId: z19.string().optional().describe("Rich menu ID to assign (for 'set_rich_menu')")
1515
+ },
1516
+ async ({ action, friendId, metadata, richMenuId }) => {
1517
+ try {
1518
+ const client = getClient();
1519
+ if (action === "count") {
1520
+ const count = await client.friends.count();
1521
+ return {
1522
+ content: [{ type: "text", text: JSON.stringify({ success: true, count }, null, 2) }]
1523
+ };
1524
+ }
1525
+ if (!friendId) throw new Error("friendId is required for this action");
1526
+ if (action === "set_metadata") {
1527
+ if (!metadata) throw new Error("metadata (JSON string) is required for set_metadata");
1528
+ const fields = JSON.parse(metadata);
1529
+ const friend = await client.friends.setMetadata(friendId, fields);
1530
+ return {
1531
+ content: [{ type: "text", text: JSON.stringify({ success: true, friend }, null, 2) }]
1532
+ };
1533
+ }
1534
+ if (action === "set_rich_menu") {
1535
+ if (!richMenuId) throw new Error("richMenuId is required for set_rich_menu");
1536
+ await client.friends.setRichMenu(friendId, richMenuId);
1537
+ return {
1538
+ content: [{ type: "text", text: JSON.stringify({ success: true, friendId, richMenuId }, null, 2) }]
1539
+ };
1540
+ }
1541
+ if (action === "remove_rich_menu") {
1542
+ await client.friends.removeRichMenu(friendId);
1543
+ return {
1544
+ content: [{ type: "text", text: JSON.stringify({ success: true, friendId, removed: true }, null, 2) }]
1545
+ };
1546
+ }
1547
+ throw new Error(`Unknown action: ${action}`);
1548
+ } catch (err) {
1549
+ return {
1550
+ content: [{ type: "text", text: JSON.stringify({ success: false, error: String(err) }) }],
1551
+ isError: true
1552
+ };
1553
+ }
1554
+ }
1555
+ );
1556
+ }
1557
+
1558
+ // src/tools/manage-scenarios.ts
1559
+ import { z as z20 } from "zod";
1560
+ function registerManageScenarios(server2) {
1561
+ server2.tool(
1562
+ "manage_scenarios",
1563
+ "\u30B7\u30CA\u30EA\u30AA\u306E\u7BA1\u7406\u64CD\u4F5C\u3002list: \u4E00\u89A7\u3001get: \u8A73\u7D30\uFF08\u30B9\u30C6\u30C3\u30D7\u542B\u3080\uFF09\u3001update: \u66F4\u65B0\u3001delete: \u524A\u9664\u3001add_step: \u30B9\u30C6\u30C3\u30D7\u8FFD\u52A0\u3001update_step: \u30B9\u30C6\u30C3\u30D7\u66F4\u65B0\u3001delete_step: \u30B9\u30C6\u30C3\u30D7\u524A\u9664\u3002",
1564
+ {
1565
+ action: z20.enum(["list", "get", "update", "delete", "add_step", "update_step", "delete_step"]).describe("Action to perform"),
1566
+ scenarioId: z20.string().optional().describe("Scenario ID (required for get, update, delete, add_step, update_step, delete_step)"),
1567
+ stepId: z20.string().optional().describe("Step ID (required for update_step, delete_step)"),
1568
+ name: z20.string().optional().describe("Scenario name (for update)"),
1569
+ description: z20.string().nullable().optional().describe("Scenario description (for update)"),
1570
+ triggerType: z20.enum(["friend_add", "tag_added", "manual"]).optional().describe("Trigger type (for update)"),
1571
+ triggerTagId: z20.string().nullable().optional().describe("Trigger tag ID (for update)"),
1572
+ isActive: z20.boolean().optional().describe("Active status (for update)"),
1573
+ stepOrder: z20.number().optional().describe("Step order number (for add_step, update_step)"),
1574
+ delayMinutes: z20.number().optional().describe("Delay in minutes (for add_step, update_step)"),
1575
+ messageType: z20.enum(["text", "image", "flex"]).optional().describe("Message type (for add_step, update_step)"),
1576
+ messageContent: z20.string().optional().describe("Message content (for add_step, update_step)"),
1577
+ conditionType: z20.string().nullable().optional().describe("Condition type (for add_step, update_step)"),
1578
+ conditionValue: z20.string().nullable().optional().describe("Condition value (for add_step, update_step)"),
1579
+ nextStepOnFalse: z20.number().nullable().optional().describe("Next step on false (for add_step, update_step)"),
1580
+ accountId: z20.string().optional().describe("LINE account ID for list (uses default if omitted)")
1581
+ },
1582
+ async ({ action, scenarioId, stepId, name, description, triggerType, triggerTagId, isActive, stepOrder, delayMinutes, messageType, messageContent, conditionType, conditionValue, nextStepOnFalse, accountId }) => {
1583
+ try {
1584
+ const client = getClient();
1585
+ if (action === "list") {
1586
+ const scenarios = await client.scenarios.list(accountId ? { accountId } : void 0);
1587
+ return { content: [{ type: "text", text: JSON.stringify({ success: true, scenarios }, null, 2) }] };
1588
+ }
1589
+ if (!scenarioId) throw new Error("scenarioId is required for this action");
1590
+ if (action === "get") {
1591
+ const scenario = await client.scenarios.get(scenarioId);
1592
+ return { content: [{ type: "text", text: JSON.stringify({ success: true, scenario }, null, 2) }] };
1593
+ }
1594
+ if (action === "update") {
1595
+ const input = {};
1596
+ if (name !== void 0) input.name = name;
1597
+ if (description !== void 0) input.description = description;
1598
+ if (triggerType !== void 0) input.triggerType = triggerType;
1599
+ if (triggerTagId !== void 0) input.triggerTagId = triggerTagId;
1600
+ if (isActive !== void 0) input.isActive = isActive;
1601
+ const scenario = await client.scenarios.update(scenarioId, input);
1602
+ return { content: [{ type: "text", text: JSON.stringify({ success: true, scenario }, null, 2) }] };
1603
+ }
1604
+ if (action === "delete") {
1605
+ await client.scenarios.delete(scenarioId);
1606
+ return { content: [{ type: "text", text: JSON.stringify({ success: true, deleted: scenarioId }, null, 2) }] };
1607
+ }
1608
+ if (action === "add_step") {
1609
+ if (stepOrder === void 0 || delayMinutes === void 0 || !messageType || !messageContent) {
1610
+ throw new Error("stepOrder, delayMinutes, messageType, messageContent are required for add_step");
1611
+ }
1612
+ const step = await client.scenarios.addStep(scenarioId, {
1613
+ stepOrder,
1614
+ delayMinutes,
1615
+ messageType,
1616
+ messageContent,
1617
+ conditionType: conditionType ?? null,
1618
+ conditionValue: conditionValue ?? null,
1619
+ nextStepOnFalse: nextStepOnFalse ?? null
1620
+ });
1621
+ return { content: [{ type: "text", text: JSON.stringify({ success: true, step }, null, 2) }] };
1622
+ }
1623
+ if (action === "update_step") {
1624
+ if (!stepId) throw new Error("stepId is required for update_step");
1625
+ const input = {};
1626
+ if (stepOrder !== void 0) input.stepOrder = stepOrder;
1627
+ if (delayMinutes !== void 0) input.delayMinutes = delayMinutes;
1628
+ if (messageType !== void 0) input.messageType = messageType;
1629
+ if (messageContent !== void 0) input.messageContent = messageContent;
1630
+ if (conditionType !== void 0) input.conditionType = conditionType;
1631
+ if (conditionValue !== void 0) input.conditionValue = conditionValue;
1632
+ if (nextStepOnFalse !== void 0) input.nextStepOnFalse = nextStepOnFalse;
1633
+ const step = await client.scenarios.updateStep(scenarioId, stepId, input);
1634
+ return { content: [{ type: "text", text: JSON.stringify({ success: true, step }, null, 2) }] };
1635
+ }
1636
+ if (action === "delete_step") {
1637
+ if (!stepId) throw new Error("stepId is required for delete_step");
1638
+ await client.scenarios.deleteStep(scenarioId, stepId);
1639
+ return { content: [{ type: "text", text: JSON.stringify({ success: true, deleted: stepId }, null, 2) }] };
1640
+ }
1641
+ throw new Error(`Unknown action: ${action}`);
1642
+ } catch (err) {
1643
+ return { content: [{ type: "text", text: JSON.stringify({ success: false, error: String(err) }) }], isError: true };
1644
+ }
1645
+ }
1646
+ );
1647
+ }
1648
+
1649
+ // src/tools/manage-broadcasts.ts
1650
+ import { z as z21 } from "zod";
1651
+ function registerManageBroadcasts(server2) {
1652
+ server2.tool(
1653
+ "manage_broadcasts",
1654
+ "\u914D\u4FE1\u306E\u7BA1\u7406\u64CD\u4F5C\u3002list: \u4E00\u89A7\u3001get: \u8A73\u7D30\u3001create_draft: \u4E0B\u66F8\u304D\u4F5C\u6210\uFF08\u9001\u4FE1\u3057\u306A\u3044\uFF09\u3001update: \u66F4\u65B0\u3001send: \u9001\u4FE1\u3001send_to_segment: \u30BB\u30B0\u30E1\u30F3\u30C8\u914D\u4FE1\u3002",
1655
+ {
1656
+ action: z21.enum(["list", "get", "create_draft", "update", "send", "send_to_segment"]).describe("Action to perform"),
1657
+ broadcastId: z21.string().optional().describe("Broadcast ID (required for get, update, send, send_to_segment)"),
1658
+ title: z21.string().optional().describe("Broadcast title (for create_draft, update)"),
1659
+ messageType: z21.enum(["text", "image", "flex"]).optional().describe("Message type (for create_draft, update)"),
1660
+ messageContent: z21.string().optional().describe("Message content (for create_draft, update)"),
1661
+ targetType: z21.enum(["all", "tag"]).optional().describe("Target type (for create_draft, update)"),
1662
+ targetTagId: z21.string().nullable().optional().describe("Target tag ID (for create_draft, update)"),
1663
+ scheduledAt: z21.string().nullable().optional().describe("ISO 8601 datetime to schedule (for create_draft, update)"),
1664
+ segmentConditions: z21.string().optional().describe("JSON string of segment conditions: {operator: 'AND'|'OR', rules: [{type, value}]} (for send_to_segment)"),
1665
+ accountId: z21.string().optional().describe("LINE account ID (uses default if omitted)")
1666
+ },
1667
+ async ({ action, broadcastId, title, messageType, messageContent, targetType, targetTagId, scheduledAt, segmentConditions, accountId }) => {
1668
+ try {
1669
+ const client = getClient();
1670
+ if (action === "list") {
1671
+ const broadcasts = await client.broadcasts.list(accountId ? { accountId } : void 0);
1672
+ return { content: [{ type: "text", text: JSON.stringify({ success: true, broadcasts }, null, 2) }] };
1673
+ }
1674
+ if (action === "create_draft") {
1675
+ if (!title || !messageType || !messageContent) {
1676
+ throw new Error("title, messageType, messageContent are required for create_draft");
1677
+ }
1678
+ const input = { title, messageType, messageContent, targetType: targetType ?? "all" };
1679
+ if (targetTagId) input.targetTagId = targetTagId;
1680
+ if (scheduledAt) input.scheduledAt = scheduledAt;
1681
+ if (accountId) input.lineAccountId = accountId;
1682
+ const broadcast = await client.broadcasts.create(input);
1683
+ return { content: [{ type: "text", text: JSON.stringify({ success: true, broadcast }, null, 2) }] };
1684
+ }
1685
+ if (!broadcastId) throw new Error("broadcastId is required for this action");
1686
+ if (action === "get") {
1687
+ const broadcast = await client.broadcasts.get(broadcastId);
1688
+ return { content: [{ type: "text", text: JSON.stringify({ success: true, broadcast }, null, 2) }] };
1689
+ }
1690
+ if (action === "update") {
1691
+ const input = {};
1692
+ if (title !== void 0) input.title = title;
1693
+ if (messageType !== void 0) input.messageType = messageType;
1694
+ if (messageContent !== void 0) input.messageContent = messageContent;
1695
+ if (targetType !== void 0) input.targetType = targetType;
1696
+ if (targetTagId !== void 0) input.targetTagId = targetTagId;
1697
+ if (scheduledAt !== void 0) input.scheduledAt = scheduledAt;
1698
+ const broadcast = await client.broadcasts.update(broadcastId, input);
1699
+ return { content: [{ type: "text", text: JSON.stringify({ success: true, broadcast }, null, 2) }] };
1700
+ }
1701
+ if (action === "send") {
1702
+ const broadcast = await client.broadcasts.send(broadcastId);
1703
+ return { content: [{ type: "text", text: JSON.stringify({ success: true, broadcast }, null, 2) }] };
1704
+ }
1705
+ if (action === "send_to_segment") {
1706
+ if (!segmentConditions) throw new Error("segmentConditions (JSON string) is required for send_to_segment");
1707
+ const conditions = JSON.parse(segmentConditions);
1708
+ const broadcast = await client.broadcasts.sendToSegment(broadcastId, conditions);
1709
+ return { content: [{ type: "text", text: JSON.stringify({ success: true, broadcast }, null, 2) }] };
1710
+ }
1711
+ throw new Error(`Unknown action: ${action}`);
1712
+ } catch (err) {
1713
+ return { content: [{ type: "text", text: JSON.stringify({ success: false, error: String(err) }) }], isError: true };
1714
+ }
1715
+ }
1716
+ );
1717
+ }
1718
+
1719
+ // src/tools/manage-rich-menus.ts
1720
+ import { z as z22 } from "zod";
1721
+ function registerManageRichMenus(server2) {
1722
+ server2.tool(
1723
+ "manage_rich_menus",
1724
+ "\u30EA\u30C3\u30C1\u30E1\u30CB\u30E5\u30FC\u306E\u7BA1\u7406\u64CD\u4F5C\u3002list: \u4E00\u89A7\u53D6\u5F97\u3001delete: \u524A\u9664\u3001set_default: \u30C7\u30D5\u30A9\u30EB\u30C8\u8A2D\u5B9A\u3002\u4F5C\u6210\u306F create_rich_menu \u30C4\u30FC\u30EB\u3092\u4F7F\u7528\u3002",
1725
+ {
1726
+ action: z22.enum(["list", "delete", "set_default"]).describe("Action to perform"),
1727
+ richMenuId: z22.string().optional().describe("Rich menu ID (required for delete, set_default)")
1728
+ },
1729
+ async ({ action, richMenuId }) => {
1730
+ try {
1731
+ const client = getClient();
1732
+ if (action === "list") {
1733
+ const menus = await client.richMenus.list();
1734
+ return { content: [{ type: "text", text: JSON.stringify({ success: true, richMenus: menus }, null, 2) }] };
1735
+ }
1736
+ if (!richMenuId) throw new Error("richMenuId is required for this action");
1737
+ if (action === "delete") {
1738
+ await client.richMenus.delete(richMenuId);
1739
+ return { content: [{ type: "text", text: JSON.stringify({ success: true, deleted: richMenuId }, null, 2) }] };
1740
+ }
1741
+ if (action === "set_default") {
1742
+ await client.richMenus.setDefault(richMenuId);
1743
+ return { content: [{ type: "text", text: JSON.stringify({ success: true, defaultRichMenuId: richMenuId }, null, 2) }] };
1744
+ }
1745
+ throw new Error(`Unknown action: ${action}`);
1746
+ } catch (err) {
1747
+ return { content: [{ type: "text", text: JSON.stringify({ success: false, error: String(err) }) }], isError: true };
1748
+ }
1749
+ }
1750
+ );
1751
+ }
1752
+
1753
+ // src/tools/manage-forms.ts
1754
+ import { z as z23 } from "zod";
1755
+ function registerManageForms(server2) {
1756
+ server2.tool(
1757
+ "manage_forms",
1758
+ "\u30D5\u30A9\u30FC\u30E0\u306E\u7BA1\u7406\u64CD\u4F5C\u3002list: \u4E00\u89A7\u3001get: \u8A73\u7D30\u3001update: \u66F4\u65B0\u3001delete: \u524A\u9664\u3002\u4F5C\u6210\u306F create_form \u30C4\u30FC\u30EB\u3092\u4F7F\u7528\u3002",
1759
+ {
1760
+ action: z23.enum(["list", "get", "update", "delete"]).describe("Action to perform"),
1761
+ formId: z23.string().optional().describe("Form ID (required for get, update, delete)"),
1762
+ name: z23.string().optional().describe("Form name (for update)"),
1763
+ description: z23.string().nullable().optional().describe("Form description (for update)"),
1764
+ fields: z23.string().optional().describe("JSON string of form fields array (for update)"),
1765
+ onSubmitTagId: z23.string().nullable().optional().describe("Tag to add on submit (for update)"),
1766
+ onSubmitScenarioId: z23.string().nullable().optional().describe("Scenario to enroll on submit (for update)"),
1767
+ saveToMetadata: z23.boolean().optional().describe("Save responses to friend metadata (for update)"),
1768
+ isActive: z23.boolean().optional().describe("Active status (for update)")
1769
+ },
1770
+ async ({ action, formId, name, description, fields, onSubmitTagId, onSubmitScenarioId, saveToMetadata, isActive }) => {
1771
+ try {
1772
+ const client = getClient();
1773
+ if (action === "list") {
1774
+ const forms = await client.forms.list();
1775
+ return { content: [{ type: "text", text: JSON.stringify({ success: true, forms }, null, 2) }] };
1776
+ }
1777
+ if (!formId) throw new Error("formId is required for this action");
1778
+ if (action === "get") {
1779
+ const form = await client.forms.get(formId);
1780
+ return { content: [{ type: "text", text: JSON.stringify({ success: true, form }, null, 2) }] };
1781
+ }
1782
+ if (action === "update") {
1783
+ const input = {};
1784
+ if (name !== void 0) input.name = name;
1785
+ if (description !== void 0) input.description = description;
1786
+ if (fields !== void 0) input.fields = JSON.parse(fields);
1787
+ if (onSubmitTagId !== void 0) input.onSubmitTagId = onSubmitTagId;
1788
+ if (onSubmitScenarioId !== void 0) input.onSubmitScenarioId = onSubmitScenarioId;
1789
+ if (saveToMetadata !== void 0) input.saveToMetadata = saveToMetadata;
1790
+ if (isActive !== void 0) input.isActive = isActive;
1791
+ const form = await client.forms.update(formId, input);
1792
+ return { content: [{ type: "text", text: JSON.stringify({ success: true, form }, null, 2) }] };
1793
+ }
1794
+ if (action === "delete") {
1795
+ await client.forms.delete(formId);
1796
+ return { content: [{ type: "text", text: JSON.stringify({ success: true, deleted: formId }, null, 2) }] };
1797
+ }
1798
+ throw new Error(`Unknown action: ${action}`);
1799
+ } catch (err) {
1800
+ return { content: [{ type: "text", text: JSON.stringify({ success: false, error: String(err) }) }], isError: true };
1801
+ }
1802
+ }
1803
+ );
1804
+ }
1805
+
1806
+ // src/tools/manage-tracked-links.ts
1807
+ import { z as z24 } from "zod";
1808
+ function registerManageTrackedLinks(server2) {
1809
+ server2.tool(
1810
+ "manage_tracked_links",
1811
+ "\u30C8\u30E9\u30C3\u30AD\u30F3\u30B0\u30EA\u30F3\u30AF\u306E\u7BA1\u7406\u64CD\u4F5C\u3002list: \u4E00\u89A7\u3001delete: \u524A\u9664\u3002\u4F5C\u6210\u306F create_tracked_link \u30C4\u30FC\u30EB\u3092\u4F7F\u7528\u3002",
1812
+ {
1813
+ action: z24.enum(["list", "delete"]).describe("Action to perform"),
1814
+ linkId: z24.string().optional().describe("Tracked link ID (required for delete)")
1815
+ },
1816
+ async ({ action, linkId }) => {
1817
+ try {
1818
+ const client = getClient();
1819
+ if (action === "list") {
1820
+ const links = await client.trackedLinks.list();
1821
+ return { content: [{ type: "text", text: JSON.stringify({ success: true, trackedLinks: links }, null, 2) }] };
1822
+ }
1823
+ if (action === "delete") {
1824
+ if (!linkId) throw new Error("linkId is required for delete");
1825
+ await client.trackedLinks.delete(linkId);
1826
+ return { content: [{ type: "text", text: JSON.stringify({ success: true, deleted: linkId }, null, 2) }] };
1827
+ }
1828
+ throw new Error(`Unknown action: ${action}`);
1829
+ } catch (err) {
1830
+ return { content: [{ type: "text", text: JSON.stringify({ success: false, error: String(err) }) }], isError: true };
1831
+ }
1832
+ }
1833
+ );
1834
+ }
1835
+
1489
1836
  // src/tools/index.ts
1490
1837
  function registerAllTools(server2) {
1491
1838
  registerSendMessage(server2);
@@ -1506,6 +1853,12 @@ function registerAllTools(server2) {
1506
1853
  registerGetConversionLogs(server2);
1507
1854
  registerManageStaff(server2);
1508
1855
  registerUploadImage(server2);
1856
+ registerManageFriends(server2);
1857
+ registerManageScenarios(server2);
1858
+ registerManageBroadcasts(server2);
1859
+ registerManageRichMenus(server2);
1860
+ registerManageForms(server2);
1861
+ registerManageTrackedLinks(server2);
1509
1862
  }
1510
1863
 
1511
1864
  // src/resources/index.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@line-harness/mcp-server",
3
- "version": "0.6.6",
3
+ "version": "0.7.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "line-harness-mcp": "./dist/index.js"
@@ -9,7 +9,7 @@
9
9
  "dependencies": {
10
10
  "@modelcontextprotocol/sdk": "^1.12.1",
11
11
  "zod": "^3.24.4",
12
- "@line-harness/sdk": "0.2.3"
12
+ "@line-harness/sdk": "0.2.4"
13
13
  },
14
14
  "devDependencies": {
15
15
  "tsup": "^8.4.0",
@@ -17,6 +17,12 @@ import { registerManageAdPlatforms } from "./manage-ad-platforms.js";
17
17
  import { registerGetConversionLogs } from "./get-conversion-logs.js";
18
18
  import { registerManageStaff } from "./manage-staff.js";
19
19
  import { registerUploadImage } from "./upload-image.js";
20
+ import { registerManageFriends } from "./manage-friends.js";
21
+ import { registerManageScenarios } from "./manage-scenarios.js";
22
+ import { registerManageBroadcasts } from "./manage-broadcasts.js";
23
+ import { registerManageRichMenus } from "./manage-rich-menus.js";
24
+ import { registerManageForms } from "./manage-forms.js";
25
+ import { registerManageTrackedLinks } from "./manage-tracked-links.js";
20
26
 
21
27
  export function registerAllTools(server: McpServer): void {
22
28
  registerSendMessage(server);
@@ -37,4 +43,10 @@ export function registerAllTools(server: McpServer): void {
37
43
  registerGetConversionLogs(server);
38
44
  registerManageStaff(server);
39
45
  registerUploadImage(server);
46
+ registerManageFriends(server);
47
+ registerManageScenarios(server);
48
+ registerManageBroadcasts(server);
49
+ registerManageRichMenus(server);
50
+ registerManageForms(server);
51
+ registerManageTrackedLinks(server);
40
52
  }
@@ -5,8 +5,9 @@ import { getClient } from "../client.js";
5
5
  export function registerListFriends(server: McpServer): void {
6
6
  server.tool(
7
7
  "list_friends",
8
- "List friends with optional filtering by tag. Returns paginated results with friend details.",
8
+ "List friends with optional filtering by tag or name search. Returns paginated results with friend details.",
9
9
  {
10
+ search: z.string().optional().describe("Search friends by display name (partial match)"),
10
11
  tagId: z.string().optional().describe("Filter by tag ID"),
11
12
  limit: z
12
13
  .number()
@@ -18,10 +19,11 @@ export function registerListFriends(server: McpServer): void {
18
19
  .optional()
19
20
  .describe("LINE account ID (uses default if omitted)"),
20
21
  },
21
- async ({ tagId, limit, offset, accountId }) => {
22
+ async ({ search, tagId, limit, offset, accountId }) => {
22
23
  try {
23
24
  const client = getClient();
24
25
  const result = await client.friends.list({
26
+ search,
25
27
  tagId,
26
28
  limit,
27
29
  offset,
@@ -0,0 +1,81 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { z } from "zod";
3
+ import { getClient } from "../client.js";
4
+
5
+ export function registerManageBroadcasts(server: McpServer): void {
6
+ server.tool(
7
+ "manage_broadcasts",
8
+ "配信の管理操作。list: 一覧、get: 詳細、create_draft: 下書き作成(送信しない)、update: 更新、send: 送信、send_to_segment: セグメント配信。",
9
+ {
10
+ action: z
11
+ .enum(["list", "get", "create_draft", "update", "send", "send_to_segment"])
12
+ .describe("Action to perform"),
13
+ broadcastId: z.string().optional().describe("Broadcast ID (required for get, update, send, send_to_segment)"),
14
+ title: z.string().optional().describe("Broadcast title (for create_draft, update)"),
15
+ messageType: z.enum(["text", "image", "flex"]).optional().describe("Message type (for create_draft, update)"),
16
+ messageContent: z.string().optional().describe("Message content (for create_draft, update)"),
17
+ targetType: z.enum(["all", "tag"]).optional().describe("Target type (for create_draft, update)"),
18
+ targetTagId: z.string().nullable().optional().describe("Target tag ID (for create_draft, update)"),
19
+ scheduledAt: z.string().nullable().optional().describe("ISO 8601 datetime to schedule (for create_draft, update)"),
20
+ segmentConditions: z.string().optional().describe("JSON string of segment conditions: {operator: 'AND'|'OR', rules: [{type, value}]} (for send_to_segment)"),
21
+ accountId: z.string().optional().describe("LINE account ID (uses default if omitted)"),
22
+ },
23
+ async ({ action, broadcastId, title, messageType, messageContent, targetType, targetTagId, scheduledAt, segmentConditions, accountId }) => {
24
+ try {
25
+ const client = getClient();
26
+
27
+ if (action === "list") {
28
+ const broadcasts = await client.broadcasts.list(accountId ? { accountId } : undefined);
29
+ return { content: [{ type: "text" as const, text: JSON.stringify({ success: true, broadcasts }, null, 2) }] };
30
+ }
31
+
32
+ if (action === "create_draft") {
33
+ if (!title || !messageType || !messageContent) {
34
+ throw new Error("title, messageType, messageContent are required for create_draft");
35
+ }
36
+ const input: Record<string, unknown> = { title, messageType, messageContent, targetType: targetType ?? "all" };
37
+ if (targetTagId) input.targetTagId = targetTagId;
38
+ if (scheduledAt) input.scheduledAt = scheduledAt;
39
+ if (accountId) input.lineAccountId = accountId;
40
+ const broadcast = await client.broadcasts.create(input as never);
41
+ return { content: [{ type: "text" as const, text: JSON.stringify({ success: true, broadcast }, null, 2) }] };
42
+ }
43
+
44
+ if (!broadcastId) throw new Error("broadcastId is required for this action");
45
+
46
+ if (action === "get") {
47
+ const broadcast = await client.broadcasts.get(broadcastId);
48
+ return { content: [{ type: "text" as const, text: JSON.stringify({ success: true, broadcast }, null, 2) }] };
49
+ }
50
+
51
+ if (action === "update") {
52
+ const input: Record<string, unknown> = {};
53
+ if (title !== undefined) input.title = title;
54
+ if (messageType !== undefined) input.messageType = messageType;
55
+ if (messageContent !== undefined) input.messageContent = messageContent;
56
+ if (targetType !== undefined) input.targetType = targetType;
57
+ if (targetTagId !== undefined) input.targetTagId = targetTagId;
58
+ if (scheduledAt !== undefined) input.scheduledAt = scheduledAt;
59
+ const broadcast = await client.broadcasts.update(broadcastId, input);
60
+ return { content: [{ type: "text" as const, text: JSON.stringify({ success: true, broadcast }, null, 2) }] };
61
+ }
62
+
63
+ if (action === "send") {
64
+ const broadcast = await client.broadcasts.send(broadcastId);
65
+ return { content: [{ type: "text" as const, text: JSON.stringify({ success: true, broadcast }, null, 2) }] };
66
+ }
67
+
68
+ if (action === "send_to_segment") {
69
+ if (!segmentConditions) throw new Error("segmentConditions (JSON string) is required for send_to_segment");
70
+ const conditions = JSON.parse(segmentConditions);
71
+ const broadcast = await client.broadcasts.sendToSegment(broadcastId, conditions);
72
+ return { content: [{ type: "text" as const, text: JSON.stringify({ success: true, broadcast }, null, 2) }] };
73
+ }
74
+
75
+ throw new Error(`Unknown action: ${action}`);
76
+ } catch (err) {
77
+ return { content: [{ type: "text" as const, text: JSON.stringify({ success: false, error: String(err) }) }], isError: true };
78
+ }
79
+ },
80
+ );
81
+ }
@@ -0,0 +1,54 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { z } from "zod";
3
+ import { getClient } from "../client.js";
4
+
5
+ export function registerManageForms(server: McpServer): void {
6
+ server.tool(
7
+ "manage_forms",
8
+ "フォームの管理操作。list: 一覧、get: 詳細、update: 更新、delete: 削除。作成は create_form ツールを使用。",
9
+ {
10
+ action: z.enum(["list", "get", "update", "delete"]).describe("Action to perform"),
11
+ formId: z.string().optional().describe("Form ID (required for get, update, delete)"),
12
+ name: z.string().optional().describe("Form name (for update)"),
13
+ description: z.string().nullable().optional().describe("Form description (for update)"),
14
+ fields: z.string().optional().describe("JSON string of form fields array (for update)"),
15
+ onSubmitTagId: z.string().nullable().optional().describe("Tag to add on submit (for update)"),
16
+ onSubmitScenarioId: z.string().nullable().optional().describe("Scenario to enroll on submit (for update)"),
17
+ saveToMetadata: z.boolean().optional().describe("Save responses to friend metadata (for update)"),
18
+ isActive: z.boolean().optional().describe("Active status (for update)"),
19
+ },
20
+ async ({ action, formId, name, description, fields, onSubmitTagId, onSubmitScenarioId, saveToMetadata, isActive }) => {
21
+ try {
22
+ const client = getClient();
23
+ if (action === "list") {
24
+ const forms = await client.forms.list();
25
+ return { content: [{ type: "text" as const, text: JSON.stringify({ success: true, forms }, null, 2) }] };
26
+ }
27
+ if (!formId) throw new Error("formId is required for this action");
28
+ if (action === "get") {
29
+ const form = await client.forms.get(formId);
30
+ return { content: [{ type: "text" as const, text: JSON.stringify({ success: true, form }, null, 2) }] };
31
+ }
32
+ if (action === "update") {
33
+ const input: Record<string, unknown> = {};
34
+ if (name !== undefined) input.name = name;
35
+ if (description !== undefined) input.description = description;
36
+ if (fields !== undefined) input.fields = JSON.parse(fields);
37
+ if (onSubmitTagId !== undefined) input.onSubmitTagId = onSubmitTagId;
38
+ if (onSubmitScenarioId !== undefined) input.onSubmitScenarioId = onSubmitScenarioId;
39
+ if (saveToMetadata !== undefined) input.saveToMetadata = saveToMetadata;
40
+ if (isActive !== undefined) input.isActive = isActive;
41
+ const form = await client.forms.update(formId, input);
42
+ return { content: [{ type: "text" as const, text: JSON.stringify({ success: true, form }, null, 2) }] };
43
+ }
44
+ if (action === "delete") {
45
+ await client.forms.delete(formId);
46
+ return { content: [{ type: "text" as const, text: JSON.stringify({ success: true, deleted: formId }, null, 2) }] };
47
+ }
48
+ throw new Error(`Unknown action: ${action}`);
49
+ } catch (err) {
50
+ return { content: [{ type: "text" as const, text: JSON.stringify({ success: false, error: String(err) }) }], isError: true };
51
+ }
52
+ },
53
+ );
54
+ }
@@ -0,0 +1,72 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { z } from "zod";
3
+ import { getClient } from "../client.js";
4
+
5
+ export function registerManageFriends(server: McpServer): void {
6
+ server.tool(
7
+ "manage_friends",
8
+ "友だちの管理操作。count: 友だち数取得、set_metadata: メタデータ更新、set_rich_menu: リッチメニュー割当、remove_rich_menu: リッチメニュー解除。",
9
+ {
10
+ action: z
11
+ .enum(["count", "set_metadata", "set_rich_menu", "remove_rich_menu"])
12
+ .describe("Action to perform"),
13
+ friendId: z
14
+ .string()
15
+ .optional()
16
+ .describe("Friend ID (required for set_metadata, set_rich_menu, remove_rich_menu)"),
17
+ metadata: z
18
+ .string()
19
+ .optional()
20
+ .describe("JSON string of metadata fields to set (for 'set_metadata')"),
21
+ richMenuId: z
22
+ .string()
23
+ .optional()
24
+ .describe("Rich menu ID to assign (for 'set_rich_menu')"),
25
+ },
26
+ async ({ action, friendId, metadata, richMenuId }) => {
27
+ try {
28
+ const client = getClient();
29
+
30
+ if (action === "count") {
31
+ const count = await client.friends.count();
32
+ return {
33
+ content: [{ type: "text" as const, text: JSON.stringify({ success: true, count }, null, 2) }],
34
+ };
35
+ }
36
+
37
+ if (!friendId) throw new Error("friendId is required for this action");
38
+
39
+ if (action === "set_metadata") {
40
+ if (!metadata) throw new Error("metadata (JSON string) is required for set_metadata");
41
+ const fields = JSON.parse(metadata) as Record<string, unknown>;
42
+ const friend = await client.friends.setMetadata(friendId, fields);
43
+ return {
44
+ content: [{ type: "text" as const, text: JSON.stringify({ success: true, friend }, null, 2) }],
45
+ };
46
+ }
47
+
48
+ if (action === "set_rich_menu") {
49
+ if (!richMenuId) throw new Error("richMenuId is required for set_rich_menu");
50
+ await client.friends.setRichMenu(friendId, richMenuId);
51
+ return {
52
+ content: [{ type: "text" as const, text: JSON.stringify({ success: true, friendId, richMenuId }, null, 2) }],
53
+ };
54
+ }
55
+
56
+ if (action === "remove_rich_menu") {
57
+ await client.friends.removeRichMenu(friendId);
58
+ return {
59
+ content: [{ type: "text" as const, text: JSON.stringify({ success: true, friendId, removed: true }, null, 2) }],
60
+ };
61
+ }
62
+
63
+ throw new Error(`Unknown action: ${action}`);
64
+ } catch (err) {
65
+ return {
66
+ content: [{ type: "text" as const, text: JSON.stringify({ success: false, error: String(err) }) }],
67
+ isError: true,
68
+ };
69
+ }
70
+ },
71
+ );
72
+ }
@@ -0,0 +1,35 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { z } from "zod";
3
+ import { getClient } from "../client.js";
4
+
5
+ export function registerManageRichMenus(server: McpServer): void {
6
+ server.tool(
7
+ "manage_rich_menus",
8
+ "リッチメニューの管理操作。list: 一覧取得、delete: 削除、set_default: デフォルト設定。作成は create_rich_menu ツールを使用。",
9
+ {
10
+ action: z.enum(["list", "delete", "set_default"]).describe("Action to perform"),
11
+ richMenuId: z.string().optional().describe("Rich menu ID (required for delete, set_default)"),
12
+ },
13
+ async ({ action, richMenuId }) => {
14
+ try {
15
+ const client = getClient();
16
+ if (action === "list") {
17
+ const menus = await client.richMenus.list();
18
+ return { content: [{ type: "text" as const, text: JSON.stringify({ success: true, richMenus: menus }, null, 2) }] };
19
+ }
20
+ if (!richMenuId) throw new Error("richMenuId is required for this action");
21
+ if (action === "delete") {
22
+ await client.richMenus.delete(richMenuId);
23
+ return { content: [{ type: "text" as const, text: JSON.stringify({ success: true, deleted: richMenuId }, null, 2) }] };
24
+ }
25
+ if (action === "set_default") {
26
+ await client.richMenus.setDefault(richMenuId);
27
+ return { content: [{ type: "text" as const, text: JSON.stringify({ success: true, defaultRichMenuId: richMenuId }, null, 2) }] };
28
+ }
29
+ throw new Error(`Unknown action: ${action}`);
30
+ } catch (err) {
31
+ return { content: [{ type: "text" as const, text: JSON.stringify({ success: false, error: String(err) }) }], isError: true };
32
+ }
33
+ },
34
+ );
35
+ }
@@ -0,0 +1,98 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { z } from "zod";
3
+ import { getClient } from "../client.js";
4
+
5
+ export function registerManageScenarios(server: McpServer): void {
6
+ server.tool(
7
+ "manage_scenarios",
8
+ "シナリオの管理操作。list: 一覧、get: 詳細(ステップ含む)、update: 更新、delete: 削除、add_step: ステップ追加、update_step: ステップ更新、delete_step: ステップ削除。",
9
+ {
10
+ action: z
11
+ .enum(["list", "get", "update", "delete", "add_step", "update_step", "delete_step"])
12
+ .describe("Action to perform"),
13
+ scenarioId: z.string().optional().describe("Scenario ID (required for get, update, delete, add_step, update_step, delete_step)"),
14
+ stepId: z.string().optional().describe("Step ID (required for update_step, delete_step)"),
15
+ name: z.string().optional().describe("Scenario name (for update)"),
16
+ description: z.string().nullable().optional().describe("Scenario description (for update)"),
17
+ triggerType: z.enum(["friend_add", "tag_added", "manual"]).optional().describe("Trigger type (for update)"),
18
+ triggerTagId: z.string().nullable().optional().describe("Trigger tag ID (for update)"),
19
+ isActive: z.boolean().optional().describe("Active status (for update)"),
20
+ stepOrder: z.number().optional().describe("Step order number (for add_step, update_step)"),
21
+ delayMinutes: z.number().optional().describe("Delay in minutes (for add_step, update_step)"),
22
+ messageType: z.enum(["text", "image", "flex"]).optional().describe("Message type (for add_step, update_step)"),
23
+ messageContent: z.string().optional().describe("Message content (for add_step, update_step)"),
24
+ conditionType: z.string().nullable().optional().describe("Condition type (for add_step, update_step)"),
25
+ conditionValue: z.string().nullable().optional().describe("Condition value (for add_step, update_step)"),
26
+ nextStepOnFalse: z.number().nullable().optional().describe("Next step on false (for add_step, update_step)"),
27
+ accountId: z.string().optional().describe("LINE account ID for list (uses default if omitted)"),
28
+ },
29
+ async ({ action, scenarioId, stepId, name, description, triggerType, triggerTagId, isActive, stepOrder, delayMinutes, messageType, messageContent, conditionType, conditionValue, nextStepOnFalse, accountId }) => {
30
+ try {
31
+ const client = getClient();
32
+
33
+ if (action === "list") {
34
+ const scenarios = await client.scenarios.list(accountId ? { accountId } : undefined);
35
+ return { content: [{ type: "text" as const, text: JSON.stringify({ success: true, scenarios }, null, 2) }] };
36
+ }
37
+
38
+ if (!scenarioId) throw new Error("scenarioId is required for this action");
39
+
40
+ if (action === "get") {
41
+ const scenario = await client.scenarios.get(scenarioId);
42
+ return { content: [{ type: "text" as const, text: JSON.stringify({ success: true, scenario }, null, 2) }] };
43
+ }
44
+
45
+ if (action === "update") {
46
+ const input: Record<string, unknown> = {};
47
+ if (name !== undefined) input.name = name;
48
+ if (description !== undefined) input.description = description;
49
+ if (triggerType !== undefined) input.triggerType = triggerType;
50
+ if (triggerTagId !== undefined) input.triggerTagId = triggerTagId;
51
+ if (isActive !== undefined) input.isActive = isActive;
52
+ const scenario = await client.scenarios.update(scenarioId, input);
53
+ return { content: [{ type: "text" as const, text: JSON.stringify({ success: true, scenario }, null, 2) }] };
54
+ }
55
+
56
+ if (action === "delete") {
57
+ await client.scenarios.delete(scenarioId);
58
+ return { content: [{ type: "text" as const, text: JSON.stringify({ success: true, deleted: scenarioId }, null, 2) }] };
59
+ }
60
+
61
+ if (action === "add_step") {
62
+ if (stepOrder === undefined || delayMinutes === undefined || !messageType || !messageContent) {
63
+ throw new Error("stepOrder, delayMinutes, messageType, messageContent are required for add_step");
64
+ }
65
+ const step = await client.scenarios.addStep(scenarioId, {
66
+ stepOrder, delayMinutes, messageType, messageContent,
67
+ conditionType: conditionType ?? null, conditionValue: conditionValue ?? null, nextStepOnFalse: nextStepOnFalse ?? null,
68
+ });
69
+ return { content: [{ type: "text" as const, text: JSON.stringify({ success: true, step }, null, 2) }] };
70
+ }
71
+
72
+ if (action === "update_step") {
73
+ if (!stepId) throw new Error("stepId is required for update_step");
74
+ const input: Record<string, unknown> = {};
75
+ if (stepOrder !== undefined) input.stepOrder = stepOrder;
76
+ if (delayMinutes !== undefined) input.delayMinutes = delayMinutes;
77
+ if (messageType !== undefined) input.messageType = messageType;
78
+ if (messageContent !== undefined) input.messageContent = messageContent;
79
+ if (conditionType !== undefined) input.conditionType = conditionType;
80
+ if (conditionValue !== undefined) input.conditionValue = conditionValue;
81
+ if (nextStepOnFalse !== undefined) input.nextStepOnFalse = nextStepOnFalse;
82
+ const step = await client.scenarios.updateStep(scenarioId, stepId, input);
83
+ return { content: [{ type: "text" as const, text: JSON.stringify({ success: true, step }, null, 2) }] };
84
+ }
85
+
86
+ if (action === "delete_step") {
87
+ if (!stepId) throw new Error("stepId is required for delete_step");
88
+ await client.scenarios.deleteStep(scenarioId, stepId);
89
+ return { content: [{ type: "text" as const, text: JSON.stringify({ success: true, deleted: stepId }, null, 2) }] };
90
+ }
91
+
92
+ throw new Error(`Unknown action: ${action}`);
93
+ } catch (err) {
94
+ return { content: [{ type: "text" as const, text: JSON.stringify({ success: false, error: String(err) }) }], isError: true };
95
+ }
96
+ },
97
+ );
98
+ }
@@ -5,9 +5,9 @@ import { getClient } from "../client.js";
5
5
  export function registerManageTags(server: McpServer): void {
6
6
  server.tool(
7
7
  "manage_tags",
8
- "Create tags, add tags to friends, or remove tags from friends. Supports batch operations on multiple friends.",
8
+ "List, create, or delete tags, and add/remove tags to/from friends. Supports batch operations on multiple friends.",
9
9
  {
10
- action: z.enum(["create", "add", "remove"]).describe("Action to perform"),
10
+ action: z.enum(["list", "create", "delete", "add", "remove"]).describe("Action to perform"),
11
11
  tagName: z
12
12
  .string()
13
13
  .optional()
@@ -31,6 +31,21 @@ export function registerManageTags(server: McpServer): void {
31
31
  try {
32
32
  const client = getClient();
33
33
 
34
+ if (action === "list") {
35
+ const tags = await client.tags.list();
36
+ return {
37
+ content: [{ type: "text" as const, text: JSON.stringify({ success: true, tags }, null, 2) }],
38
+ };
39
+ }
40
+
41
+ if (action === "delete") {
42
+ if (!tagId) throw new Error("tagId is required for delete action");
43
+ await client.tags.delete(tagId);
44
+ return {
45
+ content: [{ type: "text" as const, text: JSON.stringify({ success: true, deleted: tagId }, null, 2) }],
46
+ };
47
+ }
48
+
34
49
  if (action === "create") {
35
50
  if (!tagName) throw new Error("tagName is required for create action");
36
51
  const tag = await client.tags.create({
@@ -0,0 +1,31 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { z } from "zod";
3
+ import { getClient } from "../client.js";
4
+
5
+ export function registerManageTrackedLinks(server: McpServer): void {
6
+ server.tool(
7
+ "manage_tracked_links",
8
+ "トラッキングリンクの管理操作。list: 一覧、delete: 削除。作成は create_tracked_link ツールを使用。",
9
+ {
10
+ action: z.enum(["list", "delete"]).describe("Action to perform"),
11
+ linkId: z.string().optional().describe("Tracked link ID (required for delete)"),
12
+ },
13
+ async ({ action, linkId }) => {
14
+ try {
15
+ const client = getClient();
16
+ if (action === "list") {
17
+ const links = await client.trackedLinks.list();
18
+ return { content: [{ type: "text" as const, text: JSON.stringify({ success: true, trackedLinks: links }, null, 2) }] };
19
+ }
20
+ if (action === "delete") {
21
+ if (!linkId) throw new Error("linkId is required for delete");
22
+ await client.trackedLinks.delete(linkId);
23
+ return { content: [{ type: "text" as const, text: JSON.stringify({ success: true, deleted: linkId }, null, 2) }] };
24
+ }
25
+ throw new Error(`Unknown action: ${action}`);
26
+ } catch (err) {
27
+ return { content: [{ type: "text" as const, text: JSON.stringify({ success: false, error: String(err) }) }], isError: true };
28
+ }
29
+ },
30
+ );
31
+ }