🎯 A customizable, anti-detection cloud browser powered by self-developed Chromium designed for web crawlers and AI Agents.👉Try Now
Back to Blog

LangGraph + Scrapeless: Wire Live Web Tools Into Your Agent Graph

Ava Wilson
Ava Wilson

Expert in Web Scraping Technologies

22-Jul-2026

TL;DR:

  • LangGraph loads the Scrapeless MCP Server's tools through langchain-mcp-adapters and hands all 21 to an agent graph, from scrape_markdown to a full browser set.
  • MultiServerMCPClient.get_tools runs the handshake and returns the tools; no model-provider key is needed to load them or to call one directly.
  • langchain-mcp-adapters returns each tool result as a list of content blocks, so you read result[0]["text"] rather than stringifying the list.
  • The agent itself is built with from langchain.agents import create_agent, the current replacement for the deprecated create_react_agent.
  • Only the create_agent graph and its ainvoke run need a model key; loading and calling the tools do not.
  • Start on the Scrapeless free plan and give your graph real web tools.

LangGraph builds an agent as a graph: a state machine that loops between the model and its tools until the task is done. That design is only as useful as the tools in the graph, and a bare LangGraph agent has none that reach the live web. The Model Context Protocol fills that gap. Point LangGraph's MCP adapter at a server and every tool it exposes becomes a LangChain tool your graph can call.

This guide connects LangGraph to the Scrapeless MCP Server, loads its 21 tools, calls one for real, and shows exactly where a model-provider key becomes necessary. The tool-loading and the direct call are verified against the live server; the generation step is marked as the one prerequisite it needs.

Why Scrapeless MCP

The Scrapeless MCP Server exposes web-scraping and browser tools an agent can call directly, so the scraping layer is not something you build or host. One connection serves 21 tools: scrape_markdown and scrape_html for content, google_search and google_trends for search data, scrape_screenshot for captures, and a full browser_* set that drives a cloud browser. LangGraph already has a strong MCP story through langchain-mcp-adapters, which turns those tools into standard LangChain tools with no glue code.

The browser_* tools drive the Scrapeless cloud browser, so an agent can navigate an interactive page and read what renders, all on Scrapeless infrastructure rather than a local browser pool. If you are on plain LangChain rather than LangGraph, the LangChain + Scrapeless MCP post covers the same server from that side.

Prerequisites

  • Python 3.10 or later.
  • A Scrapeless API key from the dashboard, exported as SCRAPELESS_API_KEY.
  • A model-provider key (such as OPENAI_API_KEY) only for the agent run. Loading and calling the tools does not need one.

Install

Install LangGraph, LangChain, and the MCP adapter.

bash Copy
pip install langgraph langchain langchain-mcp-adapters

Set your Scrapeless key in the shell. Use the real key at run time and keep the placeholder out of your source.

bash Copy
export SCRAPELESS_API_KEY="sk_your_key_here"

Load the Tools

MultiServerMCPClient takes a mapping of server names to connection configs. Each config names the transport, the URL, and the headers; the Scrapeless key rides in the x-api-token header. get_tools runs the handshake and returns the tools as LangChain tools.

python Copy
import asyncio
import os

from langchain_mcp_adapters.client import MultiServerMCPClient

client = MultiServerMCPClient(
    {
        "scrapeless": {
            "url": "https://api.scrapeless.com/mcp",
            "transport": "streamable_http",
            "headers": {"x-api-token": os.environ["SCRAPELESS_API_KEY"]},
        }
    }
)


async def main() -> None:
    tools = await client.get_tools()
    names = sorted(t.name for t in tools)
    print("tool count:", len(names))
    print("tools:", ", ".join(names))


asyncio.run(main())

The live server returns 21 tools, loaded with only the Scrapeless key set.

text Copy
tool count: 21
tools: browser_click, browser_close, browser_create, browser_get_html, browser_get_text, browser_go_back, browser_go_forward, browser_goto, browser_press_key, browser_screenshot, browser_scroll, browser_scroll_to, browser_snapshot, browser_type, browser_wait, browser_wait_for, google_search, google_trends, scrape_html, scrape_markdown, scrape_screenshot

The client is named MultiServerMCPClient because it federates several MCP servers at once; here it holds one server, and adding another is another entry in the mapping, not a change to the agent. The transport and message layer follow the Model Context Protocol specification, which rides on the JSON-RPC 2.0 specification.

Call a Tool

Call a tool by hand before wiring it into a graph. Each loaded tool is a LangChain tool with an ainvoke method, so you pass the arguments and read the result. One detail matters: the adapter returns a list of content blocks, not a plain string, so take the text from the first block.

python Copy
import asyncio
import os

from langchain_mcp_adapters.client import MultiServerMCPClient

