MCP Research Friend Server

ทางการ

เครื่องมือวิจัย รวมถึงที่เก็บเอกสารที่ใช้ Sqlite เป็นฐานข้อมูล

เอกสาร

Research Friend

ผู้ช่วยที่เป็นมิตรสำหรับผู้ช่วย AI ที่ต้องการค้นหาข้อมูลบนเว็บและจัดการคลังเอกสารวิจัยในเครื่อง

Research Friend คือเซิร์ฟเวอร์ MCP ที่มอบความสามารถในการดึงหน้าเว็บและค้นหาอินเทอร์เน็ตให้กับเครื่องมือ AI ของคุณ โดยใช้เบราว์เซอร์จริงเบื้องหลัง จึงทำงานได้แม้กับเว็บไซต์สมัยใหม่ที่พึ่งพา JavaScript อย่างมาก นอกจากนี้ยังมี "คลังเอกสาร" ในเครื่องสำหรับจัดเก็บเอกสาร แยกข้อความ และค้นหาทั่วทั้งคลังของคุณ

เพื่อใช้ประโยชน์จากฟีเจอร์ทั้งหมด คุณจะต้องมีไคลเอนต์ MCP ที่รองรับ prompts (ทั่วไป) และ sampling (พบได้น้อยกว่า) เรากำลังพัฒนา Research Friend ควบคู่ไปกับ Chabeau ซึ่งรองรับทั้งสองอย่าง

ทำอะไรได้บ้าง?

  • ดึงหน้าเว็บ ด้วยเบราว์เซอร์จริง (รวมถึงไซต์ที่ใช้ JS จำนวนมาก)
  • ดึงไฟล์ PDF และแยกเนื้อหาข้อความ
  • ค้นหาเว็บ ผ่าน DuckDuckGo หรือ Google
  • ดูแลคลังเอกสารในเครื่อง สำหรับการค้นหา แสดงรายการ และแยกข้อมูล

เริ่มต้นใช้งาน

คุณต้องติดตั้ง Node.js เวอร์ชัน 20 หรือใหม่กว่าบนคอมพิวเตอร์ของคุณ

1. ติดตั้งส่วนประกอบที่จำเป็น

เปิดเทอร์มินัลในโฟลเดอร์นี้แล้วรัน:

npm install

2. ติดตั้งส่วนสนับสนุนเบราว์เซอร์

Research Friend ใช้ Playwright เพื่อควบคุมเว็บเบราว์เซอร์ หลังจากติดตั้งส่วนประกอบที่จำเป็นแล้ว คุณต้องติดตั้งเบราว์เซอร์:

npx playwright install chromium

คำสั่งนี้จะดาวน์โหลดสำเนาของ Chromium ที่ Playwright จะใช้ ซึ่งแยกจากเบราว์เซอร์ใดๆ ที่คุณติดตั้งไว้แล้ว

3. เริ่มเซิร์ฟเวอร์

node src/index.js

เซิร์ฟเวอร์สื่อสารผ่าน stdio (อินพุต/เอาต์พุตมาตรฐาน) ซึ่งเป็นวิธีที่ไคลเอนต์ MCP เชื่อมต่อ

การเพิ่มลงในไคลเอนต์ MCP ของคุณ

วิธีการเพิ่ม Research Friend ขึ้นอยู่กับไคลเอนต์ MCP ที่คุณใช้ นี่คือตัวอย่างทั่วไปของการกำหนดค่า:

[[mcp_servers]]
id = "research-friend"
command = "node"
args = ["/path/to/mcp-research-friend/src"]
transport = "stdio"

แทนที่ /path/to/mcp-research-friend ด้วยพาธจริงไปยังโฟลเดอร์นี้บนคอมพิวเตอร์ของคุณ

เครื่องมือ

เครื่องมือเว็บ

friendly_web_fetch

ดึงหน้าเว็บและส่งคืนเนื้อหา โดยค่าเริ่มต้นจะส่งคืนเป็น markdown พร้อมรักษาลิงก์ไว้ — เหมาะสำหรับ LLM ใช้ Readability เพื่อแยกเนื้อหาหลัก (ตัดการนำทาง โฆษณา ฯลฯ) สำหรับ PDF การแบ่งหน้า หรือการค้นหาภายในเนื้อหา ให้ใช้ friendly_web_extract แทน

