ask-web-fetch-mcp 0.4.1 → 0.6.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6f34204d8bcf16d483e5292a58672fd6011e3d7ed825b802beb07738c77a8ff1
4
- data.tar.gz: c65b7193404995255cba3aa906d88442a559d2dc17e88835d9ed72ad8ca41601
3
+ metadata.gz: 33e377fca58f50a8e93cbe112374c0fe853dc5048505d7e7417d22d97e2c446d
4
+ data.tar.gz: 3aeb0347430bb21442599c38502c4d9063a9d75e3d3f88dcb812284ba5908b36
5
5
  SHA512:
6
- metadata.gz: ad9196aa7fc0a8c19def71913eb8d69cc656ea01ea8ac218f20d973709a66eb51cda0017d9d2e2b492d813d4669d27fa8857f77136c0588d4845694766b660ba
7
- data.tar.gz: 2c9dafac6c69c6cc699d721abdabaa86c013700a64a3548b9fc9b3b32de353a624694e3a2c22ad72078456f2b4d7ff8428653f6b76381e70e9591ad044a1ec50
6
+ metadata.gz: 6ff9783fb23e9b8912c4668787d64667949e69f5234dee7db4d2db52221bcf74bae27e0ce88ed3b96220516991bd3e8a0cb29b6b87da8ec81d1ffeb7a39890c7
7
+ data.tar.gz: aa002fe73da25c7b754941ebc27a69fa5c799e0ab5c05b1e1c65f2d58f1c9b2df617d4bd28d1231cd80dd8a9652920699752a6d97547b4154a256a6becfe2830
data/CHANGELOG.md CHANGED
@@ -1,3 +1,47 @@
1
+ ## [0.6.0] — 2026-08-12
2
+
3
+ ### Changed
4
+
5
+ - **The server owns its tool shell.** `ask_web_fetch` is now a
6
+ duck-typed tool (`Ask::WebFetch::MCP::Tool` — `name` /
7
+ `description` / `params_schema` / `call`) wrapping the library entry
8
+ `Ask::WebFetch.fetch`, instead of a renamed `Ask::Tools::WebFetch`.
9
+ The MCP adapter's contract is duck-typed by design, so the server
10
+ gains nothing from the ask-tools machinery — and the ask-tools /
11
+ ask-core / ask-schema dependency chain is gone from the server
12
+ process entirely. `ask-web-fetch` floor raised to `>= 0.7.1` (the
13
+ module-level API with the failure collapse and parked-domain
14
+ detection on every backend).
15
+ - **Cleaner error framing.** A failed call now surfaces as
16
+ `Error: Ask::WebFetch::ParkedDomainError: ...` — the class is still
17
+ named, without the tool layer's double wrap. Terminal verdicts
18
+ (parked, empty, dead 4xx) are never retried by clients; transient
19
+ failures raise the base `Error`.
20
+ - **The native agent tool stays available for non-MCP consumers.**
21
+ `Ask::Tools::WebFetch` lives in ask-web-fetch as an optional
22
+ integration (registered when ask-tools is present) for agent
23
+ frameworks that resolve tools by name.
24
+
25
+ ## [0.5.0] — 2026-08-12
26
+
27
+ ### Changed
28
+
29
+ - `ask-web-fetch` floor raised to `>= 0.6.1`. The server exposes the tool
30
+ unchanged, but `ask_web_fetch` now answers with the full current stack:
31
+ the pooled-httpx transport (no more hangs on multi-host crawls), real
32
+ network-idle waits in CDP-attached mode, JS-app-shell detection that
33
+ fails client-rendered pages through to a rendering backend, parked-domain
34
+ detection on every backend (GoDaddy/Namecheap registrar ads are rejected,
35
+ never returned as content), and warm-and-retry challenge handling.
36
+ - **Failure verdicts are now classed.** When every backend fails, the tool
37
+ raises the most definitive class — `ParkedDomainError` beats
38
+ `EmptyContentError` beats a deterministic `FetchError` (every backend
39
+ failed dead), and any transient failure in the mix keeps the retryable
40
+ base `Error`. A client calling `ask_web_fetch` on a parked domain gets
41
+ an error naming `ParkedDomainError` instead of a generic failure, so it
42
+ stops retrying the unretryable. The message still lists every backend
43
+ and what it said.
44
+
1
45
  ## [0.4.1] — 2026-08-11