client = MultiServerMCPClient(
    {
        "scrapeless": {
            "url": "https://api.scrapeless.com/mcp",
            "transport": "streamable_http",
            "headers": {"x-api-token": os.environ["SCRAPELESS_API_KEY"]},
        }
    }
)


async def main() -> None:
    tools = await client.get_tools()
    scrape_markdown = next(t for t in tools if t.name == "scrape_markdown")
    result = await scrape_markdown.ainvoke({"url": "https://quotes.toscrape.com/"})
    # langchain-mcp-adapters returns a list of content blocks; take the text block
    text = result[0]["text"] if isinstance(result, list) and result else str(result)
    print("markdown chars:", len(text))
    print("contains a quote:", "The world as we have created it" in text)


asyncio.run(main())

The call returns the page as Markdown, and the content check confirms a real quote is present.

text Copy
markdown chars: 4308
contains a quote: True

Reading result[0]["text"] is the part naive code gets wrong: stringifying the whole list gives you a Python repr with escape sequences, not the clean Markdown. The LangChain MCP adapter guide documents the client and the result shape in full.

Build the Agent Graph

With the tools loaded, the agent is one call. create_agent builds a ReAct-style graph that loops between the model and the tools, and it is the current replacement for the deprecated create_react_agent. This is the step that needs a model-provider key: the graph runs the model, and the model decides when to call scrape_markdown or any other tool.

Note: building and running the graph needs a model-provider key such as OPENAI_API_KEY, which is not set here. Loading the 21 tools and the direct scrape_markdown call above run without it. This block is shown with its exact shape; only the model round-trip is a prerequisite gap.

python Copy
from langchain.agents import create_agent


async def run_graph(tools) -> None:
    agent = create_agent("openai:gpt-4o", tools)
    result = await agent.ainvoke(
        {"messages": [{"role": "user", "content": "Fetch https://quotes.toscrape.com/ with scrape_markdown and list the first three quotes with authors."}]}
    )
    print(result["messages"][-1].content)

At run time the graph passes the prompt to the model, the model calls scrape_markdown with the URL, the tool returns the Markdown the direct call already demonstrated, and the model writes the answer. The tools are the same objects whether the model calls them or you do.

Conclusion

LangGraph plus the Scrapeless MCP Server is a short path from a bare graph to one that reads the live web. MultiServerMCPClient loads the 21 tools, ainvoke proves one works and shows how to read its content blocks, and create_agent turns the tools into a running graph. Only that last step needs a model key, so you can load and test the entire tool surface first. Start from the scripts above, scope the tools to what the graph needs, and let the model drive.

Create a free Scrapeless account to get an API key, and check Scrapeless pricing when you plan a recurring agent.

FAQ

Q: Does LangGraph need a model key to load MCP tools?

No. MultiServerMCPClient.get_tools runs the handshake and returns the tools with only the Scrapeless API key set, and each tool can be called directly with ainvoke. A model-provider key is required only when you build and run the agent graph with create_agent, because that is when the model itself decides which tools to call.

Q: Why does the tool result come back as a list instead of a string?

langchain-mcp-adapters returns each MCP tool result as a list of content blocks, which is how MCP represents tool output. Read the text from the first block with result[0]["text"]; stringifying the whole list gives you a repr with escape sequences rather than the clean content.

Q: Should I use create_react_agent or create_agent?

Use create_agent from langchain.agents. create_react_agent was moved out of langgraph.prebuilt in LangGraph 1.0 and now emits a deprecation warning, so the current, warning-free path is from langchain.agents import create_agent with the same model-and-tools arguments.

Q: What is MultiServerMCPClient for if I only have one server?

The client is designed to federate several MCP servers at once, but it works with a single server as a mapping of one entry. Using it now means adding a second server later is one more entry in the config, with no change to how the agent consumes the tools.

Q: How do I give the graph only some of the tools?

get_tools returns a list, so filter it before passing it to create_agent. Handing the graph only scrape_markdown and google_search is safer than the full 21-tool set when the task needs just content and search.

Q: Is scraping through the tools bound by the target's rules?

Yes. The tools fetch public pages, and you remain responsible for honoring each target's terms and its Robots Exclusion Protocol directives. Keep the volume bounded and the data public, and scope the graph to the tools the task actually needs.

At Scrapeless, we only access publicly available data while strictly complying with applicable laws, regulations, and website privacy policies. The content in this blog is for demonstration purposes only and does not involve any illegal or infringing activities. We make no guarantees and disclaim all liability for the use of information from this blog or third-party links. Before engaging in any scraping activities, consult your legal advisor and review the target website's terms of service or obtain the necessary permissions.

Most Popular Articles

Catalogue