@j0hanz/fetch-url-mcp 1.11.8 → 1.12.1

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.
Files changed (62) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +182 -79
  3. package/dist/http/auth.d.ts.map +1 -1
  4. package/dist/http/auth.js +58 -17
  5. package/dist/http/helpers.d.ts +1 -1
  6. package/dist/http/helpers.d.ts.map +1 -1
  7. package/dist/http/helpers.js +7 -9
  8. package/dist/http/native.d.ts.map +1 -1
  9. package/dist/http/native.js +232 -27
  10. package/dist/http/rate-limit.d.ts.map +1 -1
  11. package/dist/http/rate-limit.js +2 -1
  12. package/dist/index.js +5 -4
  13. package/dist/lib/config.d.ts +1 -1
  14. package/dist/lib/config.d.ts.map +1 -1
  15. package/dist/lib/config.js +8 -1
  16. package/dist/lib/core.d.ts +8 -4
  17. package/dist/lib/core.d.ts.map +1 -1
  18. package/dist/lib/core.js +240 -73
  19. package/dist/lib/fetch-pipeline.d.ts.map +1 -1
  20. package/dist/lib/fetch-pipeline.js +15 -2
  21. package/dist/lib/http.d.ts.map +1 -1
  22. package/dist/lib/http.js +1 -1
  23. package/dist/lib/mcp-interop.d.ts +15 -3
  24. package/dist/lib/mcp-interop.d.ts.map +1 -1
  25. package/dist/lib/mcp-interop.js +94 -25
  26. package/dist/lib/url.d.ts.map +1 -1
  27. package/dist/lib/url.js +1 -1
  28. package/dist/lib/utils.d.ts.map +1 -1
  29. package/dist/lib/utils.js +5 -5
  30. package/dist/resources/index.d.ts +4 -0
  31. package/dist/resources/index.d.ts.map +1 -1
  32. package/dist/resources/index.js +39 -4
  33. package/dist/schemas.d.ts +5 -5
  34. package/dist/schemas.d.ts.map +1 -1
  35. package/dist/schemas.js +7 -9
  36. package/dist/server.d.ts +3 -1
  37. package/dist/server.d.ts.map +1 -1
  38. package/dist/server.js +20 -11
  39. package/dist/tasks/execution.d.ts +1 -1
  40. package/dist/tasks/execution.d.ts.map +1 -1
  41. package/dist/tasks/execution.js +72 -25
  42. package/dist/tasks/handlers.d.ts.map +1 -1
  43. package/dist/tasks/handlers.js +31 -24
  44. package/dist/tasks/manager.d.ts +5 -2
  45. package/dist/tasks/manager.d.ts.map +1 -1
  46. package/dist/tasks/manager.js +58 -19
  47. package/dist/tasks/owner.d.ts +5 -0
  48. package/dist/tasks/owner.d.ts.map +1 -1
  49. package/dist/tasks/owner.js +15 -7
  50. package/dist/tasks/registry.d.ts +10 -8
  51. package/dist/tasks/registry.d.ts.map +1 -1
  52. package/dist/tasks/registry.js +27 -15
  53. package/dist/tools/fetch-url.d.ts +2 -0
  54. package/dist/tools/fetch-url.d.ts.map +1 -1
  55. package/dist/tools/fetch-url.js +76 -21
  56. package/dist/transform/dom-prep.d.ts.map +1 -1
  57. package/dist/transform/dom-prep.js +6 -6
  58. package/dist/transform/transform.d.ts.map +1 -1
  59. package/dist/transform/transform.js +17 -14
  60. package/dist/transform/worker-pool.d.ts.map +1 -1
  61. package/dist/transform/worker-pool.js +43 -3
  62. package/package.json +14 -5
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 j0hanz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -6,28 +6,36 @@
6
6
 