2
46
 
3
47
  ### Changed
data/README.md CHANGED
@@ -5,9 +5,10 @@
5
5
  A minimal MCP (Model Context Protocol) server that exposes
6
6
  `Ask::Tools::WebFetch` as a callable tool over stdio. Designed for use with
7
7
  clients that support MCP (ZCode, Claude Code, etc.), it fetches a URL and
8
- returns clean markdown for LLM consumption — via the local pure-Ruby backend
9
- by default, with an automatic Jina Reader fallback for JS-rendered or blocked
10
- pages.
8
+ returns clean markdown for LLM consumption — through the full ask-web-fetch
9
+ backend chain: the fast pure-Ruby httpx fetch first, Jina Reader and
10
+ self-hosted Crawl4AI in between, and a real Chrome (launched, or attached
11
+ over CDP) last for JS-rendered and challenge-gated pages.
11
12
 
12
13
  ## Installation
13
14
 
@@ -56,9 +57,23 @@ collisions with client-side tools of the same name, matching
56
57
  The `ask-web-fetch` backend chain applies unchanged. Optional environment
57
58
  variables:
58
59
 
60
+ - `ASK_WEB_FETCH_CDP_URL` — CDP endpoint of an already-running Chrome
61
+ (e.g. `http://127.0.0.1:9222`); routes challenge-gated pages through a
62
+ trusted browser that has already solved them
63
+ - `ASK_WEB_FETCH_CHROME_PATH` / `ASK_WEB_FETCH_PROFILE` — tune the
64
+ launched-browser mode (binary path, persistent profile for solved
65
+ cookies)
66
+ - `CRAWL4AI_URL` / `CRAWL4AI_TOKEN` — lead the chain with a self-hosted
67
+ Crawl4AI renderer (`http://localhost:11235` when unset)
59
68
  - `JINA_API_KEY` — enables the Jina fallback with higher rate limits
60
69
  - `DEBUG=1` — ask-mcp debug logging on stderr
61
70
 
71
+ When every backend fails, the error names the verdict class: terminal
72
+ outcomes — a parked domain (`ParkedDomainError`), a page with no usable
73
+ content (`EmptyContentError`), a dead URL (`FetchError`) — are never
74
+ retryable; transient failures (timeouts, 5xx) raise the base
75
+ `Ask::WebFetch::Error`.
76
+
62
77
  ## Full documentation
63
78
 
64
79
  The full ask-rb documentation lives at https://ask-rb.github.io/ask-docs.
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ask/web_fetch'
4
+
5
+ module Ask
6
+ module WebFetch
7
+ module MCP
8
+ # The ask_web_fetch tool, duck-typed for Ask::MCP's ToolServer
9
+ # adapter (name / description / params_schema / call). The tool
10
+ # framing lives with its consumer — this server — not in the
11
+ # library: the capability is Ask::WebFetch.fetch, this is the
12
+ # agent-facing shell around it.
13
+ class Tool
14
+ def name
15
+ 'ask_web_fetch'
16
+ end
17
+
18
+ def description
19
+ 'Fetch a URL and return its content as clean markdown for LLM consumption. ' \
20
+ 'Use this to read web pages, articles, and documentation.'
21
+ end
22
+
23
+ def params_schema
24
+ {
25
+ 'type' => 'object',
26
+ 'properties' => {
27
+ 'url' => { 'type' => 'string', 'description' => 'The URL to fetch' },
28
+ 'max_chars' => { 'type' => 'integer', 'description' => 'Maximum number of characters to return (default 20000)' }
29
+ },
30
+ 'required' => ['url']
31
+ }
32
+ end
33
+
34
+ # Returns the fetched markdown (a String is a success for the
35
+ # adapter) or raises. The terminal verdicts — ParkedDomainError,
36
+ # EmptyContentError, FetchError — reach the client as their class,
37
+ # so it never retries the unretryable; transient failures raise
38
+ # the base Error.
39
+ def call(args)
40
+ url = args['url'].to_s
41
+ raise ArgumentError, 'missing required parameter: url' if url.empty?
42
+
43
+ max_chars = args['max_chars']
44
+ Ask::WebFetch.fetch(url, max_chars: max_chars || Ask::WebFetch::DEFAULT_MAX_CHARS)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -3,7 +3,7 @@
3
3
  module Ask
