bn-telegram-mcp-server 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1031 -0
- package/dist/debug-middleware.d.ts +12 -0
- package/dist/debug-middleware.d.ts.map +1 -0
- package/dist/debug-middleware.js +36 -0
- package/dist/debug-middleware.js.map +1 -0
- package/dist/encryption.d.ts +11 -0
- package/dist/encryption.d.ts.map +1 -0
- package/dist/encryption.js +26 -0
- package/dist/encryption.js.map +1 -0
- package/dist/helpers.d.ts +27 -0
- package/dist/helpers.d.ts.map +1 -0
- package/dist/helpers.js +103 -0
- package/dist/helpers.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +176 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +29 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +114 -0
- package/dist/logger.js.map +1 -0
- package/dist/request-context.d.ts +24 -0
- package/dist/request-context.d.ts.map +1 -0
- package/dist/request-context.js +32 -0
- package/dist/request-context.js.map +1 -0
- package/dist/resolvers.d.ts +36 -0
- package/dist/resolvers.d.ts.map +1 -0
- package/dist/resolvers.js +252 -0
- package/dist/resolvers.js.map +1 -0
- package/dist/schemas.d.ts +150 -0
- package/dist/schemas.d.ts.map +1 -0
- package/dist/schemas.js +216 -0
- package/dist/schemas.js.map +1 -0
- package/dist/telegram-client.d.ts +19 -0
- package/dist/telegram-client.d.ts.map +1 -0
- package/dist/telegram-client.js +112 -0
- package/dist/telegram-client.js.map +1 -0
- package/dist/tool-loader.d.ts +31 -0
- package/dist/tool-loader.d.ts.map +1 -0
- package/dist/tool-loader.js +121 -0
- package/dist/tool-loader.js.map +1 -0
- package/dist/tool-registry.d.ts +47 -0
- package/dist/tool-registry.d.ts.map +1 -0
- package/dist/tool-registry.js +58 -0
- package/dist/tool-registry.js.map +1 -0
- package/dist/tools/getChat.d.ts +28 -0
- package/dist/tools/getChat.d.ts.map +1 -0
- package/dist/tools/getChat.js +69 -0
- package/dist/tools/getChat.js.map +1 -0
- package/dist/tools/getChatMembers.d.ts +34 -0
- package/dist/tools/getChatMembers.d.ts.map +1 -0
- package/dist/tools/getChatMembers.js +150 -0
- package/dist/tools/getChatMembers.js.map +1 -0
- package/dist/tools/getContacts.d.ts +28 -0
- package/dist/tools/getContacts.d.ts.map +1 -0
- package/dist/tools/getContacts.js +73 -0
- package/dist/tools/getContacts.js.map +1 -0
- package/dist/tools/getFile.d.ts +21 -0
- package/dist/tools/getFile.d.ts.map +1 -0
- package/dist/tools/getFile.js +33 -0
- package/dist/tools/getFile.js.map +1 -0
- package/dist/tools/getGroup.d.ts +27 -0
- package/dist/tools/getGroup.d.ts.map +1 -0
- package/dist/tools/getGroup.js +100 -0
- package/dist/tools/getGroup.js.map +1 -0
- package/dist/tools/getMe.d.ts +17 -0
- package/dist/tools/getMe.d.ts.map +1 -0
- package/dist/tools/getMe.js +20 -0
- package/dist/tools/getMe.js.map +1 -0
- package/dist/tools/getMessageContext.d.ts +21 -0
- package/dist/tools/getMessageContext.d.ts.map +1 -0
- package/dist/tools/getMessageContext.js +164 -0
- package/dist/tools/getMessageContext.js.map +1 -0
- package/dist/tools/getMessages.d.ts +38 -0
- package/dist/tools/getMessages.d.ts.map +1 -0
- package/dist/tools/getMessages.js +123 -0
- package/dist/tools/getMessages.js.map +1 -0
- package/dist/tools/getUser.d.ts +22 -0
- package/dist/tools/getUser.d.ts.map +1 -0
- package/dist/tools/getUser.js +38 -0
- package/dist/tools/getUser.js.map +1 -0
- package/dist/tools/index.d.ts +11 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +12 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/sendMessage.d.ts +39 -0
- package/dist/tools/sendMessage.d.ts.map +1 -0
- package/dist/tools/sendMessage.js +116 -0
- package/dist/tools/sendMessage.js.map +1 -0
- package/dist/transformers.d.ts +133 -0
- package/dist/transformers.d.ts.map +1 -0
- package/dist/transformers.js +335 -0
- package/dist/transformers.js.map +1 -0
- package/dist/types.d.ts +55 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +45 -0
- package/tools.json +252 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ToolResponse } from "./types.js";
|
|
2
|
+
export declare const DEBUG_MODE: boolean;
|
|
3
|
+
/**
|
|
4
|
+
* Wraps a tool execution with debug metadata when DEBUG mode is enabled.
|
|
5
|
+
*
|
|
6
|
+
* @param toolName - Name of the tool being executed
|
|
7
|
+
* @param toolInput - Input arguments passed to the tool
|
|
8
|
+
* @param executeToolFn - Async function that executes the tool and returns data
|
|
9
|
+
* @returns ToolResponse with data and optional debug metadata
|
|
10
|
+
*/
|
|
11
|
+
export declare function wrapWithDebug<T>(toolName: string, toolInput: unknown, executeToolFn: () => Promise<T>): Promise<ToolResponse<T>>;
|
|
12
|
+
//# sourceMappingURL=debug-middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debug-middleware.d.ts","sourceRoot":"","sources":["../src/debug-middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,YAAY,EAAE,MAAM,YAAY,CAAC;AAG9D,eAAO,MAAM,UAAU,SAA+B,CAAC;AAEvD;;;;;;;GAOG;AACH,wBAAsB,aAAa,CAAC,CAAC,EACnC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,OAAO,EAClB,aAAa,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAC9B,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CA0B1B"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Check if DEBUG mode is enabled via environment variable
|
|
2
|
+
export const DEBUG_MODE = process.env.DEBUG === "true";
|
|
3
|
+
/**
|
|
4
|
+
* Wraps a tool execution with debug metadata when DEBUG mode is enabled.
|
|
5
|
+
*
|
|
6
|
+
* @param toolName - Name of the tool being executed
|
|
7
|
+
* @param toolInput - Input arguments passed to the tool
|
|
8
|
+
* @param executeToolFn - Async function that executes the tool and returns data
|
|
9
|
+
* @returns ToolResponse with data and optional debug metadata
|
|
10
|
+
*/
|
|
11
|
+
export async function wrapWithDebug(toolName, toolInput, executeToolFn) {
|
|
12
|
+
const startTime = performance.now();
|
|
13
|
+
try {
|
|
14
|
+
const data = await executeToolFn();
|
|
15
|
+
const endTime = performance.now();
|
|
16
|
+
const toolCallTime = endTime - startTime;
|
|
17
|
+
if (DEBUG_MODE) {
|
|
18
|
+
return {
|
|
19
|
+
data,
|
|
20
|
+
debug: {
|
|
21
|
+
toolName,
|
|
22
|
+
toolInput,
|
|
23
|
+
toolCallTime,
|
|
24
|
+
timestamp: new Date().toISOString(),
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
// In non-debug mode, return just the data wrapped
|
|
29
|
+
return { data };
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
// Re-throw the error to be handled by caller
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=debug-middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debug-middleware.js","sourceRoot":"","sources":["../src/debug-middleware.ts"],"names":[],"mappings":"AAEA,0DAA0D;AAC1D,MAAM,CAAC,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,MAAM,CAAC;AAEvD;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,QAAgB,EAChB,SAAkB,EAClB,aAA+B;IAE/B,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IAEpC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,aAAa,EAAE,CAAC;QACnC,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAClC,MAAM,YAAY,GAAG,OAAO,GAAG,SAAS,CAAC;QAEzC,IAAI,UAAU,EAAE,CAAC;YACf,OAAO;gBACL,IAAI;gBACJ,KAAK,EAAE;oBACL,QAAQ;oBACR,SAAS;oBACT,YAAY;oBACZ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;iBACpC;aACF,CAAC;QACJ,CAAC;QAED,kDAAkD;QAClD,OAAO,EAAE,IAAI,EAAE,CAAC;IAClB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,6CAA6C;QAC7C,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decode the binlog from base64 format
|
|
3
|
+
*
|
|
4
|
+
* BlueNexus stores the TDLib binlog as raw base64 in providerData.binlog.
|
|
5
|
+
* This function simply decodes the base64 string to get the raw binlog bytes.
|
|
6
|
+
*
|
|
7
|
+
* @param base64Binlog - The base64-encoded binlog from the request body
|
|
8
|
+
* @returns Decoded binlog as Buffer
|
|
9
|
+
*/
|
|
10
|
+
export declare function decodeBinlog(base64Binlog: string): Buffer;
|
|
11
|
+
//# sourceMappingURL=encryption.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encryption.d.ts","sourceRoot":"","sources":["../src/encryption.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAmBzD"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decode the binlog from base64 format
|
|
3
|
+
*
|
|
4
|
+
* BlueNexus stores the TDLib binlog as raw base64 in providerData.binlog.
|
|
5
|
+
* This function simply decodes the base64 string to get the raw binlog bytes.
|
|
6
|
+
*
|
|
7
|
+
* @param base64Binlog - The base64-encoded binlog from the request body
|
|
8
|
+
* @returns Decoded binlog as Buffer
|
|
9
|
+
*/
|
|
10
|
+
export function decodeBinlog(base64Binlog) {
|
|
11
|
+
if (!base64Binlog || base64Binlog.trim() === "") {
|
|
12
|
+
throw new Error("Invalid binlog: empty or missing");
|
|
13
|
+
}
|
|
14
|
+
// Validate base64 format
|
|
15
|
+
const base64Regex = /^[A-Za-z0-9+/]*={0,2}$/;
|
|
16
|
+
if (!base64Regex.test(base64Binlog)) {
|
|
17
|
+
throw new Error("Invalid binlog: not a valid base64 string");
|
|
18
|
+
}
|
|
19
|
+
// Decode the base64 string to get raw binlog bytes
|
|
20
|
+
const buffer = Buffer.from(base64Binlog, "base64");
|
|
21
|
+
if (buffer.length === 0) {
|
|
22
|
+
throw new Error("Invalid binlog: decoded to empty buffer");
|
|
23
|
+
}
|
|
24
|
+
return buffer;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=encryption.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encryption.js","sourceRoot":"","sources":["../src/encryption.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,UAAU,YAAY,CAAC,YAAoB;IAC/C,IAAI,CAAC,YAAY,IAAI,YAAY,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QAChD,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;IAED,yBAAyB;IACzB,MAAM,WAAW,GAAG,wBAAwB,CAAC;IAC7C,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC/D,CAAC;IAED,mDAAmD;IACnD,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;IAEnD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;IAC7D,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Request } from "express";
|
|
2
|
+
import type { Client } from "tdl";
|
|
3
|
+
/**
|
|
4
|
+
* Get a TDLib client for the current request
|
|
5
|
+
*
|
|
6
|
+
* This function:
|
|
7
|
+
* 1. Extracts credentials and config from request headers
|
|
8
|
+
* 2. Generates a session ID from the access token
|
|
9
|
+
* 3. Decodes the base64-encoded binlog
|
|
10
|
+
* 4. Creates a TDLib client with the restored session
|
|
11
|
+
*
|
|
12
|
+
* @param req - Express request object
|
|
13
|
+
* @returns Object containing the TDLib client and session ID
|
|
14
|
+
*/
|
|
15
|
+
export declare function getClientForRequest(req: Request): Promise<{
|
|
16
|
+
client: Client;
|
|
17
|
+
sessionId: string;
|
|
18
|
+
}>;
|
|
19
|
+
/**
|
|
20
|
+
* Execute a tool with automatic client cleanup
|
|
21
|
+
*
|
|
22
|
+
* @param req - Express request object
|
|
23
|
+
* @param toolFn - Function to execute with the client
|
|
24
|
+
* @returns Result of the tool function
|
|
25
|
+
*/
|
|
26
|
+
export declare function withClient<T>(req: Request, toolFn: (client: Client) => Promise<T>): Promise<T>;
|
|
27
|
+
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAIvC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAwElC;;;;;;;;;;;GAWG;AACH,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC;IAC/D,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC,CAkBD;AAED;;;;;;GAMG;AACH,wBAAsB,UAAU,CAAC,CAAC,EAChC,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,GACrC,OAAO,CAAC,CAAC,CAAC,CA0BZ"}
|
package/dist/helpers.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import crypto from "crypto";
|
|
2
|
+
import { decodeBinlog } from "./encryption.js";
|
|
3
|
+
import { createTelegramClient, cleanupSession } from "./telegram-client.js";
|
|
4
|
+
import { createLogger } from "./logger.js";
|
|
5
|
+
const logger = createLogger("Helpers");
|
|
6
|
+
/**
|
|
7
|
+
* Extract Telegram credentials and config from request
|
|
8
|
+
*
|
|
9
|
+
* Expected headers:
|
|
10
|
+
* - Authorization: Bearer <accessToken>
|
|
11
|
+
* - X-Telegram-Api-Id: <API ID> (or fallback to env TELEGRAM_API_ID)
|
|
12
|
+
* - X-Telegram-Api-Hash: <API Hash> (or fallback to env TELEGRAM_API_HASH)
|
|
13
|
+
*
|
|
14
|
+
* The binlog is passed in the request body as _telegramBinlog but
|
|
15
|
+
* extracted and stored on req._telegramBinlog by index.ts before SDK processing
|
|
16
|
+
* (the MCP SDK's Zod validation rejects unrecognized keys in the body).
|
|
17
|
+
* The binlog is base64-encoded (NOT encrypted).
|
|
18
|
+
*/
|
|
19
|
+
function extractCredentials(req) {
|
|
20
|
+
const authHeader = req.headers.authorization;
|
|
21
|
+
if (!authHeader?.toLowerCase().startsWith("bearer ")) {
|
|
22
|
+
throw new Error("Missing or invalid Authorization header. Expected format: Bearer <token>");
|
|
23
|
+
}
|
|
24
|
+
const accessToken = authHeader.substring(7).trim();
|
|
25
|
+
// Get binlog from request object (extracted from body by index.ts)
|
|
26
|
+
const binlog = req._telegramBinlog;
|
|
27
|
+
if (!binlog) {
|
|
28
|
+
throw new Error("Missing _telegramBinlog. This field must be sent in the request body and contains the base64-encoded TDLib session binlog.");
|
|
29
|
+
}
|
|
30
|
+
// Get API credentials from headers first, then fallback to env vars
|
|
31
|
+
const apiIdHeader = req.headers["x-telegram-api-id"];
|
|
32
|
+
const apiHashHeader = req.headers["x-telegram-api-hash"];
|
|
33
|
+
const apiId = parseInt(apiIdHeader || process.env.TELEGRAM_API_ID || "0", 10);
|
|
34
|
+
const apiHash = apiHashHeader || process.env.TELEGRAM_API_HASH || "";
|
|
35
|
+
// Validate required config
|
|
36
|
+
if (!apiId || apiId === 0) {
|
|
37
|
+
throw new Error("Telegram API ID not provided. Set X-Telegram-Api-Id header or TELEGRAM_API_ID environment variable.");
|
|
38
|
+
}
|
|
39
|
+
if (!apiHash) {
|
|
40
|
+
throw new Error("Telegram API Hash not provided. Set X-Telegram-Api-Hash header or TELEGRAM_API_HASH environment variable.");
|
|
41
|
+
}
|
|
42
|
+
return { apiId, apiHash, accessToken, binlog };
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Get a TDLib client for the current request
|
|
46
|
+
*
|
|
47
|
+
* This function:
|
|
48
|
+
* 1. Extracts credentials and config from request headers
|
|
49
|
+
* 2. Generates a session ID from the access token
|
|
50
|
+
* 3. Decodes the base64-encoded binlog
|
|
51
|
+
* 4. Creates a TDLib client with the restored session
|
|
52
|
+
*
|
|
53
|
+
* @param req - Express request object
|
|
54
|
+
* @returns Object containing the TDLib client and session ID
|
|
55
|
+
*/
|
|
56
|
+
export async function getClientForRequest(req) {
|
|
57
|
+
const { apiId, apiHash, accessToken, binlog: base64Binlog } = extractCredentials(req);
|
|
58
|
+
// Generate session ID from access token (for temp directory isolation)
|
|
59
|
+
const sessionId = crypto
|
|
60
|
+
.createHash("sha256")
|
|
61
|
+
.update(accessToken)
|
|
62
|
+
.digest("hex")
|
|
63
|
+
.substring(0, 16);
|
|
64
|
+
// Decode base64-encoded binlog
|
|
65
|
+
const binlog = decodeBinlog(base64Binlog);
|
|
66
|
+
// Create TDLib client with restored session
|
|
67
|
+
const client = await createTelegramClient(sessionId, binlog, apiId, apiHash);
|
|
68
|
+
return { client, sessionId };
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Execute a tool with automatic client cleanup
|
|
72
|
+
*
|
|
73
|
+
* @param req - Express request object
|
|
74
|
+
* @param toolFn - Function to execute with the client
|
|
75
|
+
* @returns Result of the tool function
|
|
76
|
+
*/
|
|
77
|
+
export async function withClient(req, toolFn) {
|
|
78
|
+
const { client, sessionId } = await getClientForRequest(req);
|
|
79
|
+
try {
|
|
80
|
+
return await toolFn(client);
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
// Ensure client is fully closed before cleanup
|
|
84
|
+
let clientClosed = false;
|
|
85
|
+
try {
|
|
86
|
+
await client.close();
|
|
87
|
+
clientClosed = true;
|
|
88
|
+
}
|
|
89
|
+
catch (closeError) {
|
|
90
|
+
logger.warn("Failed to close TDLib client", {
|
|
91
|
+
sessionId,
|
|
92
|
+
error: closeError instanceof Error ? closeError : new Error(String(closeError)),
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
// Only cleanup session files after client is closed
|
|
96
|
+
// Add a small delay to ensure TDLib releases file handles
|
|
97
|
+
if (clientClosed) {
|
|
98
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
99
|
+
}
|
|
100
|
+
await cleanupSession(sessionId);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
4
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
5
|
+
import express from "express";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
// Import schemas
|
|
8
|
+
import { GetMeSchema, GetChatSchema, GetMessagesSchema, SendMessageSchema, GetUserSchema, GetContactsSchema, GetFileSchema, GetGroupSchema, GetChatMembersSchema, GetMessageContextSchema, } from "./schemas.js";
|
|
9
|
+
// Import tool handlers
|
|
10
|
+
import { getMe, getChat, getMessages, sendMessage, getUser, getContacts, getFile, getGroup, getChatMembers, getMessageContext, } from "./tools/index.js";
|
|
11
|
+
// Import tool loader
|
|
12
|
+
import { loadToolDefinitions } from "./tool-loader.js";
|
|
13
|
+
// Import tool registry
|
|
14
|
+
import { ToolRegistry } from "./tool-registry.js";
|
|
15
|
+
// Import debug mode flag
|
|
16
|
+
import { DEBUG_MODE } from "./debug-middleware.js";
|
|
17
|
+
// Import logger
|
|
18
|
+
import { createLogger } from "./logger.js";
|
|
19
|
+
// Import request context
|
|
20
|
+
import { runWithRequest, requireCurrentRequest, } from "./request-context.js";
|
|
21
|
+
const logger = createLogger("MCPServer");
|
|
22
|
+
// Create tool registry and register all tools
|
|
23
|
+
const toolRegistry = new ToolRegistry();
|
|
24
|
+
// Register consolidated tools (10 tools total)
|
|
25
|
+
toolRegistry.register("getMe", GetMeSchema, getMe);
|
|
26
|
+
toolRegistry.register("getChat", GetChatSchema, getChat);
|
|
27
|
+
toolRegistry.register("getMessages", GetMessagesSchema, getMessages);
|
|
28
|
+
toolRegistry.register("sendMessage", SendMessageSchema, sendMessage);
|
|
29
|
+
toolRegistry.register("getUser", GetUserSchema, getUser);
|
|
30
|
+
toolRegistry.register("getContacts", GetContactsSchema, getContacts);
|
|
31
|
+
toolRegistry.register("getFile", GetFileSchema, getFile);
|
|
32
|
+
toolRegistry.register("getGroup", GetGroupSchema, getGroup);
|
|
33
|
+
toolRegistry.register("getChatMembers", GetChatMembersSchema, getChatMembers);
|
|
34
|
+
toolRegistry.register("getMessageContext", GetMessageContextSchema, getMessageContext);
|
|
35
|
+
// Create MCP server
|
|
36
|
+
const server = new Server({
|
|
37
|
+
name: "telegram-mcp-server",
|
|
38
|
+
version: "0.0.1",
|
|
39
|
+
}, {
|
|
40
|
+
capabilities: {
|
|
41
|
+
tools: {},
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
// Register tool handlers
|
|
45
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
46
|
+
// Load tool definitions from JSON (reloads on each request in dev mode)
|
|
47
|
+
const toolDefinitions = loadToolDefinitions();
|
|
48
|
+
return {
|
|
49
|
+
tools: toolDefinitions,
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
53
|
+
if (DEBUG_MODE) {
|
|
54
|
+
logger.debug("CallToolRequestSchema handler called", {
|
|
55
|
+
toolName: request.params.name,
|
|
56
|
+
arguments: request.params.arguments,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
// Get current request from AsyncLocalStorage context
|
|
60
|
+
const currentRequest = requireCurrentRequest();
|
|
61
|
+
try {
|
|
62
|
+
// Execute tool via registry (includes automatic validation and debug wrapping)
|
|
63
|
+
const result = await toolRegistry.execute(request.params.name, request.params.arguments, currentRequest);
|
|
64
|
+
if (DEBUG_MODE) {
|
|
65
|
+
logger.debug("Tool execution completed", { toolName: request.params.name });
|
|
66
|
+
}
|
|
67
|
+
// Return formatted response with data and optional debug info
|
|
68
|
+
// Debug info is included in the response when DEBUG mode is enabled
|
|
69
|
+
return {
|
|
70
|
+
content: [
|
|
71
|
+
{
|
|
72
|
+
type: "text",
|
|
73
|
+
text: JSON.stringify(result, null, 2),
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
logger.error("Tool execution error", {
|
|
80
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
81
|
+
toolName: request.params.name,
|
|
82
|
+
});
|
|
83
|
+
if (error instanceof z.ZodError) {
|
|
84
|
+
throw new Error(`Invalid arguments: ${error.message}`, { cause: error });
|
|
85
|
+
}
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
// Create Express app with stateless HTTP transport
|
|
90
|
+
const app = express();
|
|
91
|
+
app.use(express.json());
|
|
92
|
+
// Create stateless transport (no session management)
|
|
93
|
+
const transport = new StreamableHTTPServerTransport({
|
|
94
|
+
sessionIdGenerator: undefined, // Stateless mode
|
|
95
|
+
enableJsonResponse: true,
|
|
96
|
+
});
|
|
97
|
+
// Connect server to transport
|
|
98
|
+
await server.connect(transport);
|
|
99
|
+
// Handle MCP requests
|
|
100
|
+
app.post("/mcp", async (req, res) => {
|
|
101
|
+
try {
|
|
102
|
+
// Log incoming request in DEBUG mode
|
|
103
|
+
if (DEBUG_MODE) {
|
|
104
|
+
logger.debug("Incoming MCP request", {
|
|
105
|
+
method: req.body?.method,
|
|
106
|
+
params: req.body?.params,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
// Extract _telegramBinlog from body before passing to SDK
|
|
110
|
+
// The MCP SDK's Zod validation rejects unrecognized keys, so we strip it here
|
|
111
|
+
// and store it on the request for tool handlers to access
|
|
112
|
+
const { _telegramBinlog, ...cleanBody } = req.body;
|
|
113
|
+
// Store binlog on request object for helpers.ts to access
|
|
114
|
+
const telegramReq = req;
|
|
115
|
+
telegramReq._telegramBinlog = _telegramBinlog;
|
|
116
|
+
if (DEBUG_MODE) {
|
|
117
|
+
logger.debug("Binlog status", {
|
|
118
|
+
hasBinlog: !!_telegramBinlog,
|
|
119
|
+
binlogLength: _telegramBinlog?.length,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
// Run the request handler within AsyncLocalStorage context
|
|
123
|
+
// This ensures proper request isolation for concurrent requests
|
|
124
|
+
await runWithRequest(telegramReq, async () => {
|
|
125
|
+
try {
|
|
126
|
+
await transport.handleRequest(req, res, cleanBody);
|
|
127
|
+
if (DEBUG_MODE) {
|
|
128
|
+
logger.debug("Request handled successfully");
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
catch (transportError) {
|
|
132
|
+
logger.error("Transport error", {
|
|
133
|
+
error: transportError instanceof Error ? transportError : new Error(String(transportError)),
|
|
134
|
+
});
|
|
135
|
+
throw transportError;
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
logger.error("Error handling MCP request", {
|
|
141
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
142
|
+
});
|
|
143
|
+
res.status(500).json({
|
|
144
|
+
error: "Internal server error",
|
|
145
|
+
message: error instanceof Error ? error.message : "Unknown error",
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
// Health check endpoint
|
|
150
|
+
app.get("/health", (_req, res) => {
|
|
151
|
+
res.json({
|
|
152
|
+
status: "healthy",
|
|
153
|
+
server: "telegram-mcp-server",
|
|
154
|
+
version: "0.0.1",
|
|
155
|
+
stateless: true,
|
|
156
|
+
debug: DEBUG_MODE,
|
|
157
|
+
registeredTools: toolRegistry.getToolNames(),
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
// Start server
|
|
161
|
+
const PORT = process.env.PORT || 30001;
|
|
162
|
+
app.listen(PORT, () => {
|
|
163
|
+
logger.info("Server started", {
|
|
164
|
+
port: PORT,
|
|
165
|
+
mcpEndpoint: `http://localhost:${PORT}/mcp`,
|
|
166
|
+
healthEndpoint: `http://localhost:${PORT}/health`,
|
|
167
|
+
mode: "Stateless",
|
|
168
|
+
debug: DEBUG_MODE,
|
|
169
|
+
});
|
|
170
|
+
if (DEBUG_MODE) {
|
|
171
|
+
logger.debug("Registered tools", {
|
|
172
|
+
tools: toolRegistry.getToolNames().join(", "),
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logger utility with PII sanitization for safe logging
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Context object for sanitized logging
|
|
6
|
+
*/
|
|
7
|
+
export interface LogContext {
|
|
8
|
+
sessionId?: string;
|
|
9
|
+
userId?: string | number;
|
|
10
|
+
phone?: string;
|
|
11
|
+
token?: string;
|
|
12
|
+
[key: string]: unknown;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Logger class with PII sanitization
|
|
16
|
+
*/
|
|
17
|
+
export declare class Logger {
|
|
18
|
+
private readonly component;
|
|
19
|
+
constructor(component: string);
|
|
20
|
+
info(message: string, context?: LogContext): void;
|
|
21
|
+
warn(message: string, context?: LogContext): void;
|
|
22
|
+
error(message: string, context?: LogContext): void;
|
|
23
|
+
debug(message: string, context?: LogContext): void;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Create a logger for a specific component
|
|
27
|
+
*/
|
|
28
|
+
export declare function createLogger(component: string): Logger;
|
|
29
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA;;GAEG;AAwCH;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACxB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AA4DD;;GAEG;AACH,qBAAa,MAAM;IACL,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAAT,SAAS,EAAE,MAAM;IAE9C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI;IAIjD,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI;IAIjD,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI;IAIlD,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI;CAGnD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEtD"}
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logger utility with PII sanitization for safe logging
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Sanitize a session ID by showing only the first 4 characters
|
|
6
|
+
*/
|
|
7
|
+
function sanitizeSessionId(sessionId) {
|
|
8
|
+
if (sessionId.length <= 4) {
|
|
9
|
+
return "****";
|
|
10
|
+
}
|
|
11
|
+
return `${sessionId.substring(0, 4)}****`;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Sanitize a phone number by masking all but the last 4 digits
|
|
15
|
+
*/
|
|
16
|
+
function sanitizePhoneNumber(phone) {
|
|
17
|
+
const digitsOnly = phone.replace(/\D/g, "");
|
|
18
|
+
if (digitsOnly.length <= 4) {
|
|
19
|
+
return "****";
|
|
20
|
+
}
|
|
21
|
+
return `****${digitsOnly.slice(-4)}`;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Sanitize an access token by showing only first 8 characters
|
|
25
|
+
*/
|
|
26
|
+
function sanitizeToken(token) {
|
|
27
|
+
if (token.length <= 8) {
|
|
28
|
+
return "****";
|
|
29
|
+
}
|
|
30
|
+
return `${token.substring(0, 8)}****`;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Sanitize user ID by keeping it (IDs are not PII on their own, but can be partially masked if needed)
|
|
34
|
+
*/
|
|
35
|
+
function sanitizeUserId(userId) {
|
|
36
|
+
return String(userId);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Sanitize a context object for safe logging
|
|
40
|
+
*/
|
|
41
|
+
function sanitizeContext(context) {
|
|
42
|
+
const sanitized = {};
|
|
43
|
+
for (const [key, value] of Object.entries(context)) {
|
|
44
|
+
if (value === undefined || value === null) {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
// Apply specific sanitization based on key name
|
|
48
|
+
if (key === "sessionId" && typeof value === "string") {
|
|
49
|
+
sanitized[key] = sanitizeSessionId(value);
|
|
50
|
+
}
|
|
51
|
+
else if (key === "phone" && typeof value === "string") {
|
|
52
|
+
sanitized[key] = sanitizePhoneNumber(value);
|
|
53
|
+
}
|
|
54
|
+
else if ((key === "token" || key === "accessToken" || key === "refreshToken") &&
|
|
55
|
+
typeof value === "string") {
|
|
56
|
+
sanitized[key] = sanitizeToken(value);
|
|
57
|
+
}
|
|
58
|
+
else if (key === "userId") {
|
|
59
|
+
sanitized[key] = sanitizeUserId(value);
|
|
60
|
+
}
|
|
61
|
+
else if (key === "error" && value instanceof Error) {
|
|
62
|
+
// Preserve error objects properly
|
|
63
|
+
sanitized[key] = {
|
|
64
|
+
message: value.message,
|
|
65
|
+
name: value.name,
|
|
66
|
+
stack: value.stack,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
sanitized[key] = value;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return sanitized;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Format a log message with optional context
|
|
77
|
+
*/
|
|
78
|
+
function formatMessage(level, component, message, context) {
|
|
79
|
+
const timestamp = new Date().toISOString();
|
|
80
|
+
const prefix = `[${timestamp}] [${level}] [${component}]`;
|
|
81
|
+
if (context && Object.keys(context).length > 0) {
|
|
82
|
+
const sanitized = sanitizeContext(context);
|
|
83
|
+
return `${prefix} ${message} ${JSON.stringify(sanitized)}`;
|
|
84
|
+
}
|
|
85
|
+
return `${prefix} ${message}`;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Logger class with PII sanitization
|
|
89
|
+
*/
|
|
90
|
+
export class Logger {
|
|
91
|
+
component;
|
|
92
|
+
constructor(component) {
|
|
93
|
+
this.component = component;
|
|
94
|
+
}
|
|
95
|
+
info(message, context) {
|
|
96
|
+
console.log(formatMessage("INFO", this.component, message, context));
|
|
97
|
+
}
|
|
98
|
+
warn(message, context) {
|
|
99
|
+
console.warn(formatMessage("WARN", this.component, message, context));
|
|
100
|
+
}
|
|
101
|
+
error(message, context) {
|
|
102
|
+
console.error(formatMessage("ERROR", this.component, message, context));
|
|
103
|
+
}
|
|
104
|
+
debug(message, context) {
|
|
105
|
+
console.debug(formatMessage("DEBUG", this.component, message, context));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Create a logger for a specific component
|
|
110
|
+
*/
|
|
111
|
+
export function createLogger(component) {
|
|
112
|
+
return new Logger(component);
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Request } from "express";
|
|
2
|
+
/**
|
|
3
|
+
* Extended Express Request with Telegram binlog (session data)
|
|
4
|
+
*/
|
|
5
|
+
export type TelegramRequest = Request & {
|
|
6
|
+
_telegramBinlog?: string;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Run a callback with request context
|
|
10
|
+
* All async operations within the callback will have access to the request
|
|
11
|
+
*
|
|
12
|
+
* @param req - Express request object
|
|
13
|
+
* @param callback - Async callback to run with request context
|
|
14
|
+
* @returns Result of the callback
|
|
15
|
+
*/
|
|
16
|
+
export declare function runWithRequest<T>(req: TelegramRequest, callback: () => Promise<T>): Promise<T>;
|
|
17
|
+
/**
|
|
18
|
+
* Get the current request from context, throwing if not available
|
|
19
|
+
*
|
|
20
|
+
* @returns Current request
|
|
21
|
+
* @throws Error if not in request context
|
|
22
|
+
*/
|
|
23
|
+
export declare function requireCurrentRequest(): TelegramRequest;
|
|
24
|
+
//# sourceMappingURL=request-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../src/request-context.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAEvC;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG;IAAE,eAAe,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AASrE;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAC9B,GAAG,EAAE,eAAe,EACpB,QAAQ,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACzB,OAAO,CAAC,CAAC,CAAC,CAEZ;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,IAAI,eAAe,CAQvD"}
|