Skip to content

Commit 95a0313

Browse files
authored
Merge pull request #57 from artgas1/feature/add-contact-username-support
feat: Add support for adding contacts by username without phone number
2 parents 73ea210 + 359b863 commit 95a0313

File tree

1 file changed

+107
-34
lines changed

1 file changed

+107
-34
lines changed

main.py

Lines changed: 107 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1300,59 +1300,132 @@ async def get_message_context(
13001300
title="Add Contact", openWorldHint=True, destructiveHint=True, idempotentHint=True
13011301
)
13021302
)
1303-
async def add_contact(phone: str, first_name: str, last_name: str = "") -> str:
1303+
async def add_contact(
1304+
phone: Optional[str] = None,
1305+
first_name: str = "",
1306+
last_name: str = "",
1307+
username: Optional[str] = None,
1308+
) -> str:
13041309
"""
13051310
Add a new contact to your Telegram account.
13061311
Args:
1307-
phone: The phone number of the contact (with country code).
1312+
phone: The phone number of the contact (with country code). Required if username is not provided.
13081313
first_name: The contact's first name.
13091314
last_name: The contact's last name (optional).
1315+
username: The Telegram username (without @). Use this for adding contacts without phone numbers.
1316+
1317+
Note: Either phone or username must be provided. If username is provided, the function will resolve it
1318+
and add the contact using contacts.addContact API (which supports adding contacts without phone numbers).
13101319
"""
13111320
try:
1312-
# Try to import the required types first
1313-
from telethon.tl.types import InputPhoneContact
1321+
# Normalize None to empty string for easier checking
1322+
phone = phone or ""
1323+
username = username or ""
1324+
1325+
# Validate that at least one identifier is provided
1326+
if not phone and not username:
1327+
return "Error: Either phone or username must be provided."
1328+
1329+
# If username is provided, use it for username-based contact addition
1330+
if username:
1331+
# Remove @ if present
1332+
username_clean = username.lstrip("@")
1333+
if not username_clean:
1334+
return "Error: Username cannot be empty."
1335+
1336+
# Resolve username to get user information
1337+
try:
1338+
resolve_result = await client(
1339+
functions.contacts.ResolveUsernameRequest(username=username_clean)
1340+
)
13141341

1315-
result = await client(
1316-
functions.contacts.ImportContactsRequest(
1317-
contacts=[
1318-
InputPhoneContact(
1319-
client_id=0,
1320-
phone=phone,
1342+
# Extract user from the result
1343+
if not resolve_result.users:
1344+
return f"Error: User with username @{username_clean} not found."
1345+
1346+
user = resolve_result.users[0]
1347+
if not isinstance(user, User):
1348+
return f"Error: Resolved entity is not a user."
1349+
1350+
user_id = user.id
1351+
access_hash = user.access_hash
1352+
1353+
# Use contacts.addContact to add the contact by user ID
1354+
from telethon.tl.types import InputUser
1355+
1356+
result = await client(
1357+
functions.contacts.AddContactRequest(
1358+
id=InputUser(user_id=user_id, access_hash=access_hash),
13211359
first_name=first_name,
13221360
last_name=last_name,
1361+
phone="", # Empty phone for username-based contacts
13231362
)
1324-
]
1325-
)
1326-
)
1327-
if result.imported:
1328-
return f"Contact {first_name} {last_name} added successfully."
1329-
else:
1330-
return f"Contact not added. Response: {str(result)}"
1331-
except (ImportError, AttributeError) as type_err:
1332-
# Try alternative approach using raw API
1333-
try:
1363+
)
1364+
1365+
if hasattr(result, "updates") and result.updates:
1366+
return (
1367+
f"Contact {first_name} {last_name} (@{username_clean}) added successfully."
1368+
)
1369+
else:
1370+
return f"Contact {first_name} {last_name} (@{username_clean}) added successfully (no updates returned)."
1371+
1372+
except Exception as resolve_e:
1373+
logger.exception(
1374+
f"add_contact (username resolve) failed (username={username_clean})"
1375+
)
1376+
return log_and_format_error("add_contact", resolve_e, username=username_clean)
1377+
1378+
elif phone:
1379+
# Original phone-based contact addition
1380+
from telethon.tl.types import InputPhoneContact
1381+
13341382
result = await client(
13351383
functions.contacts.ImportContactsRequest(
13361384
contacts=[
1337-
{
1338-
"client_id": 0,
1339-
"phone": phone,
1340-
"first_name": first_name,
1341-
"last_name": last_name,
1342-
}
1385+
InputPhoneContact(
1386+
client_id=0,
1387+
phone=phone,
1388+
first_name=first_name,
1389+
last_name=last_name,
1390+
)
13431391
]
13441392
)
13451393
)
1346-
if hasattr(result, "imported") and result.imported:
1347-
return f"Contact {first_name} {last_name} added successfully (alt method)."
1394+
if result.imported:
1395+
return f"Contact {first_name} {last_name} added successfully."
13481396
else:
1349-
return f"Contact not added. Alternative method response: {str(result)}"
1350-
except Exception as alt_e:
1351-
logger.exception(f"add_contact (alt method) failed (phone={phone})")
1352-
return log_and_format_error("add_contact", alt_e, phone=phone)
1397+
return f"Contact not added. Response: {str(result)}"
1398+
else:
1399+
return "Error: Phone number is required when username is not provided."
1400+
except (ImportError, AttributeError) as type_err:
1401+
# Try alternative approach using raw API (only for phone-based)
1402+
if phone and not username:
1403+
try:
1404+
result = await client(
1405+
functions.contacts.ImportContactsRequest(
1406+
contacts=[
1407+
{
1408+
"client_id": 0,
1409+
"phone": phone,
1410+
"first_name": first_name,
1411+
"last_name": last_name,
1412+
}
1413+
]
1414+
)
1415+
)
1416+
if hasattr(result, "imported") and result.imported:
1417+
return f"Contact {first_name} {last_name} added successfully (alt method)."
1418+
else:
1419+
return f"Contact not added. Alternative method response: {str(result)}"
1420+
except Exception as alt_e:
1421+
logger.exception(f"add_contact (alt method) failed (phone={phone})")
1422+
return log_and_format_error("add_contact", alt_e, phone=phone)
1423+
else:
1424+
logger.exception(f"add_contact (type error) failed")
1425+
return log_and_format_error("add_contact", type_err)
13531426
except Exception as e:
1354-
logger.exception(f"add_contact failed (phone={phone})")
1355-
return log_and_format_error("add_contact", e, phone=phone)
1427+
logger.exception(f"add_contact failed (phone={phone}, username={username})")
1428+
return log_and_format_error("add_contact", e, phone=phone, username=username)
13561429

13571430

13581431
@mcp.tool(

0 commit comments

Comments
 (0)