พารามิเตอร์:

  • url (จำเป็น) - ที่อยู่เว็บที่จะดึง
  • outputFormat - รูปแบบผลลัพธ์: markdown (ค่าเริ่มต้น), text, หรือ html
  • waitMs - เวลาพิเศษที่รอหลังจากโหลดหน้าเสร็จ ในกรณีที่เนื้อหาปรากฏช้า
  • timeoutMs - ระยะเวลารอก่อนยกเลิก (ค่าเริ่มต้น: 15 วินาที)
  • maxChars - จำนวนเนื้อหาสูงสุดที่จะส่งคืน (ค่าเริ่มต้น: 40,000 ตัวอักษร)
  • includeHtml - ตั้งเป็น true เพื่อส่งคืน HTML ดิบพร้อมกับเนื้อหาด้วย
  • headless - ตั้งเป็น false เพื่อดูหน้าต่างเบราว์เซอร์ (มีประโยชน์สำหรับการดีบัก)

ส่งคืน:

  • url - URL ที่ถูกร้องขอ
  • finalUrl - URL หลังจากการเปลี่ยนเส้นทางใดๆ
  • title - ชื่อหน้า
  • content - เนื้อหาที่แยกออกมา (ในรูปแบบที่ร้องขอ)
  • html - HTML ดิบ (เฉพาะเมื่อ includeHtml เป็นจริง)
  • meta - ข้อมูลเมตาของหน้า (คำอธิบาย, ผู้เขียน, เวลาที่เผยแพร่, ฯลฯ)
  • fetchedAt - เวลาประทับ ISO เมื่อดึงหน้า
  • truncated - ว่าเนื้อหาถูกตัดทอนให้พอดีกับ maxChars หรือไม่

friendly_search

ค้นหาเว็บและส่งคืนรายการผลลัพธ์

พารามิเตอร์:

  • query (จำเป็น) - สิ่งที่ต้องการค้นหา
  • engine - เครื่องมือค้นหาที่จะใช้ (duckduckgo หรือ google)
  • maxResults - จำนวนผลลัพธ์ที่จะส่งคืน (ค่าเริ่มต้น: 10, สูงสุด: 50)
  • timeoutMs - ระยะเวลารอก่อนยกเลิก (ค่าเริ่มต้น: 15 วินาที)
  • headless - ตั้งเป็น false เพื่อดูหน้าต่างเบราว์เซอร์

ส่งคืน:

  • query - คำค้นหาที่ใช้
  • engine - เครื่องมือค้นหาที่ใช้
  • results - อาร์เรย์ของผลลัพธ์ แต่ละรายการมี title, url, และ snippet
  • searchedAt - เวลาประทับ ISO เมื่อทำการค้นหา
  • fallback_result_html - HTML ดิบของหน้า (รวมเฉพาะเมื่อไม่พบผลลัพธ์)
  • debug_info - ข้อมูลการวินิจฉัยเกี่ยวกับความพยายามค้นหา

การจัดการ CAPTCHA: หากตรวจพบ CAPTCHA ขณะทำงานในโหมด headless เครื่องมือจะลองใหม่โดยอัตโนมัติด้วยหน้าต่างเบราว์เซอร์ที่มองเห็นได้ ซึ่งเปิดโอกาสให้คุณแก้ CAPTCHA ด้วยตนเอง ฟิลด์ debug_info.retried ระบุว่ามีการใช้ทางเลือกสำรองนี้หรือไม่

friendly_web_extract

แยกเนื้อหาจาก URL ตรวจจับอัตโนมัติว่า URL ชี้ไปยัง PDF หรือหน้าเว็บ และจัดการแต่ละอย่างอย่างเหมาะสม

