ai newsDo., 5. Nov.
EilmeldungRun LLMs Locally in 2026: Ollama vs LM Studio vs llama.cpp, Compared

We Gave a Local LLM Live Web Access. Here’s How

This article was originally published on the Zenrows blog . We gave a local LLM live web access, and this post shows how. You'll connect a qwen3 model in Ollama to Zenrows MCP , first with no code through the ollmcp bridge and then with a short Python agent that is its own MCP client. You'll need O

dev.toDonnerstag 07:47 · 05.11.8 Min. Lesezeit
Bild: dev.to

Posted on Nov 5 • Originally published at zenrows.com

This article was originally published on the Zenrows blog.

We gave a local LLM live web access, and this post shows how. You'll connect a qwen3 model in Ollama to Zenrows MCP, first with no code through the ollmcp bridge and then with a short Python agent that is its own MCP client. You'll need Ollama, a tool-capable model, Node.js, and Python 3.11 or later. A Zenrows API key is optional.

Ollama publishes web_search and web_fetch as hosted APIs that you call with an Ollama API key, and it has no MCP client of its own. In our test runs, the local qwen3 agent read a Cloudflare-fronted Indeed search and cleared an anti-bot challenge page through Zenrows MCP. A plain requests.get() to the same challenge page returned a 403. The code is on GitHub.

Zenrows MCP has two transports. The remote server runs over Streamable HTTP and authenticates with your API key as a Bearer token. The local server runs as a STDIO subprocess through the @zenrows/mcp npm package with your key in an environment variable. This tutorial uses the local one, since it runs next to Ollama on your machine.

brew install ollama brew services start ollama Enter fullscreen mode Exit fullscreen mode

ollama pull qwen3 ollama show qwen3:latest Enter fullscreen mode Exit fullscreen mode Ollama registers the model as qwen3:latest. The ollama show output lists tools under Capabilities, which confirms the model can call the Zenrows tools.

Model architecture qwen3 parameters 8.2B context length 40960 embedding length 4096 quantization Q4_K_M Capabilities completion tools thinking Enter fullscreen mode Exit fullscreen mode 2. Set Up the Project python3 -m venv.venv source.venv/bin/activate Enter fullscreen mode Exit fullscreen mode

pip install python-dotenv requests Enter fullscreen mode Exit fullscreen mode Without a key, the local server creates a Free account with 5,000 credits a month on its first tool call. To use your own account, create one and save the key in.env.

ZENROWS_API_KEY = your_key_here Enter fullscreen mode Exit fullscreen mode 3. Install the ollmcp Bridge ollmcp is an open-source Python bridge that connects MCP servers to a local Ollama model over STDIO, SSE, and Streamable HTTP. It also installs the ollama and mcp packages the agent imports later. This tutorial was tested with ollmcp 0.35.0 on Python 3.14.

pip install ollmcp Enter fullscreen mode Exit fullscreen mode 4. Configure the Server and Chat With No Code Create zenrows-mcp.json.

{ "mcpServers": { "zenrows": { "command": "sh", "args": [ "-c", "set -a &&../.env && set +a && exec npx -y @zenrows/mcp" ] } } } Enter fullscreen mode Exit fullscreen mode The sh -c command sources.env into the environment before starting npx, so the JSON holds no secret and can be committed. Add.env to.gitignore, and run ollmcp from this directory because the.env path is relative.

ollmcp --servers-json zenrows-mcp.json --model qwen3:latest Enter fullscreen mode Exit fullscreen mode On October 21, 2026, the bridge connected and listed the Zenrows tools (output trimmed).

Found server in config: zenrows Connecting to server: zenrows Successfully connected to zenrows with 62 tool(s) and 3 prompt(s) and 1 resource(s)/template(s) ╭──────────────────────────── 🔧 Available Tools ────────────────────────────╮ │ ✓ zenrows.scrape ✓ zenrows.extract │ │ ✓ zenrows.batch_create ✓ zenrows.batch_status │... │ ✓ zenrows.browser_switch_tab ✓ zenrows.browser_batch │ ╰─────────────────────────── 62/62 tools enabled ────────────────────────────╯ ╭───────────────────────────────────────────────╮ │ Current model: qwen3:latest (ollama) │ │ Capabilities: 🔧 Tools │ 💭 Thinking (medium) │ ╰───────────────────────────────────────────────╯ Enter fullscreen mode Exit fullscreen mode Every enabled tool's schema goes into the model's context, so type /tools and keep scrape and extract switched on for a small local model. /human-in-the-loop asks you to approve each tool call before it runs.

The script starts the Zenrows MCP server with npx, so it doesn't need ollmcp or zenrows-mcp.json to run. Create agent.py. The pinned versions are in the repo's requirements.txt.

