AI agents
LangChain, CrewAI and OpenAI Agents
Give LangChain, CrewAI, the OpenAI Agents SDK or LlamaIndex agents a captcha tool, either as ready tool code or through the Solvecha MCP server.
On this page
Every framework below can use Solvecha in two ways: through the MCP server, or with a small tool that calls the REST API. The MCP way needs no tool code.
#Through MCP
OpenAI Agents SDK
import os
from agents import Agent, Runner
from agents.mcp import MCPServerStreamableHttp
async with MCPServerStreamableHttp(
name="solvecha",
params={
"url": "https://api.solvecha.com/mcp",
"headers": {"Authorization": f"Bearer {os.environ['SOLVECHA_API_KEY']}"},
"timeout": 100,
},
client_session_timeout_seconds=100,
) as server:
agent = Agent(name="Browser agent", instructions="Use solvecha tools for captcha images.", mcp_servers=[server])
result = await Runner.run(agent, "Solve the captcha in this screenshot: ...")LangChain
import os
from langchain_mcp_adapters.client import MultiServerMCPClient
client = MultiServerMCPClient({
"solvecha": {
"transport": "streamable_http",
"url": "https://api.solvecha.com/mcp",
"headers": {"Authorization": f"Bearer {os.environ['SOLVECHA_API_KEY']}"},
}
})
tools = await client.get_tools() # pass these tools to your agentGoogle ADK
import os
from google.adk.agents import LlmAgent
from google.adk.tools.mcp_tool import McpToolset, StreamableHTTPConnectionParams
agent = LlmAgent(
model="gemini-flash-latest",
name="browser_agent",
instruction="Use the solvecha tools for captcha images.",
tools=[McpToolset(connection_params=StreamableHTTPConnectionParams(
url="https://api.solvecha.com/mcp",
headers={"Authorization": f"Bearer {os.environ['SOLVECHA_API_KEY']}"},
))],
)#As a plain tool
This function solves a reCAPTCHA grid from a PNG file or base64 text. It uses only requests. Wrap it with the decorator of your framework.
import base64
import os
import time
import requests
API = "https://api.solvecha.com"
def solve_recaptcha_grid(task: str, grid: str, image_base64: str) -> list[int]:
"""Solve a reCAPTCHA v2 image challenge.
Args:
task: The instruction text, for example 'Select all images with buses'.
grid: '3x3' or '4x4'.
image_base64: One base64 picture of the whole grid.
Returns the tile numbers to click, counted from 1, left to right, top to bottom.
"""
headers = {"Authorization": f"Bearer {os.environ['SOLVECHA_API_KEY']}"}
job = requests.post(f"{API}/v1/recognition/recaptcha", headers=headers, timeout=30,
json={"task": task, "grid": grid, "image_data": [image_base64]}).json()
if "data" not in job:
raise RuntimeError(f"Solvecha error {job.get('error')}: {job.get('message')}")
for _ in range(40):
time.sleep(1)
answer = requests.get(f"{API}/v1/recognition/recaptcha", headers=headers, timeout=30,
params={"id": job["data"]}).json()
if answer.get("error") == 14: # still working
continue
if "data" in answer:
return [i + 1 for i, picked in enumerate(answer["data"]) if picked]
raise RuntimeError(f"Solvecha error {answer.get('error')}: {answer.get('message')}")
raise TimeoutError("No answer in 40 seconds")LangChain
from langchain_core.tools import tool
solve_tool = tool(solve_recaptcha_grid) # the docstring becomes the tool descriptionCrewAI
from crewai.tools import tool
@tool("Solve reCAPTCHA grid")
def solve_tool(task: str, grid: str, image_base64: str) -> str:
"""Solve a reCAPTCHA v2 image challenge. Returns the tile numbers to click."""
return str(solve_recaptcha_grid(task, grid, image_base64))OpenAI Agents SDK
from agents import function_tool
solve_tool = function_tool(solve_recaptcha_grid)LlamaIndex
from llama_index.core.tools import FunctionTool
solve_tool = FunctionTool.from_defaults(fn=solve_recaptcha_grid)A model cannot pass a large picture reliably as a tool argument in every framework. If your agent has trouble with long base64 text, give the tool a file path instead and read the file inside the function.
See reCAPTCHA image grids for the request and answer format, and Errors for the codes.
Solvecha is an independent service. It is not affiliated with NopeCHA, 2Captcha, CapSolver, Google or CloakHQ. Their names describe compatibility or recommendations only. Figures come from our own tests, see the compare page.