พารามิเตอร์:

  • url (จำเป็น) - URL ที่จะดึง (PDF หรือหน้าเว็บ)
  • maxChars - จำนวนข้อความสูงสุดที่จะส่งคืน (ค่าเริ่มต้น: 40,000 ตัวอักษร)
  • offset - ตำแหน่งตัวอักษรที่จะเริ่มต้น (ค่าเริ่มต้น: 0) ใช้เพื่อแบ่งหน้าผ่านเนื้อหาขนาดใหญ่
  • search - ค้นหาวลีและส่งคืนรายการที่ตรงกันพร้อมบริบทรอบๆ แทนเนื้อหาทั้งหมด
  • contextChars - จำนวนตัวอักษรของบริบทรอบๆ แต่ละรายการที่ค้นหาพบ (ค่าเริ่มต้น: 200)
  • waitMs - เวลาพิเศษที่รอหลังจากโหลดหน้า สำหรับเนื้อหาแบบไดนามิก (เฉพาะหน้าเว็บ)
  • timeoutMs - ระยะเวลารอก่อนยกเลิก (ค่าเริ่มต้น: 15 วินาที, เฉพาะหน้าเว็บ)
  • headless - ตั้งเป็น false เพื่อดูหน้าต่างเบราว์เซอร์ (เฉพาะหน้าเว็บ)

ส่งคืน (โหมดปกติ):

  • url - URL ที่ถูกร้องขอ
  • contentType - อย่างใดอย่างหนึ่งระหว่าง pdf หรือ html
  • title - ชื่อหน้า/เอกสาร
  • author - ผู้เขียน PDF (เฉพาะ PDF, หากมี)
  • creationDate - เวลาที่สร้าง PDF (เฉพาะ PDF, หากมี)
  • pageCount - จำนวนหน้า (เฉพาะ PDF)
  • totalChars - จำนวนตัวอักษรทั้งหมด (ใช้กับ offset เพื่อแบ่งหน้า)
  • offset - ออฟเซ็ตที่ใช้
  • content - เนื้อหาข้อความที่แยกออกมา
  • fetchedAt - เวลาประทับ ISO
  • truncated - ว่ายังมีเนื้อหาเหลือหลังจากส่วนนี้หรือไม่

ส่งคืน (โหมดค้นหา):

  • url, contentType, title, totalChars, fetchedAt - เช่นเดียวกับข้างต้น
  • search - วลีค้นหาที่ใช้
  • matchCount - จำนวนรายการที่พบ
  • matches - อาร์เรย์ของรายการที่ตรงกัน แต่ละรายการมี position, context, prefix, และ suffix

friendly_web_ask

ดึง URL (PDF หรือหน้าเว็บ) และให้ LLM ตอบคำถามเกี่ยวกับเนื้อหานั้น ตรวจจับประเภทเนื้อหาอัตโนมัติ เอกสารถูกประมวลผลในบริบทแยกต่างหาก ทำให้การสนทนาหลักของคุณกระชับ

พารามิเตอร์:

  • url (จำเป็น) - URL ที่จะดึง (PDF หรือหน้าเว็บ)
  • ask (จำเป็น) - คำถามหรือคำสั่งสำหรับ LLM (สรุป, แยกข้อมูล, ตอบคำถาม, ฯลฯ)
  • askMaxInputTokens - โทเค็นอินพุตสูงสุดต่อการเรียก LLM (ค่าเริ่มต้น: 150,000)
  • askMaxOutputTokens - โทเค็นเอาต์พุตสูงสุดต่อการเรียก LLM (ค่าเริ่มต้น: 4,096)
  • askTimeout - หมดเวลาในหน่วยมิลลิวินาที (ค่าเริ่มต้น: 300,000 = 5 นาที)
  • askSplitAndSynthesize - สำหรับเอกสารขนาดใหญ่: แบ่งเป็นส่วนๆ ประมวลผลแต่ละส่วน แล้วสังเคราะห์ผลลัพธ์ (ค่าเริ่มต้น: false) คำเตือน: ใช้โทเค็นจำนวนมาก
  • waitMs - เวลาพิเศษที่รอหลังจากโหลดหน้า สำหรับเนื้อหาแบบไดนามิก (เฉพาะหน้าเว็บ)
  • timeoutMs - ระยะเวลารอก่อนยกเลิก (ค่าเริ่มต้น: 15 วินาที, เฉพาะหน้าเว็บ)
  • headless - ตั้งเป็น false เพื่อดูหน้าต่างเบราว์เซอร์ (เฉพาะหน้าเว็บ)

ส่งคืน:

  • url - URL ที่ถูกร้องขอ
  • contentType - อย่างใดอย่างหนึ่งระหว่าง pdf หรือ html
  • title - ชื่อหน้า/เอกสาร
  • totalChars - จำนวนตัวอักษรทั้งหมดในเอกสาร
  • ask - คำสั่งที่ให้ไว้
  • answer - การตอบกลับของ LLM
  • model - โมเดลที่สร้างการตอบกลับ
  • chunksProcessed - จำนวนส่วนที่ประมวลผล (1 สำหรับเอกสารขนาดเล็ก, มากกว่าเมื่อใช้ askSplitAndSynthesize)
  • fetchedAt - เวลาประทับ ISO

โหมดถาม ใช้การสุ่มตัวอย่าง MCP เพื่อให้ LLM ประมวลผลเอกสารด้วยคำสั่งใดๆ มีประโยชน์สำหรับ:

  • เอกสารขนาดใหญ่ที่อาจล้นบริบท
  • ลดต้นทุนโทเค็นในการสนทนาหลัก

เมื่อเปิดใช้งาน askSplitAndSynthesize เอกสารที่เกิน askMaxInputTokens จะถูกแบ่งเป็นส่วนที่ซ้อนทับกันโดยอัตโนมัติ แต่ละส่วนถูกประมวลผลแยกกัน และผลลัพธ์จะถูกสังเคราะห์เป็นคำตอบเดียวที่สอดคล้องกัน การตอบกลับสุดท้ายจะให้ในภาษาเดียวกับคำขอของคุณ โดยไม่คำนึงถึงภาษาของเอกสาร

คลังเอกสาร

คลังเอกสารคือคลังเอกสารในเครื่องที่ค้นหาได้ รองรับ PDF, ไฟล์ HTML, และข้อความธรรมดา (Markdown/TXT) เมื่อคุณเพิ่มเอกสาร Research Friend จะจัดเก็บไฟล์ต้นฉบับ แยกข้อความ (สำหรับ PDF/HTML) และบันทึกข้อมูลเมตาในฐานข้อมูลในเครื่อง การค้นหาใช้ ripgrep เบื้องหลังเพื่อการจับคู่ที่รวดเร็วและรับรู้วลี

ตำแหน่งคลังเอกสาร

คลังเอกสารอยู่ภายใต้ ~/.research-friend/:

  • inbox/ - วางไฟล์ที่นี่เพื่อประมวลผล
  • store/ - การจัดเก็บเอกสารที่เป็นระเบียบและข้อความที่แยกออกมา
  • stash.db - ฐานข้อมูลเมตาดาต้า

ประเภทไฟล์ที่รองรับ

  • PDF: .pdf (แยกข้อความ)
  • HTML: .html, .htm (แยกข้อความ)
  • Markdown: .md, .markdown (จัดเก็บเป็นข้อความธรรมดา)
  • ข้อความ: .txt (จัดเก็บเป็นข้อความธรรมดา)

เครื่องมือคลังเอกสาร

stash_open_inbox

เปิดโฟลเดอร์กล่องขาเข้าของคลังเอกสารในตัวจัดการไฟล์ของคุณเพื่อการลากและวางที่ง่ายขึ้น

ส่งคืน:

  • opened - ว่าคำขอเปิดโฟลเดอร์ถูกส่งหรือไม่
  • inboxPath - พาธสัมบูรณ์ไปยังกล่องขาเข้า
  • command - คำสั่ง OS ที่ใช้
  • args - อาร์กิวเมนต์คำสั่งที่ใช้

stash_process_inbox

ประมวลผลไฟล์ใน inbox/ จัดประเภทเป็นหัวข้อ แยกข้อความ และจัดเก็บผลลัพธ์ สำหรับเอกสารขนาดยาว การจัดประเภทใช้ส่วนที่สุ่มตัวอย่าง (เริ่มต้น/กลาง/สิ้นสุด บวกกับส่วนสุ่มอีกสองสามส่วน) เพื่อปรับปรุงความแม่นยำของหัวข้อ

ส่งคืน:

  • processed - อาร์เรย์ของชื่อไฟล์ที่ประมวลผลสำเร็จ
  • errors - ข้อผิดพลาดใดๆ ที่พบ
  • documents - อาร์เรย์ของระเบียนเอกสารที่สร้างขึ้น

reindex_stash

สร้างบทสรุปใหม่ จัดสรรหัวข้อใหม่ และอัปเดตข้อมูลเมตาของคลังสำหรับเอกสารในคลัง หากละเว้น ids หรือเว้นว่าง เอกสารทั้งหมดจะถูกทำดัชนีใหม่

พารามิเตอร์:

  • ids - ID เอกสารที่จะทำดัชนีใหม่ (ไม่บังคับ)

ส่งคืน:

  • reindexed - ID เอกสารที่ทำดัชนีใหม่
  • errors - ข้อผิดพลาดใดๆ ที่พบ
  • documents - อาร์เรย์ของระเบียนเอกสารที่อัปเดต

stash_list

แสดงรายการเอกสารในคลัง

พารามิเตอร์:

  • topic - กรองตามหัวข้อ (ไม่บังคับ)
  • limit - ผลลัพธ์สูงสุด (ค่าเริ่มต้น: 50)
  • offset - ออฟเซ็ตการแบ่งหน้า (ค่าเริ่มต้น: 0)

ส่งคืน:

  • type - all หรือ topic
  • totalDocuments - เอกสารทั้งหมด (เฉพาะเมื่อ type เป็น all)
  • count - ผลลัพธ์ที่ส่งคืนหลังการแบ่งหน้า
  • offset - ออฟเซ็ตการแบ่งหน้าที่ใช้
  • limit - ขีดจำกัดการแบ่งหน้าที่ใช้
  • topics - สรุปหัวข้อที่รู้จักและจำนวนเอกสาร
  • documents - รายการเอกสารพร้อมข้อมูลเมตา (รวม isPrimary เมื่อแสดงรายการหัวข้อ)

stash_search

ค้นหาชื่อไฟล์และเนื้อหาทั่วทั้งคลัง คำค้นหาทั้งหมดต้องมีอยู่ (ตรรกะ AND) การจับคู่ชื่อไฟล์จะแสดงก่อน ใช้เครื่องหมายคำพูดสำหรับวลีที่ตรงทั้งหมด

พารามิเตอร์:

  • query (จำเป็น) - คำค้นหา ใช้เครื่องหมายคำพูดสำหรับวลี: "sparkling wine"
  • topic - กรองตามหัวข้อ (ไม่บังคับ)
  • ids - กรองตาม ID เอกสารเฉพาะ (ไม่บังคับ)
  • limit - เอกสารสูงสุดที่จะส่งคืน (ค่าเริ่มต้น: 20)
  • offset - ออฟเซ็ตการแบ่งหน้า (ค่าเริ่มต้น: 0)
  • maxMatchesPerDoc - การจับคู่สูงสุดต่อเอกสาร (ค่าเริ่มต้น: 50)
  • context - บรรทัดของบริบทรอบๆ แต่ละการจับคู่ (ค่าเริ่มต้น: 1, สูงสุด: 5) ควบคุมทั้งความใกล้เคียงที่คำต้องปรากฏเพื่อให้ตรงกัน และจำนวนข้อความรอบๆ ที่ส่งคืน ผลลัพธ์:
  • totalMatches - จำนวนเอกสารทั้งหมดที่ตรงกันก่อนการแบ่งหน้า
  • count - ผลลัพธ์ที่ส่งกลับหลังการแบ่งหน้า
  • results - อาร์เรย์ของเอกสาร แต่ละรายการประกอบด้วย:
    • id, filename, fileType, summary, charCount, createdAt
    • matchType - filename, content, หรือ filename+content
    • matches - อาร์เรย์ของ { line, context } สำหรับแต่ละตำแหน่งที่ตรงกัน

ใช้ค่า line ร่วมกับ stash_extract เพื่อข้ามไปยังตำแหน่งที่ตรงกันโดยตรง

stash_extract

แยกเนื้อหาจากเอกสารที่เก็บไว้เพื่ออ่าน ใช้หมายเลขบรรทัดจากผลลัพธ์ stash_search เพื่อข้ามไปยังตำแหน่งที่ตรงกันโดยตรง

