Decorate Loop's REST calls with @tool and pass them to create_react_agent from LangGraph — or any LangChain AgentExecutor. The agent searches, verifies, and reports outcomes automatically. No key required in the free tier.
create_react_agent from langgraph.prebuilt is the modern LangChain-ecosystem way to build tool-calling agents. Decorate each Loop wrapper with @tool from langchain.tools, pass them with a chat model — the agent handles tool dispatch and looping.
pip install langchain langchain-openai langgraph requestsfrom langchain.tools import tool from langchain_openai import ChatOpenAI from langgraph.prebuilt import create_react_agent import requests BASE = "https://api.stayinloop.dev/v1" @tool def search_loop(query: str, location: str = "Kreuzberg, Berlin") -> list: """Search for local businesses using Loop. Args: query: Natural-language description, e.g. 'vegan outdoor seating table for 4'. location: Area hint, default Kreuzberg, Berlin. """ return requests.get(f"{BASE}/search", params={"q": query, "location": location}).json()[ "results" ] @tool def get_loop_details(result_id: str) -> dict: """Get full details for a Loop search result, including a result_token for report(). Args: result_id: id from a search result. """ return requests.get(f"{BASE}/details/{result_id}").json() @tool def verify_loop(result_id: str, claim: str) -> dict: """Re-check a specific claim against live sources before acting. Args: result_id: id from a search result. claim: What to verify, e.g. 'is_open_now', 'has_outdoor_seating'. """ return requests.get(f"{BASE}/verify/{result_id}", params={"claim": claim}).json() @tool def report_loop(result_token: str, outcome: str) -> dict: """Report what happened after acting on a Loop result. Improves data for everyone. Args: result_token: From get_loop_details(), valid 30 minutes. outcome: One of correct, wrong, booked, closed, other. """ return requests.post( f"{BASE}/report", json={"result_token": result_token, "outcome": outcome} ).json() tools = [search_loop, get_loop_details, verify_loop, report_loop] llm = ChatOpenAI(model="gpt-4o", temperature=0) agent = create_react_agent(llm, tools) result = agent.invoke({"messages": [("user", "Find a vegan restaurant with outdoor seating in Kreuzberg")]}) print(result["messages"][-1].content)
LangGraph supports async tools natively. Use httpx.AsyncClient to fan out get_details and verify in parallel — useful when the agent needs to check multiple candidates quickly.
pip install langchain langchain-openai langgraph httpximport asyncio import httpx from langchain.tools import tool from langchain_openai import ChatOpenAI from langgraph.prebuilt import create_react_agent BASE = "https://api.stayinloop.dev/v1" @tool async def search_loop_async(query: str, location: str = "Kreuzberg, Berlin") -> list: """Search for local businesses using Loop (async). Args: query: Natural-language need, e.g. 'quiet table for 2'. location: Area hint, default Kreuzberg, Berlin. """ async with httpx.AsyncClient() as client: r = await client.get(f"{BASE}/search", params={"q": query, "location": location}) return r.json()["results"] @tool async def get_and_verify(result_id: str, claim: str = "open now") -> dict: """Get full details and verify a claim in parallel. Args: result_id: id from a search result. claim: Claim to verify live, default 'open now'. """ async with httpx.AsyncClient() as client: details_req = client.get(f"{BASE}/details/{result_id}") verify_req = client.get(f"{BASE}/verify/{result_id}", params={"claim": claim}) details_r, verify_r = await asyncio.gather(details_req, verify_req) return {**details_r.json(), "observation": verify_r.json()} llm = ChatOpenAI(model="gpt-4o", temperature=0) agent = create_react_agent(llm, [search_loop_async, get_and_verify]) async def main(): result = await agent.ainvoke( {"messages": [("user", "Outdoor vegan table for 4 in Kreuzberg, verify it's open now")]} ) print(result["messages"][-1].content) asyncio.run(main())
https://stayinloop.dev/mcp. The four tools load automatically with no schema wrappers. See the Claude guide for the MCP connector path.Authorization: Bearer sk_live_… as a header or append ?key=sk_live_… to any URL.