Skip to main content
Glama
README.md
# mcp-web-calc — MCP server cho LM Studio (không cần API key)

**Phiên bản:** 0.3.0

**6 công cụ tích hợp**
- `search_web` — Tìm web hai tầng (Nhanh: DuckDuckGo HTML → Sâu: Playwright/Bing)
- `fetch_url` — Tải & trích xuất nội dung từ URL/HTML/PDF (Readability + pdf-parse)
- `summarize_url` — Lấy nội dung từ URL rồi tóm tắt ngắn gọn
- `math_eval` — Máy tính chính xác (Number / BigNumber / Fraction)
- `wiki_get` — Lấy tóm tắt 1 trang Wikipedia theo ngôn ngữ
- `wiki_multi` — Lấy tóm tắt Wikipedia theo **nhiều ngôn ngữ** trong một lần gọi

> Không dùng API key. Hoạt động hoàn toàn qua MCP/stdio.

---

## Yêu cầu
- Node.js 18+
- Windows/macOS/Linux
- (Tìm kiếm sâu) **Playwright Chromium**

## Cài đặt
```bash
npm i
npx playwright install chromium   # cần cho 'deep' (Bing/Playwright)
# Dev:
npm run dev
# hoặc build & chạy prod:
npm run build && npm run start
```

## Biến môi trường (khuyến nghị)
Đặt trong LM Studio hoặc `.env`:
```env
USER_AGENT=mcp-web-calc/0.3 (https://local)
HTTP_TIMEOUT=15000       # ms cho mọi yêu cầu mạng
MAX_RESULTS=10           # mặc định cho search_web
LANG_DEFAULT=vi          # ngôn ngữ mặc định
MAX_BYTES=20971520       # giới hạn tải 20MB cho fetch_url
```

> **Bảo vệ SSRF**: `fetch_url` sẽ **chặn** `localhost/127.0.0.1/::1/.local/.localhost`.

---

## Thêm MCP server trong LM Studio
**Settings → Developer → Model Context Protocol (MCP) Servers → Add**

- **Name**: `mcp-web-calc`
- **Command**: `npm`
- **Args**: `run`, `dev`  *(hoặc `start` nếu đã build)*
- **Working directory**: đường dẫn tới thư mục dự án
- **Environment variables**: như ở phần trên

Khi chạy thành công, log sẽ hiện: `mcp-web-calc ready (stdio)…`

---

## Công cụ & cú pháp (tool schema)

### 1) `search_web`
- **Input**
```ts
{ 
  q: string;
  limit?: number;          // default: MAX_RESULTS (env), clamp 1..50
  lang?: string;           // "vi" | "en" | ...
  mode?: "fast"|"deep"|"auto"; // default: "auto"
}
```
- **Output (rút gọn)**
```ts
{
  items: { title: string; url: string; snippet?: string; source: "ddg_html"|"bing_pw" }[];
  modeUsed: "fast"|"deep"|"auto";
  enginesUsed: ("ddg_html"|"bing_pw")[];
  escalated: boolean;      // auto có leo sang deep hay không
  diagnostics?: Record<string, unknown>;
}
```
- **Ví dụ**
```
search_web: { "q": "Node.js LTS release schedule", "mode": "fast", "limit": 5, "lang": "vi" }
```

---

### 2) `fetch_url`
- **Input**
```ts
{ url: string }  // hỗ trợ HTML & PDF
```
- **Output (rút gọn)**
```ts
{
  text: string;
  url: string;
  title?: string;
  byline?: string;
  siteName?: string;
  lang?: string;
  length?: number; // nếu có
}
```
- **Ví dụ**
```
fetch_url: { "url": "https://example.com" }
```

---

### 3) `summarize_url`
- **Input**
```ts
{ url: string }
```
- **Hành vi**
  - Lấy nội dung bằng `fetch_url`, sau đó *thử* gọi model phía server (nếu được LM Studio cấp) để tóm tắt ngắn gọn tiếng Việt.
  - **Fallback**: nếu không gọi được model, trả về tối đa ~2000 ký tự đầu của bài.
- **Ví dụ**
```
summarize_url: { "url": "https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API" }
```

---

### 4) `math_eval`
- **Input**
```ts
{
  expression: string;                      // cú pháp mathjs
  mode?: "number"|"BigNumber"|"Fraction";  // default: "BigNumber"
  precision?: number;                      // default: 64 (khi BigNumber)
}
```
- **Lưu ý**
  - `mathjs` **không có** hàm `integrate`. Dùng `derivative`, `simplify`, ma trận, đơn vị, v.v.
  - Cần lượng giác? Dùng `mode="number"` để có sin/cos… chính xác kiểu số JS.
- **Ví dụ**
```
math_eval: { "expression": "derivative(sin(x)*exp(x), x)", "mode": "number" }
```

---

### 5) `wiki_get`
- **Input**
```ts
{ title: string; lang?: string /* default "vi" */ }
```
- **Output (rút gọn)**
```ts
{ lang: string; title: string; url: string; description?: string; extract?: string; thumbnailUrl?: string }
```
- **Ví dụ**
```
wiki_get: { "title": "Việt Nam", "lang": "vi" }
```

---

### 6) `wiki_multi`
- **Input**
```ts
{
  term: string,                 // thuật ngữ gốc, ví dụ "Cá"
  baseLang?: string,            // mặc định "vi"
  langs?: string[]              // mặc định ["vi","en"]
}
```
- **Output (rút gọn)**
```ts
{
  baseLang: string;
  base: { /* WikiSummary của baseLang */ };
  items: Record<string, WikiSummary | null>; // null nếu không tìm thấy
  resolved: Record<string, { title?: string; source: "base"|"langlinks"|"direct"|"none" }>
}
```
- **Ví dụ**
```
wiki_multi: { "term": "Cá", "baseLang": "vi", "langs": ["vi","en","ja","fr"] }
```

---

## Mẹo kiểm thử nhanh
```text
search_web: { "q": "site:developer.apple.com App Intents", "mode": "deep", "limit": 5, "lang": "vi" }
fetch_url: { "url": "https://example.com" }
summarize_url: { "url": "https://www.python.org/dev/peps/pep-0008/" }
math_eval: { "expression": "inv([[1,2],[3,4]])", "mode": "number" }
wiki_get: { "title": "Lambda calculus", "lang": "en" }
wiki_multi: { "term": "Cá", "baseLang": "vi", "langs": ["vi","en","ja","fr"] }
```

---

## Khắc phục sự cố
- **CAPTCHA / chặn tạm thời**: giảm tần suất, ưu tiên `mode="fast"`, thử lại sau vài phút.
- **Playwright chưa cài**: `npx playwright install chromium`.
- **Timeout / treo khi tải**: tăng `HTTP_TIMEOUT`, hoặc nội dung vượt `MAX_BYTES`.
- **URL nội bộ bị chặn**: đây là chủ đích (SSRF guard).

## Giấy phép
MIT — xem tệp `LICENSE`.