feat: enhance Telegram MCP server with new features and improvements
- Added support for string session authentication in main.py. - Introduced new tools for searching contacts and retrieving message context. - Updated README.md with detailed usage examples and security considerations. - Modified pyproject.toml for versioning and dependency updates. - Expanded .gitignore to include Telegram session files.
This commit is contained in:
parent
1f7474aa5c
commit
ecb5b88b12
9 changed files with 1224 additions and 83 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -172,3 +172,7 @@ cython_debug/
|
|||
|
||||
# PyPI configuration file
|
||||
.pypirc
|
||||
|
||||
# Telegram session files
|
||||
*.session
|
||||
*.session-journal
|
||||
|
|
|
|||
171
README.md
171
README.md
|
|
@ -1,89 +1,99 @@
|
|||

|
||||
# Telegram MCP for Claude
|
||||
|
||||

|
||||
[](https://opensource.org/licenses/Apache-2.0)
|
||||
[](https://www.linkedin.com/in/eugene-evstafev-716669181/)
|
||||
|
||||
# Telegram MCP Server
|
||||
A powerful Telegram integration for Claude via the Model Context Protocol (MCP), allowing you to interact with your Telegram account directly from Claude Desktop.
|
||||
|
||||
A Telegram MCP (Model Context Protocol) server built using Python, Telethon, and MCP Python SDK. This MCP server provides simple tools for interacting with Telegram chats directly through MCP-compatible hosts, such as Claude for Desktop.
|
||||

|
||||
|
||||
## Tools Provided
|
||||
## 🚀 Features
|
||||
|
||||
- **`get_chats`**: Retrieve a paginated list of your Telegram chats.
|
||||
- **`get_messages`**: Retrieve paginated messages from a specific chat.
|
||||
- **`send_message`**: Send a message to a specific chat.
|
||||
This MCP server provides a comprehensive suite of tools for seamless Telegram interaction:
|
||||
|
||||
## Requirements
|
||||
### Chat Management
|
||||
- **get_chats** - Get a paginated list of your chats
|
||||
- **list_chats** - List all chats with detailed metadata and filtering options
|
||||
- **get_chat** - Get detailed information about a specific chat
|
||||
|
||||
- Python 3.10 or higher
|
||||
- [Telethon](https://docs.telethon.dev/) package
|
||||
### Messaging
|
||||
- **get_messages** - Get messages from a specific chat with pagination
|
||||
- **list_messages** - Retrieve messages with powerful filtering (text search, date ranges)
|
||||
- **send_message** - Send messages to any chat
|
||||
- **get_message_context** - View the context around a specific message
|
||||
|
||||
### Contact Management
|
||||
- **search_contacts** - Find contacts by name, username or phone number
|
||||
- **get_direct_chat_by_contact** - Find personal chats with specific contacts
|
||||
- **get_contact_chats** - List all chats (including groups) involving a contact
|
||||
- **get_last_interaction** - View your most recent exchanges with a contact
|
||||
|
||||
## 📋 Requirements
|
||||
|
||||
- Python 3.10+
|
||||
- [Telethon](https://docs.telethon.dev/) for Telegram API access
|
||||
- [MCP Python SDK](https://modelcontextprotocol.io/docs/)
|
||||
- [UV](https://astral.sh/uv/) (optional but recommended)
|
||||
- [UV](https://astral.sh/uv/) package manager
|
||||
- [Claude Desktop](https://claude.ai/desktop) app
|
||||
|
||||
## Installation and Setup
|
||||
## 🔧 Installation
|
||||
|
||||
### Clone the Repository
|
||||
### 1. Clone the Repository
|
||||
|
||||
```bash
|
||||
git clone https://github.com/chigwell/telegram-mcp
|
||||
cd telegram-mcp
|
||||
```
|
||||
|
||||
### Create Environment File
|
||||
### 2. Generate Session String
|
||||
|
||||
Copy and rename `.env.example` to `.env` and fill it with your Telegram credentials obtained from [https://my.telegram.org/apps](https://my.telegram.org/apps):
|
||||
For better security and portability, this project uses Telethon's StringSession. Generate your session string:
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
python session_string_generator.py
|
||||
```
|
||||
|
||||
Your `.env` file should look like:
|
||||
This will:
|
||||
1. Ask for your phone number
|
||||
2. Send a verification code to your Telegram app
|
||||
3. Generate a session string and add it to your `.env` file
|
||||
|
||||
```env
|
||||
The session string allows authentication without storing SQLite session files, which helps avoid database lock issues and improves portability.
|
||||
|
||||
### 3. Set Up Your Environment
|
||||
|
||||
Create a `.env` file with your Telegram credentials:
|
||||
|
||||
```
|
||||
TELEGRAM_API_ID=your_api_id_here
|
||||
TELEGRAM_API_HASH=your_api_hash_here
|
||||
TELEGRAM_SESSION_NAME=your_session_name
|
||||
TELEGRAM_SESSION_NAME=anon
|
||||
TELEGRAM_SESSION_STRING=your_session_string_here
|
||||
```
|
||||
|
||||
### Setup Python Environment
|
||||
You can obtain API credentials at [my.telegram.org/apps](https://my.telegram.org/apps).
|
||||
|
||||
Use `uv` to set up the Python environment and install dependencies:
|
||||
### 4. Install Dependencies
|
||||
|
||||
```bash
|
||||
uv venv
|
||||
source .venv/bin/activate
|
||||
source .venv/bin/activate # On Windows: .venv\Scripts\activate
|
||||
uv add "mcp[cli]" telethon python-dotenv nest_asyncio
|
||||
```
|
||||
|
||||
### Run the Server (First-time Auth)
|
||||
### 5. Configure Claude Desktop
|
||||
|
||||
The first time you run the server, Telethon will prompt you to enter a Telegram authentication code:
|
||||
|
||||
```bash
|
||||
uv run main.py
|
||||
```
|
||||
|
||||
Authenticate by entering the code sent to your Telegram client. This step is only required once.
|
||||
|
||||
## Integrating with Claude for Desktop
|
||||
|
||||
### macOS/Linux
|
||||
|
||||
Edit your Claude Desktop configuration:
|
||||
|
||||
```bash
|
||||
nano ~/Library/Application\ Support/Claude/claude_desktop_config.json
|
||||
```
|
||||
|
||||
Add this MCP server configuration:
|
||||
#### On macOS/Linux:
|
||||
Edit `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"telegram-mcp": {
|
||||
"command": "uv",
|
||||
"command": "/full/path/to/uv",
|
||||
"args": [
|
||||
"--directory",
|
||||
"/ABSOLUTE_PATH/telegram-mcp",
|
||||
"/full/path/to/telegram-mcp-server",
|
||||
"run",
|
||||
"main.py"
|
||||
]
|
||||
|
|
@ -92,40 +102,57 @@ Add this MCP server configuration:
|
|||
}
|
||||
```
|
||||
|
||||
Ensure you replace `/ABSOLUTE_PATH/telegram-mcp` with your project's absolute path.
|
||||
#### On Windows:
|
||||
Edit `%APPDATA%\Claude\claude_desktop_config.json` with similar configuration.
|
||||
|
||||
### Windows
|
||||
## 🎮 Usage Examples
|
||||
|
||||
Edit your Claude Desktop configuration:
|
||||
Here are some ways to interact with Telegram through Claude:
|
||||
|
||||
```powershell
|
||||
nano $env:AppData\Claude\claude_desktop_config.json
|
||||
```
|
||||
### Basic Chat Navigation
|
||||
- "Show me my most recent chats"
|
||||
- "List my group chats with unread messages"
|
||||
- "Show detailed information about chat 123456789"
|
||||
|
||||
Add this MCP server configuration:
|
||||
### Messaging
|
||||
- "Show me the last 10 messages from chat 123456789"
|
||||
- "Send 'I'll be there in 10 minutes' to chat 123456789"
|
||||
- "Find messages containing 'meeting' in chat 123456789"
|
||||
- "Show messages from March 1-15, 2023 in chat 123456789"
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"telegram-mcp": {
|
||||
"command": "uv",
|
||||
"args": [
|
||||
"--directory",
|
||||
"C:\\ABSOLUTE_PATH\\telegram-mcp",
|
||||
"run",
|
||||
"main.py"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
### Contact Interactions
|
||||
- "Search for contacts named 'Alex'"
|
||||
- "Find my direct chat with John"
|
||||
- "Show all chats where I interact with contact 987654321"
|
||||
- "Show my last conversation with Lisa"
|
||||
|
||||
Ensure you replace `C:\ABSOLUTE_PATH\telegram-mcp` with your project's absolute path.
|
||||
### Advanced Features
|
||||
- "Show the context around message 42 in chat 123456789"
|
||||
- "List all channels I'm subscribed to"
|
||||
|
||||
## Usage
|
||||
## 🔒 Security Considerations
|
||||
|
||||
Once integrated, your Telegram tools (`get_chats`, `get_messages`, and `send_message`) will become available within the Claude for Desktop UI or any other MCP-compatible client.
|
||||
- **Private API Keys**: Never commit your `.env` file or session files to Git repositories
|
||||
- **Session String**: The session string in your `.env` file provides full access to your Telegram account. Keep it secure.
|
||||
- **Local Processing**: All Telegram data is processed locally on your machine - no data is sent to external servers beyond Telegram's own API.
|
||||
- **Permissions**: The MCP server has the same access to Telegram as you would have with the official app, including reading and sending messages.
|
||||
|
||||
## License
|
||||
## 🛠️ Troubleshooting
|
||||
|
||||
This project is licensed under the [Apache 2.0 License](https://opensource.org/licenses/Apache-2.0).
|
||||
If you encounter issues:
|
||||
|
||||
1. Check Claude Desktop logs for error messages
|
||||
2. Ensure your Telegram API credentials are correct
|
||||
3. Verify that the paths in your Claude Desktop config are absolute and correct
|
||||
4. If you see database lock errors, use the session string authentication method
|
||||
5. If you need to regenerate your session string, run `python session_string_generator.py` again
|
||||
|
||||
## 📄 License
|
||||
|
||||
This project is licensed under the [Apache 2.0 License](LICENSE).
|
||||
|
||||
## 🙏 Acknowledgements
|
||||
|
||||
- [Telethon](https://github.com/LonamiWebs/Telethon) for the Telegram client library
|
||||
- [Model Context Protocol](https://modelcontextprotocol.io/) for the integration framework
|
||||
- [Anthropic](https://www.anthropic.com/) for Claude and the Claude Desktop app
|
||||
13
claude_desktop_config.json
Normal file
13
claude_desktop_config.json
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"mcpServers": {
|
||||
"telegram-mcp": {
|
||||
"command": "/PATH-TO/uv",
|
||||
"args": [
|
||||
"--directory",
|
||||
"/PATH-TO/telegram-mcp",
|
||||
"run",
|
||||
"main.py"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
504
main.py
504
main.py
|
|
@ -1,9 +1,19 @@
|
|||
import os
|
||||
import sys
|
||||
import time
|
||||
from dotenv import load_dotenv
|
||||
import asyncio
|
||||
import nest_asyncio
|
||||
from mcp.server.fastmcp import FastMCP
|
||||
from telethon import TelegramClient
|
||||
from telethon.sessions import StringSession
|
||||
import sqlite3
|
||||
from telethon import utils
|
||||
from telethon.tl.types import User, Chat, Channel
|
||||
from telethon.tl.functions.contacts import SearchRequest
|
||||
from datetime import datetime, timedelta
|
||||
import json
|
||||
from typing import List, Dict, Optional, Union, Any
|
||||
|
||||
load_dotenv()
|
||||
|
||||
|
|
@ -11,13 +21,62 @@ TELEGRAM_API_ID = int(os.getenv("TELEGRAM_API_ID"))
|
|||
TELEGRAM_API_HASH = os.getenv("TELEGRAM_API_HASH")
|
||||
TELEGRAM_SESSION_NAME = os.getenv("TELEGRAM_SESSION_NAME")
|
||||
|
||||
# Check if a string session exists in environment, otherwise use file-based session
|
||||
SESSION_STRING = os.getenv("TELEGRAM_SESSION_STRING")
|
||||
|
||||
mcp = FastMCP("telegram")
|
||||
client = TelegramClient(TELEGRAM_SESSION_NAME, TELEGRAM_API_ID, TELEGRAM_API_HASH)
|
||||
|
||||
if SESSION_STRING:
|
||||
# Use the string session if available
|
||||
client = TelegramClient(StringSession(SESSION_STRING), TELEGRAM_API_ID, TELEGRAM_API_HASH)
|
||||
else:
|
||||
# Use file-based session
|
||||
client = TelegramClient(TELEGRAM_SESSION_NAME, TELEGRAM_API_ID, TELEGRAM_API_HASH)
|
||||
|
||||
|
||||
def format_entity(entity) -> Dict[str, Any]:
|
||||
"""Helper function to format entity information consistently."""
|
||||
result = {"id": entity.id}
|
||||
|
||||
if hasattr(entity, "title"):
|
||||
result["name"] = entity.title
|
||||
result["type"] = "group" if isinstance(entity, Chat) else "channel"
|
||||
elif hasattr(entity, "first_name"):
|
||||
name_parts = []
|
||||
if entity.first_name:
|
||||
name_parts.append(entity.first_name)
|
||||
if hasattr(entity, "last_name") and entity.last_name:
|
||||
name_parts.append(entity.last_name)
|
||||
result["name"] = " ".join(name_parts)
|
||||
result["type"] = "user"
|
||||
if hasattr(entity, "username") and entity.username:
|
||||
result["username"] = entity.username
|
||||
if hasattr(entity, "phone") and entity.phone:
|
||||
result["phone"] = entity.phone
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def format_message(message) -> Dict[str, Any]:
|
||||
"""Helper function to format message information consistently."""
|
||||
result = {
|
||||
"id": message.id,
|
||||
"date": message.date.isoformat(),
|
||||
"text": message.message or "",
|
||||
}
|
||||
|
||||
if message.from_id:
|
||||
result["from_id"] = utils.get_peer_id(message.from_id)
|
||||
|
||||
if message.media:
|
||||
result["has_media"] = True
|
||||
result["media_type"] = type(message.media).__name__
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
async def get_chats(page: int, page_size: int = 20) -> str:
|
||||
async def get_chats(page: int = 1, page_size: int = 20) -> str:
|
||||
"""
|
||||
Get a paginated list of chats.
|
||||
|
||||
|
|
@ -42,7 +101,7 @@ async def get_chats(page: int, page_size: int = 20) -> str:
|
|||
|
||||
|
||||
@mcp.tool()
|
||||
async def get_messages(chat_id: int, page: int, page_size: int = 20) -> str:
|
||||
async def get_messages(chat_id: int, page: int = 1, page_size: int = 20) -> str:
|
||||
"""
|
||||
Get paginated messages from a specific chat.
|
||||
|
||||
|
|
@ -87,14 +146,443 @@ async def send_message(chat_id: int, message: str) -> str:
|
|||
return f"Failed to send message: {e}"
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
async def search_contacts(query: str) -> str:
|
||||
"""
|
||||
Search for contacts by name or phone number.
|
||||
|
||||
Args:
|
||||
query: The search term to look for in contact names or phone numbers.
|
||||
"""
|
||||
try:
|
||||
# Search in your contacts
|
||||
contacts = await client.get_contacts()
|
||||
results = []
|
||||
|
||||
for contact in contacts:
|
||||
if not contact:
|
||||
continue
|
||||
|
||||
name = f"{getattr(contact, 'first_name', '')} {getattr(contact, 'last_name', '')}".strip()
|
||||
username = getattr(contact, 'username', '')
|
||||
phone = getattr(contact, 'phone', '')
|
||||
|
||||
if (query.lower() in name.lower() or
|
||||
(username and query.lower() in username.lower()) or
|
||||
(phone and query in phone)):
|
||||
|
||||
contact_info = f"ID: {contact.id}, Name: {name}"
|
||||
if username:
|
||||
contact_info += f", Username: @{username}"
|
||||
if phone:
|
||||
contact_info += f", Phone: {phone}"
|
||||
|
||||
results.append(contact_info)
|
||||
|
||||
if not results:
|
||||
return f"No contacts found matching '{query}'."
|
||||
|
||||
return "\n".join(results)
|
||||
except Exception as e:
|
||||
return f"Error searching contacts: {e}"
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
async def list_messages(chat_id: int, limit: int = 20, search_query: str = None,
|
||||
from_date: str = None, to_date: str = None) -> str:
|
||||
"""
|
||||
Retrieve messages with optional filters.
|
||||
|
||||
Args:
|
||||
chat_id: The ID of the chat to get messages from.
|
||||
limit: Maximum number of messages to retrieve.
|
||||
search_query: Filter messages containing this text.
|
||||
from_date: Filter messages starting from this date (format: YYYY-MM-DD).
|
||||
to_date: Filter messages until this date (format: YYYY-MM-DD).
|
||||
"""
|
||||
try:
|
||||
entity = await client.get_entity(chat_id)
|
||||
|
||||
# Parse date filters if provided
|
||||
from_date_obj = None
|
||||
to_date_obj = None
|
||||
|
||||
if from_date:
|
||||
try:
|
||||
from_date_obj = datetime.strptime(from_date, "%Y-%m-%d")
|
||||
except ValueError:
|
||||
return f"Invalid from_date format. Use YYYY-MM-DD."
|
||||
|
||||
if to_date:
|
||||
try:
|
||||
to_date_obj = datetime.strptime(to_date, "%Y-%m-%d")
|
||||
# Set to end of day
|
||||
to_date_obj = to_date_obj + timedelta(days=1, microseconds=-1)
|
||||
except ValueError:
|
||||
return f"Invalid to_date format. Use YYYY-MM-DD."
|
||||
|
||||
# Prepare filter parameters
|
||||
params = {}
|
||||
if search_query:
|
||||
params['search'] = search_query
|
||||
|
||||
messages = await client.get_messages(entity, limit=limit, **params)
|
||||
|
||||
# Apply date filters (Telethon doesn't support date filtering in get_messages directly)
|
||||
if from_date_obj or to_date_obj:
|
||||
filtered_messages = []
|
||||
for msg in messages:
|
||||
if from_date_obj and msg.date < from_date_obj:
|
||||
continue
|
||||
if to_date_obj and msg.date > to_date_obj:
|
||||
continue
|
||||
filtered_messages.append(msg)
|
||||
messages = filtered_messages
|
||||
|
||||
if not messages:
|
||||
return "No messages found matching the criteria."
|
||||
|
||||
lines = []
|
||||
for msg in messages:
|
||||
sender = ""
|
||||
if msg.sender:
|
||||
sender_name = getattr(msg.sender, 'first_name', '') or getattr(msg.sender, 'title', 'Unknown')
|
||||
sender = f"{sender_name} | "
|
||||
|
||||
lines.append(f"ID: {msg.id} | {sender}Date: {msg.date} | Message: {msg.message or '[Media/No text]'}")
|
||||
|
||||
return "\n".join(lines)
|
||||
except Exception as e:
|
||||
return f"Error retrieving messages: {e}"
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
async def list_chats(chat_type: str = None, limit: int = 20) -> str:
|
||||
"""
|
||||
List available chats with metadata.
|
||||
|
||||
Args:
|
||||
chat_type: Filter by chat type ('user', 'group', 'channel', or None for all)
|
||||
limit: Maximum number of chats to retrieve.
|
||||
"""
|
||||
try:
|
||||
dialogs = await client.get_dialogs(limit=limit)
|
||||
|
||||
results = []
|
||||
for dialog in dialogs:
|
||||
entity = dialog.entity
|
||||
|
||||
# Filter by type if requested
|
||||
current_type = None
|
||||
if isinstance(entity, User):
|
||||
current_type = "user"
|
||||
elif isinstance(entity, Chat):
|
||||
current_type = "group"
|
||||
elif isinstance(entity, Channel):
|
||||
if getattr(entity, 'broadcast', False):
|
||||
current_type = "channel"
|
||||
else:
|
||||
current_type = "group" # Supergroup
|
||||
|
||||
if chat_type and current_type != chat_type.lower():
|
||||
continue
|
||||
|
||||
# Format chat info
|
||||
chat_info = f"Chat ID: {entity.id}"
|
||||
|
||||
if hasattr(entity, 'title'):
|
||||
chat_info += f", Title: {entity.title}"
|
||||
elif hasattr(entity, 'first_name'):
|
||||
name = f"{entity.first_name}"
|
||||
if hasattr(entity, 'last_name') and entity.last_name:
|
||||
name += f" {entity.last_name}"
|
||||
chat_info += f", Name: {name}"
|
||||
|
||||
chat_info += f", Type: {current_type}"
|
||||
|
||||
if hasattr(entity, 'username') and entity.username:
|
||||
chat_info += f", Username: @{entity.username}"
|
||||
|
||||
# Add unread count if available
|
||||
if hasattr(dialog, 'unread_count') and dialog.unread_count > 0:
|
||||
chat_info += f", Unread: {dialog.unread_count}"
|
||||
|
||||
results.append(chat_info)
|
||||
|
||||
if not results:
|
||||
return f"No chats found matching the criteria."
|
||||
|
||||
return "\n".join(results)
|
||||
except Exception as e:
|
||||
return f"Error listing chats: {e}"
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
async def get_chat(chat_id: int) -> str:
|
||||
"""
|
||||
Get detailed information about a specific chat.
|
||||
|
||||
Args:
|
||||
chat_id: The ID of the chat.
|
||||
"""
|
||||
try:
|
||||
entity = await client.get_entity(chat_id)
|
||||
|
||||
result = []
|
||||
result.append(f"ID: {entity.id}")
|
||||
|
||||
if hasattr(entity, 'title'):
|
||||
result.append(f"Title: {entity.title}")
|
||||
chat_type = "Channel" if getattr(entity, 'broadcast', False) else "Group"
|
||||
result.append(f"Type: {chat_type}")
|
||||
if hasattr(entity, 'username') and entity.username:
|
||||
result.append(f"Username: @{entity.username}")
|
||||
if hasattr(entity, 'participants_count'):
|
||||
result.append(f"Participants: {entity.participants_count}")
|
||||
elif isinstance(entity, User):
|
||||
name = f"{entity.first_name}"
|
||||
if entity.last_name:
|
||||
name += f" {entity.last_name}"
|
||||
result.append(f"Name: {name}")
|
||||
result.append(f"Type: User")
|
||||
if entity.username:
|
||||
result.append(f"Username: @{entity.username}")
|
||||
if entity.phone:
|
||||
result.append(f"Phone: {entity.phone}")
|
||||
result.append(f"Bot: {'Yes' if entity.bot else 'No'}")
|
||||
result.append(f"Verified: {'Yes' if entity.verified else 'No'}")
|
||||
|
||||
# Get last activity if it's a dialog
|
||||
try:
|
||||
dialogs = await client.get_dialogs(limit=100)
|
||||
for dialog in dialogs:
|
||||
if dialog.entity.id == chat_id:
|
||||
result.append(f"Unread Messages: {dialog.unread_count}")
|
||||
if dialog.message:
|
||||
last_msg = dialog.message
|
||||
sender = getattr(last_msg.sender, 'first_name', '') or 'Unknown'
|
||||
result.append(f"Last Message: From {sender} at {last_msg.date}")
|
||||
result.append(f"Message: {last_msg.message or '[Media/No text]'}")
|
||||
break
|
||||
except:
|
||||
pass
|
||||
|
||||
return "\n".join(result)
|
||||
except Exception as e:
|
||||
return f"Error getting chat info: {e}"
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
async def get_direct_chat_by_contact(contact_query: str) -> str:
|
||||
"""
|
||||
Find a direct chat with a specific contact by name, username, or phone.
|
||||
|
||||
Args:
|
||||
contact_query: Name, username, or phone number to search for.
|
||||
"""
|
||||
try:
|
||||
# First search for the contact
|
||||
contacts = await client.get_contacts()
|
||||
found_contacts = []
|
||||
|
||||
for contact in contacts:
|
||||
if not contact:
|
||||
continue
|
||||
|
||||
name = f"{getattr(contact, 'first_name', '')} {getattr(contact, 'last_name', '')}".strip()
|
||||
username = getattr(contact, 'username', '')
|
||||
phone = getattr(contact, 'phone', '')
|
||||
|
||||
if (contact_query.lower() in name.lower() or
|
||||
(username and contact_query.lower() in username.lower()) or
|
||||
(phone and contact_query in phone)):
|
||||
found_contacts.append(contact)
|
||||
|
||||
if not found_contacts:
|
||||
return f"No contacts found matching '{contact_query}'."
|
||||
|
||||
# If we found contacts, look for direct chats with them
|
||||
results = []
|
||||
dialogs = await client.get_dialogs()
|
||||
|
||||
for contact in found_contacts:
|
||||
contact_name = f"{getattr(contact, 'first_name', '')} {getattr(contact, 'last_name', '')}".strip()
|
||||
for dialog in dialogs:
|
||||
if isinstance(dialog.entity, User) and dialog.entity.id == contact.id:
|
||||
chat_info = f"Chat ID: {dialog.entity.id}, Contact: {contact_name}"
|
||||
if getattr(contact, 'username', ''):
|
||||
chat_info += f", Username: @{contact.username}"
|
||||
if dialog.unread_count:
|
||||
chat_info += f", Unread: {dialog.unread_count}"
|
||||
results.append(chat_info)
|
||||
break
|
||||
|
||||
if not results:
|
||||
found_names = ", ".join([f"{c.first_name} {c.last_name}".strip() for c in found_contacts])
|
||||
return f"Found contacts: {found_names}, but no direct chats were found with them."
|
||||
|
||||
return "\n".join(results)
|
||||
except Exception as e:
|
||||
return f"Error finding direct chat: {e}"
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
async def get_contact_chats(contact_id: int) -> str:
|
||||
"""
|
||||
List all chats involving a specific contact.
|
||||
|
||||
Args:
|
||||
contact_id: The ID of the contact.
|
||||
"""
|
||||
try:
|
||||
# Get contact info
|
||||
contact = await client.get_entity(contact_id)
|
||||
if not isinstance(contact, User):
|
||||
return f"ID {contact_id} is not a user/contact."
|
||||
|
||||
contact_name = f"{getattr(contact, 'first_name', '')} {getattr(contact, 'last_name', '')}".strip()
|
||||
|
||||
# Find direct chat
|
||||
direct_chat = None
|
||||
dialogs = await client.get_dialogs()
|
||||
|
||||
results = []
|
||||
|
||||
# Look for direct chat
|
||||
for dialog in dialogs:
|
||||
if isinstance(dialog.entity, User) and dialog.entity.id == contact_id:
|
||||
chat_info = f"Direct Chat ID: {dialog.entity.id}, Type: Private"
|
||||
if dialog.unread_count:
|
||||
chat_info += f", Unread: {dialog.unread_count}"
|
||||
results.append(chat_info)
|
||||
break
|
||||
|
||||
# Look for common groups/channels
|
||||
common_chats = []
|
||||
try:
|
||||
common = await client.get_common_chats(contact)
|
||||
for chat in common:
|
||||
chat_type = "Channel" if getattr(chat, 'broadcast', False) else "Group"
|
||||
chat_info = f"Chat ID: {chat.id}, Title: {chat.title}, Type: {chat_type}"
|
||||
results.append(chat_info)
|
||||
except:
|
||||
results.append("Could not retrieve common groups.")
|
||||
|
||||
if not results:
|
||||
return f"No chats found with {contact_name} (ID: {contact_id})."
|
||||
|
||||
return f"Chats with {contact_name} (ID: {contact_id}):\n" + "\n".join(results)
|
||||
except Exception as e:
|
||||
return f"Error retrieving contact chats: {e}"
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
async def get_last_interaction(contact_id: int) -> str:
|
||||
"""
|
||||
Get the most recent message with a contact.
|
||||
|
||||
Args:
|
||||
contact_id: The ID of the contact.
|
||||
"""
|
||||
try:
|
||||
# Get contact info
|
||||
contact = await client.get_entity(contact_id)
|
||||
if not isinstance(contact, User):
|
||||
return f"ID {contact_id} is not a user/contact."
|
||||
|
||||
contact_name = f"{getattr(contact, 'first_name', '')} {getattr(contact, 'last_name', '')}".strip()
|
||||
|
||||
# Get the last few messages
|
||||
messages = await client.get_messages(contact, limit=5)
|
||||
|
||||
if not messages:
|
||||
return f"No messages found with {contact_name} (ID: {contact_id})."
|
||||
|
||||
results = [f"Last interactions with {contact_name} (ID: {contact_id}):"]
|
||||
|
||||
for msg in messages:
|
||||
sender = "You" if msg.out else contact_name
|
||||
message_text = msg.message or "[Media/No text]"
|
||||
results.append(f"Date: {msg.date}, From: {sender}, Message: {message_text}")
|
||||
|
||||
return "\n".join(results)
|
||||
except Exception as e:
|
||||
return f"Error retrieving last interaction: {e}"
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
async def get_message_context(chat_id: int, message_id: int, context_size: int = 3) -> str:
|
||||
"""
|
||||
Retrieve context around a specific message.
|
||||
|
||||
Args:
|
||||
chat_id: The ID of the chat.
|
||||
message_id: The ID of the central message.
|
||||
context_size: Number of messages before and after to include.
|
||||
"""
|
||||
try:
|
||||
chat = await client.get_entity(chat_id)
|
||||
|
||||
# Get messages around the specified message
|
||||
messages_before = await client.get_messages(
|
||||
chat,
|
||||
limit=context_size,
|
||||
max_id=message_id
|
||||
)
|
||||
|
||||
central_message = await client.get_messages(
|
||||
chat,
|
||||
ids=message_id
|
||||
)
|
||||
|
||||
messages_after = await client.get_messages(
|
||||
chat,
|
||||
limit=context_size,
|
||||
min_id=message_id,
|
||||
reverse=True
|
||||
)
|
||||
|
||||
if not central_message:
|
||||
return f"Message with ID {message_id} not found in chat {chat_id}."
|
||||
|
||||
# Combine messages in chronological order
|
||||
all_messages = list(messages_before) + list(central_message) + list(messages_after)
|
||||
all_messages.sort(key=lambda m: m.id)
|
||||
|
||||
results = [f"Context for message {message_id} in chat {chat_id}:"]
|
||||
|
||||
for msg in all_messages:
|
||||
sender_name = "Unknown"
|
||||
if msg.sender:
|
||||
sender_name = getattr(msg.sender, 'first_name', '') or getattr(msg.sender, 'title', 'Unknown')
|
||||
|
||||
highlight = " [THIS MESSAGE]" if msg.id == message_id else ""
|
||||
results.append(f"ID: {msg.id} | {sender_name} | {msg.date}{highlight}\n{msg.message or '[Media/No text]'}\n")
|
||||
|
||||
return "\n".join(results)
|
||||
except Exception as e:
|
||||
return f"Error retrieving message context: {e}"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
nest_asyncio.apply()
|
||||
|
||||
async def main() -> None:
|
||||
# Start the Telethon client.
|
||||
await client.start()
|
||||
print("Telegram client started. Running MCP server...")
|
||||
# Use the asynchronous entrypoint instead of mcp.run()
|
||||
await mcp.run_stdio_async()
|
||||
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)
|
||||
|
||||
asyncio.run(main())
|
||||
|
|
|
|||
|
|
@ -1,13 +1,35 @@
|
|||
[build-system]
|
||||
requires = ["setuptools>=42", "wheel"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "telegram-mcp"
|
||||
version = "2025.3.201549"
|
||||
description = "A Telegram MCP (Model Context Protocol) server built using Python, Telethon, and MCP Python SDK. This MCP server provides simple tools for interacting with Telegram chats directly through MCP-compatible hosts, such as Claude for Desktop."
|
||||
version = "1.5.0"
|
||||
description = "Telegram MCP (Model Context Protocol) server built using Python, Telethon, and MCP Python SDK"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.13"
|
||||
authors = [
|
||||
{name = "chigwell"}
|
||||
]
|
||||
license = {text = "Apache-2.0"}
|
||||
classifiers = [
|
||||
"Development Status :: 4 - Beta",
|
||||
"Intended Audience :: Developers",
|
||||
"License :: OSI Approved :: Apache Software License",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
]
|
||||
requires-python = ">=3.10"
|
||||
dependencies = [
|
||||
"dotenv>=0.9.9",
|
||||
"httpx>=0.28.1",
|
||||
"mcp[cli]>=1.4.1",
|
||||
"nest-asyncio>=1.6.0",
|
||||
"python-dotenv>=1.1.0",
|
||||
"telethon>=1.39.0",
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
"Homepage" = "https://github.com/chigwell/telegram-mcp"
|
||||
"Bug Tracker" = "https://github.com/chigwell/telegram-mcp/issues"
|
||||
|
|
|
|||
6
requirements.txt
Normal file
6
requirements.txt
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
dotenv>=0.9.9
|
||||
httpx>=0.28.1
|
||||
mcp[cli]>=1.4.1
|
||||
nest-asyncio>=1.6.0
|
||||
python-dotenv>=1.1.0
|
||||
telethon>=1.39.0
|
||||
BIN
screenshots/1.png
Normal file
BIN
screenshots/1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 170 KiB |
91
session_string_generator.py
Executable file
91
session_string_generator.py
Executable file
|
|
@ -0,0 +1,91 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Telegram Session String Generator
|
||||
|
||||
This script generates a session string that can be used for Telegram authentication
|
||||
with the Telegram MCP server. The session string allows for portable authentication
|
||||
without storing session files.
|
||||
|
||||
Usage:
|
||||
python session_string_generator.py
|
||||
|
||||
Requirements:
|
||||
- telethon
|
||||
- python-dotenv
|
||||
"""
|
||||
|
||||
import os
|
||||
from telethon.sync import TelegramClient
|
||||
from telethon.sessions import StringSession
|
||||
from dotenv import load_dotenv
|
||||
import sys
|
||||
|
||||
# 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)
|
||||
490
uv.lock
Normal file
490
uv.lock
Normal file
|
|
@ -0,0 +1,490 @@
|
|||
version = 1
|
||||
revision = 1
|
||||
requires-python = ">=3.10"
|
||||
|
||||
[[package]]
|
||||
name = "annotated-types"
|
||||
version = "0.7.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyio"
|
||||
version = "4.9.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
|
||||
{ name = "idna" },
|
||||
{ name = "sniffio" },
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/95/7d/4c1bd541d4dffa1b52bd83fb8527089e097a106fc90b467a7313b105f840/anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028", size = 190949 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c", size = 100916 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2025.1.31"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1c/ab/c9f1e32b7b1bf505bf26f0ef697775960db7932abeb7b516de930ba2705f/certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651", size = 167577 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/38/fc/bce832fd4fd99766c04d1ee0eead6b0ec6486fb100ae5e74c1d91292b982/certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe", size = 166393 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "click"
|
||||
version = "8.1.8"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colorama"
|
||||
version = "0.4.6"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dotenv"
|
||||
version = "0.9.9"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "python-dotenv" },
|
||||
]
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b2/b7/545d2c10c1fc15e48653c91efde329a790f2eecfbbf2bd16003b5db2bab0/dotenv-0.9.9-py2.py3-none-any.whl", hash = "sha256:29cf74a087b31dafdb5a446b6d7e11cbce8ed2741540e2339c69fbef92c94ce9", size = 1892 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "exceptiongroup"
|
||||
version = "1.2.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/09/35/2495c4ac46b980e4ca1f6ad6db102322ef3ad2410b79fdde159a4b0f3b92/exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc", size = 28883 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/02/cc/b7e31358aac6ed1ef2bb790a9746ac2c69bcb3c8588b41616914eb106eaf/exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", size = 16453 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "h11"
|
||||
version = "0.14.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f5/38/3af3d3633a34a3316095b39c8e8fb4853a28a536e55d347bd8d8e9a14b03/h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", size = 100418 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httpcore"
|
||||
version = "1.0.7"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "certifi" },
|
||||
{ name = "h11" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/6a/41/d7d0a89eb493922c37d343b607bc1b5da7f5be7e383740b4753ad8943e90/httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c", size = 85196 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/87/f5/72347bc88306acb359581ac4d52f23c0ef445b57157adedb9aee0cd689d2/httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd", size = 78551 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httpx"
|
||||
version = "0.28.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "anyio" },
|
||||
{ name = "certifi" },
|
||||
{ name = "httpcore" },
|
||||
{ name = "idna" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httpx-sse"
|
||||
version = "0.4.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/4c/60/8f4281fa9bbf3c8034fd54c0e7412e66edbab6bc74c4996bd616f8d0406e/httpx-sse-0.4.0.tar.gz", hash = "sha256:1e81a3a3070ce322add1d3529ed42eb5f70817f45ed6ec915ab753f961139721", size = 12624 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e1/9b/a181f281f65d776426002f330c31849b86b31fc9d848db62e16f03ff739f/httpx_sse-0.4.0-py3-none-any.whl", hash = "sha256:f329af6eae57eaa2bdfd962b42524764af68075ea87370a2de920af5341e318f", size = 7819 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "3.10"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "markdown-it-py"
|
||||
version = "3.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "mdurl" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mcp"
|
||||
version = "1.6.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "anyio" },
|
||||
{ name = "httpx" },
|
||||
{ name = "httpx-sse" },
|
||||
{ name = "pydantic" },
|
||||
{ name = "pydantic-settings" },
|
||||
{ name = "sse-starlette" },
|
||||
{ name = "starlette" },
|
||||
{ name = "uvicorn" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/95/d2/f587cb965a56e992634bebc8611c5b579af912b74e04eb9164bd49527d21/mcp-1.6.0.tar.gz", hash = "sha256:d9324876de2c5637369f43161cd71eebfd803df5a95e46225cab8d280e366723", size = 200031 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/10/30/20a7f33b0b884a9d14dd3aa94ff1ac9da1479fe2ad66dd9e2736075d2506/mcp-1.6.0-py3-none-any.whl", hash = "sha256:7bd24c6ea042dbec44c754f100984d186620d8b841ec30f1b19eda9b93a634d0", size = 76077 },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
cli = [
|
||||
{ name = "python-dotenv" },
|
||||
{ name = "typer" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mdurl"
|
||||
version = "0.1.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nest-asyncio"
|
||||
version = "1.6.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyaes"
|
||||
version = "1.6.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/44/66/2c17bae31c906613795711fc78045c285048168919ace2220daa372c7d72/pyaes-1.6.1.tar.gz", hash = "sha256:02c1b1405c38d3c370b085fb952dd8bea3fadcee6411ad99f312cc129c536d8f", size = 28536 }
|
||||
|
||||
[[package]]
|
||||
name = "pyasn1"
|
||||
version = "0.6.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ba/e9/01f1a64245b89f039897cb0130016d79f77d52669aae6ee7b159a6c4c018/pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034", size = 145322 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/c8/f1/d6a797abb14f6283c0ddff96bbdd46937f64122b8c925cab503dd37f8214/pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629", size = 83135 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pydantic"
|
||||
version = "2.11.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "annotated-types" },
|
||||
{ name = "pydantic-core" },
|
||||
{ name = "typing-extensions" },
|
||||
{ name = "typing-inspection" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/93/a3/698b87a4d4d303d7c5f62ea5fbf7a79cab236ccfbd0a17847b7f77f8163e/pydantic-2.11.1.tar.gz", hash = "sha256:442557d2910e75c991c39f4b4ab18963d57b9b55122c8b2a9cd176d8c29ce968", size = 782817 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/cc/12/f9221a949f2419e2e23847303c002476c26fbcfd62dc7f3d25d0bec5ca99/pydantic-2.11.1-py3-none-any.whl", hash = "sha256:5b6c415eee9f8123a14d859be0c84363fec6b1feb6b688d6435801230b56e0b8", size = 442648 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pydantic-core"
|
||||
version = "2.33.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b9/05/91ce14dfd5a3a99555fce436318cc0fd1f08c4daa32b3248ad63669ea8b4/pydantic_core-2.33.0.tar.gz", hash = "sha256:40eb8af662ba409c3cbf4a8150ad32ae73514cd7cb1f1a2113af39763dd616b3", size = 434080 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/29/43/0649ad07e66b36a3fb21442b425bd0348ac162c5e686b36471f363201535/pydantic_core-2.33.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:71dffba8fe9ddff628c68f3abd845e91b028361d43c5f8e7b3f8b91d7d85413e", size = 2042968 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a0/a6/975fea4774a459e495cb4be288efd8b041ac756a0a763f0b976d0861334b/pydantic_core-2.33.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:abaeec1be6ed535a5d7ffc2e6c390083c425832b20efd621562fbb5bff6dc518", size = 1860347 },
|
||||
{ url = "https://files.pythonhosted.org/packages/aa/49/7858dadad305101a077ec4d0c606b6425a2b134ea8d858458a6d287fd871/pydantic_core-2.33.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:759871f00e26ad3709efc773ac37b4d571de065f9dfb1778012908bcc36b3a73", size = 1910060 },
|
||||
{ url = "https://files.pythonhosted.org/packages/8d/4f/6522527911d9c5fe6d76b084d8b388d5c84b09d113247b39f91937500b34/pydantic_core-2.33.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dcfebee69cd5e1c0b76a17e17e347c84b00acebb8dd8edb22d4a03e88e82a207", size = 1997129 },
|
||||
{ url = "https://files.pythonhosted.org/packages/75/d0/06f396da053e3d73001ea4787e56b4d7132a87c0b5e2e15a041e808c35cd/pydantic_core-2.33.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b1262b912435a501fa04cd213720609e2cefa723a07c92017d18693e69bf00b", size = 2140389 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f5/6b/b9ff5b69cd4ef007cf665463f3be2e481dc7eb26c4a55b2f57a94308c31a/pydantic_core-2.33.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4726f1f3f42d6a25678c67da3f0b10f148f5655813c5aca54b0d1742ba821b8f", size = 2754237 },
|
||||
{ url = "https://files.pythonhosted.org/packages/53/80/b4879de375cdf3718d05fcb60c9aa1f119d28e261dafa51b6a69c78f7178/pydantic_core-2.33.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e790954b5093dff1e3a9a2523fddc4e79722d6f07993b4cd5547825c3cbf97b5", size = 2007433 },
|
||||
{ url = "https://files.pythonhosted.org/packages/46/24/54054713dc0af98a94eab37e0f4294dfd5cd8f70b2ca9dcdccd15709fd7e/pydantic_core-2.33.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:34e7fb3abe375b5c4e64fab75733d605dda0f59827752debc99c17cb2d5f3276", size = 2123980 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3a/4c/257c1cb89e14cfa6e95ebcb91b308eb1dd2b348340ff76a6e6fcfa9969e1/pydantic_core-2.33.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ecb158fb9b9091b515213bed3061eb7deb1d3b4e02327c27a0ea714ff46b0760", size = 2087433 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0c/62/927df8a39ad78ef7b82c5446e01dec9bb0043e1ad71d8f426062f5f014db/pydantic_core-2.33.0-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:4d9149e7528af8bbd76cc055967e6e04617dcb2a2afdaa3dea899406c5521faa", size = 2260242 },
|
||||
{ url = "https://files.pythonhosted.org/packages/74/f2/389414f7c77a100954e84d6f52a82bd1788ae69db72364376d8a73b38765/pydantic_core-2.33.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e81a295adccf73477220e15ff79235ca9dcbcee4be459eb9d4ce9a2763b8386c", size = 2258227 },
|
||||
{ url = "https://files.pythonhosted.org/packages/53/99/94516313e15d906a1264bb40faf24a01a4af4e2ca8a7c10dd173b6513c5a/pydantic_core-2.33.0-cp310-cp310-win32.whl", hash = "sha256:f22dab23cdbce2005f26a8f0c71698457861f97fc6318c75814a50c75e87d025", size = 1925523 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7d/67/cc789611c6035a0b71305a1ec6ba196256ced76eba8375f316f840a70456/pydantic_core-2.33.0-cp310-cp310-win_amd64.whl", hash = "sha256:9cb2390355ba084c1ad49485d18449b4242da344dea3e0fe10babd1f0db7dcfc", size = 1951872 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f0/93/9e97af2619b4026596487a79133e425c7d3c374f0a7f100f3d76bcdf9c83/pydantic_core-2.33.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a608a75846804271cf9c83e40bbb4dab2ac614d33c6fd5b0c6187f53f5c593ef", size = 2042784 },
|
||||
{ url = "https://files.pythonhosted.org/packages/42/b4/0bba8412fd242729feeb80e7152e24f0e1a1c19f4121ca3d4a307f4e6222/pydantic_core-2.33.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e1c69aa459f5609dec2fa0652d495353accf3eda5bdb18782bc5a2ae45c9273a", size = 1858179 },
|
||||
{ url = "https://files.pythonhosted.org/packages/69/1f/c1c40305d929bd08af863df64b0a26203b70b352a1962d86f3bcd52950fe/pydantic_core-2.33.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9ec80eb5a5f45a2211793f1c4aeddff0c3761d1c70d684965c1807e923a588b", size = 1909396 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0f/99/d2e727375c329c1e652b5d450fbb9d56e8c3933a397e4bd46e67c68c2cd5/pydantic_core-2.33.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e925819a98318d17251776bd3d6aa9f3ff77b965762155bdad15d1a9265c4cfd", size = 1998264 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9c/2e/3119a33931278d96ecc2e9e1b9d50c240636cfeb0c49951746ae34e4de74/pydantic_core-2.33.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5bf68bb859799e9cec3d9dd8323c40c00a254aabb56fe08f907e437005932f2b", size = 2140588 },
|
||||
{ url = "https://files.pythonhosted.org/packages/35/bd/9267bd1ba55f17c80ef6cb7e07b3890b4acbe8eb6014f3102092d53d9300/pydantic_core-2.33.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1b2ea72dea0825949a045fa4071f6d5b3d7620d2a208335207793cf29c5a182d", size = 2746296 },
|
||||
{ url = "https://files.pythonhosted.org/packages/6f/ed/ef37de6478a412ee627cbebd73e7b72a680f45bfacce9ff1199de6e17e88/pydantic_core-2.33.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1583539533160186ac546b49f5cde9ffc928062c96920f58bd95de32ffd7bffd", size = 2005555 },
|
||||
{ url = "https://files.pythonhosted.org/packages/dd/84/72c8d1439585d8ee7bc35eb8f88a04a4d302ee4018871f1f85ae1b0c6625/pydantic_core-2.33.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:23c3e77bf8a7317612e5c26a3b084c7edeb9552d645742a54a5867635b4f2453", size = 2124452 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a7/8f/cb13de30c6a3e303423751a529a3d1271c2effee4b98cf3e397a66ae8498/pydantic_core-2.33.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a7a7f2a3f628d2f7ef11cb6188bcf0b9e1558151d511b974dfea10a49afe192b", size = 2087001 },
|
||||
{ url = "https://files.pythonhosted.org/packages/83/d0/e93dc8884bf288a63fedeb8040ac8f29cb71ca52e755f48e5170bb63e55b/pydantic_core-2.33.0-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:f1fb026c575e16f673c61c7b86144517705865173f3d0907040ac30c4f9f5915", size = 2261663 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4c/ba/4b7739c95efa0b542ee45fd872c8f6b1884ab808cf04ce7ac6621b6df76e/pydantic_core-2.33.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:635702b2fed997e0ac256b2cfbdb4dd0bf7c56b5d8fba8ef03489c03b3eb40e2", size = 2257786 },
|
||||
{ url = "https://files.pythonhosted.org/packages/cc/98/73cbca1d2360c27752cfa2fcdcf14d96230e92d7d48ecd50499865c56bf7/pydantic_core-2.33.0-cp311-cp311-win32.whl", hash = "sha256:07b4ced28fccae3f00626eaa0c4001aa9ec140a29501770a88dbbb0966019a86", size = 1925697 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9a/26/d85a40edeca5d8830ffc33667d6fef329fd0f4bc0c5181b8b0e206cfe488/pydantic_core-2.33.0-cp311-cp311-win_amd64.whl", hash = "sha256:4927564be53239a87770a5f86bdc272b8d1fbb87ab7783ad70255b4ab01aa25b", size = 1949859 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/0b/5a381605f0b9870465b805f2c86c06b0a7c191668ebe4117777306c2c1e5/pydantic_core-2.33.0-cp311-cp311-win_arm64.whl", hash = "sha256:69297418ad644d521ea3e1aa2e14a2a422726167e9ad22b89e8f1130d68e1e9a", size = 1907978 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a9/c4/c9381323cbdc1bb26d352bc184422ce77c4bc2f2312b782761093a59fafc/pydantic_core-2.33.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:6c32a40712e3662bebe524abe8abb757f2fa2000028d64cc5a1006016c06af43", size = 2025127 },
|
||||
{ url = "https://files.pythonhosted.org/packages/6f/bd/af35278080716ecab8f57e84515c7dc535ed95d1c7f52c1c6f7b313a9dab/pydantic_core-2.33.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8ec86b5baa36f0a0bfb37db86c7d52652f8e8aa076ab745ef7725784183c3fdd", size = 1851687 },
|
||||
{ url = "https://files.pythonhosted.org/packages/12/e4/a01461225809c3533c23bd1916b1e8c2e21727f0fea60ab1acbffc4e2fca/pydantic_core-2.33.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4deac83a8cc1d09e40683be0bc6d1fa4cde8df0a9bf0cda5693f9b0569ac01b6", size = 1892232 },
|
||||
{ url = "https://files.pythonhosted.org/packages/51/17/3d53d62a328fb0a49911c2962036b9e7a4f781b7d15e9093c26299e5f76d/pydantic_core-2.33.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:175ab598fb457a9aee63206a1993874badf3ed9a456e0654273e56f00747bbd6", size = 1977896 },
|
||||
{ url = "https://files.pythonhosted.org/packages/30/98/01f9d86e02ec4a38f4b02086acf067f2c776b845d43f901bd1ee1c21bc4b/pydantic_core-2.33.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5f36afd0d56a6c42cf4e8465b6441cf546ed69d3a4ec92724cc9c8c61bd6ecf4", size = 2127717 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3c/43/6f381575c61b7c58b0fd0b92134c5a1897deea4cdfc3d47567b3ff460a4e/pydantic_core-2.33.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0a98257451164666afafc7cbf5fb00d613e33f7e7ebb322fbcd99345695a9a61", size = 2680287 },
|
||||
{ url = "https://files.pythonhosted.org/packages/01/42/c0d10d1451d161a9a0da9bbef023b8005aa26e9993a8cc24dc9e3aa96c93/pydantic_core-2.33.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ecc6d02d69b54a2eb83ebcc6f29df04957f734bcf309d346b4f83354d8376862", size = 2008276 },
|
||||
{ url = "https://files.pythonhosted.org/packages/20/ca/e08df9dba546905c70bae44ced9f3bea25432e34448d95618d41968f40b7/pydantic_core-2.33.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a69b7596c6603afd049ce7f3835bcf57dd3892fc7279f0ddf987bebed8caa5a", size = 2115305 },
|
||||
{ url = "https://files.pythonhosted.org/packages/03/1f/9b01d990730a98833113581a78e595fd40ed4c20f9693f5a658fb5f91eff/pydantic_core-2.33.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ea30239c148b6ef41364c6f51d103c2988965b643d62e10b233b5efdca8c0099", size = 2068999 },
|
||||
{ url = "https://files.pythonhosted.org/packages/20/18/fe752476a709191148e8b1e1139147841ea5d2b22adcde6ee6abb6c8e7cf/pydantic_core-2.33.0-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:abfa44cf2f7f7d7a199be6c6ec141c9024063205545aa09304349781b9a125e6", size = 2241488 },
|
||||
{ url = "https://files.pythonhosted.org/packages/81/22/14738ad0a0bf484b928c9e52004f5e0b81dd8dabbdf23b843717b37a71d1/pydantic_core-2.33.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:20d4275f3c4659d92048c70797e5fdc396c6e4446caf517ba5cad2db60cd39d3", size = 2248430 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e8/27/be7571e215ac8d321712f2433c445b03dbcd645366a18f67b334df8912bc/pydantic_core-2.33.0-cp312-cp312-win32.whl", hash = "sha256:918f2013d7eadea1d88d1a35fd4a1e16aaf90343eb446f91cb091ce7f9b431a2", size = 1908353 },
|
||||
{ url = "https://files.pythonhosted.org/packages/be/3a/be78f28732f93128bd0e3944bdd4b3970b389a1fbd44907c97291c8dcdec/pydantic_core-2.33.0-cp312-cp312-win_amd64.whl", hash = "sha256:aec79acc183865bad120b0190afac467c20b15289050648b876b07777e67ea48", size = 1955956 },
|
||||
{ url = "https://files.pythonhosted.org/packages/21/26/b8911ac74faa994694b76ee6a22875cc7a4abea3c381fdba4edc6c6bef84/pydantic_core-2.33.0-cp312-cp312-win_arm64.whl", hash = "sha256:5461934e895968655225dfa8b3be79e7e927e95d4bd6c2d40edd2fa7052e71b6", size = 1903259 },
|
||||
{ url = "https://files.pythonhosted.org/packages/79/20/de2ad03ce8f5b3accf2196ea9b44f31b0cd16ac6e8cfc6b21976ed45ec35/pydantic_core-2.33.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f00e8b59e1fc8f09d05594aa7d2b726f1b277ca6155fc84c0396db1b373c4555", size = 2032214 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f9/af/6817dfda9aac4958d8b516cbb94af507eb171c997ea66453d4d162ae8948/pydantic_core-2.33.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1a73be93ecef45786d7d95b0c5e9b294faf35629d03d5b145b09b81258c7cd6d", size = 1852338 },
|
||||
{ url = "https://files.pythonhosted.org/packages/44/f3/49193a312d9c49314f2b953fb55740b7c530710977cabe7183b8ef111b7f/pydantic_core-2.33.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ff48a55be9da6930254565ff5238d71d5e9cd8c5487a191cb85df3bdb8c77365", size = 1896913 },
|
||||
{ url = "https://files.pythonhosted.org/packages/06/e0/c746677825b2e29a2fa02122a8991c83cdd5b4c5f638f0664d4e35edd4b2/pydantic_core-2.33.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:26a4ea04195638dcd8c53dadb545d70badba51735b1594810e9768c2c0b4a5da", size = 1986046 },
|
||||
{ url = "https://files.pythonhosted.org/packages/11/ec/44914e7ff78cef16afb5e5273d480c136725acd73d894affdbe2a1bbaad5/pydantic_core-2.33.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:41d698dcbe12b60661f0632b543dbb119e6ba088103b364ff65e951610cb7ce0", size = 2128097 },
|
||||
{ url = "https://files.pythonhosted.org/packages/fe/f5/c6247d424d01f605ed2e3802f338691cae17137cee6484dce9f1ac0b872b/pydantic_core-2.33.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ae62032ef513fe6281ef0009e30838a01057b832dc265da32c10469622613885", size = 2681062 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f0/85/114a2113b126fdd7cf9a9443b1b1fe1b572e5bd259d50ba9d5d3e1927fa9/pydantic_core-2.33.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f225f3a3995dbbc26affc191d0443c6c4aa71b83358fd4c2b7d63e2f6f0336f9", size = 2007487 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e6/40/3c05ed28d225c7a9acd2b34c5c8010c279683a870219b97e9f164a5a8af0/pydantic_core-2.33.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5bdd36b362f419c78d09630cbaebc64913f66f62bda6d42d5fbb08da8cc4f181", size = 2121382 },
|
||||
{ url = "https://files.pythonhosted.org/packages/8a/22/e70c086f41eebd323e6baa92cc906c3f38ddce7486007eb2bdb3b11c8f64/pydantic_core-2.33.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:2a0147c0bef783fd9abc9f016d66edb6cac466dc54a17ec5f5ada08ff65caf5d", size = 2072473 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3e/84/d1614dedd8fe5114f6a0e348bcd1535f97d76c038d6102f271433cd1361d/pydantic_core-2.33.0-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:c860773a0f205926172c6644c394e02c25421dc9a456deff16f64c0e299487d3", size = 2249468 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b0/c0/787061eef44135e00fddb4b56b387a06c303bfd3884a6df9bea5cb730230/pydantic_core-2.33.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:138d31e3f90087f42aa6286fb640f3c7a8eb7bdae829418265e7e7474bd2574b", size = 2254716 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ae/e2/27262eb04963201e89f9c280f1e10c493a7a37bc877e023f31aa72d2f911/pydantic_core-2.33.0-cp313-cp313-win32.whl", hash = "sha256:d20cbb9d3e95114325780f3cfe990f3ecae24de7a2d75f978783878cce2ad585", size = 1916450 },
|
||||
{ url = "https://files.pythonhosted.org/packages/13/8d/25ff96f1e89b19e0b70b3cd607c9ea7ca27e1dcb810a9cd4255ed6abf869/pydantic_core-2.33.0-cp313-cp313-win_amd64.whl", hash = "sha256:ca1103d70306489e3d006b0f79db8ca5dd3c977f6f13b2c59ff745249431a606", size = 1956092 },
|
||||
{ url = "https://files.pythonhosted.org/packages/1b/64/66a2efeff657b04323ffcd7b898cb0354d36dae3a561049e092134a83e9c/pydantic_core-2.33.0-cp313-cp313-win_arm64.whl", hash = "sha256:6291797cad239285275558e0a27872da735b05c75d5237bbade8736f80e4c225", size = 1908367 },
|
||||
{ url = "https://files.pythonhosted.org/packages/52/54/295e38769133363d7ec4a5863a4d579f331728c71a6644ff1024ee529315/pydantic_core-2.33.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:7b79af799630af263eca9ec87db519426d8c9b3be35016eddad1832bac812d87", size = 1813331 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4c/9c/0c8ea02db8d682aa1ef48938abae833c1d69bdfa6e5ec13b21734b01ae70/pydantic_core-2.33.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eabf946a4739b5237f4f56d77fa6668263bc466d06a8036c055587c130a46f7b", size = 1986653 },
|
||||
{ url = "https://files.pythonhosted.org/packages/8e/4f/3fb47d6cbc08c7e00f92300e64ba655428c05c56b8ab6723bd290bae6458/pydantic_core-2.33.0-cp313-cp313t-win_amd64.whl", hash = "sha256:8a1d581e8cdbb857b0e0e81df98603376c1a5c34dc5e54039dcc00f043df81e7", size = 1931234 },
|
||||
{ url = "https://files.pythonhosted.org/packages/44/77/85e173b715e1a277ce934f28d877d82492df13e564fa68a01c96f36a47ad/pydantic_core-2.33.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e2762c568596332fdab56b07060c8ab8362c56cf2a339ee54e491cd503612c50", size = 2040129 },
|
||||
{ url = "https://files.pythonhosted.org/packages/33/e7/33da5f8a94bbe2191cfcd15bd6d16ecd113e67da1b8c78d3cc3478112dab/pydantic_core-2.33.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5bf637300ff35d4f59c006fff201c510b2b5e745b07125458a5389af3c0dff8c", size = 1872656 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b4/7a/9600f222bea840e5b9ba1f17c0acc79b669b24542a78c42c6a10712c0aae/pydantic_core-2.33.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62c151ce3d59ed56ebd7ce9ce5986a409a85db697d25fc232f8e81f195aa39a1", size = 1903731 },
|
||||
{ url = "https://files.pythonhosted.org/packages/81/d2/94c7ca4e24c5dcfb74df92e0836c189e9eb6814cf62d2f26a75ea0a906db/pydantic_core-2.33.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ee65f0cc652261744fd07f2c6e6901c914aa6c5ff4dcfaf1136bc394d0dd26b", size = 2083966 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b8/74/a0259989d220e8865ed6866a6d40539e40fa8f507e587e35d2414cc081f8/pydantic_core-2.33.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:024d136ae44d233e6322027bbf356712b3940bee816e6c948ce4b90f18471b3d", size = 2118951 },
|
||||
{ url = "https://files.pythonhosted.org/packages/13/4c/87405ed04d6d07597920b657f082a8e8e58bf3034178bb9044b4d57a91e2/pydantic_core-2.33.0-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:e37f10f6d4bc67c58fbd727108ae1d8b92b397355e68519f1e4a7babb1473442", size = 2079632 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5a/4c/bcb02970ef91d4cd6de7c6893101302637da456bc8b52c18ea0d047b55ce/pydantic_core-2.33.0-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:502ed542e0d958bd12e7c3e9a015bce57deaf50eaa8c2e1c439b512cb9db1e3a", size = 2250541 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a3/2b/dbe5450c4cd904be5da736dcc7f2357b828199e29e38de19fc81f988b288/pydantic_core-2.33.0-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:715c62af74c236bf386825c0fdfa08d092ab0f191eb5b4580d11c3189af9d330", size = 2255685 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ca/a6/ca1d35f695d81f639c5617fc9efb44caad21a9463383fa45364b3044175a/pydantic_core-2.33.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:bccc06fa0372151f37f6b69834181aa9eb57cf8665ed36405fb45fbf6cac3bae", size = 2082395 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2b/b2/553e42762e7b08771fca41c0230c1ac276f9e79e78f57628e1b7d328551d/pydantic_core-2.33.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5d8dc9f63a26f7259b57f46a7aab5af86b2ad6fbe48487500bb1f4b27e051e4c", size = 2041207 },
|
||||
{ url = "https://files.pythonhosted.org/packages/85/81/a91a57bbf3efe53525ab75f65944b8950e6ef84fe3b9a26c1ec173363263/pydantic_core-2.33.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:30369e54d6d0113d2aa5aee7a90d17f225c13d87902ace8fcd7bbf99b19124db", size = 1873736 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9c/d2/5ab52e9f551cdcbc1ee99a0b3ef595f56d031f66f88e5ca6726c49f9ce65/pydantic_core-2.33.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3eb479354c62067afa62f53bb387827bee2f75c9c79ef25eef6ab84d4b1ae3b", size = 1903794 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2f/5f/a81742d3f3821b16f1265f057d6e0b68a3ab13a814fe4bffac536a1f26fd/pydantic_core-2.33.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0310524c833d91403c960b8a3cf9f46c282eadd6afd276c8c5edc617bd705dc9", size = 2083457 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b5/2f/e872005bc0fc47f9c036b67b12349a8522d32e3bda928e82d676e2a594d1/pydantic_core-2.33.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:eddb18a00bbb855325db27b4c2a89a4ba491cd6a0bd6d852b225172a1f54b36c", size = 2119537 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d3/13/183f13ce647202eaf3dada9e42cdfc59cbb95faedd44d25f22b931115c7f/pydantic_core-2.33.0-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:ade5dbcf8d9ef8f4b28e682d0b29f3008df9842bb5ac48ac2c17bc55771cc976", size = 2080069 },
|
||||
{ url = "https://files.pythonhosted.org/packages/23/8b/b6be91243da44a26558d9c3a9007043b3750334136c6550551e8092d6d96/pydantic_core-2.33.0-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:2c0afd34f928383e3fd25740f2050dbac9d077e7ba5adbaa2227f4d4f3c8da5c", size = 2251618 },
|
||||
{ url = "https://files.pythonhosted.org/packages/aa/c5/fbcf1977035b834f63eb542e74cd6c807177f383386175b468f0865bcac4/pydantic_core-2.33.0-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:7da333f21cd9df51d5731513a6d39319892947604924ddf2e24a4612975fb936", size = 2255374 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2f/f8/66f328e411f1c9574b13c2c28ab01f308b53688bbbe6ca8fb981e6cabc42/pydantic_core-2.33.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:4b6d77c75a57f041c5ee915ff0b0bb58eabb78728b69ed967bc5b780e8f701b8", size = 2082099 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pydantic-settings"
|
||||
version = "2.8.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "pydantic" },
|
||||
{ name = "python-dotenv" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/88/82/c79424d7d8c29b994fb01d277da57b0a9b09cc03c3ff875f9bd8a86b2145/pydantic_settings-2.8.1.tar.gz", hash = "sha256:d5c663dfbe9db9d5e1c646b2e161da12f0d734d422ee56f567d0ea2cee4e8585", size = 83550 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/0b/53/a64f03044927dc47aafe029c42a5b7aabc38dfb813475e0e1bf71c4a59d0/pydantic_settings-2.8.1-py3-none-any.whl", hash = "sha256:81942d5ac3d905f7f3ee1a70df5dfb62d5569c12f51a5a647defc1c3d9ee2e9c", size = 30839 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pygments"
|
||||
version = "2.19.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "python-dotenv"
|
||||
version = "1.1.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/88/2c/7bb1416c5620485aa793f2de31d3df393d3686aa8a8506d11e10e13c5baf/python_dotenv-1.1.0.tar.gz", hash = "sha256:41f90bc6f5f177fb41f53e87666db362025010eb28f60a01c9143bfa33a2b2d5", size = 39920 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/1e/18/98a99ad95133c6a6e2005fe89faedf294a748bd5dc803008059409ac9b1e/python_dotenv-1.1.0-py3-none-any.whl", hash = "sha256:d7c01d9e2293916c18baf562d95698754b0dbbb5e74d457c45d4f6561fb9d55d", size = 20256 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rich"
|
||||
version = "14.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "markdown-it-py" },
|
||||
{ name = "pygments" },
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a1/53/830aa4c3066a8ab0ae9a9955976fb770fe9c6102117c8ec4ab3ea62d89e8/rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725", size = 224078 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/0d/9b/63f4c7ebc259242c89b3acafdb37b41d1185c07ff0011164674e9076b491/rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0", size = 243229 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rsa"
|
||||
version = "4.9"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "pyasn1" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/aa/65/7d973b89c4d2351d7fb232c2e452547ddfa243e93131e7cfa766da627b52/rsa-4.9.tar.gz", hash = "sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21", size = 29711 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/49/97/fa78e3d2f65c02c8e1268b9aba606569fe97f6c8f7c2d74394553347c145/rsa-4.9-py3-none-any.whl", hash = "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7", size = 34315 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shellingham"
|
||||
version = "1.5.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sniffio"
|
||||
version = "1.3.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sse-starlette"
|
||||
version = "2.2.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "anyio" },
|
||||
{ name = "starlette" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/71/a4/80d2a11af59fe75b48230846989e93979c892d3a20016b42bb44edb9e398/sse_starlette-2.2.1.tar.gz", hash = "sha256:54470d5f19274aeed6b2d473430b08b4b379ea851d953b11d7f1c4a2c118b419", size = 17376 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/d9/e0/5b8bd393f27f4a62461c5cf2479c75a2cc2ffa330976f9f00f5f6e4f50eb/sse_starlette-2.2.1-py3-none-any.whl", hash = "sha256:6410a3d3ba0c89e7675d4c273a301d64649c03a5ef1ca101f10b47f895fd0e99", size = 10120 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "starlette"
|
||||
version = "0.46.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "anyio" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/04/1b/52b27f2e13ceedc79a908e29eac426a63465a1a01248e5f24aa36a62aeb3/starlette-0.46.1.tar.gz", hash = "sha256:3c88d58ee4bd1bb807c0d1acb381838afc7752f9ddaec81bbe4383611d833230", size = 2580102 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a0/4b/528ccf7a982216885a1ff4908e886b8fb5f19862d1962f56a3fce2435a70/starlette-0.46.1-py3-none-any.whl", hash = "sha256:77c74ed9d2720138b25875133f3a2dae6d854af2ec37dceb56aef370c1d8a227", size = 71995 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "telegram-mcp"
|
||||
version = "1.5.0"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "dotenv" },
|
||||
{ name = "httpx" },
|
||||
{ name = "mcp", extra = ["cli"] },
|
||||
{ name = "nest-asyncio" },
|
||||
{ name = "python-dotenv" },
|
||||
{ name = "telethon" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "dotenv", specifier = ">=0.9.9" },
|
||||
{ name = "httpx", specifier = ">=0.28.1" },
|
||||
{ name = "mcp", extras = ["cli"], specifier = ">=1.4.1" },
|
||||
{ name = "nest-asyncio", specifier = ">=1.6.0" },
|
||||
{ name = "python-dotenv", specifier = ">=1.1.0" },
|
||||
{ name = "telethon", specifier = ">=1.39.0" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "telethon"
|
||||
version = "1.39.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "pyaes" },
|
||||
{ name = "rsa" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/54/b2/6e48b593a0e4e678578a682332ef36e54648c78ef13a5d395e5cdd293c6d/telethon-1.39.0.tar.gz", hash = "sha256:35d4795d8c91deac515fb0bcb3723866b924de1c724e1d5c230460e96f284a63", size = 640634 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/32/f2/4e66a59c6d0cb6a25c0c2a630b4b184d81cfe8cb982bf3b65ce32b020fc8/Telethon-1.39.0-py3-none-any.whl", hash = "sha256:aa9f394b94be144799a6f6a93ab463867bc7c63503ede9631751940a98f6c703", size = 715851 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typer"
|
||||
version = "0.15.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "click" },
|
||||
{ name = "rich" },
|
||||
{ name = "shellingham" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/8b/6f/3991f0f1c7fcb2df31aef28e0594d8d54b05393a0e4e34c65e475c2a5d41/typer-0.15.2.tar.gz", hash = "sha256:ab2fab47533a813c49fe1f16b1a370fd5819099c00b119e0633df65f22144ba5", size = 100711 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/7f/fc/5b29fea8cee020515ca82cc68e3b8e1e34bb19a3535ad854cac9257b414c/typer-0.15.2-py3-none-any.whl", hash = "sha256:46a499c6107d645a9c13f7ee46c5d5096cae6f5fc57dd11eccbbb9ae3e44ddfc", size = 45061 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.13.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/0e/3e/b00a62db91a83fff600de219b6ea9908e6918664899a2d85db222f4fbf19/typing_extensions-4.13.0.tar.gz", hash = "sha256:0a4ac55a5820789d87e297727d229866c9650f6521b64206413c4fbada24d95b", size = 106520 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e0/86/39b65d676ec5732de17b7e3c476e45bb80ec64eb50737a8dce1a4178aba1/typing_extensions-4.13.0-py3-none-any.whl", hash = "sha256:c8dd92cc0d6425a97c18fbb9d1954e5ff92c1ca881a309c45f06ebc0b79058e5", size = 45683 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typing-inspection"
|
||||
version = "0.4.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/82/5c/e6082df02e215b846b4b8c0b887a64d7d08ffaba30605502639d44c06b82/typing_inspection-0.4.0.tar.gz", hash = "sha256:9765c87de36671694a67904bf2c96e395be9c6439bb6c87b5142569dcdd65122", size = 76222 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/31/08/aa4fdfb71f7de5176385bd9e90852eaf6b5d622735020ad600f2bab54385/typing_inspection-0.4.0-py3-none-any.whl", hash = "sha256:50e72559fcd2a6367a19f7a7e610e6afcb9fac940c650290eed893d61386832f", size = 14125 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uvicorn"
|
||||
version = "0.34.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "click" },
|
||||
{ name = "h11" },
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/4b/4d/938bd85e5bf2edeec766267a5015ad969730bb91e31b44021dfe8b22df6c/uvicorn-0.34.0.tar.gz", hash = "sha256:404051050cd7e905de2c9a7e61790943440b3416f49cb409f965d9dcd0fa73e9", size = 76568 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/61/14/33a3a1352cfa71812a3a21e8c9bfb83f60b0011f5e36f2b1399d51928209/uvicorn-0.34.0-py3-none-any.whl", hash = "sha256:023dc038422502fa28a09c7a30bf2b6991512da7dcdb8fd35fe57cfc154126f4", size = 62315 },
|
||||
]
|
||||
Loading…
Reference in a new issue