A fully-featured HTTP client with TLS fingerprinting (JA3/JA4, HTTP/2, QUIC) — available as a CLI tool, MCP server, and importable Go package.
fetchr is an open-source HTTP client with browser TLS fingerprinting (JA3/JA4, HTTP/2, QUIC) — a CLI, an MCP server that gives Claude Desktop, Claude Code, and other sandboxed AI assistants real HTTP access, and an importable Go package. Requests look identical to Chrome or Firefox, so they pass anti-bot and TLS-fingerprint detection that blocks standard HTTP clients.
- Why fetchr?
- fetchr vs the alternatives
- Features
- Quick Start
- CLI Usage
- MCP Integration
- MCP Tools
- Configuration
- Go Package
- FAQ
- License
AI assistants can't make HTTP requests. Claude Desktop, Claude Code, and other sandboxed AI tools block outbound network calls — they can't curl, fetch APIs, or check if a website is up. fetchr solves this as an MCP server, giving AI assistants full HTTP capabilities.
Websites block automated requests. Standard HTTP clients send a default TLS fingerprint that anti-bot systems detect instantly. fetchr impersonates real browsers at the TLS level — matching their JA3 hash, HTTP/2 SETTINGS frame, header order, and more — so your requests look identical to Chrome or Firefox.
| fetchr | curl / standard HTTP client | Headless browser | |
|---|---|---|---|
| Browser TLS fingerprint (JA3/JA4, HTTP/2, QUIC) | ✅ | ❌ | ✅ |
| Passes anti-bot TLS detection | ✅ | ❌ | |
| MCP server for AI assistants (Claude Desktop/Code) | ✅ | ❌ | ❌ |
| Lightweight — no headless browser to drive | ✅ | ✅ | ❌ |
| Single static binary | ✅ | ✅ | ❌ |
Export any request as a curl command |
✅ | n/a | ❌ |
| Importable Go package | ✅ | ❌ |
- TLS Fingerprinting — JA3, JA4, HTTP/2 SETTINGS, QUIC fingerprints
- Browser Profiles — Pre-configured Chrome and Firefox fingerprints, extensible via config
- MCP Server — stdio + SSE transport for Claude Desktop, Claude Code, and other AI assistants
- CLI Tool — Make requests, batch operations, and manage config from the terminal
- Go Package — Import
pkg/curlin your own Go applications - Curl Export — Print any request as an equivalent
curlcommand - Request Logging — File (JSONL), webhook, or both
- JSONC Config — JSON with comments, platform-aware auto-discovery, auto-created on first run
Full Usage Guide — Complete reference for every command, flag, tool parameter, config option, TLS fingerprinting guide, and recipes.
Contributing — Development setup, architecture, and internals for contributors.
Add fetchr to your AI coding agent (Claude Code, Cursor, Codex, Cline, etc.):
npx skills add thesatellite-ai/fetchrOne-liner (macOS/Linux):
curl -sL https://raw.githubusercontent.com/thesatellite-ai/fetchr/main/install.sh | shGo install:
go install github.com/thesatellite-ai/fetchr/cmd/fetchr@latestManual download:
# macOS (Apple Silicon)
curl -sL https://github.com/thesatellite-ai/fetchr/releases/latest/download/fetchr_darwin_arm64.tar.gz | tar xz
sudo mv fetchr /usr/local/bin/
# macOS (Intel)
curl -sL https://github.com/thesatellite-ai/fetchr/releases/latest/download/fetchr_darwin_amd64.tar.gz | tar xz
sudo mv fetchr /usr/local/bin/
# Linux (x86_64)
curl -sL https://github.com/thesatellite-ai/fetchr/releases/latest/download/fetchr_linux_amd64.tar.gz | tar xz
sudo mv fetchr /usr/local/bin/
# Linux (ARM64)
curl -sL https://github.com/thesatellite-ai/fetchr/releases/latest/download/fetchr_linux_arm64.tar.gz | tar xz
sudo mv fetchr /usr/local/bin/Windows (PowerShell):
Invoke-WebRequest -Uri https://github.com/thesatellite-ai/fetchr/releases/latest/download/fetchr_windows_amd64.zip -OutFile fetchr.zip
Expand-Archive fetchr.zip -DestinationPath .
Move-Item fetchr.exe C:\Windows\System32\Uninstall:
sudo rm /usr/local/bin/fetchrfetchr [command]
Commands:
serve Start the MCP server (stdio or SSE)
request Make a single HTTP request
batch Make multiple HTTP requests in parallel
config Manage configuration
version Print version and exit
completion Generate shell completion scripts
# Simple GET (returns body only by default)
fetchr request https://httpbin.org/get
# POST with JSON
fetchr request https://httpbin.org/post \
-X POST \
-H "Content-Type: application/json" \
-d '{"name": "John"}'
# Full response (status, headers, body, duration)
fetchr request https://httpbin.org/get -v
# Structured JSON output (body auto-parsed when Content-Type is JSON)
fetchr request https://httpbin.org/get --json
fetchr request https://httpbin.org/get --json | jq '.body.headers'
# Use Chrome fingerprint profile
fetchr request https://tls.peet.ws/api/all --profile chrome
# Print as curl command (does not execute the request)
fetchr request https://httpbin.org/post -X POST \
-H "Content-Type: application/json" -d '{"key":"value"}' --print-curl
# Save response to file
fetchr request https://httpbin.org/get -o response.txt
# Through a proxy
fetchr request https://httpbin.org/ip --proxy socks5://127.0.0.1:1080
# Skip TLS verification / don't follow redirects / force HTTP/1.1
fetchr request https://self-signed.local/api --insecure
fetchr request https://httpbin.org/redirect/3 --no-redirect
fetchr request https://httpbin.org/get --http1# From a JSON file
fetchr batch -f requests.json
# From stdin
echo '[{"url":"https://httpbin.org/get"},{"url":"https://httpbin.org/ip"}]' | fetchr batch --stdin
# Apply profile to all
fetchr batch -f requests.json --profile chrome
# JSON output
fetchr batch -f requests.json --jsonExample requests.json:
[
{"url": "https://httpbin.org/get"},
{
"url": "https://httpbin.org/post",
"method": "POST",
"headers": {"Content-Type": "application/json"},
"body": "{\"action\": \"create\"}"
},
{"url": "https://httpbin.org/headers", "headers": {"X-Custom": "hello"}}
]# Show where config lives
fetchr config path
# Create default config
fetchr config init
# Show resolved config (defaults + profiles)
fetchr config show
# Validate config syntax
fetchr config validate
# Use a specific config file
fetchr request https://example.com --config ./my-config.jsonc# Stdio (default, for Claude Desktop / Claude Code)
fetchr serve
# SSE transport
fetchr serve --transport sse --port :3000Add to ~/.claude/settings.json or project .claude/settings.json:
{
"mcpServers": {
"curl": {
"command": "fetchr",
"args": ["serve"]
}
}
}Add to claude_desktop_config.json:
{
"mcpServers": {
"curl": {
"command": "fetchr",
"args": ["serve"]
}
}
}fetchr serve --transport sse --port :3000
# Connect any MCP-compatible client to http://localhost:3000# Stdio mode
task inspect
# Or manually
npx @modelcontextprotocol/inspector ./fetchr serveMake a single HTTP request with full TLS fingerprinting support.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
url |
string | yes | — | The URL to request |
method |
string | no | GET |
GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS |
headers |
object | no | — | HTTP headers as key-value pairs |
header_order |
array | no | — | Header order (critical for fingerprint accuracy) |
body |
string | no | — | Request body |
cookies |
array | no | — | Cookies as [{name, value}] |
ja3 |
string | no | — | JA3 TLS fingerprint |
ja4r |
string | no | — | JA4 raw fingerprint |
http2_fingerprint |
string | no | — | HTTP/2 SETTINGS frame fingerprint |
quic_fingerprint |
string | no | — | QUIC fingerprint |
user_agent |
string | no | — | User-Agent header |
proxy |
string | no | — | Proxy URL (http, https, socks5) |
timeout |
integer | no | 30 |
Timeout in seconds |
insecure |
boolean | no | false |
Skip TLS certificate verification |
disable_redirect |
boolean | no | false |
Don't follow redirects |
force_http1 |
boolean | no | false |
Force HTTP/1.1 |
force_http3 |
boolean | no | false |
Force HTTP/3 (QUIC) |
protocol |
string | no | — | http1, http2, or http3 |
profile |
string | no | — | Named profile from config (chrome, firefox, etc.) |
print_curl |
boolean | no | false |
Include equivalent curl command in output |
{
"name": "request",
"arguments": {
"url": "https://httpbin.org/get"
}
}{
"name": "request",
"arguments": {
"url": "https://httpbin.org/post",
"method": "POST",
"headers": {
"Content-Type": "application/json",
"Authorization": "Bearer my-token"
},
"body": "{\"name\": \"John\", \"email\": \"john@example.com\"}"
}
}{
"name": "request",
"arguments": {
"url": "https://tls.peet.ws/api/all",
"profile": "chrome"
}
}{
"name": "request",
"arguments": {
"url": "https://tls.peet.ws/api/all",
"ja3": "771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,0-23-65281-10-11-35-16-5-13-18-51-45-43-27-17513,29-23-24,0",
"http2_fingerprint": "1:65536;2:0;4:6291456;6:262144|15663105|0|m,a,s,p",
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0.0.0"
}
}{
"name": "request",
"arguments": {
"url": "https://httpbin.org/ip",
"proxy": "socks5://127.0.0.1:1080"
}
}{
"name": "request",
"arguments": {
"url": "https://httpbin.org/post",
"method": "POST",
"headers": {"Content-Type": "application/json"},
"body": "{\"key\": \"value\"}",
"print_curl": true
}
}Make multiple HTTP requests concurrently. Returns a JSON array in the same order.
| Parameter | Type | Required | Description |
|---|---|---|---|
requests |
array | yes | Array of request objects (same parameters as request) |
profile |
string | no | Apply this profile to all requests that don't have their own |
{
"name": "batch",
"arguments": {
"requests": [
{"url": "https://httpbin.org/get"},
{"url": "https://httpbin.org/ip"},
{"url": "https://httpbin.org/user-agent"}
]
}
}{
"name": "batch",
"arguments": {
"profile": "chrome",
"requests": [
{"url": "https://httpbin.org/get"},
{
"url": "https://httpbin.org/post",
"method": "POST",
"headers": {"Content-Type": "application/json"},
"body": "{\"action\": \"create\"}"
}
]
}
}fetchr uses JSONC (JSON with comments) configuration files. On first run, a default config is auto-created.
Config is searched in order (first found wins):
| Platform | Search Order |
|---|---|
| macOS | ./fetchr.jsonc > ~/.config/fetchr/config.jsonc > ~/Library/Application Support/fetchr/config.jsonc |
| Linux | ./fetchr.jsonc > $XDG_CONFIG_HOME/fetchr/config.jsonc > ~/.config/fetchr/config.jsonc |
| Windows | .\fetchr.jsonc > %APPDATA%\fetchr\config.jsonc > %USERPROFILE%\.config\fetchr\config.jsonc |
Use --config path/to/config.jsonc on any command to override.
Profiles are named presets that bundle TLS fingerprint + User-Agent + HTTP/2 settings to impersonate a specific browser. Use them via --profile (CLI) or "profile" (MCP tool input).
The default config ships with chrome and firefox. Add your own:
{
"profiles": {
"safari": {
"ja3": "771,4865-4866-4867-49196-49195-52393-49200-49199-52392-49162-49161-49172-49171-157-156-53-47-49160-49170-10,0-23-65281-10-11-16-5-13-18-51-45-43-27-21,29-23-24-25,0",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_0) AppleWebKit/605.1.15 Safari/605.1.15",
"http2_fingerprint": "1:65536;3:100;4:65535|1048576|0|m,s,p,a"
},
"api": {
"user_agent": "MyApp/1.0",
"timeout": 60
}
}
}When logging is enabled, every request/response pair is recorded.
File logging writes JSONL (one JSON object per line) to the configured path:
{"timestamp":"2026-03-26T10:00:00Z","request":{"url":"https://example.com","method":"GET"},"response":{"status":200},"duration":245000000}Webhook logging POSTs the same JSON to a URL (fire-and-forget, non-blocking).
Import pkg/curl to use fetchr as a library:
package main
import (
"context"
"fmt"
"log"
"github.com/thesatellite-ai/fetchr/pkg/curl"
)
func main() {
client := curl.New(
curl.WithDefaults(curl.RequestOptions{
UserAgent: "Mozilla/5.0 Chrome/120.0.0.0",
Timeout: 30,
}),
)
defer client.Close()
// Simple GET
resp, err := client.Do(context.Background(), curl.RequestOptions{
URL: "https://httpbin.org/get",
})
if err != nil {
log.Fatal(err)
}
fmt.Println(resp.Format())
// POST with JA3 fingerprint
resp, err = client.Do(context.Background(), curl.RequestOptions{
URL: "https://httpbin.org/post",
Method: "POST",
Headers: map[string]string{
"Content-Type": "application/json",
},
Body: `{"key": "value"}`,
Ja3: "771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,0-23-65281-10-11-35-16-5-13-18-51-45-43-27-17513,29-23-24,0",
})
if err != nil {
log.Fatal(err)
}
fmt.Println(resp.Format())
// Batch requests
results, _ := client.Batch(context.Background(), []curl.RequestOptions{
{URL: "https://httpbin.org/get"},
{URL: "https://httpbin.org/ip"},
{URL: "https://httpbin.org/user-agent"},
})
for _, r := range results {
if r.Error != "" {
fmt.Printf("[%d] %s ERROR: %s\n", r.Index, r.URL, r.Error)
} else {
fmt.Printf("[%d] %s -> %d\n", r.Index, r.URL, r.Response.Status)
}
}
// Print as curl command
cmd := curl.ToCurl(curl.RequestOptions{
URL: "https://httpbin.org/post",
Method: "POST",
Headers: map[string]string{
"Content-Type": "application/json",
"Authorization": "Bearer token",
},
Body: `{"key": "value"}`,
Timeout: 30,
})
fmt.Println(cmd)
// Output:
// curl \
// -X POST \
// 'https://httpbin.org/post' \
// -H 'Authorization: Bearer token' \
// -H 'Content-Type: application/json' \
// -d '{"key": "value"}' \
// --connect-timeout 30
}Can AI assistants actually make HTTP requests through fetchr? Yes. fetchr runs as an MCP server (stdio + SSE), so Claude Desktop, Claude Code, and other MCP-compatible assistants get real HTTP tools — GET/POST, headers, proxies, file downloads — even though they're otherwise sandboxed from the network.
How does it bypass bot detection?
It impersonates a real browser at the TLS layer — matching the JA3/JA4 hash, HTTP/2 SETTINGS frame, header order, and ALPN of Chrome or Firefox. Standard HTTP clients (including curl) send a default fingerprint that anti-bot systems flag instantly; fetchr's requests look identical to a real browser's.
Is this just a curl wrapper?
No. curl and standard clients can't change their TLS fingerprint, which is exactly what gets them blocked. fetchr does real browser-grade fingerprinting — and it can still export any request as an equivalent curl command when you want one.
Can I use it inside my own Go program?
Yes — import pkg/curl and make fingerprinted requests directly from Go, no CLI or server needed.
Is it free and open source? Yes — licensed Apache-2.0. Free to use, modify, and distribute.
What platforms are supported? A single static Go binary for macOS and Linux. No runtime dependencies, no headless browser.
Apache-2.0 — free to use, modify, and distribute.
fetchr — open-source HTTP client with browser TLS fingerprinting (JA3/JA4, HTTP/2, QUIC). A CLI, an MCP server that gives Claude Desktop & Claude Code real HTTP access, and an importable Go package. Pass anti-bot detection that blocks standard HTTP clients and curl.
{ // Default options applied to every request "defaults": { "ja3": "771,4865-4867-4866-49195-49199-52393-52392-49196-49200-49162-49161-49171-49172-51-57-47-53-10,0-23-65281-10-11-35-16-5-51-43-13-45-28-21,29-23-24-25-256-257,0", "user_agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:87.0) Gecko/20100101 Firefox/87.0", "timeout": 30 }, // Named browser profiles "profiles": { "chrome": { "ja3": "771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,0-23-65281-10-11-35-16-5-13-18-51-45-43-27-17513,29-23-24,0", "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0.0.0", "http2_fingerprint": "1:65536;2:0;4:6291456;6:262144|15663105|0|m,a,s,p" }, "firefox": { "ja3": "771,4865-4867-4866-49195-49199-52393-52392-49196-49200-49162-49161-49171-49172-51-57-47-53-10,0-23-65281-10-11-35-16-5-51-43-13-45-28-21,29-23-24-25-256-257,0", "user_agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:87.0) Gecko/20100101 Firefox/87.0", "http2_fingerprint": "1:65536;2:0;4:131072;5:16384|12517377|0|m,p,a,s" } }, // Request logging "logging": { "enabled": true, "file": "~/.fetchr/requests.jsonl", "webhook": "https://your-webhook.example.com/log" } }