import { initStderrTee } from "../../../../lib/mcp-stderr-tee/dist/index.js";
initStderrTee("telegram");
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { eagerTool } from "../../../../lib/mcp-eager/dist/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import { message } from "./tools/message.js";
import { messageHistory } from "./tools/message-history.js";
import { setWebhook, getWebhookInfo } from "./lib/telegram.js";
const server = new McpServer({
    name: "maxy-messaging",
    version: "0.1.0",
});
eagerTool(server, "message", "Send a message via Telegram. Supports text with HTML formatting and inline keyboards for interactive choices.", {
    channel: z.literal("telegram").describe("Delivery channel"),
    chatId: z
        .union([z.string(), z.number()])
        .describe("Telegram chat ID to send to"),
    text: z.string().describe("Message text (HTML formatting supported)"),
    parseMode: z
        .enum(["HTML", "Markdown", "MarkdownV2"])
        .optional()
        .describe("Parse mode (default: HTML)"),
    inlineKeyboard: z
        .array(z.array(z.object({
        text: z.string().describe("Button label"),
        callbackData: z
            .string()
            .optional()
            .describe("Callback data for button press"),
        url: z.string().optional().describe("URL to open on button press"),
    })))
        .optional()
        .describe("Inline keyboard rows for interactive buttons"),
}, async (params) => {
    try {
        const result = await message(params);
        if (!result.sent) {
            return {
                content: [
                    {
                        type: "text",
                        text: `Message failed: ${result.error}`,
                    },
                ],
                isError: true,
            };
        }
        return {
            content: [
                {
                    type: "text",
                    text: `Message sent via ${result.channel} (ID: ${result.messageId})`,
                },
            ],
        };
    }
    catch (err) {
        return {
            content: [
                {
                    type: "text",
                    text: `Send failed: ${err instanceof Error ? err.message : String(err)}`,
                },
            ],
            isError: true,
        };
    }
});
eagerTool(server, "message-history", "Query conversation history from the message log.", {
    channel: z.string().optional().describe("Filter by channel (telegram)"),
    chatId: z.string().optional().describe("Filter by chat ID"),
    limit: z.number().optional().describe("Max messages to return (default 20)"),
}, async ({ channel, chatId, limit }) => {
    try {
        const history = await messageHistory({ channel, chatId, limit });
        if (history.length === 0) {
            return {
                content: [
                    { type: "text", text: "No message history found." },
                ],
            };
        }
        const formatted = history
            .map((h) => `[${h.timestamp}] ${h.channel}/${h.chatId} (${h.role}): ${h.content.slice(0, 200)}${h.content.length > 200 ? "..." : ""}`)
            .join("\n");
        return {
            content: [{ type: "text", text: formatted }],
        };
    }
    catch (err) {
        return {
            content: [
                {
                    type: "text",
                    text: `History query failed: ${err instanceof Error ? err.message : String(err)}`,
                },
            ],
            isError: true,
        };
    }
});
import { homedir } from "node:os";
import { resolve, join } from "node:path";
import { existsSync, readFileSync } from "node:fs";
// Derive the webhook secret file path (mirrors paths.ts logic).
// Restricted to known filenames — prevents path traversal.
function resolveSecretFilePath(botType) {
    let configDirName = ".maxy";
    const platformRoot = process.env.PLATFORM_ROOT;
    if (platformRoot) {
        const brandPath = join(platformRoot, "config", "brand.json");
        if (existsSync(brandPath)) {
            try {
                const brand = JSON.parse(readFileSync(brandPath, "utf-8"));
                if (brand.configDir)
                    configDirName = brand.configDir;
            }
            catch { /* fall back to .maxy */ }
        }
    }
    const maxyDir = resolve(homedir(), configDirName);
    const filename = botType === "admin"
        ? ".telegram-admin-webhook-secret"
        : ".telegram-webhook-secret";
    return resolve(maxyDir, filename);
}
eagerTool(server, "telegram-webhook-register", "Register or re-register a Telegram bot webhook. Generates a cryptographic secret, persists it to disk, and passes it to the Telegram Bot API. Call this after obtaining a bot token from BotFather.", {
    botToken: z.string().describe("Telegram bot token from BotFather"),
    webhookUrl: z.string().url().describe("Full webhook URL including ?bot=public or ?bot=admin query param"),
    botType: z.enum(["public", "admin"]).describe("Bot type — determines which secret file to write"),
}, async ({ botToken, webhookUrl, botType }) => {
    const secretFilePath = resolveSecretFilePath(botType);
    try {
        // Verify the token is valid by calling getMe
        const meRes = await fetch(`https://api.telegram.org/bot${botToken}/getMe`);
        const meData = (await meRes.json());
        if (!meData.ok) {
            return {
                content: [
                    {
                        type: "text",
                        text: `Invalid bot token: ${meData.description ?? "getMe failed"}`,
                    },
                ],
                isError: true,
            };
        }
        const botUsername = meData.result?.username ?? "unknown";
        // Register webhook with secret generation
        const result = await setWebhook(botToken, webhookUrl, secretFilePath);
        if (!result.ok) {
            return {
                content: [
                    {
                        type: "text",
                        text: `Webhook registration failed: ${result.error}`,
                    },
                ],
                isError: true,
            };
        }
        // Verify registration — guarded because getWebhookInfo can fail
        // independently of a successful registration (e.g., transient API error).
        let verifyInfo = "";
        try {
            const info = await getWebhookInfo(botToken);
            verifyInfo = `\nURL: ${info.url}\nPending updates: ${info.pendingUpdateCount}`;
        }
        catch {
            verifyInfo = "\n(Could not verify — getWebhookInfo failed, but registration succeeded)";
        }
        return {
            content: [
                {
                    type: "text",
                    text: `Webhook registered for @${botUsername}` +
                        `\nSecret: generated and saved to ${secretFilePath}` +
                        verifyInfo,
                },
            ],
        };
    }
    catch (err) {
        return {
            content: [
                {
                    type: "text",
                    text: `Webhook registration error: ${err instanceof Error ? err.message : String(err)}`,
                },
            ],
            isError: true,
        };
    }
});
const transport = new StdioServerTransport();
await server.connect(transport);
//# sourceMappingURL=index.js.map