@dauthau/mcp-dauthau 0.1.2
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/LICENSE +339 -0
- package/README.md +171 -0
- package/dist/assets/mcp-instructions.md +46 -0
- package/dist/assets/mcp-prompts-tools.json +90 -0
- package/dist/config.d.ts +30 -0
- package/dist/config.js +94 -0
- package/dist/diagnose.d.ts +8 -0
- package/dist/diagnose.js +105 -0
- package/dist/forward.d.ts +34 -0
- package/dist/forward.js +153 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +108 -0
- package/dist/log.d.ts +21 -0
- package/dist/log.js +29 -0
- package/dist/prompts.d.ts +8 -0
- package/dist/prompts.js +38 -0
- package/dist/sign.d.ts +22 -0
- package/dist/sign.js +38 -0
- package/dist/tools.d.ts +20 -0
- package/dist/tools.js +62 -0
- package/package.json +51 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Entrypoint @dauthau/mcp-dauthau — chạy MCP server stdio local, forward HTTPS lên gateway.
|
|
4
|
+
*
|
|
5
|
+
* Xem README.md cho hướng dẫn cài đặt và mẫu config `.mcp.json`.
|
|
6
|
+
*/
|
|
7
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
8
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
9
|
+
import { loadConfig } from "./config.js";
|
|
10
|
+
import { logError, logInfo, logWarn, setLogLevel } from "./log.js";
|
|
11
|
+
import { loadInstructions } from "./prompts.js";
|
|
12
|
+
import { registerProxyHandlers } from "./tools.js";
|
|
13
|
+
// package.json version — injected khi build (sau publish: process.env.npm_package_version).
|
|
14
|
+
const VERSION = process.env.npm_package_version ?? "0.1.0";
|
|
15
|
+
async function main() {
|
|
16
|
+
// Handle --version / --help trước khi load config (cho nhanh).
|
|
17
|
+
const arg = process.argv[2];
|
|
18
|
+
if (arg === "--version" || arg === "-v") {
|
|
19
|
+
process.stdout.write(`@dauthau/mcp-dauthau ${VERSION}\n`);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if (arg === "--help" || arg === "-h") {
|
|
23
|
+
process.stdout.write(helpText());
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
let cfg;
|
|
27
|
+
try {
|
|
28
|
+
cfg = loadConfig();
|
|
29
|
+
setLogLevel(cfg.logLevel);
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
process.stderr.write(`[fatal] ${err.message}\n`);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
if (arg === "--diagnose") {
|
|
36
|
+
const { runDiagnose } = await import("./diagnose.js");
|
|
37
|
+
const ok = await runDiagnose(cfg);
|
|
38
|
+
process.exit(ok ? 0 : 1);
|
|
39
|
+
}
|
|
40
|
+
logInfo("@dauthau/mcp-dauthau starting", {
|
|
41
|
+
version: VERSION,
|
|
42
|
+
gateway: cfg.gatewayUrl,
|
|
43
|
+
hash_algo: cfg.hashAlgo,
|
|
44
|
+
node: process.version,
|
|
45
|
+
});
|
|
46
|
+
// Load shared prompt từ dist/assets/ (copy từ sibling repo Go lúc build)
|
|
47
|
+
let instructions;
|
|
48
|
+
try {
|
|
49
|
+
instructions = loadInstructions();
|
|
50
|
+
logInfo("loaded mcp-instructions.md", { length: instructions.length });
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
logWarn("không load được mcp-instructions.md, chạy không có instructions", {
|
|
54
|
+
err: err.message,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
const server = new Server({ name: "dauthau-mcp-wrapper", version: VERSION }, {
|
|
58
|
+
capabilities: {
|
|
59
|
+
tools: {},
|
|
60
|
+
},
|
|
61
|
+
...(instructions ? { instructions } : {}),
|
|
62
|
+
});
|
|
63
|
+
registerProxyHandlers(server, cfg);
|
|
64
|
+
// Graceful shutdown — Claude Code / Cursor đóng stdio khi user reload.
|
|
65
|
+
const shutdown = async (signal) => {
|
|
66
|
+
logInfo("shutdown", { signal });
|
|
67
|
+
try {
|
|
68
|
+
await server.close();
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
logError("shutdown error", { err: err.message });
|
|
72
|
+
}
|
|
73
|
+
process.exit(0);
|
|
74
|
+
};
|
|
75
|
+
process.on("SIGINT", () => void shutdown("SIGINT"));
|
|
76
|
+
process.on("SIGTERM", () => void shutdown("SIGTERM"));
|
|
77
|
+
const transport = new StdioServerTransport();
|
|
78
|
+
await server.connect(transport);
|
|
79
|
+
logInfo("@dauthau/mcp-dauthau connected, waiting for client", {});
|
|
80
|
+
}
|
|
81
|
+
function helpText() {
|
|
82
|
+
return [
|
|
83
|
+
"@dauthau/mcp-dauthau — Node.js MCP wrapper cho dịch vụ tra cứu đấu thầu DauThau",
|
|
84
|
+
"",
|
|
85
|
+
"Env bắt buộc:",
|
|
86
|
+
" DAUTHAU_APIKEY Apikey từ tài khoản DauThau",
|
|
87
|
+
" DAUTHAU_APISECRET Apisecret (giữ local, sign hashsecret mỗi request)",
|
|
88
|
+
" MCP_GATEWAY_URL URL gateway DauThau cấp",
|
|
89
|
+
" MCP_GATEWAY_KEY Gateway subscription key DauThau cấp",
|
|
90
|
+
"",
|
|
91
|
+
"Env tuỳ chọn:",
|
|
92
|
+
" DAUTHAU_HASH_ALGO bcrypt (default) | md5",
|
|
93
|
+
" LOG_LEVEL debug | info (default) | warn | error",
|
|
94
|
+
" MCP_GATEWAY_TIMEOUT_MS 1000-120000 (default 30000)",
|
|
95
|
+
" MCP_GATEWAY_RETRY_MAX 0-10 (default 3, retry khi 5xx)",
|
|
96
|
+
" MCP_GATEWAY_RETRY_BASE_MS 50-5000 (default 200, exponential backoff)",
|
|
97
|
+
"",
|
|
98
|
+
"Cờ:",
|
|
99
|
+
" --version / -v in version",
|
|
100
|
+
" --help / -h in help",
|
|
101
|
+
" --diagnose chẩn đoán kết nối gateway (DNS, TLS, tools/list)",
|
|
102
|
+
"",
|
|
103
|
+
].join("\n");
|
|
104
|
+
}
|
|
105
|
+
main().catch((err) => {
|
|
106
|
+
process.stderr.write(`[fatal] ${err.stack ?? err}\n`);
|
|
107
|
+
process.exit(1);
|
|
108
|
+
});
|
package/dist/log.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log structured JSON ra **stderr**. CẤM log ra stdout — stdout dành cho MCP JSON-RPC stdio framing.
|
|
3
|
+
*
|
|
4
|
+
* Quy tắc:
|
|
5
|
+
* - KHÔNG log apikey, apisecret, hashsecret, gatewayKey, raw body.
|
|
6
|
+
* - Log: tool name, latency, status, error message.
|
|
7
|
+
* - Tôn trọng LOG_LEVEL từ env (debug | info | warn | error).
|
|
8
|
+
*/
|
|
9
|
+
declare const levelOrder: {
|
|
10
|
+
readonly debug: 10;
|
|
11
|
+
readonly info: 20;
|
|
12
|
+
readonly warn: 30;
|
|
13
|
+
readonly error: 40;
|
|
14
|
+
};
|
|
15
|
+
type LevelName = keyof typeof levelOrder;
|
|
16
|
+
export declare function setLogLevel(level: LevelName): void;
|
|
17
|
+
export declare const logDebug: (msg: string, fields?: Record<string, unknown>) => void;
|
|
18
|
+
export declare const logInfo: (msg: string, fields?: Record<string, unknown>) => void;
|
|
19
|
+
export declare const logWarn: (msg: string, fields?: Record<string, unknown>) => void;
|
|
20
|
+
export declare const logError: (msg: string, fields?: Record<string, unknown>) => void;
|
|
21
|
+
export {};
|
package/dist/log.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log structured JSON ra **stderr**. CẤM log ra stdout — stdout dành cho MCP JSON-RPC stdio framing.
|
|
3
|
+
*
|
|
4
|
+
* Quy tắc:
|
|
5
|
+
* - KHÔNG log apikey, apisecret, hashsecret, gatewayKey, raw body.
|
|
6
|
+
* - Log: tool name, latency, status, error message.
|
|
7
|
+
* - Tôn trọng LOG_LEVEL từ env (debug | info | warn | error).
|
|
8
|
+
*/
|
|
9
|
+
const levelOrder = { debug: 10, info: 20, warn: 30, error: 40 };
|
|
10
|
+
let currentLevel = "info";
|
|
11
|
+
export function setLogLevel(level) {
|
|
12
|
+
currentLevel = level;
|
|
13
|
+
}
|
|
14
|
+
function log(level, msg, fields = {}) {
|
|
15
|
+
if (levelOrder[level] < levelOrder[currentLevel]) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const line = JSON.stringify({
|
|
19
|
+
time: new Date().toISOString(),
|
|
20
|
+
level,
|
|
21
|
+
msg,
|
|
22
|
+
...fields,
|
|
23
|
+
});
|
|
24
|
+
process.stderr.write(line + "\n");
|
|
25
|
+
}
|
|
26
|
+
export const logDebug = (msg, fields) => log("debug", msg, fields);
|
|
27
|
+
export const logInfo = (msg, fields) => log("info", msg, fields);
|
|
28
|
+
export const logWarn = (msg, fields) => log("warn", msg, fields);
|
|
29
|
+
export const logError = (msg, fields) => log("error", msg, fields);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Load prompt assets (mcp-instructions.md + mcp-prompts-tools.json).
|
|
3
|
+
*
|
|
4
|
+
* Sau build: assets nằm ở `dist/assets/` (cùng thư mục với dist/index.js).
|
|
5
|
+
* Dev mode (tsx src/index.ts): load trực tiếp từ `../assets/`.
|
|
6
|
+
*/
|
|
7
|
+
/** Load system prompt MCP (dùng cho ServerOptions.instructions). */
|
|
8
|
+
export declare function loadInstructions(): string;
|
package/dist/prompts.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Load prompt assets (mcp-instructions.md + mcp-prompts-tools.json).
|
|
3
|
+
*
|
|
4
|
+
* Sau build: assets nằm ở `dist/assets/` (cùng thư mục với dist/index.js).
|
|
5
|
+
* Dev mode (tsx src/index.ts): load trực tiếp từ `../assets/`.
|
|
6
|
+
*/
|
|
7
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
8
|
+
import { resolve, dirname } from "node:path";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
10
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
/** Resolve đường dẫn tới assets/, hỗ trợ cả build và dev mode. */
|
|
12
|
+
function resolveAssetsDir() {
|
|
13
|
+
// Build mode: dist/assets/ nằm cạnh dist/index.js (cùng thư mục __dirname)
|
|
14
|
+
const buildPath = resolve(__dirname, "assets");
|
|
15
|
+
if (existsSync(buildPath)) {
|
|
16
|
+
return buildPath;
|
|
17
|
+
}
|
|
18
|
+
// Dev mode (tsx src/index.ts): __dirname = src/, lấy ../assets/ (đã commit sẵn)
|
|
19
|
+
const localPath = resolve(__dirname, "..", "assets");
|
|
20
|
+
if (existsSync(localPath)) {
|
|
21
|
+
return localPath;
|
|
22
|
+
}
|
|
23
|
+
// Fallback: ../dist/assets/
|
|
24
|
+
const devPath = resolve(__dirname, "..", "dist", "assets");
|
|
25
|
+
if (existsSync(devPath)) {
|
|
26
|
+
return devPath;
|
|
27
|
+
}
|
|
28
|
+
throw new Error(`Không tìm thấy thư mục assets/. Hãy chắc chắn repo của bạn chứa thư mục assets/ hoặc đã chạy "npm run build".`);
|
|
29
|
+
}
|
|
30
|
+
/** Load system prompt MCP (dùng cho ServerOptions.instructions). */
|
|
31
|
+
export function loadInstructions() {
|
|
32
|
+
const dir = resolveAssetsDir();
|
|
33
|
+
const file = resolve(dir, "mcp-instructions.md");
|
|
34
|
+
if (!existsSync(file)) {
|
|
35
|
+
throw new Error(`Thiếu file mcp-instructions.md tại ${dir}`);
|
|
36
|
+
}
|
|
37
|
+
return readFileSync(file, "utf-8");
|
|
38
|
+
}
|
package/dist/sign.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sign hashsecret cho request lên DauThau backend.
|
|
3
|
+
*
|
|
4
|
+
* Test vector chung ở test/vectors.json — đảm bảo bit-exact với backend gateway.
|
|
5
|
+
*
|
|
6
|
+
* Algo `md5`: md5(apisecret + "_" + timestamp) → hex lowercase 32 ký tự.
|
|
7
|
+
* Algo `bcrypt`: bcrypt(apisecret + "_" + timestamp, cost=10) → `$2y$...`.
|
|
8
|
+
*
|
|
9
|
+
* Backend chỉ chấp nhận skew window hẹp (vài giây) — sign per-request, KHÔNG cache.
|
|
10
|
+
*/
|
|
11
|
+
import type { HashAlgo } from "./config.js";
|
|
12
|
+
/** Trả unix timestamp (seconds). */
|
|
13
|
+
export declare function nowUnix(): number;
|
|
14
|
+
/** Sign md5 hashsecret theo công thức md5(apisecret + "_" + timestamp). */
|
|
15
|
+
export declare function signMd5(apisecret: string, timestamp: number): string;
|
|
16
|
+
/**
|
|
17
|
+
* Sign bcrypt hashsecret cho tài khoản (mặc định NukeViet dùng PASSWORD_DEFAULT = bcrypt).
|
|
18
|
+
* bcryptjs là pure JS — không cần node-gyp / native binding.
|
|
19
|
+
*/
|
|
20
|
+
export declare function signBcrypt(apisecret: string, timestamp: number): Promise<string>;
|
|
21
|
+
/** Sign theo algo cấu hình. Mỗi request 1 timestamp + 1 hashsecret mới. */
|
|
22
|
+
export declare function signHashsecret(algo: HashAlgo, apisecret: string, timestamp: number): Promise<string>;
|
package/dist/sign.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sign hashsecret cho request lên DauThau backend.
|
|
3
|
+
*
|
|
4
|
+
* Test vector chung ở test/vectors.json — đảm bảo bit-exact với backend gateway.
|
|
5
|
+
*
|
|
6
|
+
* Algo `md5`: md5(apisecret + "_" + timestamp) → hex lowercase 32 ký tự.
|
|
7
|
+
* Algo `bcrypt`: bcrypt(apisecret + "_" + timestamp, cost=10) → `$2y$...`.
|
|
8
|
+
*
|
|
9
|
+
* Backend chỉ chấp nhận skew window hẹp (vài giây) — sign per-request, KHÔNG cache.
|
|
10
|
+
*/
|
|
11
|
+
import { createHash } from "node:crypto";
|
|
12
|
+
import bcryptjs from "bcryptjs";
|
|
13
|
+
/** Trả unix timestamp (seconds). */
|
|
14
|
+
export function nowUnix() {
|
|
15
|
+
return Math.floor(Date.now() / 1000);
|
|
16
|
+
}
|
|
17
|
+
/** Sign md5 hashsecret theo công thức md5(apisecret + "_" + timestamp). */
|
|
18
|
+
export function signMd5(apisecret, timestamp) {
|
|
19
|
+
return createHash("md5").update(`${apisecret}_${timestamp}`).digest("hex");
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Sign bcrypt hashsecret cho tài khoản (mặc định NukeViet dùng PASSWORD_DEFAULT = bcrypt).
|
|
23
|
+
* bcryptjs là pure JS — không cần node-gyp / native binding.
|
|
24
|
+
*/
|
|
25
|
+
export async function signBcrypt(apisecret, timestamp) {
|
|
26
|
+
const hash = await bcryptjs.hash(`${apisecret}_${timestamp}`, 10);
|
|
27
|
+
// PHP password_hash trả prefix $2y$, bcryptjs trả $2a$ — backend chấp nhận cả hai.
|
|
28
|
+
return hash;
|
|
29
|
+
}
|
|
30
|
+
/** Sign theo algo cấu hình. Mỗi request 1 timestamp + 1 hashsecret mới. */
|
|
31
|
+
export async function signHashsecret(algo, apisecret, timestamp) {
|
|
32
|
+
switch (algo) {
|
|
33
|
+
case "md5":
|
|
34
|
+
return signMd5(apisecret, timestamp);
|
|
35
|
+
case "bcrypt":
|
|
36
|
+
return signBcrypt(apisecret, timestamp);
|
|
37
|
+
}
|
|
38
|
+
}
|
package/dist/tools.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Đăng ký tool MCP với SDK TypeScript.
|
|
3
|
+
*
|
|
4
|
+
* **Quan trọng:** wrapper KHÔNG hardcode schema 22 tool. Thay vào đó query động
|
|
5
|
+
* `tools/list` lên gateway khi MCP client gọi → gateway là source of truth.
|
|
6
|
+
* Khi backend thêm/sửa tool, wrapper KHÔNG cần release version mới.
|
|
7
|
+
*
|
|
8
|
+
* Trade-off: cold-start có thêm 1 round-trip lên gateway. Chấp nhận được vì
|
|
9
|
+
* MCP client cache tools/list sau lần đầu trong session.
|
|
10
|
+
*/
|
|
11
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
12
|
+
import type { Config } from "./config.js";
|
|
13
|
+
/**
|
|
14
|
+
* registerProxyHandlers gắn 2 handler quan trọng:
|
|
15
|
+
* - tools/list → forward GET lên gateway, trả nguyên schema.
|
|
16
|
+
* - tools/call → forward POST lên gateway, trả nguyên response.
|
|
17
|
+
*
|
|
18
|
+
* Các method khác (initialize, ping, ...) MCP SDK lo nội bộ.
|
|
19
|
+
*/
|
|
20
|
+
export declare function registerProxyHandlers(server: Server, cfg: Config): void;
|
package/dist/tools.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Đăng ký tool MCP với SDK TypeScript.
|
|
3
|
+
*
|
|
4
|
+
* **Quan trọng:** wrapper KHÔNG hardcode schema 22 tool. Thay vào đó query động
|
|
5
|
+
* `tools/list` lên gateway khi MCP client gọi → gateway là source of truth.
|
|
6
|
+
* Khi backend thêm/sửa tool, wrapper KHÔNG cần release version mới.
|
|
7
|
+
*
|
|
8
|
+
* Trade-off: cold-start có thêm 1 round-trip lên gateway. Chấp nhận được vì
|
|
9
|
+
* MCP client cache tools/list sau lần đầu trong session.
|
|
10
|
+
*/
|
|
11
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
12
|
+
import { forwardJsonRpc } from "./forward.js";
|
|
13
|
+
import { logError, logInfo } from "./log.js";
|
|
14
|
+
/**
|
|
15
|
+
* registerProxyHandlers gắn 2 handler quan trọng:
|
|
16
|
+
* - tools/list → forward GET lên gateway, trả nguyên schema.
|
|
17
|
+
* - tools/call → forward POST lên gateway, trả nguyên response.
|
|
18
|
+
*
|
|
19
|
+
* Các method khác (initialize, ping, ...) MCP SDK lo nội bộ.
|
|
20
|
+
*/
|
|
21
|
+
export function registerProxyHandlers(server, cfg) {
|
|
22
|
+
server.setRequestHandler(ListToolsRequestSchema, async (req) => {
|
|
23
|
+
logInfo("forward tools/list");
|
|
24
|
+
const { status, body } = await forwardJsonRpc({
|
|
25
|
+
jsonrpc: "2.0",
|
|
26
|
+
id: 1,
|
|
27
|
+
method: "tools/list",
|
|
28
|
+
params: req.params ?? {},
|
|
29
|
+
}, cfg);
|
|
30
|
+
if (status !== 200) {
|
|
31
|
+
logError("tools/list non-200", { status });
|
|
32
|
+
throw new Error(`tools/list gateway returned ${status}`);
|
|
33
|
+
}
|
|
34
|
+
const result = extractResult(body);
|
|
35
|
+
// as never: MCP SDK handler typing quá strict, workaround safe vì result là dynamic từ gateway
|
|
36
|
+
return result;
|
|
37
|
+
});
|
|
38
|
+
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
39
|
+
const toolName = req.params.name;
|
|
40
|
+
logInfo("forward tools/call", { tool: toolName });
|
|
41
|
+
const { status, body } = await forwardJsonRpc({
|
|
42
|
+
jsonrpc: "2.0",
|
|
43
|
+
id: 2,
|
|
44
|
+
method: "tools/call",
|
|
45
|
+
params: req.params,
|
|
46
|
+
}, cfg);
|
|
47
|
+
if (status !== 200) {
|
|
48
|
+
logError("tools/call non-200", { tool: toolName, status });
|
|
49
|
+
// Forward error JSON nguyên về client (DauThau backend trả code 1003/1004/1006/1007 cần hiển thị)
|
|
50
|
+
const errBody = extractResult(body) ?? { error: { code: status, message: "gateway error" } };
|
|
51
|
+
return errBody;
|
|
52
|
+
}
|
|
53
|
+
return extractResult(body);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
/** Bóc tách `result` từ JSON-RPC envelope. Nếu là raw object (gateway trả non-JSON-RPC), trả nguyên. */
|
|
57
|
+
function extractResult(body) {
|
|
58
|
+
if (body && typeof body === "object" && "result" in body) {
|
|
59
|
+
return body.result;
|
|
60
|
+
}
|
|
61
|
+
return body;
|
|
62
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dauthau/mcp-dauthau",
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Node.js MCP wrapper kết nối AI tool (Claude Code, Cursor, ...) tới dịch vụ tra cứu đấu thầu DauThau. Apisecret giữ local, ký hashsecret mỗi request.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"mcpdauthau-wrapper": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"files": [
|
|
12
|
+
"dist/",
|
|
13
|
+
"README.md",
|
|
14
|
+
"LICENSE"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "node scripts/copy-assets.mjs && tsc",
|
|
18
|
+
"dev": "tsx src/index.ts",
|
|
19
|
+
"test": "vitest run",
|
|
20
|
+
"test:watch": "vitest",
|
|
21
|
+
"lint": "tsc --noEmit",
|
|
22
|
+
"prepublishOnly": "npm run lint && npm run test && npm run build"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"mcp",
|
|
26
|
+
"model-context-protocol",
|
|
27
|
+
"dauthau",
|
|
28
|
+
"claude-code",
|
|
29
|
+
"anthropic"
|
|
30
|
+
],
|
|
31
|
+
"author": "DauThau team",
|
|
32
|
+
"license": "GPL-2.0-only",
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "git@github.com:vinades/mcp-dauthau.git"
|
|
36
|
+
},
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">=22.0.0"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@modelcontextprotocol/sdk": "1.29.0",
|
|
42
|
+
"bcryptjs": "3.0.3"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/node": "20.11.0",
|
|
46
|
+
"@vitest/coverage-v8": "4.1.6",
|
|
47
|
+
"tsx": "4.19.3",
|
|
48
|
+
"typescript": "5.3.3",
|
|
49
|
+
"vitest": "4.1.6"
|
|
50
|
+
}
|
|
51
|
+
}
|