gm-mcp 1.0.10 → 1.1.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/dist/helpers/search-like.d.ts +1 -0
- package/dist/helpers/search-like.js +40 -0
- package/dist/index.js +12 -0
- package/dist/services/constants/report-columns.d.ts +150 -0
- package/dist/services/constants/report-columns.js +963 -0
- package/dist/services/lark-base.service.d.ts +5 -0
- package/dist/services/lark-base.service.js +33 -0
- package/dist/services/lark.service.d.ts +37 -0
- package/dist/services/lark.service.js +33 -3
- package/dist/services/types/lark.type.d.ts +4 -0
- package/dist/services/types/lark.type.js +2 -0
- package/dist/test.js +30 -1
- package/dist/tools/lark-tool.d.ts +6 -0
- package/dist/tools/lark-tool.js +62 -0
- package/package.json +1 -1
- package/src/helpers/search-like.ts +39 -0
- package/src/index.ts +18 -0
- package/src/services/constants/report-columns.ts +962 -0
- package/src/services/lark-base.service.ts +18 -0
- package/src/services/lark.service.ts +34 -3
- package/src/services/types/lark.type.ts +4 -0
- package/src/test.ts +39 -1
- package/src/tools/lark-tool.ts +60 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.fetchReportRecords = fetchReportRecords;
|
|
16
|
+
const axios_1 = __importDefault(require("axios"));
|
|
17
|
+
const lark_service_1 = require("./lark.service");
|
|
18
|
+
function fetchReportRecords(p) {
|
|
19
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
20
|
+
const access_token = yield (0, lark_service_1.getLarkTenantAccessToken)();
|
|
21
|
+
const appToken = "V5akbIXqfaBvXqs8twfl6rALgLd";
|
|
22
|
+
const tableId = "tblQGKjGd8MnK5qs";
|
|
23
|
+
const url = `https://open.larksuite.com/open-apis/bitable/v1/apps/${appToken}/tables/${tableId}/records/search`;
|
|
24
|
+
return axios_1.default
|
|
25
|
+
.post(url, p, {
|
|
26
|
+
params: { page_size: 500 },
|
|
27
|
+
headers: {
|
|
28
|
+
Authorization: "Bearer " + access_token,
|
|
29
|
+
},
|
|
30
|
+
})
|
|
31
|
+
.then((res) => res.data.data.items);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export declare function getLarkTenantAccessToken(): Promise<string>;
|
|
1
2
|
export declare function sendStatisticX3Message(data: {
|
|
2
3
|
date: string;
|
|
3
4
|
content: string;
|
|
@@ -34,6 +35,42 @@ export declare function sendStatisticX3Message(data: {
|
|
|
34
35
|
upper_message_id?: string | undefined;
|
|
35
36
|
} | undefined;
|
|
36
37
|
}>;
|
|
38
|
+
export declare function sendReportOpsGroup(data: {
|
|
39
|
+
title: string;
|
|
40
|
+
message_content: string;
|
|
41
|
+
}): Promise<{
|
|
42
|
+
code?: number | undefined;
|
|
43
|
+
msg?: string | undefined;
|
|
44
|
+
data?: {
|
|
45
|
+
message_id?: string | undefined;
|
|
46
|
+
root_id?: string | undefined;
|
|
47
|
+
parent_id?: string | undefined;
|
|
48
|
+
thread_id?: string | undefined;
|
|
49
|
+
msg_type?: string | undefined;
|
|
50
|
+
create_time?: string | undefined;
|
|
51
|
+
update_time?: string | undefined;
|
|
52
|
+
deleted?: boolean | undefined;
|
|
53
|
+
updated?: boolean | undefined;
|
|
54
|
+
chat_id?: string | undefined;
|
|
55
|
+
sender?: {
|
|
56
|
+
id: string;
|
|
57
|
+
id_type: string;
|
|
58
|
+
sender_type: string;
|
|
59
|
+
tenant_key?: string | undefined;
|
|
60
|
+
} | undefined;
|
|
61
|
+
body?: {
|
|
62
|
+
content: string;
|
|
63
|
+
} | undefined;
|
|
64
|
+
mentions?: {
|
|
65
|
+
key: string;
|
|
66
|
+
id: string;
|
|
67
|
+
id_type: string;
|
|
68
|
+
name: string;
|
|
69
|
+
tenant_key?: string | undefined;
|
|
70
|
+
}[] | undefined;
|
|
71
|
+
upper_message_id?: string | undefined;
|
|
72
|
+
} | undefined;
|
|
73
|
+
}>;
|
|
37
74
|
export declare function sendLarkTextMessage(p: {
|
|
38
75
|
message_content: {
|
|
39
76
|
text: string;
|
|
@@ -45,7 +45,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
45
45
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
46
46
|
};
|
|
47
47
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
|
+
exports.getLarkTenantAccessToken = getLarkTenantAccessToken;
|
|
48
49
|
exports.sendStatisticX3Message = sendStatisticX3Message;
|
|
50
|
+
exports.sendReportOpsGroup = sendReportOpsGroup;
|
|
49
51
|
exports.sendLarkTextMessage = sendLarkTextMessage;
|
|
50
52
|
exports.sendMessageToX3Group = sendMessageToX3Group;
|
|
51
53
|
const axios_1 = __importDefault(require("axios"));
|
|
@@ -56,12 +58,13 @@ const env_1 = require("../env");
|
|
|
56
58
|
// group test_bot
|
|
57
59
|
// const LARK_X3_GROUP_ID = 'oc_bb4e5b8dd8ada38127c790fa368c02b9';
|
|
58
60
|
// Group dan choi front end
|
|
61
|
+
const DEBT_COLLECTION_CARD_ID = "ctp_AAXr3Fr7xcjr";
|
|
59
62
|
const larkClient = new lark.Client({
|
|
60
63
|
appId: (0, env_1.getEnv)().LARK_APP_ID,
|
|
61
64
|
appSecret: (0, env_1.getEnv)().LARK_APP_SECRET,
|
|
62
65
|
disableTokenCache: true,
|
|
63
66
|
});
|
|
64
|
-
function
|
|
67
|
+
function getLarkTenantAccessToken() {
|
|
65
68
|
return __awaiter(this, void 0, void 0, function* () {
|
|
66
69
|
const url = "https://open.larksuite.com/open-apis/auth/v3/tenant_access_token/internal";
|
|
67
70
|
return axios_1.default
|
|
@@ -111,7 +114,7 @@ function getAccessToken() {
|
|
|
111
114
|
// Split later
|
|
112
115
|
function sendStatisticX3Message(data) {
|
|
113
116
|
return __awaiter(this, void 0, void 0, function* () {
|
|
114
|
-
const access_token = yield
|
|
117
|
+
const access_token = yield getLarkTenantAccessToken();
|
|
115
118
|
const { date, content } = data;
|
|
116
119
|
const messageContent = {
|
|
117
120
|
type: "template",
|
|
@@ -136,10 +139,37 @@ function sendStatisticX3Message(data) {
|
|
|
136
139
|
}, lark.withTenantToken(access_token));
|
|
137
140
|
});
|
|
138
141
|
}
|
|
142
|
+
function sendReportOpsGroup(data) {
|
|
143
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
144
|
+
const access_token = yield getLarkTenantAccessToken();
|
|
145
|
+
const { title, message_content } = data;
|
|
146
|
+
const messageContent = {
|
|
147
|
+
type: "template",
|
|
148
|
+
data: {
|
|
149
|
+
template_id: (0, env_1.getEnv)().LARK_X3_TEMPLATE_ID,
|
|
150
|
+
// template_id: 'ctp_AAdI5Sp48YUT',
|
|
151
|
+
template_variable: {
|
|
152
|
+
title,
|
|
153
|
+
message_content,
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
return larkClient.im.message.create({
|
|
158
|
+
params: {
|
|
159
|
+
receive_id_type: "chat_id",
|
|
160
|
+
},
|
|
161
|
+
data: {
|
|
162
|
+
receive_id: (0, env_1.getEnv)().LARK_X3_GROUP_ID,
|
|
163
|
+
msg_type: "interactive",
|
|
164
|
+
content: JSON.stringify(messageContent),
|
|
165
|
+
},
|
|
166
|
+
}, lark.withTenantToken(access_token));
|
|
167
|
+
});
|
|
168
|
+
}
|
|
139
169
|
function sendLarkTextMessage(p) {
|
|
140
170
|
return __awaiter(this, void 0, void 0, function* () {
|
|
141
171
|
const { message_content, receive_id } = p;
|
|
142
|
-
const access_token = yield
|
|
172
|
+
const access_token = yield getLarkTenantAccessToken();
|
|
143
173
|
return larkClient.im.message.create({
|
|
144
174
|
params: {
|
|
145
175
|
receive_id_type: "chat_id",
|
package/dist/test.js
CHANGED
|
@@ -10,10 +10,39 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
const env_1 = require("./env");
|
|
13
|
+
const lark_tool_1 = require("./tools/lark-tool");
|
|
13
14
|
function setupTest() {
|
|
14
15
|
return __awaiter(this, void 0, void 0, function* () {
|
|
15
16
|
(0, env_1.ensureEnvVariables)();
|
|
16
|
-
const
|
|
17
|
+
const compnay = "BGG";
|
|
18
|
+
const month = "12/2025";
|
|
19
|
+
const res = yield (0, lark_tool_1.debtCollectionRateTool)({ sendMessageToLark: false, companyName: compnay, monthDate: month });
|
|
20
|
+
console.log(res);
|
|
21
|
+
// const fieldNames = REPORT_COLUMS.map((item) => item.field_name);
|
|
22
|
+
// try {
|
|
23
|
+
// const records = await fetchReportRecords({ view_id: "vewI23hNnx", field_names: fieldNames });
|
|
24
|
+
// // console.log(records);
|
|
25
|
+
// // Find by name first
|
|
26
|
+
// const companyNames = records.map((item) => (item.fields["CÔNG TY"] || "") as string);
|
|
27
|
+
// // console.log(companyNames);
|
|
28
|
+
// const searchTems = "DENKO";
|
|
29
|
+
// const monthTerm = "12";
|
|
30
|
+
// const foundName = searchLike(searchTems, companyNames)[0];
|
|
31
|
+
// const companiesMatchName = records.filter((item) => item.fields["CÔNG TY"] === foundName);
|
|
32
|
+
// // console.log(companiesMatchName);
|
|
33
|
+
// // Find by pay period
|
|
34
|
+
// const foundMonth = searchLike(
|
|
35
|
+
// monthTerm,
|
|
36
|
+
// companiesMatchName.map((item) => item.fields["KỲ LƯƠNG"])
|
|
37
|
+
// )[0];
|
|
38
|
+
// console.log(foundMonth);
|
|
39
|
+
// const finalCompnay = companiesMatchName.find((item) => item.fields["KỲ LƯƠNG"] === foundMonth);
|
|
40
|
+
// console.log(finalCompnay);
|
|
41
|
+
// // console.log(companyCandidates);
|
|
42
|
+
// } catch (e) {
|
|
43
|
+
// console.log(e);
|
|
44
|
+
// }
|
|
45
|
+
// const sendMessageToLark = getEnv().SEND_MESSAGE_TO_LARK;
|
|
17
46
|
// const reuslt = await statisticX3TodayTool({ sendMessageToLark: false });
|
|
18
47
|
// console.log(reuslt);
|
|
19
48
|
// const reuslt = await statisticX3Tool({ sendMessageToLark: false, date: "11/06/2025" });
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.debtCollectionRateTool = debtCollectionRateTool;
|
|
13
|
+
const helpers_1 = require("../helpers");
|
|
14
|
+
const search_like_1 = require("../helpers/search-like");
|
|
15
|
+
const report_columns_1 = require("../services/constants/report-columns");
|
|
16
|
+
const lark_base_service_1 = require("../services/lark-base.service");
|
|
17
|
+
const lark_service_1 = require("../services/lark.service");
|
|
18
|
+
const companyKey = "CÔNG TY";
|
|
19
|
+
const preiodKey = "KỲ LƯƠNG";
|
|
20
|
+
const debtCollectionRateKey = "TỈ LỆ THU NỢ";
|
|
21
|
+
function debtCollectionRateTool(options) {
|
|
22
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
23
|
+
const { sendMessageToLark, companyName, monthDate } = options;
|
|
24
|
+
const monthParts = (0, helpers_1.extractMonth)(monthDate);
|
|
25
|
+
if (monthParts === null) {
|
|
26
|
+
return { content: [{ type: "text", text: `${monthDate} is invalid` }] };
|
|
27
|
+
}
|
|
28
|
+
const { month, year } = monthParts;
|
|
29
|
+
const fieldNames = report_columns_1.REPORT_COLUMS.map((item) => item.field_name);
|
|
30
|
+
try {
|
|
31
|
+
const records = yield (0, lark_base_service_1.fetchReportRecords)({ view_id: "vewI23hNnx", field_names: fieldNames });
|
|
32
|
+
// console.log(records);
|
|
33
|
+
// Find by name first
|
|
34
|
+
const companyNames = records.map((item) => (item.fields["CÔNG TY"] || ""));
|
|
35
|
+
// console.log(companyNames);
|
|
36
|
+
// const searchTems = "DENKO";
|
|
37
|
+
// const monthTerm = "12";
|
|
38
|
+
const foundName = (0, search_like_1.searchLike)(companyName, companyNames)[0];
|
|
39
|
+
const companiesMatchName = records.filter((item) => item.fields["CÔNG TY"] === foundName);
|
|
40
|
+
// console.log(companiesMatchName);
|
|
41
|
+
// Find by pay period
|
|
42
|
+
const foundMonth = (0, search_like_1.searchLike)(month.toString(), companiesMatchName.map((item) => item.fields["KỲ LƯƠNG"]))[0];
|
|
43
|
+
console.log(foundMonth);
|
|
44
|
+
const finalCompnay = companiesMatchName.find((item) => item.fields["KỲ LƯƠNG"] === foundMonth);
|
|
45
|
+
if (sendMessageToLark) {
|
|
46
|
+
yield (0, lark_service_1.sendReportOpsGroup)({
|
|
47
|
+
title: "Tỉ lệ thu nợ",
|
|
48
|
+
message_content: [
|
|
49
|
+
`Công ty: ${(finalCompnay === null || finalCompnay === void 0 ? void 0 : finalCompnay.fields[companyKey]) || "N/A"}`,
|
|
50
|
+
`Kỳ lương: ${(finalCompnay === null || finalCompnay === void 0 ? void 0 : finalCompnay.fields[preiodKey]) || "N/A"}`,
|
|
51
|
+
`Tỷ lệ thu nợ: ${Number(finalCompnay === null || finalCompnay === void 0 ? void 0 : finalCompnay.fields[debtCollectionRateKey]) * 100}%`,
|
|
52
|
+
].join("<hr>"),
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return { content: [{ type: "text", text: JSON.stringify(finalCompnay) }] };
|
|
56
|
+
// console.log(finalCompnay);
|
|
57
|
+
}
|
|
58
|
+
catch (e) {
|
|
59
|
+
return { content: [{ type: "text", text: JSON.stringify(e) }] };
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export function searchLike(query: string, list: string[]) {
|
|
2
|
+
if (!query) return list;
|
|
3
|
+
|
|
4
|
+
const searchTerm = query.toLowerCase().trim();
|
|
5
|
+
|
|
6
|
+
return list
|
|
7
|
+
.map((company) => {
|
|
8
|
+
const companyLower = company.toLowerCase();
|
|
9
|
+
let score = 0;
|
|
10
|
+
|
|
11
|
+
// Exact match gets highest score
|
|
12
|
+
if (companyLower === searchTerm) {
|
|
13
|
+
score = 1000;
|
|
14
|
+
}
|
|
15
|
+
// Starts with search term
|
|
16
|
+
else if (companyLower.startsWith(searchTerm)) {
|
|
17
|
+
score = 500;
|
|
18
|
+
}
|
|
19
|
+
// Contains search term
|
|
20
|
+
else if (companyLower.includes(searchTerm)) {
|
|
21
|
+
score = 250;
|
|
22
|
+
}
|
|
23
|
+
// Check if all characters exist in order
|
|
24
|
+
else {
|
|
25
|
+
let pos = 0;
|
|
26
|
+
for (let char of searchTerm) {
|
|
27
|
+
pos = companyLower.indexOf(char, pos);
|
|
28
|
+
if (pos === -1) break;
|
|
29
|
+
score += 10;
|
|
30
|
+
pos++;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return { company, score };
|
|
35
|
+
})
|
|
36
|
+
.filter((item) => item.score > 0)
|
|
37
|
+
.sort((a, b) => b.score - a.score)
|
|
38
|
+
.map((item) => item.company);
|
|
39
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
} from "./tools";
|
|
13
13
|
import z from "zod";
|
|
14
14
|
import { ensureEnvVariables, getEnv } from "./env";
|
|
15
|
+
import { debtCollectionRateTool } from "./tools/lark-tool";
|
|
15
16
|
|
|
16
17
|
export const server = new McpServer(
|
|
17
18
|
{
|
|
@@ -88,6 +89,23 @@ server.tool(
|
|
|
88
89
|
}
|
|
89
90
|
);
|
|
90
91
|
|
|
92
|
+
server.tool(
|
|
93
|
+
"debt_collection_by_month",
|
|
94
|
+
"The company's debt collection rate by month",
|
|
95
|
+
{
|
|
96
|
+
month: z.string({ description: "Month to get data, month must be represented with format MM/yyyy" }),
|
|
97
|
+
company_name: z.string({ description: "Company name to get data" }),
|
|
98
|
+
},
|
|
99
|
+
async (args) => {
|
|
100
|
+
const { month, company_name } = args;
|
|
101
|
+
return debtCollectionRateTool({
|
|
102
|
+
sendMessageToLark: getEnv().SEND_MESSAGE_TO_LARK,
|
|
103
|
+
monthDate: month,
|
|
104
|
+
companyName: company_name,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
);
|
|
108
|
+
|
|
91
109
|
function bootstap() {
|
|
92
110
|
ensureEnvVariables();
|
|
93
111
|
const transport: StdioServerTransport = new StdioServerTransport();
|