from dotenv import load_dotenv load_dotenv () import asyncio import json import os import ollama from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client SERVER = StdioServerParameters ( command = " npx ", args = [ " -y ", " @zenrows/mcp " ], env = dict ( os. environ ), ) MODEL = " qwen3:latest " # give the model enough context to read the whole tool result OPTIONS = { " num_ctx ": 16384 } QUESTION = " Extract the page heading from https://www.scrapingcourse.com/antibot-challenge. " ALLOWED_ARGS = { " url " } async def main (): async with stdio_client ( SERVER ) as ( read, write ): async with ClientSession ( read, write ) as session: await session. initialize () listed = await session. list_tools () tools = [ { " type ": " function ", " function ": { " name ": t. name, " description ": t. description, " parameters ": t. input_schema, }} for t in listed. tools if t. name == " extract " ] messages = [{ " role ": " user ", " content ": QUESTION }] reply = ollama. chat ( model = MODEL, messages = messages, tools = tools, options = OPTIONS ) messages. append ( reply [ " message " ]) for call in reply [ " message " ]. get ( " tool_calls " ) or []: args = { k: v for k, v in call. function. arguments. items () if k in ALLOWED_ARGS } print ( " calling ", call. function. name, args ) result = await session. call_tool ( call. function. name, args ) text = result. content [ 0 ]. text print ( " result: ", text [: 300 ]) # pass the model only the parsed fields from the response data = json. loads ( text ). get ( " data " ) messages. append ({ " role ": " tool ", " content ": json. dumps ( data )}) print ( ollama. chat ( model = MODEL, messages = messages, tools = tools, options = OPTIONS )[ " message " ][ " content " ]) asyncio. run ( main ()) Enter fullscreen mode Exit fullscreen mode Three details matter on a local model.

The test target is the Scrapingcourse antibot challenge page, which reports its own verdict.

python3 agent.py Enter fullscreen mode Exit fullscreen mode

Using existing API key from env (secrets dir: /Users/user/.zenrows) Zenrows MCP server running on stdio (secrets dir: /Users/user/.zenrows) calling extract {'url': 'https://www.scrapingcourse.com/antibot-challenge'} result: {"ok":true,"mode":"auto","empty":false,"data":{"challenge_result":{"message":"You bypassed the Antibot challenge!:D","status":"bypassed"},"page":{"challenge_type":"antibot","title":"Antibot Challenge"}}} The page heading (h1) from the URL is: **Antibot Challenge** This is the title extracted from the webpage, which also happens to be the name of the antibot challenge page. Enter fullscreen mode Exit fullscreen mode For comparison, without_zenrows.py sends a plain request to the same page.

import requests r = requests. get ( " https://www.scrapingcourse.com/antibot-challenge " ) print ( r. status_code, len ( r. text )) Enter fullscreen mode Exit fullscreen mode

python3 without_zenrows.py Enter fullscreen mode Exit fullscreen mode

403 5517 Enter fullscreen mode Exit fullscreen mode The request was blocked with a 403.

curl -sI https://www.indeed.com | grep -iE "^(server|date):" Enter fullscreen mode Exit fullscreen mode

date: Wed, 21 Oct 2026 08:15:02 GMT server: cloudflare Enter fullscreen mode Exit fullscreen mode Create cloudflare_site.py with the same code as agent.py and change the QUESTION line.

QUESTION = " List the company names and job titles from https://www.indeed.com/jobs?q=data+analyst&l=Austin%2C+TX. " Enter fullscreen mode Exit fullscreen mode

python3 cloudflare_site.py Enter fullscreen mode Exit fullscreen mode

Using existing API key from env (secrets dir: /Users/user/.zenrows) Zenrows MCP server running on stdio (secrets dir: /Users/user/.zenrows) calling extract {'url': 'https://www.indeed.com/jobs?q=data+analyst&l=Austin%2C+TX'} result: {"ok":true,"mode":"auto","empty":false,"data":{"job_listings":[{"benefits":null,"company_logo_url":null,"company_name":"Paywall Bypass","detail_url":"/rc/clk?jk=1d9d5ad6081ee5e0&bb=0Jmy1L_Rym9Qr_CYZLvqO-iSA0EMSX-Z6TVgVMeYzV9VdW2jJoxc32S2GChQtdu5Qm9Zo3b5B6zKmWui0wMrKaTa7wukcUUmE83DPPtvU-K-2B_k_liBF0N Here are the company names and job titles from the Indeed search results in Austin, TX: 1. **Paywall Bypass** - Data Analyst 2. **Visa U.S.A. Inc.** - Data & Insights Analyst 3. **Texas Department of Transportation** - Data Analyst IV 4. **Austin Community College** - Analyst, Institutional Research (Hourly) 5. **Austin Community College** - Analyst, Human Resources Data 6. **University of Texas at Austin** - Data Analyst, College of Liberal Arts 7. **Steck Systems** - Data Analyst 8. **Apple** - Business Insights Analyst, Apple Store Online Operations 9. **Google** - Business Data Analyst II, Google Global Infrastructure, Strategy and Operations 10. **Google** - Business Data Analyst II, Google Global Infrastructure, Strategy and Operations 11. **University of Texas at Austin** - Senior Data Analyst 12. **The University of St. Augustine for Health...** - Institutional Research Analyst 13. **Ericsson** - Data Analyst Strategy and Operations 14. **Texas Department of Transportation** - Business Analyst II 15. **SHI International Corporation** - Associate Analytics Engineer - Data & Visualization 16. **Health & Human Services Comm** - Data Analyst V Let me know if you'd like additional details like locations or salary information! Enter fullscreen mode Exit fullscreen mode The extraction returned ok: true with 16 job listings and no challenge response, and the model listed every company and job title on the page.

Here is how three MCP servers compared, as documented on October 21, 2026.

One MCP configuration gave a local Ollama agent access to live pages, including Cloudflare-protected ones, while Zenrows handled access, rendering, and proxies for every request. For a task spanning several pages, ask in plain English and the agent can use the crawl and batch tools.

Quelle: dev.to (dev.to). Original öffnen