4
4
  module WebFetch
5
5
  module MCP
6
- VERSION = '0.4.1'
6
+ VERSION = '0.6.0'
7
7
  end
8
8
  end
9
9
  end
@@ -2,19 +2,20 @@
2
2
 
3
3
  require 'ask/mcp'
4
4
  require 'ask/web_fetch'
5
+ require_relative 'mcp/tool'
5
6
  require_relative 'mcp/version'
6
7
 
7
8
  module Ask
8
9
  module WebFetch
9
10
  # MCP (Model Context Protocol) server for ask-web-fetch.
10
11
  module MCP
11
- # Builds the tool exposed over MCP: Ask::Tools::WebFetch renamed to
12
- # "ask_web_fetch" to avoid collisions with client-side tools of the
13
- # same name (ask-web-search-mcp follows the same convention).
12
+ # Builds the tool exposed over MCP. The tool framing lives here —
13
+ # ask-web-fetch is a library (Ask::WebFetch.fetch); this server
14
+ # owns the agent-facing shell, named "ask_web_fetch" to avoid
15
+ # collisions with client-side tools of the same name
16
+ # (ask-web-search-mcp follows the same convention).
14
17
  def self.tool
15
- tool = Ask::Tools::WebFetch.new
16
- tool.define_singleton_method(:name) { 'ask_web_fetch' }
17
- tool
18
+ Tool.new
18
19
  end
19
20
 
20
21
  # Start the MCP server over stdio, exposing the ask_web_fetch tool.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ask-web-fetch-mcp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kaka Ruto
@@ -29,14 +29,14 @@ dependencies:
29
29
  requirements:
30
30
  - - ">="
31
31
  - !ruby/object:Gem::Version
32
- version: 0.5.1
32
+ version: 0.7.1
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - ">="
38
38
  - !ruby/object:Gem::Version
39
- version: 0.5.1
39
+ version: 0.7.1
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: minitest
42
42
  requirement: !ruby/object:Gem::Requirement
@@ -80,10 +80,15 @@ dependencies:
80
80
  - !ruby/object:Gem::Version
81
81
  version: '3.26'
82
82
  description: |
83
- A minimal MCP (Model Context Protocol) server that exposes Ask::Tools::WebFetch
83
+ A minimal MCP (Model Context Protocol) server that exposes ask_web_fetch
84
84
  as a callable tool over stdio. Designed for use with clients that support MCP
85
- (ZCode, Claude Code, etc.), it fetches a URL and returns clean markdown via the
86
- local pure-Ruby backend, with an automatic Jina Reader fallback.
85
+ (ZCode, Claude Code, etc.), it fetches a URL and returns clean markdown through
86
+ the ask-web-fetch backend chain fast pure-Ruby httpx fetch first, a real
87
+ Chrome (launched or CDP-attached) for JS-rendered and challenge-gated pages,
88
+ with Jina Reader and self-hosted Crawl4AI in between. Terminal failures
89
+ (parked domains, empty pages, dead 4xx) surface as their deterministic error
90
+ class, so clients never retry the unretryable. The tool shell (name, schema,
91
+ call) lives here, wrapping the Ask::WebFetch library.
87
92
  email:
88
93
  - kaka@myrrlabs.com
89
94
  executables:
@@ -97,6 +102,7 @@ files:
97
102
  - bin/ask-web-fetch-mcp
98
103
  - lib/ask-web-fetch-mcp.rb
99
104
  - lib/ask/web_fetch/mcp.rb
105
+ - lib/ask/web_fetch/mcp/tool.rb
100
106
  - lib/ask/web_fetch/mcp/version.rb
101
107
  homepage: https://github.com/ask-rb/ask-web-fetch-mcp
102
108
  licenses: