diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..d49f2ac --- /dev/null +++ b/__init__.py @@ -0,0 +1 @@ +# Telegram MCP Package diff --git a/main.py b/main.py index ce01cdf..edaf452 100644 --- a/main.py +++ b/main.py @@ -3129,25 +3129,29 @@ async def create_poll( ) -if __name__ == "__main__": - nest_asyncio.apply() +async def _main() -> None: + try: + # Start the Telethon client non-interactively + print("Starting Telegram client...") + await client.start() - async def main() -> None: - try: - # Start the Telethon client non-interactively - print("Starting Telegram client...") - await client.start() + print("Telegram client started. Running MCP server...") + # Use the asynchronous entrypoint instead of mcp.run() + await mcp.run_stdio_async() + except Exception as e: + print(f"Error starting client: {e}", file=sys.stderr) + if isinstance(e, sqlite3.OperationalError) and "database is locked" in str(e): + print( + "Database lock detected. Please ensure no other instances are running.", + file=sys.stderr, + ) + sys.exit(1) + + +def main() -> None: + nest_asyncio.apply() + asyncio.run(_main()) - print("Telegram client started. Running MCP server...") - # Use the asynchronous entrypoint instead of mcp.run() - await mcp.run_stdio_async() - except Exception as e: - print(f"Error starting client: {e}", file=sys.stderr) - if isinstance(e, sqlite3.OperationalError) and "database is locked" in str(e): - print( - "Database lock detected. Please ensure no other instances are running.", - file=sys.stderr, - ) - sys.exit(1) - asyncio.run(main()) +if __name__ == "__main__": + main() diff --git a/pyproject.toml b/pyproject.toml index c0cee02..4fcf097 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,6 @@ [build-system] requires = ["setuptools>=42", "wheel"] build-backend = "setuptools.build_meta" -package-mode = false [project] name = "telegram-mcp" @@ -26,7 +25,7 @@ requires-python = ">=3.10" dependencies = [ "dotenv>=0.9.9", "httpx>=0.28.1", - "mcp[cli]>=1.4.1", + "mcp[cli]>=1.8.0", "nest-asyncio>=1.6.0", "python-dotenv>=1.1.0", "python-json-logger>=3.3.0", @@ -37,6 +36,13 @@ dependencies = [ "Homepage" = "https://github.com/chigwell/telegram-mcp" "Bug Tracker" = "https://github.com/chigwell/telegram-mcp/issues" +[tool.setuptools] +py-modules = ["main", "session_string_generator"] + +[project.scripts] +telegram-mcp = "main:main" +telegram-mcp-generate-session = "session_string_generator:main" + [tool.black] line-length = 99 target-version = ['py311'] diff --git a/session_string_generator.py b/session_string_generator.py index 327e570..21b15d9 100755 --- a/session_string_generator.py +++ b/session_string_generator.py @@ -28,75 +28,81 @@ # Load environment variables from .env file load_dotenv() -API_ID = os.getenv("TELEGRAM_API_ID") -API_HASH = os.getenv("TELEGRAM_API_HASH") - -if not API_ID or not API_HASH: - print("Error: TELEGRAM_API_ID and TELEGRAM_API_HASH must be set in .env file") - print("Create an .env file with your credentials from https://my.telegram.org/apps") - sys.exit(1) - -# Convert API_ID to integer -try: - API_ID = int(API_ID) -except ValueError: - print("Error: TELEGRAM_API_ID must be an integer") - sys.exit(1) - -print("\n----- Telegram Session String Generator -----\n") -print("This script will generate a session string for your Telegram account.") -print( - "You will be asked to enter your phone number and the verification code sent to your Telegram app." -) -print("The generated session string can be added to your .env file.") -print( - "\nYour credentials will NOT be stored on any server and are only used for local authentication.\n" -) - -try: - # Connect to Telegram and generate the session string - with TelegramClient(StringSession(), API_ID, API_HASH) as client: - # The client.session.save() function from StringSession returns the session string - session_string = StringSession.save(client.session) - - print("\nAuthentication successful!") - print("\n----- Your Session String -----") - print(f"\n{session_string}\n") - print("Add this to your .env file as:") - print(f"TELEGRAM_SESSION_STRING={session_string}") - print("\nIMPORTANT: Keep this string private and never share it with anyone!") - - # Optional: auto-update the .env file - choice = input( - "\nWould you like to automatically update your .env file with this session string? (y/N): " - ) - if choice.lower() == "y": - try: - # Read the current .env file - with open(".env", "r") as file: - env_contents = file.readlines() - - # Update or add the SESSION_STRING line - session_string_line_found = False - for i, line in enumerate(env_contents): - if line.startswith("TELEGRAM_SESSION_STRING="): - env_contents[i] = f"TELEGRAM_SESSION_STRING={session_string}\n" - session_string_line_found = True - break - - if not session_string_line_found: - env_contents.append(f"TELEGRAM_SESSION_STRING={session_string}\n") - - # Write back to the .env file - with open(".env", "w") as file: - file.writelines(env_contents) - - print("\n.env file updated successfully!") - except Exception as e: - print(f"\nError updating .env file: {e}") - print("Please manually add the session string to your .env file.") - -except Exception as e: - print(f"\nError: {e}") - print("Failed to generate session string. Please try again.") - sys.exit(1) + +def main() -> None: + API_ID = os.getenv("TELEGRAM_API_ID") + API_HASH = os.getenv("TELEGRAM_API_HASH") + + if not API_ID or not API_HASH: + print("Error: TELEGRAM_API_ID and TELEGRAM_API_HASH must be set in .env file") + print("Create an .env file with your credentials from https://my.telegram.org/apps") + sys.exit(1) + + # Convert API_ID to integer + try: + API_ID = int(API_ID) + except ValueError: + print("Error: TELEGRAM_API_ID must be an integer") + sys.exit(1) + + print("\n----- Telegram Session String Generator -----\n") + print("This script will generate a session string for your Telegram account.") + print( + "You will be asked to enter your phone number and the verification code sent to your Telegram app." + ) + print("The generated session string can be added to your .env file.") + print( + "\nYour credentials will NOT be stored on any server and are only used for local authentication.\n" + ) + + try: + # Connect to Telegram and generate the session string + with TelegramClient(StringSession(), API_ID, API_HASH) as client: + # The client.session.save() function from StringSession returns the session string + session_string = StringSession.save(client.session) + + print("\nAuthentication successful!") + print("\n----- Your Session String -----") + print(f"\n{session_string}\n") + print("Add this to your .env file as:") + print(f"TELEGRAM_SESSION_STRING={session_string}") + print("\nIMPORTANT: Keep this string private and never share it with anyone!") + + # Optional: auto-update the .env file + choice = input( + "\nWould you like to automatically update your .env file with this session string? (y/N): " + ) + if choice.lower() == "y": + try: + # Read the current .env file + with open(".env", "r") as file: + env_contents = file.readlines() + + # Update or add the SESSION_STRING line + session_string_line_found = False + for i, line in enumerate(env_contents): + if line.startswith("TELEGRAM_SESSION_STRING="): + env_contents[i] = f"TELEGRAM_SESSION_STRING={session_string}\n" + session_string_line_found = True + break + + if not session_string_line_found: + env_contents.append(f"TELEGRAM_SESSION_STRING={session_string}\n") + + # Write back to the .env file + with open(".env", "w") as file: + file.writelines(env_contents) + + print("\n.env file updated successfully!") + except Exception as e: + print(f"\nError updating .env file: {e}") + print("Please manually add the session string to your .env file.") + + except Exception as e: + print(f"\nError: {e}") + print("Failed to generate session string. Please try again.") + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/uv.lock b/uv.lock index c8917b5..c7729fb 100644 --- a/uv.lock +++ b/uv.lock @@ -995,7 +995,7 @@ dev = [ requires-dist = [ { name = "dotenv", specifier = ">=0.9.9" }, { name = "httpx", specifier = ">=0.28.1" }, - { name = "mcp", extras = ["cli"], specifier = ">=1.4.1" }, + { name = "mcp", extras = ["cli"], specifier = ">=1.8.0" }, { name = "nest-asyncio", specifier = ">=1.6.0" }, { name = "python-dotenv", specifier = ">=1.1.0" }, { name = "python-json-logger", specifier = ">=3.3.0" },