7
7
  [![Add to LM Studio](https://files.lmstudio.ai/deeplink/mcp-install-light.svg)](https://lmstudio.ai/install-mcp?name=fetch-url&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBqMGhhbnovZmV0Y2gtdXJsLW1jcEBsYXRlc3QiXX0%3D) [![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=fetch-url&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBqMGhhbnovZmV0Y2gtdXJsLW1jcEBsYXRlc3QiXX0%3D) [![Install in Goose](https://block.github.io/goose/img/extension-install-dark.svg)](https://block.github.io/goose/extension?cmd=npx&arg=-y&arg=%40j0hanz%2Ffetch-url-mcp%40latest&id=%40j0hanz%2Ffetch-url-mcp&name=fetch-url&description=fetch-url%20MCP%20server)
8
8
 
9
- A web content fetcher MCP server that converts HTML to clean, AI and human readable markdown.
9
+ An MCP server that fetches web pages and converts them to clean, readable Markdown.
10
10
 
11
11
  ## Overview
12
12
 
13
- The Fetch URL MCP Server provides a standardized interface for fetching public web content and transforming it into Markdown enriched with structured metadata. It validates URLs and applies noise removal heuristics. The server supports both inline and task-based execution modes, making it suitable for a wide range of client applications and LLM interactions.
13
+ This server takes a URL, fetches the page, and strips away everything you don't need navigation, sidebars, banners, scripts leaving just the main content as Markdown. It's perfect for feeding into LLMs, giving them the distilled essence of a page without the noise. It also recognizes GitHub, GitLab, Bitbucket, and Gist URLs and rewrites them to fetch the raw content directly.
14
+
15
+ By default it runs over stdio. Pass `--http` if you need a proper HTTP endpoint with auth, rate limiting, TLS, and session support.
14
16
 
15
17
  ## Key Features
16
18
 
17
- - `fetch-url` validates public HTTP(S) URLs, fetches the page, and returns cleaned Markdown plus structured metadata.
18
- - The tool advertises optional task support and emits progress updates while fetching and transforming larger pages.
19
- - GitHub, GitLab, Bitbucket, and Gist page URLs are rewritten to raw-content endpoints when possible before fetch.
20
- - `internal://instructions` exposes built-in guidance as an MCP resource.
21
- - HTTP mode adds host/origin validation, auth, rate limiting, health checks, OAuth protected-resource metadata, and session-bound URLs.
19
+ - **HTML to Markdown** Turns any public web page into clean, readable Markdown with metadata like `title`, `url`, `contentSize`, and `truncated`.
20
+ - **Smart URL handling** Recognizes GitHub, GitLab, Bitbucket, and Gist page URLs and rewrites them to raw-content endpoints before fetching.
21
+ - **Task mode** — Big or slow pages can run as async MCP tasks with progress updates, instead of blocking. In HTTP mode, tasks are bound to the authenticated caller rather than a single MCP session, so they can be resumed after reconnecting with the same credentials. Polling task state also exposes `progress` and `total` when available.
22
+ - **Self-documenting** — Includes an `internal://instructions` resource and a `get-help` prompt so clients know how to use it.
23
+ - **HTTP mode** Optionally serves over Streamable HTTP with host/origin validation, bearer or OAuth auth, rate limiting, health checks, and TLS.
24
+
25
+ ## Web Client
26
+
27
+ A browser-based client is available if you want to use the server without any MCP setup.
28
+
29
+ **[Live app](https://fetch-url-client.vercel.app)** · [Source code](https://github.com/j0hanz/fetch-url)
22
30
 
23
31
  ## Requirements
24
32
 
25
- - Node.js >=24 (from `package.json`)
26
- - Docker is optional if you want to run the published container image.
33
+ - **Node.js** >= 24
34
+ - **Docker** (optional) — only needed if you want to run the container image
27
35
 
28
36
  ## Quick Start
29
37
 
30
- Use this standard MCP client configuration:
38
+ Add this to your MCP client config:
31
39
 
32
40
  ```json
33
41
  {
@@ -474,9 +482,9 @@ For more info, see [Kilo Code docs](https://kilocode.ai/docs).
474
482
 
475
483
  ## Use Cases
476
484
 
477
- - Fetch documentation pages, blog posts, or reference material into Markdown before sending them to an LLM.
478
- - Retrieve repository-hosted content from GitHub, GitLab, Bitbucket, or Gists and let the server rewrite page URLs to raw endpoints when possible.
479
- - Use task mode for large pages or slower sites when the fetch might otherwise be delayed, cancelled, or better handled asynchronously.
485
+ - **Documentation for LLMs** — Grab a docs page, blog post, or reference article as Markdown and pass it straight into a context window.
486
+ - **Repository content** Hand it a GitHub, GitLab, or Bitbucket URL and it resolves the raw content endpoint. Works with Gists too.
487
+ - **Slow or large pages** Task mode lets big fetches run in the background while sending monotonic progress updates back to the client, while `tasks/get` exposes the latest `statusMessage`, `progress`, and `total`.
480
488
 
481
489
  ## Architecture
482
490
 
@@ -522,13 +530,30 @@ For more info, see [Kilo Code docs](https://kilocode.ai/docs).
522
530
 
523
531
  #### `fetch-url`
524
532
 
525
- Fetch public webpages and convert HTML into AI-readable Markdown. The tool is read-only, does not execute page JavaScript, and supports optional task mode for larger or slower fetches.
533
+ Takes a URL and returns Markdown. Read-only — no JavaScript execution. Supports running as a background MCP task for large or slow pages. When task mode is used, `tasks/get` and `tasks/list` include `statusMessage`, `progress`, and `total` whenever progress has been reported.
526
534
 
527
535
  | Parameter | Type | Required | Description |
528
536
  | --------- | -------- | -------- | --------------------------- |
529
537
  | `url` | `string` | yes | Target URL. Max 2048 chars. |
530
538
 
531
- The response is returned as MCP text content and, when validation succeeds, as `structuredContent` containing `url`, `resolvedUrl`, `finalUrl`, `title`, `metadata`, `markdown`, `fetchedAt`, `contentSize`, and `truncated`. A `truncated: true` result means the content hit server-enforced fetch or inline limits.
539
+ You get text content back by default. If output validation passes, the response also includes `structuredContent` with typed fields: `url`, `resolvedUrl`, `finalUrl`, `title`, `metadata`, `markdown`, `fetchedAt`, `contentSize`, and `truncated`. A `true` value for `truncated` means the content hit a server-side size limit.
540
+
541
+ To opt into progress updates, include `_meta.progressToken` in the tool call. The token may be a string or number. The server may then emit monotonic `notifications/progress` updates, and task mode reuses the same token until the task reaches a terminal state.
542
+
543
+ ```json
544
+ {
545
+ "method": "tools/call",
546
+ "params": {
547
+ "name": "fetch-url",
548
+ "arguments": {
549
+ "url": "https://example.com/docs"
550
+ },
551
+ "_meta": {
552
+ "progressToken": 7
553
+ }
554
+ }
555
+ }
556
+ ```
532
557
 
533
558
  ```text
534
559
  1. [Client] -- tools/call {name: "fetch-url", arguments} --> [Server]
@@ -552,14 +577,14 @@ The response is returned as MCP text content and, when validation succeeds, as `
552
577
 
553
578
  ## MCP Capabilities
554
579
 
555
- | Capability | Status | Notes |
556
- | ------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------ |
557
- | completions | confirmed | Advertised in `createServerCapabilities()`. |
558
- | logging | confirmed | Advertised in `createServerCapabilities()` and handled through `SetLevelRequestSchema`. |
559
- | resources subscribe/listChanged | confirmed | Advertised in `createServerCapabilities()`. |
560
- | prompts | confirmed | `get-help` is registered during server startup. |
561
- | tasks | confirmed | Advertised in `createServerCapabilities()` and backed by registered task handlers plus optional tool task support. |
562
- | progress notifications | confirmed | Tool execution reports `notifications/progress` updates during fetch and transform stages. |
580
+ | Capability | Status | Notes |
581
+ | ------------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
582
+ | completions | confirmed | Advertised in `createServerCapabilities()`. |
583
+ | logging | confirmed | Advertised in `createServerCapabilities()` and handled through `SetLevelRequestSchema`. |
584
+ | resources subscribe/listChanged | confirmed | Advertised in `createServerCapabilities()`. |
585
+ | prompts | confirmed | `get-help` is registered during server startup. |
586
+ | tasks | confirmed | Advertised in `createServerCapabilities()` and backed by registered task handlers plus optional tool task support. |
587
+ | progress notifications | confirmed | Opt-in via `_meta.progressToken`. Tool execution reports monotonic `notifications/progress` updates during fetch and transform stages, and task-mode progress reuses the caller's token for the task lifetime. |
563
588
 
564
589
  ### Tool Annotations
565
590
 
@@ -572,57 +597,101 @@ The response is returned as MCP text content and, when validation succeeds, as `
572
597
 
573
598
  ### Structured Output
574
599
 
575
- - `fetch-url` publishes an explicit `outputSchema` and returns `structuredContent` when the assembled response passes validation.
600
+ The tool declares an `outputSchema` and includes `structuredContent` in the response when validation passes. Clients that support structured output get typed data directly; the rest use the text fallback.
576
601
 
577
602
  ## Configuration
578
603
 
579
- | Variable | Default | Applies To | Notes |
580
- | ------------------------------------------ | ------------------------- | ----------------- | --------------------------------------------------------------------- |
581
- | `HOST` | `127.0.0.1` | HTTP mode | Bind address. Non-loopback bindings also require `ALLOW_REMOTE=true`. |
582
- | `PORT` | `3000` | HTTP mode | Listening port for `--http`. |
583
- | `ALLOW_REMOTE` | `false` | HTTP mode | Must be enabled to bind to a non-loopback interface. |
584
- | `ACCESS_TOKENS` | unset | HTTP mode | Comma- or space-separated static bearer tokens. |
585
- | `API_KEY` | unset | HTTP mode | Alternate static token source for header auth. |
586
- | `OAUTH_ISSUER_URL` | unset | HTTP mode | Enables OAuth mode when combined with the other OAuth URLs. |
587
- | `OAUTH_AUTHORIZATION_URL` | unset | HTTP mode | Optional explicit authorization endpoint. |
588
- | `OAUTH_TOKEN_URL` | unset | HTTP mode | Optional explicit token endpoint. |
589
- | `OAUTH_REVOCATION_URL` | unset | HTTP mode | Optional OAuth revocation endpoint. |
590
- | `OAUTH_REGISTRATION_URL` | unset | HTTP mode | Optional OAuth dynamic client registration endpoint. |
591
- | `OAUTH_INTROSPECTION_URL` | unset | HTTP mode | Required for OAuth token introspection. |
592
- | `OAUTH_REQUIRED_SCOPES` | empty | HTTP mode | Required scopes enforced after auth. |
593
- | `OAUTH_CLIENT_ID` | unset | HTTP mode | Optional introspection client ID. |
594
- | `OAUTH_CLIENT_SECRET` | unset | HTTP mode | Optional introspection client secret. |
595
- | `SERVER_TLS_KEY_FILE` | unset | HTTP mode | Enable HTTPS when set together with `SERVER_TLS_CERT_FILE`. |
596
- | `SERVER_TLS_CERT_FILE` | unset | HTTP mode | TLS certificate path. |
597
- | `SERVER_TLS_CA_FILE` | unset | HTTP mode | Optional custom CA bundle. |
598
- | `SERVER_MAX_CONNECTIONS` | `0` | HTTP mode | Optional connection cap. |
599
- | `SERVER_HEADERS_TIMEOUT_MS` | unset | HTTP mode | Optional Node server tuning. |
600
- | `SERVER_REQUEST_TIMEOUT_MS` | unset | HTTP mode | Optional Node server tuning. |
601
- | `SERVER_KEEP_ALIVE_TIMEOUT_MS` | unset | HTTP mode | Optional keep-alive tuning. |
602
- | `SERVER_KEEP_ALIVE_TIMEOUT_BUFFER_MS` | unset | HTTP mode | Optional keep-alive tuning buffer. |
603
- | `SERVER_MAX_HEADERS_COUNT` | unset | HTTP mode | Optional header count limit. |
604
- | `SERVER_BLOCK_PRIVATE_CONNECTIONS` | `false` | HTTP mode | Enables inbound private-network protections. |
605
- | `ALLOWED_HOSTS` | empty | HTTP mode | Additional allowed `Host` and `Origin` values. |
606
- | `ALLOW_LOCAL_FETCH` | `false` | Fetching | Allows loopback and private-network fetch targets. |
607
- | `FETCH_TIMEOUT_MS` | `15000` | Fetching | Network fetch timeout in milliseconds. |
608
- | `USER_AGENT` | `fetch-url-mcp/<version>` | Fetching | Override the outbound user agent string. |
609
- | `MAX_INLINE_CONTENT_CHARS` | `0` | Tool output | `0` means no explicit inline truncation limit. |
610
- | `TASKS_MAX_TOTAL` | `5000` | Tasks | Total task capacity. |
611
- | `TASKS_MAX_PER_OWNER` | `1000` | Tasks | Per-owner task cap, clamped to the total cap. |
612
- | `TASKS_STATUS_NOTIFICATIONS` | `false` | Tasks | Enables status notifications for tasks. |
613
- | `TASKS_REQUIRE_INTERCEPTION` | `true` | Tasks | Requires task interception for task-capable tool execution. |
614
- | `TRANSFORM_CANCEL_ACK_TIMEOUT_MS` | `200` | Transform workers | Cancellation acknowledgement timeout. |
615
- | `TRANSFORM_WORKER_MODE` | `threads` | Transform workers | Worker execution mode. |
616
- | `TRANSFORM_WORKER_MAX_OLD_GENERATION_MB` | unset | Transform workers | Optional worker memory limit. |
617
- | `TRANSFORM_WORKER_MAX_YOUNG_GENERATION_MB` | unset | Transform workers | Optional worker memory limit. |
618
- | `TRANSFORM_WORKER_CODE_RANGE_MB` | unset | Transform workers | Optional worker memory limit. |
619
- | `TRANSFORM_WORKER_STACK_MB` | unset | Transform workers | Optional worker stack size. |
620
- | `FETCH_URL_MCP_EXTRA_NOISE_TOKENS` | empty | Content cleanup | Extra noise-removal tokens. |
621
- | `FETCH_URL_MCP_EXTRA_NOISE_SELECTORS` | empty | Content cleanup | Extra DOM selectors for noise removal. |
622
- | `FETCH_URL_MCP_LOCALE` | system default | Content cleanup | Locale override for extraction heuristics. |
623
- | `MARKDOWN_HEADING_KEYWORDS` | built-in list | Markdown cleanup | Override heading keywords used by cleanup. |
624
- | `LOG_LEVEL` | `info` | Logging | `debug`, `info`, `warn`, or `error`. |
625
- | `LOG_FORMAT` | `text` | Logging | Set to `json` for structured logs. |
604
+ All configuration is through environment variables. For basic stdio usage, nothing needs to be set.
605
+
606
+ ### HTTP Server
607
+
608
+ | Variable | Default | Notes |
609
+ | ------------------------------------- | ----------- | --------------------------------------------------------------------- |
610
+ | `HOST` | `127.0.0.1` | Bind address. Non-loopback bindings also require `ALLOW_REMOTE=true`. |
611
+ | `PORT` | `3000` | Listening port for `--http`. |
612
+ | `ALLOW_REMOTE` | `false` | Must be enabled to bind to a non-loopback interface. |
613
+ | `ALLOWED_HOSTS` | empty | Additional allowed `Host` and `Origin` values. |
614
+ | `SERVER_MAX_CONNECTIONS` | `0` | Optional connection cap. |
615
+ | `SERVER_HEADERS_TIMEOUT_MS` | unset | Optional Node server tuning. |
616
+ | `SERVER_REQUEST_TIMEOUT_MS` | unset | Optional Node server tuning. |
617
+ | `SERVER_KEEP_ALIVE_TIMEOUT_MS` | unset | Optional keep-alive tuning. |
618
+ | `SERVER_KEEP_ALIVE_TIMEOUT_BUFFER_MS` | unset | Optional keep-alive tuning buffer. |
619
+ | `SERVER_MAX_HEADERS_COUNT` | unset | Optional header count limit. |
620
+ | `SERVER_BLOCK_PRIVATE_CONNECTIONS` | `false` | Enables inbound private-network protections. |
621
+
622
+ ### Authentication & OAuth
623
+
624
+ | Variable | Default | Notes |
625
+ | ------------------------- | ------- | ----------------------------------------------------------- |
626
+ | `ACCESS_TOKENS` | unset | Comma- or space-separated static bearer tokens. |
627
+ | `API_KEY` | unset | Alternate static token source for header auth. |
628
+ | `OAUTH_ISSUER_URL` | unset | Enables OAuth mode when combined with the other OAuth URLs. |
629
+ | `OAUTH_AUTHORIZATION_URL` | unset | Optional explicit authorization endpoint. |
630
+ | `OAUTH_TOKEN_URL` | unset | Optional explicit token endpoint. |
631
+ | `OAUTH_REVOCATION_URL` | unset | Optional OAuth revocation endpoint. |
632
+ | `OAUTH_REGISTRATION_URL` | unset | Optional OAuth dynamic client registration endpoint. |
633
+ | `OAUTH_INTROSPECTION_URL` | unset | Required for OAuth token introspection. |
634
+ | `OAUTH_REQUIRED_SCOPES` | empty | Required scopes enforced after auth. |
635
+ | `OAUTH_CLIENT_ID` | unset | Optional introspection client ID. |
636
+ | `OAUTH_CLIENT_SECRET` | unset | Optional introspection client secret. |
637
+
638
+ ### TLS
639
+
640
+ | Variable | Default | Notes |
641
+ | ---------------------- | ------- | ----------------------------------------------------------- |
642
+ | `SERVER_TLS_KEY_FILE` | unset | Enable HTTPS when set together with `SERVER_TLS_CERT_FILE`. |
643
+ | `SERVER_TLS_CERT_FILE` | unset | TLS certificate path. |
644
+ | `SERVER_TLS_CA_FILE` | unset | Optional custom CA bundle. |
645
+
646
+ ### Fetching
647
+
648
+ | Variable | Default | Notes |
649
+ | ------------------- | ------------------------- | -------------------------------------------------- |
650
+ | `ALLOW_LOCAL_FETCH` | `false` | Allows loopback and private-network fetch targets. |
651
+ | `FETCH_TIMEOUT_MS` | `15000` | Network fetch timeout in milliseconds. |
652
+ | `USER_AGENT` | `fetch-url-mcp/<version>` | Override the outbound user agent string. |
653
+
654
+ ### Tool Output
655
+
656
+ | Variable | Default | Notes |
657
+ | -------------------------- | ------- | ---------------------------------------------- |
658
+ | `MAX_INLINE_CONTENT_CHARS` | `0` | `0` means no explicit inline truncation limit. |
659
+
660
+ ### Tasks
661
+
662
+ | Variable | Default | Notes |
663
+ | ---------------------------- | ------- | ------------------------------------------------------------------------------------ |
664
+ | `TASKS_MAX_TOTAL` | `5000` | Total retained task capacity, including completed/cancelled tasks until they expire. |
665
+ | `TASKS_MAX_PER_OWNER` | `1000` | Per-owner retained task cap, clamped to the total cap. |
666
+ | `TASKS_STATUS_NOTIFICATIONS` | `false` | Enables status notifications for tasks. |
667
+ | `TASKS_REQUIRE_INTERCEPTION` | `true` | Requires interception for task-capable tool execution. |
668
+
669
+ ### Transform Workers
670
+
671
+ | Variable | Default | Notes |
672
+ | ------------------------------------------ | --------- | ------------------------------------- |
673
+ | `TRANSFORM_CANCEL_ACK_TIMEOUT_MS` | `200` | Cancellation acknowledgement timeout. |
674
+ | `TRANSFORM_WORKER_MODE` | `threads` | Worker execution mode. |
675
+ | `TRANSFORM_WORKER_MAX_OLD_GENERATION_MB` | unset | Optional worker memory limit. |
676
+ | `TRANSFORM_WORKER_MAX_YOUNG_GENERATION_MB` | unset | Optional worker memory limit. |
677
+ | `TRANSFORM_WORKER_CODE_RANGE_MB` | unset | Optional worker memory limit. |
678
+ | `TRANSFORM_WORKER_STACK_MB` | unset | Optional worker stack size. |
679
+
680
+ ### Content Cleanup
681
+
682
+ | Variable | Default | Notes |
683
+ | ------------------------------------- | -------------- | ------------------------------------------ |
684
+ | `FETCH_URL_MCP_EXTRA_NOISE_TOKENS` | empty | Extra noise-removal tokens. |
685
+ | `FETCH_URL_MCP_EXTRA_NOISE_SELECTORS` | empty | Extra DOM selectors for noise removal. |
686
+ | `FETCH_URL_MCP_LOCALE` | system default | Locale override for extraction heuristics. |
687
+ | `MARKDOWN_HEADING_KEYWORDS` | built-in list | Override heading keywords used by cleanup. |
688
+
689
+ ### Logging
690
+
691
+ | Variable | Default | Notes |
692
+ | ------------ | ------- | ------------------------------------ |
693
+ | `LOG_LEVEL` | `info` | `debug`, `info`, `warn`, or `error`. |
694
+ | `LOG_FORMAT` | `text` | Set to `json` for structured logs. |
626
695
 
627
696
  ## HTTP Endpoints
628
697
 
@@ -649,6 +718,24 @@ The response is returned as MCP text content and, when validation succeeds, as `
649
718
 
650
719
  ## Development
651
720
 
721
+ ### Essential Commands
722
+
723
+ | Command | Description |
724
+ | -------------------- | ------------------------------------------------- |
725
+ | `npm run build` | Clean, compile TypeScript, copy assets. |
726
+ | `npm run dev` | Watch mode TypeScript compilation. |
727
+ | `npm run dev:run` | Run the server with `--watch` and `.env` support. |
728
+ | `npm start` | Start the compiled server. |
729
+ | `npm test` | Run the full test suite. |
730
+ | `npm run lint` | Lint with ESLint. |
731
+ | `npm run lint:fix` | Auto-fix lint issues. |
732
+ | `npm run type-check` | Type-check source and tests. |
733
+ | `npm run format` | Format with Prettier. |
734
+ | `npm run inspector` | Build and launch MCP Inspector. |
735
+
736
+ <details>
737
+ <summary><b>All npm scripts</b></summary>
738
+
652
739
  | Script | Command |
653
740
  | ------------------------ | ------------------------------------------------------------------------------------------------------------------- |
654
741
  | `clean` | `node scripts/tasks.mjs clean` |
@@ -675,17 +762,26 @@ The response is returned as MCP text content and, when validation succeeds, as `
675
762
  | `inspector` | `npm run build && npx -y @modelcontextprotocol/inspector node dist/index.js --stdio` |
676
763
  | `prepublishOnly` | `npm run lint && npm run type-check && npm run build` |
677
764
 
765
+ </details>
766
+
678
767
  ## Build and Release
679
768
 
680
- - The repository includes release automation under `.github/workflows/`.
681
- - `Dockerfile` and `docker-compose.yml` are available for container-based packaging and local runs.
682
- - `npm run prepublishOnly` runs the release gate: lint, type-check, and build.
769
+ - `npm run prepublishOnly` runs lint, type-check, and build as a single release gate.
770
+ - CI workflows are under `.github/workflows/`.
771
+ - `Dockerfile` and `docker-compose.yml` are included for containerized runs.
772
+ - Published on npm as [`@j0hanz/fetch-url-mcp`](https://www.npmjs.com/package/@j0hanz/fetch-url-mcp).
683
773
 
684
774
  ## Troubleshooting
685
775
 
686
- - For stdio mode, avoid writing logs to stdout; keep logs on stderr.
687
- - For HTTP mode, verify MCP protocol headers and endpoint routing.
688
- - Update client snippets when client MCP configuration formats change.
776
+ | Symptom | Likely Cause | Fix |
777
+ | --------------------------------------------- | ----------------------------------- | ----------------------------------------------------------------------------- |
778
+ | Server output mixes with MCP traffic on stdio | Logs going to stdout | Ensure all logging writes to stderr; the server does this by default. |
779
+ | HTTP mode returns `403` | Host/origin mismatch | Add the domain to `ALLOWED_HOSTS` or verify loopback bindings. |
780
+ | HTTP mode returns `401` | Missing or invalid token | Set `ACCESS_TOKENS` or configure OAuth env vars for remote bindings. |
781
+ | Fetch returns private-IP error | SSRF protections blocked the target | Set `ALLOW_LOCAL_FETCH=true` if the target is intentionally local. |
782
+ | `truncated: true` in response | Content exceeded inline limits | Increase `MAX_INLINE_CONTENT_CHARS` or accept truncated output. |
783
+ | Transform timeout or worker crash | Large or complex HTML | Tune `TRANSFORM_WORKER_MAX_OLD_GENERATION_MB` or increase `FETCH_TIMEOUT_MS`. |
784
+ | Client config not working | Wrong config format for the client | Check the matching `<details>` block above — config keys vary by client. |
689
785
 
690
786
  ## Credits
691
787
 
@@ -700,5 +796,12 @@ The response is returned as MCP text content and, when validation succeeds, as `
700
796
 
701
797
  ## Contributing and License
702
798
 
703
- - License: MIT
704
- - Contributions are welcome via pull requests.
799
+ Pull requests welcome. Please make sure these pass before submitting:
800
+
801
+ 1. `npm run lint` and `npm run type-check`
802
+ 2. `npm test`
803
+ 3. `npm run format`
804
+
805
+ ## License
806
+
807
+ MIT License. See [LICENSE](LICENSE) for details.
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/http/auth.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/http/auth.ts"],"names":[],"mappings":"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"}
package/dist/http/auth.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { randomBytes } from 'node:crypto';
2
2
  import { InvalidTokenError, ServerError, } from '@modelcontextprotocol/sdk/server/auth/errors.js';
3
- import { config } from '../lib/core.js';
3
+ import { config, logDebug, logWarn } from '../lib/core.js';
4
4
  import { normalizeHost } from '../lib/url.js';
5
5
  import { composeAbortSignal, hmacSha256Hex, isObject, parseUrlOrNull, timingSafeEqualUtf8, } from '../lib/utils.js';
6
6
  import { getHeaderValue, sendEmpty, sendError, sendJson, } from './helpers.js';
@@ -74,26 +74,28 @@ function buildAllowedHosts() {
74
74
  const ALLOWED_HOSTS = buildAllowedHosts();
75
75
  class HostOriginPolicy {
76
76
  validate(ctx) {
77
- const { req, res } = ctx;
77
+ const { req } = ctx;
78
78
  const host = this.resolveHostHeader(req);
79
79
  if (!host)
80
- return this.reject(res, 400, 'Missing or invalid Host header');
80
+ return this.reject(ctx, 400, 'Missing or invalid Host header');
81
81
  if (!ALLOWED_HOSTS.has(host))
82
- return this.reject(res, 403, 'Host not allowed');
82
+ return this.reject(ctx, 403, 'Host not allowed');
83
83
  const originHeader = getHeaderValue(req, 'origin');
84
84
  if (!originHeader)
85
85
  return true;
86
86
  const requestOrigin = this.resolveRequestOrigin(req);
87
87
  const origin = this.resolveOrigin(originHeader);
88
- if (!requestOrigin || !origin)
89
- return this.reject(res, 403, 'Invalid Origin header');
90
- if (!ALLOWED_HOSTS.has(origin.host))
91
- return this.reject(res, 403, 'Origin not allowed');
88
+ if (!requestOrigin || !origin) {
89
+ return this.reject(ctx, 403, 'Invalid Origin header');
90
+ }
91
+ if (!ALLOWED_HOSTS.has(origin.host)) {
92
+ return this.reject(ctx, 403, 'Origin not allowed');
93
+ }
92
94
  const isSameOrigin = requestOrigin.scheme === origin.scheme &&
93
95
  requestOrigin.host === origin.host &&
94
96
  requestOrigin.port === origin.port;
95
97
  if (!isSameOrigin)
96
- return this.reject(res, 403, 'Origin not allowed');
98
+ return this.reject(ctx, 403, 'Origin not allowed');
97
99
  return true;
98
100
  }
99
101
  resolveHostHeader(req) {
@@ -142,8 +144,16 @@ class HostOriginPolicy {
142
144
  defaultPortForScheme(scheme) {
143
145
  return scheme === 'https' ? '443' : '80';
144
146
  }
145
- reject(res, status, message) {
146
- sendJson(res, status, { error: message });
147
+ reject(ctx, status, message) {
148
+ logWarn('Host/Origin policy rejection', {
149
+ status,
150
+ reason: message,
151
+ method: ctx.method,
152
+ path: ctx.url.pathname,
153
+ host: getHeaderValue(ctx.req, 'host'),
154
+ origin: getHeaderValue(ctx.req, 'origin'),
155
+ }, 'http');
156
+ sendJson(ctx.res, status, { error: message });
147
157
  return false;
148
158
  }
149
159
  }
@@ -184,16 +194,30 @@ function resolveMcpProtocolVersion(req) {
184
194
  }
185
195
  export function ensureMcpProtocolVersion(req, res, options) {
186
196
  const version = resolveMcpProtocolVersion(req);
197
+ const path = URL.parse(req.url ?? '', 'http://localhost')?.pathname;
187
198
  if (!version) {
199
+ // Tolerate missing header on sessioned requests (expectedVersion set)
200
+ // to avoid breaking older clients that don't send it yet.
201
+ if (options?.expectedVersion) {
202
+ return true;
203
+ }
204
+ logWarn('MCP protocol version rejected', { reason: 'missing_header', path }, 'http');
188
205
  sendError(res, -32600, 'Missing MCP-Protocol-Version header');
189
206
  return false;
190
207
  }
191
208
  if (!SUPPORTED_MCP_PROTOCOL_VERSIONS.has(version)) {
209
+ logWarn('MCP protocol version rejected', { reason: 'unsupported_version', version, path }, 'http');
192
210
  sendError(res, -32600, `Unsupported MCP-Protocol-Version: ${version}`);
193
211
  return false;
194
212
  }
195
213
  const expectedVersion = options?.expectedVersion;
196
214
  if (expectedVersion && version !== expectedVersion) {
215
+ logWarn('MCP protocol version rejected', {
216
+ reason: 'version_mismatch',
217
+ version,
218
+ expectedVersion,
219
+ path,
220
+ }, 'http');
197
221
  sendError(res, -32600, `MCP-Protocol-Version mismatch: expected ${expectedVersion}, got ${version}`);
198
222
  return false;
199
223
  }
@@ -227,11 +251,17 @@ class AuthService {
227
251
  introspectionCache = new Map();
228
252
  async authenticate(req, signal) {
229
253
  const authHeader = getHeaderValue(req, 'authorization');
230
- if (!authHeader) {
231
- return this.authenticateWithApiKey(req);
232
- }
233
- const token = this.resolveBearerToken(authHeader);
234
- return this.authenticateWithToken(token, signal);
254
+ const source = authHeader ? 'authorization' : 'api-key';
255
+ const info = authHeader
256
+ ? await this.authenticateWithToken(this.resolveBearerToken(authHeader), signal)
257
+ : this.authenticateWithApiKey(req);
258
+ logDebug('Authentication succeeded', {
259
+ mode: config.auth.mode,
260
+ source,
261
+ clientId: info.clientId,
262
+ scopeCount: info.scopes.length,
263
+ }, 'auth');
264
+ return info;
235
265
  }
236
266
  authenticateWithToken(token, signal) {
237
267
  return config.auth.mode === 'oauth'
@@ -244,8 +274,10 @@ class AuthService {
244
274
  return this.verifyStaticToken(apiKey);
245
275
  }
246
276
  if (apiKey && config.auth.mode === 'oauth') {
277
+ logWarn('Auth failed: X-API-Key not supported for OAuth', {}, 'auth');
247
278
  throw new InvalidTokenError('X-API-Key not supported for OAuth');
248
279
  }
280
+ logWarn('Auth failed: missing credentials', { authMode: config.auth.mode }, 'auth');
249
281
  throw new InvalidTokenError(config.auth.mode === 'static'
250
282
  ? 'Missing Authorization or X-API-Key header'
251
283
  : 'Missing Authorization header');
@@ -275,8 +307,10 @@ class AuthService {
275
307
  }
276
308
  const tokenDigest = hmacSha256Hex(STATIC_TOKEN_HMAC_KEY, token);
277
309
  const matched = hasConstantTimeMatch(this.staticTokenDigests, tokenDigest);
278
- if (!matched)
310
+ if (!matched) {
311
+ logWarn('Auth failed: invalid static token', {}, 'auth');
279
312
  throw new InvalidTokenError('Invalid token');
313
+ }
280
314
  return this.buildStaticAuthInfo(token);
281
315
  }
282
316
  stripHash(url) {
@@ -320,9 +354,11 @@ class AuthService {
320
354
  .map((value) => this.canonicalizeResourceUri(value))
321
355
  .filter((value) => value !== null);
322
356
  if (audiences.length === 0) {
357
+ logWarn('Auth failed: token missing audience binding', {}, 'auth');
323
358
  throw new InvalidTokenError('Token missing audience binding');
324
359
  }
325
360
  if (!audiences.includes(expected)) {
361
+ logWarn('Auth failed: audience mismatch', {}, 'auth');
326
362
  throw new InvalidTokenError('Token audience does not match this MCP server');
327
363
  }
328
364
  }
@@ -357,6 +393,7 @@ class AuthService {
357
393
  if (response.body) {
358
394
  await response.body.cancel();
359
395
  }
396
+ logWarn('Token introspection HTTP error', { status: response.status }, 'auth');
360
397
  throw new ServerError(`Token introspection failed: ${response.status}`);
361
398
  }
362
399
  return response.json();
@@ -382,6 +419,7 @@ class AuthService {
382
419
  const tokenScopeSet = new Set(tokenScopes);
383
420
  const missing = requiredScopes.filter((s) => !tokenScopeSet.has(s));
384
421
  if (missing.length > 0) {
422
+ logWarn('Auth failed: insufficient scopes', { missingCount: missing.length }, 'auth');
385
423
  throw new InsufficientScopeError(missing);
386
424
  }
387
425
  }
@@ -394,17 +432,20 @@ class AuthService {
394
432
  if (cached && cached.expiresAt > Date.now()) {
395
433
  this.introspectionCache.delete(cacheKey);
396
434
  this.introspectionCache.set(cacheKey, cached);
435
+ logDebug('Token introspection cache hit', {}, 'auth');
397
436
  return cached.info;
398
437
  }
399
438
  const req = this.buildIntrospectionRequest(token, config.auth.resourceUrl, config.auth.clientId, config.auth.clientSecret);
400
439
  const payload = await this.requestIntrospection(config.auth.introspectionUrl, req, config.auth.introspectionTimeoutMs, signal);
401
440
  if (!isObject(payload) || payload['active'] !== true) {
402
441
  this.introspectionCache.delete(cacheKey);
442
+ logWarn('Auth failed: token inactive', {}, 'auth');
403
443
  throw new InvalidTokenError('Token is inactive');
404
444
  }
405
445
  this.assertTokenAudience(payload);
406
446
  const info = this.buildIntrospectionAuthInfo(token, payload);
407
447
  this.assertRequiredScopes(info.scopes);
448
+ logDebug('Token introspection successful', { clientId: info.clientId }, 'auth');
408
449
  this.evictStaleEntries();
409
450
  this.introspectionCache.set(cacheKey, {
410
451
  info,
@@ -63,6 +63,6 @@ interface SessionTeardownOptions {
63
63
  }
64
64
  export declare function teardownSessionResources(session: SessionRecordLike, options: SessionTeardownOptions): Promise<void>;
65
65
  export declare function teardownUnregisteredSessionResources(session: SessionRecordLike, context: string): Promise<void>;
66
- export declare function teardownSessionRegistration(server: McpServer, cancelMessage: string): void;
66
+ export declare function teardownSessionRegistration(server: McpServer): void;
67
67
  export {};
68
68
  //# sourceMappingURL=helpers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/http/helpers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/http/helpers.ts"],"names":[],"mappings":"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"}