พารามิเตอร์:

  • id (จำเป็น) - รหัสเอกสารจาก stash_list/stash_search
  • maxChars - จำนวนข้อความสูงสุดที่จะส่งกลับ (ค่าเริ่มต้น: 40,000 ตัวอักษร)
  • offset - ตำแหน่งตัวอักษรที่จะเริ่มต้น (ใช้ร่วมกับ line ไม่ได้)
  • line - หมายเลขบรรทัดที่จะเริ่มต้น (ใช้ร่วมกับ offset ไม่ได้)

ผลลัพธ์:

  • id, filename, fileType, summary - ข้อมูลเมตาของเอกสาร
  • totalChars - จำนวนตัวอักษรทั้งหมดในเอกสาร
  • offset - ออฟเซ็ตตัวอักษร (รวมอยู่เมื่อใช้ line สำหรับการอ้างอิง)
  • line - หมายเลขบรรทัด (เฉพาะเมื่อใช้พารามิเตอร์ line)
  • content - เนื้อหาข้อความที่แยกออกมา
  • truncated - ระบุว่ายังมีเนื้อหาเหลืออยู่หลังจากส่วนนี้หรือไม่

stash_ask

ให้ LLM ตอบคำถามเกี่ยวกับเอกสารที่เก็บไว้ เอกสารถูกประมวลผลในบริบทที่แยกต่างหาก ทำให้การสนทนาหลักของคุณกระชับ

พารามิเตอร์:

  • id (จำเป็น) - รหัสเอกสารจาก stash_list/stash_search
  • ask (จำเป็น) - คำถามหรือคำสั่งสำหรับ LLM
  • askMaxInputTokens - โทเค็นอินพุตสูงสุดต่อการเรียก LLM (ค่าเริ่มต้น: 150,000)
  • askMaxOutputTokens - โทเค็นเอาต์พุตสูงสุดต่อการเรียก LLM (ค่าเริ่มต้น: 4,096)
  • askTimeout - หมดเวลาในหน่วยมิลลิวินาที (ค่าเริ่มต้น: 300,000 = 5 นาที)
  • askSplitAndSynthesize - สำหรับเอกสารขนาดใหญ่: แบ่งเป็นส่วนๆ ประมวลผลแต่ละส่วน แล้วสังเคราะห์ผลลัพธ์ (ค่าเริ่มต้น: false)

ผลลัพธ์:

  • id, filename, fileType, summary - ข้อมูลเมตาของเอกสาร
  • totalChars - จำนวนตัวอักษรทั้งหมดในเอกสาร
  • ask - คำสั่งที่ได้รับ
  • answer - การตอบกลับของ LLM
  • model - โมเดลที่สร้างการตอบกลับ
  • chunksProcessed - จำนวนส่วนที่ประมวลผล

ขั้นตอนการทำงานทั่วไป

  1. วางไฟล์ลงใน ~/.research-friend/inbox/
  2. รัน stash_process_inbox
  3. ใช้ stash_list เพื่อเรียกดูหัวข้อ
  4. ใช้ stash_search เพื่อค้นหาเอกสารที่เกี่ยวข้อง
  5. ใช้ stash_extract เพื่ออ่านเอกสารที่ต้องการ หรือ stash_ask เพื่อถามคำถามเกี่ยวกับเอกสารนั้น

การแก้ไขปัญหา

ข้อผิดพลาด "Browser closed unexpectedly" หรือคล้ายกัน

ลองติดตั้งเบราว์เซอร์ใหม่:

npx playwright install chromium --force

บน Linux คุณอาจต้องใช้ dependencies ของระบบด้วย:

npx playwright install-deps chromium

เซิร์ฟเวอร์ไม่เริ่มทำงาน

ตรวจสอบให้แน่ใจว่าคุณใช้ Node.js เวอร์ชัน 20 หรือใหม่กว่า:

node --version

หากเวอร์ชันของคุณเก่ากว่า ไปที่ nodejs.org เพื่อดาวน์โหลดเวอร์ชันใหม่กว่า

ใบอนุญาต

MIT