TLLX Model Context Protocol (MCP) servers
  • JavaScript 100%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Luis 3dac845954 web_search: proactively instruct the model to research before asserting
Align the tool description with the CHAT-TLLX style: explicit
'Use PROACTIVELY' guidance to search before asserting anything not
fully certain (news, versions, prices, people, products, docs/APIs,
real-world claims), ground answers in results with source URLs, and
keep the honest evidence-boundary caveat (snippets are evidence,
not proof).
2026-10-04 15:39:33 +00:00
src tllx-websearch: MCP server exposing CHAT-TLLX web_search (text-only web search) 2026-10-04 15:27:24 +00:00
.gitignore tllx-websearch: MCP server exposing CHAT-TLLX web_search (text-only web search) 2026-10-04 15:27:24 +00:00
index.mjs web_search: proactively instruct the model to research before asserting 2026-10-04 15:39:33 +00:00
LICENSE tllx-websearch: MCP server exposing CHAT-TLLX web_search (text-only web search) 2026-10-04 15:27:24 +00:00
NOTICE tllx-websearch: MCP server exposing CHAT-TLLX web_search (text-only web search) 2026-10-04 15:27:24 +00:00
package-lock.json tllx-websearch: MCP server exposing CHAT-TLLX web_search (text-only web search) 2026-10-04 15:27:24 +00:00
package.json tllx-websearch: MCP server exposing CHAT-TLLX web_search (text-only web search) 2026-10-04 15:27:24 +00:00
README.md tllx-websearch: MCP server exposing CHAT-TLLX web_search (text-only web search) 2026-10-04 15:27:24 +00:00
test-e2e.mjs tllx-websearch: MCP server exposing CHAT-TLLX web_search (text-only web search) 2026-10-04 15:27:24 +00:00

tllx-websearch

A Model Context Protocol (MCP) server that exposes the CHAT-TLLX web_search tool — a text-only DuckDuckGo web search (titles, links, snippets, no images) — as a standard MCP tool.

The search core (the DuckDuckGo HTML parser in src/web-search.mjs and the HTML→text stripper in src/html-text.mjs) is copied from the CHAT-TLLX project (TLLX/CHAT-TLLX, src/server/tools/web-search.js and src/server/tools/html-text.js, AGPL-3.0-or-later). See NOTICE.

What is deliberately not included: the image tools (web_image_search, web_search_hybrid, show_image, …) and the web_extract social reader. If you need those later, they are separate, larger tools in CHAT-TLLX and would need their own port.


What it does

One tool: web_search

Arg Type Required Default Notes
query string yes — Search query. Use a concise site:domain query for public social posts.
limit int no 5 1–10. How many results to return.

It returns both:

  • a human/model-readable text block (same [Result N] presentation CHAT-TLLX uses), and
  • a machine-readable structuredContent object: { query, count, results: [{ number, title, url, snippet }] }, validated against a published outputSchema.

Cancellations are honoured: an abort from the client aborts the in-flight HTTP request.

Safety invariants (inherited from CHAT-TLLX)

  • 12 s hard per-request timeout.
  • 2 MB hard response-size cap, enforced while streaming.
  • Only one fixed, public endpoint is ever fetched (https://duckduckgo.com/html/), so the original full SSRF guard (DNS pinning, private-range blocking) is not needed and was dropped; the timeout and size limits are kept (see src/safe-fetch.mjs for the note).

Reliability note (inherited, not introduced here): this scrapes DuckDuckGo's HTML endpoint, the same way CHAT-TLLX does. It can be rate-limited, geo-restricted, or break if the page layout changes. When it can't parse results it degrades gracefully to No search results found for: ….


Requirements

  • Node.js ≥ 18 (uses the global fetch). Developed and tested on Node 24.
  • npm (to install dependencies).

Install & run

cd tllx-websearch-mcp
npm install
npm start            # = node index.mjs  → speaks MCP JSON-RPC over stdio

The process reads the MCP protocol on stdin, writes it on stdout, and logs diagnostics to stderr (so stdout stays a clean protocol channel).

Quick self-test

node test-e2e.mjs

Spawns the server, then drives it through the official MCP client: initialize → tools/list → tools/call. Exits 0 on success.


Wiring it into OpenCode

OpenCode spawns local MCP servers from mcp.servers. Add the server to your opencode.jsonc (global ~/.config/opencode/opencode.jsonc, or a project opencode.jsonc / .opencode/opencode.jsonc). Replace __ABS_PATH__ with the absolute path to this folder:

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "servers": {
      // The key here becomes the tool namespace. Keep it short and unique:
      //   flat name  ->  tllx_web_search
      //   code mode  ->  tools.tllx.web_search(...)
      "tllx": {
        "type": "local",
        "command": ["node", "__ABS_PATH__/index.mjs"]
      }
    }
  }
}

Then verify it is connected:

opencode mcp list        # should show:  ✓ tllx  connected

In the TUI you can also manage it with /mcps.

Calling the tool

With the tllx key above, the tool is namespaced under tllx. In OpenCode's default Code Mode it appears as:

tools.tllx.web_search({ query: "Model Context Protocol", limit: 3 })

(If your client does not use Code Mode, the flat name is tllx_web_search.)

The mcp.servers key is yours to choose. It only controls the namespace OpenCode derives for the tool name — it does not change the server's behaviour. Avoid a key that collides with an existing server or with OpenCode's built-in websearch tool.


Project layout

tllx-websearch-mcp/
├── index.mjs            # MCP server entry (stdio transport, registers web_search)
├── src/
│   ├── web-search.mjs   # copied DuckDuckGo parser + webSearch() + result formatter
│   ├── html-text.mjs    # copied htmlToText()/truncateText()
│   └── safe-fetch.mjs   # timeout + size-capped fetch (adapted from CHAT-TLLX)
├── test-e2e.mjs         # end-to-end stdio client test
├── package.json
└── NOTICE               # attribution for the copied CHAT-TLLX code

Design notes / future work

  • web_extract (CHAT-TLLX's social-aware page reader) is a much larger tool and is not ported. Adding it later would mean porting src/server/tools/web-extract.js and its adapters.
  • Image search is intentionally out of scope per the current requirement.
  • The webSearch wrapper returns structured data (no CHAT-TLLX session state). If you later want cross-call result numbering (e.g. to feed an extract-style tool), you would add a server-side session map keyed by the sessionId the SDK passes to the tool callback (extra.sessionId) — CHAT-TLLX does exactly this in web-tools.js.

License

This project is licensed under AGPL-3.0-or-later (see LICENSE). Portions are copied from CHAT-TLLX (AGPL-3.0-or-later) — see NOTICE for attribution.