using Telegram.Bot.Types;
using Volcanic.AgenticCore.Extensions.Mcp.Remote;
using Volcanic.AgenticCore.Features.Extensions;
using Volcanic.AgenticCore.Features.Processes;
namespace Volcanic.AgenticCore.Telegram;
///
/// Remote MCP servers per chat (). Keys are sealed with MCP_ENCRYPTION_SECRET, or
/// the bot token when that is unset; agent processes see neither (both match the default deny-list).
///
public static class RemoteMcpSetup
{
public const string SecretVariable = "MCP_ENCRYPTION_SECRET";
public static readonly IReadOnlyList Menu =
[
new() { Command = "mcp_list", Description = "Remote MCP servers of this chat" },
new() { Command = "mcp_add", Description = "Add an MCP server: /mcp_add " },
new() { Command = "mcp_remove", Description = "Remove an MCP server: /mcp_remove " },
new() { Command = "mcp_tools", Description = "Show or limit a server's tools" },
];
public const string HelpLines =
"\n/mcp_list, /mcp_add , /mcp_remove , /mcp_tools [a,b|all] – this chat's remote MCP servers";
public static IReadOnlyList MenuFor(IReadOnlyList menu) => [.. menu, .. Menu];
/// The dedicated secret, else the bot token. Adds the dedicated one to the redacted secret values.
public static RemoteMcpOptions Options(TelegramOptions telegram, Func getEnv, ProcessEnvironmentOptions processEnvironment)
{
ArgumentNullException.ThrowIfNull(telegram);
ArgumentNullException.ThrowIfNull(getEnv);
ArgumentNullException.ThrowIfNull(processEnvironment);
var dedicated = getEnv(SecretVariable) is { } value && !string.IsNullOrWhiteSpace(value) ? value.Trim() : null;
if (dedicated is not null) processEnvironment.SecretValues.Add(dedicated);
return new RemoteMcpOptions { Secret = dedicated ?? (string.IsNullOrWhiteSpace(telegram.BotToken) ? null : telegram.BotToken) };
}
public static string Describe(Func getEnv) =>
string.IsNullOrWhiteSpace(getEnv(SecretVariable))
? $"Remote MCP: keys sealed with the bot token (set {SecretVariable} to keep them across a token change)"
: $"Remote MCP: keys sealed with {SecretVariable}";
/// A command whose message holds a key: the router deletes it from the chat after handing it over.
public static bool CarriesKey(string command, string args) =>
command == "mcp_add" && (args.Contains("--bearer", StringComparison.Ordinal) || args.Contains("--header", StringComparison.Ordinal));
/// A new extension instance per chat session.
public static ExtensionRegistration Registration(RemoteMcpOptions options) =>
new(RemoteMcpExtension.ExtensionName, _ => new RemoteMcpExtension(options), "telegram");
}