mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-27 21:08:00 +00:00
Add type casting helpers for Telegram MTProto API
- Introduced `apiCastHelpers.ts` to centralize type casting functions for Telegram's complex union types, improving type safety and code clarity. - Updated multiple Telegram tools to utilize these helpers for casting input entities, enhancing maintainability and consistency across the codebase. - Modified `apiResultTypes.ts` to refine type definitions, ensuring better integration with the Telegram API. These changes streamline type handling in Telegram MCP tools, facilitating improved development practices and reducing the risk of type-related errors.
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Type bridge utilities for Telegram MTProto API.
|
||||
*
|
||||
* The `telegram` library's `client.invoke()` returns complex union types,
|
||||
* and `getInputEntity()` returns `TypeInputPeer` which doesn't directly
|
||||
* narrow to specific entity types like `TypeInputChannel`.
|
||||
*
|
||||
* These helpers centralize the necessary type casts in one documented
|
||||
* location rather than scattering casts throughout tool files.
|
||||
*/
|
||||
import type { Api } from "telegram";
|
||||
|
||||
/** Cast getInputEntity() result to Api.TypeInputChannel */
|
||||
export function toInputChannel(entity: object): Api.TypeInputChannel {
|
||||
return entity as Api.TypeInputChannel;
|
||||
}
|
||||
|
||||
/** Cast getInputEntity() result to Api.TypeInputUser */
|
||||
export function toInputUser(entity: object): Api.TypeInputUser {
|
||||
return entity as Api.TypeInputUser;
|
||||
}
|
||||
|
||||
/** Cast getInputEntity() result to Api.TypeInputPeer */
|
||||
export function toInputPeer(entity: object): Api.TypeInputPeer {
|
||||
return entity as Api.TypeInputPeer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Narrow an invoke() result to the expected shape.
|
||||
* Telegram's client.invoke() returns complex union types that can't
|
||||
* be narrowed purely via control flow. This provides a typed
|
||||
* alternative to inline casts in tool files.
|
||||
*/
|
||||
export function narrow<T extends object>(result: object): T {
|
||||
return result as T;
|
||||
}
|
||||
@@ -82,7 +82,7 @@ export interface BotCallbackAnswer {
|
||||
|
||||
/** Contact import result */
|
||||
export interface ImportContactsResult {
|
||||
imported?: unknown[];
|
||||
imported?: object[];
|
||||
}
|
||||
|
||||
/** Contact ID entry */
|
||||
|
||||
@@ -5,6 +5,7 @@ import { validateId } from "../../validation";
|
||||
import { getChatById } from "../telegramApi";
|
||||
import { mtprotoService } from "../../../../services/mtprotoService";
|
||||
import { Api } from "telegram";
|
||||
import { toInputChannel, toInputPeer } from "../apiCastHelpers";
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: "ban_user",
|
||||
@@ -54,8 +55,8 @@ export async function banUser(
|
||||
const inputUser = await client.getInputEntity(userId);
|
||||
await client.invoke(
|
||||
new Api.channels.EditBanned({
|
||||
channel: inputChannel as unknown as Api.TypeInputChannel,
|
||||
participant: inputUser as unknown as Api.TypeInputPeer,
|
||||
channel: toInputChannel(inputChannel),
|
||||
participant: toInputPeer(inputUser),
|
||||
bannedRights: new Api.ChatBannedRights({
|
||||
viewMessages: true,
|
||||
sendMessages: true,
|
||||
|
||||
@@ -4,6 +4,7 @@ import { ErrorCategory, logAndFormatError } from '../../errorHandler';
|
||||
import { validateId } from '../../validation';
|
||||
import { mtprotoService } from '../../../../services/mtprotoService';
|
||||
import { Api } from 'telegram';
|
||||
import { toInputPeer } from '../apiCastHelpers';
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: 'block_user',
|
||||
@@ -28,7 +29,7 @@ export async function blockUser(
|
||||
await mtprotoService.withFloodWaitHandling(async () => {
|
||||
const inputUser = await client.getInputEntity(userId);
|
||||
await client.invoke(
|
||||
new Api.contacts.Block({ id: inputUser as unknown as Api.TypeInputPeer }),
|
||||
new Api.contacts.Block({ id: toInputPeer(inputUser) }),
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import { mtprotoService } from "../../../../services/mtprotoService";
|
||||
import { Api } from "telegram";
|
||||
import { optString } from "../args";
|
||||
import type { ResultWithChats } from "../apiResultTypes";
|
||||
import { narrow } from "../apiCastHelpers";
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: "create_channel",
|
||||
@@ -51,7 +52,7 @@ export async function createChannel(
|
||||
);
|
||||
});
|
||||
|
||||
const channelId = (result as unknown as ResultWithChats)?.chats?.[0]?.id ?? "unknown";
|
||||
const channelId = narrow<ResultWithChats>(result)?.chats?.[0]?.id ?? "unknown";
|
||||
const type = megagroup ? "Supergroup" : "Channel";
|
||||
return {
|
||||
content: [
|
||||
|
||||
@@ -4,6 +4,7 @@ import { ErrorCategory, logAndFormatError } from "../../errorHandler";
|
||||
import { mtprotoService } from "../../../../services/mtprotoService";
|
||||
import { Api } from "telegram";
|
||||
import type { ResultWithChats } from "../apiResultTypes";
|
||||
import { toInputUser, narrow } from "../apiCastHelpers";
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: "create_group",
|
||||
@@ -46,14 +47,14 @@ export async function createGroup(
|
||||
const users: Api.TypeInputUser[] = [];
|
||||
for (const uid of userIds) {
|
||||
const inputUser = await client.getInputEntity(String(uid));
|
||||
users.push(inputUser as unknown as Api.TypeInputUser);
|
||||
users.push(toInputUser(inputUser));
|
||||
}
|
||||
|
||||
const result = await mtprotoService.withFloodWaitHandling(async () => {
|
||||
return client.invoke(new Api.messages.CreateChat({ title, users }));
|
||||
});
|
||||
|
||||
const chatId = (result as unknown as ResultWithChats)?.chats?.[0]?.id ?? "unknown";
|
||||
const chatId = narrow<ResultWithChats>(result)?.chats?.[0]?.id ?? "unknown";
|
||||
return {
|
||||
content: [
|
||||
{ type: "text", text: `Group "${title}" created. Chat ID: ${chatId}` },
|
||||
|
||||
@@ -6,6 +6,7 @@ import { getChatById } from "../telegramApi";
|
||||
import { mtprotoService } from "../../../../services/mtprotoService";
|
||||
import { Api } from "telegram";
|
||||
import bigInt from "big-integer";
|
||||
import { toInputChannel } from "../apiCastHelpers";
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: "delete_chat_photo",
|
||||
@@ -41,7 +42,7 @@ export async function deleteChatPhoto(
|
||||
const inputChannel = await client.getInputEntity(entity);
|
||||
await client.invoke(
|
||||
new Api.channels.EditPhoto({
|
||||
channel: inputChannel as unknown as Api.TypeInputChannel,
|
||||
channel: toInputChannel(inputChannel),
|
||||
photo: new Api.InputChatPhotoEmpty(),
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -4,6 +4,7 @@ import { ErrorCategory, logAndFormatError } from '../../errorHandler';
|
||||
import { validateId } from '../../validation';
|
||||
import { mtprotoService } from '../../../../services/mtprotoService';
|
||||
import { Api } from 'telegram';
|
||||
import { toInputUser } from '../apiCastHelpers';
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: 'delete_contact',
|
||||
@@ -29,7 +30,7 @@ export async function deleteContact(
|
||||
const inputUser = await client.getInputEntity(userId);
|
||||
await client.invoke(
|
||||
new Api.contacts.DeleteContacts({
|
||||
id: [inputUser as unknown as Api.TypeInputUser],
|
||||
id: [toInputUser(inputUser)],
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@ import { mtprotoService } from '../../../../services/mtprotoService';
|
||||
import { Api } from 'telegram';
|
||||
import bigInt from 'big-integer';
|
||||
import type { ApiPhoto } from '../apiResultTypes';
|
||||
import { narrow } from '../apiCastHelpers';
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: "delete_profile_photo",
|
||||
@@ -34,7 +35,7 @@ export async function deleteProfilePhoto(
|
||||
return { content: [{ type: 'text', text: 'No profile photo to delete.' }] };
|
||||
}
|
||||
|
||||
const photo = photos.photos[0] as unknown as ApiPhoto;
|
||||
const photo = narrow<ApiPhoto>(photos.photos[0]);
|
||||
|
||||
await mtprotoService.withFloodWaitHandling(async () => {
|
||||
await client.invoke(
|
||||
|
||||
@@ -5,6 +5,7 @@ import { validateId } from "../../validation";
|
||||
import { getChatById } from "../telegramApi";
|
||||
import { mtprotoService } from "../../../../services/mtprotoService";
|
||||
import { Api } from "telegram";
|
||||
import { toInputChannel, toInputUser } from "../apiCastHelpers";
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: "demote_admin",
|
||||
@@ -54,8 +55,8 @@ export async function demoteAdmin(
|
||||
const inputUser = await client.getInputEntity(userId);
|
||||
await client.invoke(
|
||||
new Api.channels.EditAdmin({
|
||||
channel: inputChannel as unknown as Api.TypeInputChannel,
|
||||
userId: inputUser as unknown as Api.TypeInputUser,
|
||||
channel: toInputChannel(inputChannel),
|
||||
userId: toInputUser(inputUser),
|
||||
adminRights: new Api.ChatAdminRights({}),
|
||||
rank: "",
|
||||
}),
|
||||
|
||||
@@ -6,6 +6,7 @@ import { getChatById } from "../telegramApi";
|
||||
import { mtprotoService } from "../../../../services/mtprotoService";
|
||||
import { Api } from "telegram";
|
||||
import bigInt from "big-integer";
|
||||
import { toInputChannel } from "../apiCastHelpers";
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: "edit_chat_title",
|
||||
@@ -48,7 +49,7 @@ export async function editChatTitle(
|
||||
const inputChannel = await client.getInputEntity(entity);
|
||||
await client.invoke(
|
||||
new Api.channels.EditTitle({
|
||||
channel: inputChannel as unknown as Api.TypeInputChannel,
|
||||
channel: toInputChannel(inputChannel),
|
||||
title,
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -7,6 +7,7 @@ import { mtprotoService } from '../../../../services/mtprotoService';
|
||||
import { Api } from 'telegram';
|
||||
import { optString } from '../args';
|
||||
import type { ChatInviteResult } from '../apiResultTypes';
|
||||
import { narrow } from '../apiCastHelpers';
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: 'export_chat_invite',
|
||||
@@ -51,7 +52,7 @@ export async function exportChatInvite(
|
||||
);
|
||||
});
|
||||
|
||||
const link = (result as unknown as ChatInviteResult)?.link;
|
||||
const link = narrow<ChatInviteResult>(result)?.link;
|
||||
if (!link) {
|
||||
return { content: [{ type: 'text', text: 'Could not create invite link.' }], isError: true };
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { mtprotoService } from "../../../../services/mtprotoService";
|
||||
import { Api } from "telegram";
|
||||
import bigInt from "big-integer";
|
||||
import type { ApiUser } from "../apiResultTypes";
|
||||
import { toInputChannel, narrow } from "../apiCastHelpers";
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: "get_admins",
|
||||
@@ -44,7 +45,7 @@ export async function getAdmins(
|
||||
const inputChannel = await client.getInputEntity(entity);
|
||||
return client.invoke(
|
||||
new Api.channels.GetParticipants({
|
||||
channel: inputChannel as unknown as Api.TypeInputChannel,
|
||||
channel: toInputChannel(inputChannel),
|
||||
filter: new Api.ChannelParticipantsAdmins(),
|
||||
offset: 0,
|
||||
limit: 100,
|
||||
@@ -53,7 +54,7 @@ export async function getAdmins(
|
||||
);
|
||||
});
|
||||
if (result && "users" in result && Array.isArray(result.users)) {
|
||||
admins = result.users as unknown as ApiUser[];
|
||||
admins = narrow<ApiUser[]>(result.users);
|
||||
}
|
||||
} else {
|
||||
const result = await mtprotoService.withFloodWaitHandling(async () => {
|
||||
@@ -62,7 +63,7 @@ export async function getAdmins(
|
||||
);
|
||||
});
|
||||
if (result && "users" in result && Array.isArray(result.users)) {
|
||||
admins = result.users as unknown as ApiUser[];
|
||||
admins = narrow<ApiUser[]>(result.users);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import { Api } from "telegram";
|
||||
import { optNumber } from "../args";
|
||||
import bigInt from "big-integer";
|
||||
import type { ApiUser } from "../apiResultTypes";
|
||||
import { toInputChannel } from "../apiCastHelpers";
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: "get_banned_users",
|
||||
@@ -56,7 +57,7 @@ export async function getBannedUsers(
|
||||
const inputChannel = await client.getInputEntity(entity);
|
||||
return client.invoke(
|
||||
new Api.channels.GetParticipants({
|
||||
channel: inputChannel as unknown as Api.TypeInputChannel,
|
||||
channel: toInputChannel(inputChannel),
|
||||
filter: new Api.ChannelParticipantsKicked({ q: "" }),
|
||||
offset: 0,
|
||||
limit,
|
||||
|
||||
@@ -5,6 +5,7 @@ import { validateId } from '../../validation';
|
||||
import { mtprotoService } from '../../../../services/mtprotoService';
|
||||
import { Api } from 'telegram';
|
||||
import type { FullUserResult } from '../apiResultTypes';
|
||||
import { toInputUser, narrow } from "../apiCastHelpers";
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: "get_bot_info",
|
||||
@@ -29,12 +30,12 @@ export async function getBotInfo(
|
||||
const result = await mtprotoService.withFloodWaitHandling(async () => {
|
||||
const inputUser = await client.getInputEntity(botId);
|
||||
return client.invoke(
|
||||
new Api.users.GetFullUser({ id: inputUser as unknown as Api.TypeInputUser }),
|
||||
new Api.users.GetFullUser({ id: toInputUser(inputUser) }),
|
||||
);
|
||||
});
|
||||
|
||||
const fullUser = (result as unknown as FullUserResult)?.fullUser;
|
||||
const user = (result as unknown as FullUserResult)?.users?.[0];
|
||||
const fullUser = narrow<FullUserResult>(result)?.fullUser;
|
||||
const user = narrow<FullUserResult>(result)?.users?.[0];
|
||||
|
||||
if (!user) {
|
||||
return { content: [{ type: 'text', text: 'Bot not found: ' + botId }], isError: true };
|
||||
|
||||
@@ -5,6 +5,7 @@ import { mtprotoService } from '../../../../services/mtprotoService';
|
||||
import { Api } from 'telegram';
|
||||
import bigInt from 'big-integer';
|
||||
import type { ContactIdEntry } from '../apiResultTypes';
|
||||
import { narrow } from '../apiCastHelpers';
|
||||
|
||||
type ContactIdResult = number | ContactIdEntry;
|
||||
|
||||
@@ -29,7 +30,7 @@ export async function getContactIds(
|
||||
return { content: [{ type: 'text', text: 'No contact IDs found.' }] };
|
||||
}
|
||||
|
||||
const ids = (result as unknown as ContactIdResult[]).map((c) =>
|
||||
const ids = narrow<ContactIdResult[]>(result).map((c) =>
|
||||
String(typeof c === 'number' ? c : c.userId ?? c),
|
||||
);
|
||||
return { content: [{ type: 'text', text: ids.length + ' contacts:\n' + ids.join('\n') }] };
|
||||
|
||||
@@ -4,6 +4,7 @@ import { ErrorCategory, logAndFormatError } from '../../errorHandler';
|
||||
import { mtprotoService } from '../../../../services/mtprotoService';
|
||||
import { Api } from 'telegram';
|
||||
import type { UpdatesResult } from '../apiResultTypes';
|
||||
import { narrow } from "../apiCastHelpers";
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: "get_drafts",
|
||||
@@ -22,7 +23,7 @@ export async function getDrafts(
|
||||
return client.invoke(new Api.messages.GetAllDrafts());
|
||||
});
|
||||
|
||||
const updates = result as unknown as UpdatesResult;
|
||||
const updates = narrow<UpdatesResult>(result);
|
||||
if (!updates || !updates.updates || updates.updates.length === 0) {
|
||||
return { content: [{ type: 'text', text: 'No drafts found.' }] };
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { mtprotoService } from '../../../../services/mtprotoService';
|
||||
import { Api } from 'telegram';
|
||||
import { optNumber } from '../args';
|
||||
import type { InlineBotResults } from '../apiResultTypes';
|
||||
import { toInputUser, narrow } from "../apiCastHelpers";
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: "get_gif_search",
|
||||
@@ -34,7 +35,7 @@ export async function getGifSearch(
|
||||
const bot = await client.getInputEntity('gif');
|
||||
return client.invoke(
|
||||
new Api.messages.GetInlineBotResults({
|
||||
bot: bot as unknown as Api.TypeInputUser,
|
||||
bot: toInputUser(bot),
|
||||
peer: new Api.InputPeerSelf(),
|
||||
query,
|
||||
offset: '',
|
||||
@@ -42,7 +43,7 @@ export async function getGifSearch(
|
||||
);
|
||||
});
|
||||
|
||||
const results = (result as unknown as InlineBotResults)?.results;
|
||||
const results = narrow<InlineBotResults>(result)?.results;
|
||||
if (!results || !Array.isArray(results) || results.length === 0) {
|
||||
return { content: [{ type: 'text', text: 'No GIFs found for: ' + query }] };
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import { getChatById } from "../telegramApi";
|
||||
import { mtprotoService } from "../../../../services/mtprotoService";
|
||||
import { Api } from "telegram";
|
||||
import type { ChatInviteResult } from "../apiResultTypes";
|
||||
import { narrow } from "../apiCastHelpers";
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: "get_invite_link",
|
||||
@@ -46,7 +47,7 @@ export async function getInviteLink(
|
||||
);
|
||||
});
|
||||
|
||||
const link = (result as unknown as ChatInviteResult)?.link;
|
||||
const link = narrow<ChatInviteResult>(result)?.link;
|
||||
if (!link) {
|
||||
return {
|
||||
content: [{ type: "text", text: "Could not generate invite link." }],
|
||||
|
||||
@@ -6,6 +6,7 @@ import { getChatById } from '../telegramApi';
|
||||
import { mtprotoService } from '../../../../services/mtprotoService';
|
||||
import { Api } from 'telegram';
|
||||
import type { UpdatesResult } from '../apiResultTypes';
|
||||
import { narrow } from "../apiCastHelpers";
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: 'get_message_reactions',
|
||||
@@ -48,7 +49,7 @@ export async function getMessageReactions(
|
||||
);
|
||||
});
|
||||
|
||||
const updates = result as unknown as UpdatesResult;
|
||||
const updates = narrow<UpdatesResult>(result);
|
||||
if (!updates || !updates.updates || updates.updates.length === 0) {
|
||||
return { content: [{ type: 'text', text: 'No reactions found on message ' + messageId + '.' }] };
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import { Api } from "telegram";
|
||||
import { optNumber } from "../args";
|
||||
import bigInt from "big-integer";
|
||||
import type { ApiUser } from "../apiResultTypes";
|
||||
import { toInputChannel, narrow } from "../apiCastHelpers";
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: "get_participants",
|
||||
@@ -47,7 +48,7 @@ export async function getParticipants(
|
||||
const inputChannel = await client.getInputEntity(entity);
|
||||
return client.invoke(
|
||||
new Api.channels.GetParticipants({
|
||||
channel: inputChannel as unknown as Api.TypeInputChannel,
|
||||
channel: toInputChannel(inputChannel),
|
||||
filter: new Api.ChannelParticipantsRecent(),
|
||||
offset: 0,
|
||||
limit,
|
||||
@@ -56,7 +57,7 @@ export async function getParticipants(
|
||||
);
|
||||
});
|
||||
if (result && "users" in result && Array.isArray(result.users)) {
|
||||
participants = result.users as unknown as ApiUser[];
|
||||
participants = narrow<ApiUser[]>(result.users);
|
||||
}
|
||||
} else {
|
||||
const result = await mtprotoService.withFloodWaitHandling(async () => {
|
||||
@@ -65,7 +66,7 @@ export async function getParticipants(
|
||||
);
|
||||
});
|
||||
if (result && "users" in result && Array.isArray(result.users)) {
|
||||
participants = result.users as unknown as ApiUser[];
|
||||
participants = narrow<ApiUser[]>(result.users);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import { mtprotoService } from '../../../../services/mtprotoService';
|
||||
import { Api } from 'telegram';
|
||||
import bigInt from 'big-integer';
|
||||
import type { ApiMessage } from '../apiResultTypes';
|
||||
import { narrow } from '../apiCastHelpers';
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: 'get_pinned_messages',
|
||||
@@ -54,7 +55,7 @@ export async function getPinnedMessages(
|
||||
);
|
||||
|
||||
if ('messages' in result && Array.isArray(result.messages)) {
|
||||
pinnedLines = (result.messages as unknown as ApiMessage[]).map((msg) => {
|
||||
pinnedLines = narrow<ApiMessage[]>(result.messages).map((msg) => {
|
||||
const id = msg.id ?? '?';
|
||||
const text = msg.message ?? '[Media/No text]';
|
||||
const date = msg.date ? new Date(msg.date * 1000).toISOString() : 'unknown';
|
||||
@@ -65,7 +66,7 @@ export async function getPinnedMessages(
|
||||
// Fallback: check cached messages for pinned flag
|
||||
const allMessages = await getMessages(chatId, 500, 0);
|
||||
if (allMessages) {
|
||||
const pinned = allMessages.filter((m) => (m as unknown as ApiMessage).pinned);
|
||||
const pinned = allMessages.filter((m) => narrow<ApiMessage>(m).pinned);
|
||||
pinnedLines = pinned.map((msg) => {
|
||||
const f = formatMessage(msg);
|
||||
return `ID: ${f.id} | Date: ${f.date} | ${f.text || '[Media/No text]'}`;
|
||||
|
||||
@@ -4,6 +4,7 @@ import { ErrorCategory, logAndFormatError } from '../../errorHandler';
|
||||
import { mtprotoService } from '../../../../services/mtprotoService';
|
||||
import { Api } from 'telegram';
|
||||
import type { PrivacyResult } from '../apiResultTypes';
|
||||
import { narrow } from "../apiCastHelpers";
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: "get_privacy_settings",
|
||||
@@ -42,7 +43,7 @@ export async function getPrivacySettings(
|
||||
return client.invoke(new Api.account.GetPrivacy({ key }));
|
||||
});
|
||||
|
||||
const rules = (result as unknown as PrivacyResult)?.rules;
|
||||
const rules = narrow<PrivacyResult>(result)?.rules;
|
||||
if (!rules || !Array.isArray(rules)) {
|
||||
return { content: [{ type: 'text', text: 'No privacy rules found for ' + keyStr + '.' }] };
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import { Api } from 'telegram';
|
||||
import bigInt from 'big-integer';
|
||||
import { optNumber } from '../args';
|
||||
import type { AdminLogResult } from '../apiResultTypes';
|
||||
import { toInputChannel, narrow } from "../apiCastHelpers";
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: "get_recent_actions",
|
||||
@@ -44,7 +45,7 @@ export async function getRecentActions(
|
||||
const inputChannel = await client.getInputEntity(entity);
|
||||
return client.invoke(
|
||||
new Api.channels.GetAdminLog({
|
||||
channel: inputChannel as unknown as Api.TypeInputChannel,
|
||||
channel: toInputChannel(inputChannel),
|
||||
q: '',
|
||||
maxId: bigInt(0),
|
||||
minId: bigInt(0),
|
||||
@@ -53,7 +54,7 @@ export async function getRecentActions(
|
||||
);
|
||||
});
|
||||
|
||||
const events = (result as unknown as AdminLogResult)?.events;
|
||||
const events = narrow<AdminLogResult>(result)?.events;
|
||||
if (!events || !Array.isArray(events) || events.length === 0) {
|
||||
return { content: [{ type: 'text', text: 'No recent actions found.' }] };
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { mtprotoService } from '../../../../services/mtprotoService';
|
||||
import { Api } from 'telegram';
|
||||
import bigInt from 'big-integer';
|
||||
import type { StickerSetsResult } from '../apiResultTypes';
|
||||
import { narrow } from "../apiCastHelpers";
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: "get_sticker_sets",
|
||||
@@ -23,7 +24,7 @@ export async function getStickerSets(
|
||||
return client.invoke(new Api.messages.GetAllStickers({ hash: bigInt(0) }));
|
||||
});
|
||||
|
||||
const sets = (result as unknown as StickerSetsResult)?.sets;
|
||||
const sets = narrow<StickerSetsResult>(result)?.sets;
|
||||
if (!sets || !Array.isArray(sets) || sets.length === 0) {
|
||||
return { content: [{ type: 'text', text: 'No sticker sets found.' }] };
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { Api } from 'telegram';
|
||||
import bigInt from 'big-integer';
|
||||
import { optNumber } from '../args';
|
||||
import type { ApiPhoto } from '../apiResultTypes';
|
||||
import { toInputUser, narrow } from "../apiCastHelpers";
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: 'get_user_photos',
|
||||
@@ -34,7 +35,7 @@ export async function getUserPhotos(
|
||||
const inputUser = await client.getInputEntity(userId);
|
||||
return client.invoke(
|
||||
new Api.photos.GetUserPhotos({
|
||||
userId: inputUser as unknown as Api.TypeInputUser,
|
||||
userId: toInputUser(inputUser),
|
||||
offset: 0,
|
||||
maxId: bigInt(0),
|
||||
limit,
|
||||
@@ -46,7 +47,7 @@ export async function getUserPhotos(
|
||||
return { content: [{ type: 'text', text: 'No photos found.' }] };
|
||||
}
|
||||
|
||||
const lines = (result.photos as unknown as ApiPhoto[]).map((photo, i: number) => {
|
||||
const lines = narrow<ApiPhoto[]>(result.photos).map((photo, i: number) => {
|
||||
const date = photo.date ? new Date(photo.date * 1000).toISOString() : 'unknown';
|
||||
return 'Photo ' + (i + 1) + ': ID ' + photo.id + ' | Date: ' + date;
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@ import { validateId } from '../../validation';
|
||||
import { mtprotoService } from '../../../../services/mtprotoService';
|
||||
import { Api } from 'telegram';
|
||||
import type { ApiUser } from '../apiResultTypes';
|
||||
import { toInputUser, narrow } from "../apiCastHelpers";
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: 'get_user_status',
|
||||
@@ -29,7 +30,7 @@ export async function getUserStatus(
|
||||
const result = await mtprotoService.withFloodWaitHandling(async () => {
|
||||
const inputUser = await client.getInputEntity(userId);
|
||||
return client.invoke(
|
||||
new Api.users.GetUsers({ id: [inputUser as unknown as Api.TypeInputUser] }),
|
||||
new Api.users.GetUsers({ id: [toInputUser(inputUser)] }),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -37,7 +38,7 @@ export async function getUserStatus(
|
||||
return { content: [{ type: 'text', text: 'User ' + userId + ' not found.' }], isError: true };
|
||||
}
|
||||
|
||||
const user = result[0] as unknown as ApiUser;
|
||||
const user = narrow<ApiUser>(result[0]);
|
||||
const name = [user.firstName, user.lastName].filter(Boolean).join(' ') || 'Unknown';
|
||||
let statusText = 'unknown';
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import { ErrorCategory, logAndFormatError } from "../../errorHandler";
|
||||
import { mtprotoService } from "../../../../services/mtprotoService";
|
||||
import { Api } from "telegram";
|
||||
import type { ResultWithChats } from "../apiResultTypes";
|
||||
import { narrow } from "../apiCastHelpers";
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: "import_chat_invite",
|
||||
@@ -38,7 +39,7 @@ export async function importChatInvite(
|
||||
return client.invoke(new Api.messages.ImportChatInvite({ hash }));
|
||||
});
|
||||
|
||||
const chatTitle = (result as unknown as ResultWithChats)?.chats?.[0]?.title ?? "unknown";
|
||||
const chatTitle = narrow<ResultWithChats>(result)?.chats?.[0]?.title ?? "unknown";
|
||||
return { content: [{ type: "text", text: `Joined chat: ${chatTitle}` }] };
|
||||
} catch (error) {
|
||||
return logAndFormatError(
|
||||
|
||||
@@ -5,6 +5,7 @@ import { mtprotoService } from "../../../../services/mtprotoService";
|
||||
import { Api } from "telegram";
|
||||
import bigInt from "big-integer";
|
||||
import type { ContactInput, ImportContactsResult } from "../apiResultTypes";
|
||||
import { narrow } from "../apiCastHelpers";
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: "import_contacts",
|
||||
@@ -66,7 +67,7 @@ export async function importContacts(
|
||||
);
|
||||
});
|
||||
|
||||
const imported = (result as unknown as ImportContactsResult)?.imported?.length ?? 0;
|
||||
const imported = narrow<ImportContactsResult>(result)?.imported?.length ?? 0;
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@ import { getChatById } from "../telegramApi";
|
||||
import { mtprotoService } from "../../../../services/mtprotoService";
|
||||
import { Api } from "telegram";
|
||||
import bigInt from "big-integer";
|
||||
import { toInputChannel, toInputUser } from "../apiCastHelpers";
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: "invite_to_group",
|
||||
@@ -50,7 +51,7 @@ export async function inviteToGroup(
|
||||
const users: Api.TypeInputUser[] = [];
|
||||
for (const uid of userIds) {
|
||||
const inputUser = await client.getInputEntity(String(uid));
|
||||
users.push(inputUser as unknown as Api.TypeInputUser);
|
||||
users.push(toInputUser(inputUser));
|
||||
}
|
||||
|
||||
const inputPeer = await client.getInputEntity(entity);
|
||||
@@ -59,7 +60,7 @@ export async function inviteToGroup(
|
||||
await mtprotoService.withFloodWaitHandling(async () => {
|
||||
await client.invoke(
|
||||
new Api.channels.InviteToChannel({
|
||||
channel: inputPeer as unknown as Api.TypeInputChannel,
|
||||
channel: toInputChannel(inputPeer),
|
||||
users,
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -4,6 +4,7 @@ import { ErrorCategory, logAndFormatError } from '../../errorHandler';
|
||||
import { mtprotoService } from '../../../../services/mtprotoService';
|
||||
import { Api } from 'telegram';
|
||||
import type { ResultWithChats } from '../apiResultTypes';
|
||||
import { narrow } from '../apiCastHelpers';
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: 'join_chat_by_link',
|
||||
@@ -38,7 +39,7 @@ export async function joinChatByLink(
|
||||
return client.invoke(new Api.messages.ImportChatInvite({ hash }));
|
||||
});
|
||||
|
||||
const chatTitle = (result as unknown as ResultWithChats)?.chats?.[0]?.title ?? 'unknown';
|
||||
const chatTitle = narrow<ResultWithChats>(result)?.chats?.[0]?.title ?? 'unknown';
|
||||
return { content: [{ type: 'text', text: `Joined chat: ${chatTitle}` }] };
|
||||
} catch (error) {
|
||||
return logAndFormatError(
|
||||
|
||||
@@ -6,6 +6,7 @@ import { getChatById } from "../telegramApi";
|
||||
import { mtprotoService } from "../../../../services/mtprotoService";
|
||||
import { Api } from "telegram";
|
||||
import bigInt from "big-integer";
|
||||
import { toInputChannel } from "../apiCastHelpers";
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: "leave_chat",
|
||||
@@ -41,7 +42,7 @@ export async function leaveChat(
|
||||
const inputChannel = await client.getInputEntity(entity);
|
||||
await client.invoke(
|
||||
new Api.channels.LeaveChannel({
|
||||
channel: inputChannel as unknown as Api.TypeInputChannel,
|
||||
channel: toInputChannel(inputChannel),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -4,6 +4,7 @@ import { ErrorCategory, logAndFormatError } from '../../errorHandler';
|
||||
import { validateId } from '../../validation';
|
||||
import { getChatById, getMessages } from '../telegramApi';
|
||||
import type { MessageWithReplyMarkup, ReplyMarkupRow } from '../apiResultTypes';
|
||||
import { narrow } from '../apiCastHelpers';
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: "list_inline_buttons",
|
||||
@@ -36,7 +37,8 @@ export async function listInlineButtons(
|
||||
const messages = await getMessages(chatId, 200, 0);
|
||||
if (!messages) return { content: [{ type: 'text', text: 'No messages found.' }] };
|
||||
|
||||
const msg = messages.find((m) => String(m.id) === String(messageId)) as unknown as MessageWithReplyMarkup | undefined;
|
||||
const found = messages.find((m) => String(m.id) === String(messageId));
|
||||
const msg = found ? narrow<MessageWithReplyMarkup>(found) : undefined;
|
||||
if (!msg) return { content: [{ type: 'text', text: 'Message ' + messageId + ' not found in cache.' }], isError: true };
|
||||
|
||||
if (!msg.replyMarkup || !msg.replyMarkup.rows) {
|
||||
|
||||
@@ -6,6 +6,7 @@ import { getChatById } from '../telegramApi';
|
||||
import { mtprotoService } from '../../../../services/mtprotoService';
|
||||
import { Api } from 'telegram';
|
||||
import type { ForumTopicsResult } from '../apiResultTypes';
|
||||
import { toInputChannel, narrow } from "../apiCastHelpers";
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: 'list_topics',
|
||||
@@ -34,7 +35,7 @@ export async function listTopics(
|
||||
const inputChannel = await client.getInputEntity(entity);
|
||||
return client.invoke(
|
||||
new Api.channels.GetForumTopics({
|
||||
channel: inputChannel as unknown as Api.TypeInputChannel,
|
||||
channel: toInputChannel(inputChannel),
|
||||
offsetDate: 0,
|
||||
offsetId: 0,
|
||||
offsetTopic: 0,
|
||||
@@ -43,7 +44,7 @@ export async function listTopics(
|
||||
);
|
||||
});
|
||||
|
||||
const topics = (result as unknown as ForumTopicsResult)?.topics;
|
||||
const topics = narrow<ForumTopicsResult>(result)?.topics;
|
||||
if (!topics || !Array.isArray(topics) || topics.length === 0) {
|
||||
return { content: [{ type: 'text', text: 'No forum topics found.' }] };
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import { getChatById } from '../telegramApi';
|
||||
import { mtprotoService } from '../../../../services/mtprotoService';
|
||||
import { Api } from 'telegram';
|
||||
import type { BotCallbackAnswer } from '../apiResultTypes';
|
||||
import { narrow } from "../apiCastHelpers";
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: "press_inline_button",
|
||||
@@ -52,7 +53,7 @@ export async function pressInlineButton(
|
||||
);
|
||||
});
|
||||
|
||||
const answer = (result as unknown as BotCallbackAnswer)?.message ?? 'Button pressed (no response message).';
|
||||
const answer = narrow<BotCallbackAnswer>(result)?.message ?? 'Button pressed (no response message).';
|
||||
return { content: [{ type: 'text', text: answer }] };
|
||||
} catch (error) {
|
||||
return logAndFormatError(
|
||||
|
||||
@@ -5,6 +5,7 @@ import { validateId } from "../../validation";
|
||||
import { getChatById } from "../telegramApi";
|
||||
import { mtprotoService } from "../../../../services/mtprotoService";
|
||||
import { Api } from "telegram";
|
||||
import { toInputChannel, toInputUser } from "../apiCastHelpers";
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: "promote_admin",
|
||||
@@ -54,8 +55,8 @@ export async function promoteAdmin(
|
||||
const inputUser = await client.getInputEntity(userId);
|
||||
await client.invoke(
|
||||
new Api.channels.EditAdmin({
|
||||
channel: inputChannel as unknown as Api.TypeInputChannel,
|
||||
userId: inputUser as unknown as Api.TypeInputUser,
|
||||
channel: toInputChannel(inputChannel),
|
||||
userId: toInputUser(inputUser),
|
||||
adminRights: new Api.ChatAdminRights({
|
||||
changeInfo: true,
|
||||
deleteMessages: true,
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { TelegramMCPContext } from "../types";
|
||||
import { ErrorCategory, logAndFormatError } from "../../errorHandler";
|
||||
import { mtprotoService } from "../../../../services/mtprotoService";
|
||||
import { Api } from "telegram";
|
||||
import { toInputChannel } from "../apiCastHelpers";
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: "subscribe_public_channel",
|
||||
@@ -34,7 +35,7 @@ export async function subscribePublicChannel(
|
||||
const inputChannel = await client.getInputEntity(username);
|
||||
await client.invoke(
|
||||
new Api.channels.JoinChannel({
|
||||
channel: inputChannel as unknown as Api.TypeInputChannel,
|
||||
channel: toInputChannel(inputChannel),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@ import { validateId } from '../../validation';
|
||||
import { getChatById } from '../telegramApi';
|
||||
import { mtprotoService } from '../../../../services/mtprotoService';
|
||||
import { Api } from 'telegram';
|
||||
import { toInputChannel, toInputPeer } from '../apiCastHelpers';
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: 'unban_user',
|
||||
@@ -42,8 +43,8 @@ export async function unbanUser(
|
||||
const inputUser = await client.getInputEntity(userId);
|
||||
await client.invoke(
|
||||
new Api.channels.EditBanned({
|
||||
channel: inputChannel as unknown as Api.TypeInputChannel,
|
||||
participant: inputUser as unknown as Api.TypeInputPeer,
|
||||
channel: toInputChannel(inputChannel),
|
||||
participant: toInputPeer(inputUser),
|
||||
bannedRights: new Api.ChatBannedRights({ untilDate: 0 }),
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -4,6 +4,7 @@ import { ErrorCategory, logAndFormatError } from '../../errorHandler';
|
||||
import { validateId } from '../../validation';
|
||||
import { mtprotoService } from '../../../../services/mtprotoService';
|
||||
import { Api } from 'telegram';
|
||||
import { toInputPeer } from '../apiCastHelpers';
|
||||
|
||||
export const tool: MCPTool = {
|
||||
name: 'unblock_user',
|
||||
@@ -28,7 +29,7 @@ export async function unblockUser(
|
||||
await mtprotoService.withFloodWaitHandling(async () => {
|
||||
const inputUser = await client.getInputEntity(userId);
|
||||
await client.invoke(
|
||||
new Api.contacts.Unblock({ id: inputUser as unknown as Api.TypeInputPeer }),
|
||||
new Api.contacts.Unblock({ id: toInputPeer(inputUser) }),
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user