LangChain / LangGraph
agent.json actions map naturally to LangChain tools. Each action becomes a StructuredTool with the parameter schema derived directly from the discovery document.
LangChain tools
Section titled “LangChain tools”1. Auto-generate tools from the discovery document
Section titled “1. Auto-generate tools from the discovery document”import httpxfrom langchain_core.tools import StructuredToolfrom pydantic import create_model, Field
# Fetch discovery documentdiscovery = httpx.get("https://agent-json.com/.well-known/agent.json").json()INBOX_URL = discovery["message_endpoint"]TOKEN = "your-bearer-token"
TYPE_MAP = {"string": str, "number": float, "boolean": bool}
def make_inbox_tool(action: dict) -> StructuredTool: """Create a LangChain tool from an agent.json action."""
# Build a Pydantic model from the action's parameter schema fields = {} props = action["parameters"].get("properties", {}) required = set(action["parameters"].get("required", []))
for name, schema in props.items(): python_type = TYPE_MAP.get(schema.get("type", "string"), str) if name in required: fields[name] = (python_type, Field(description=schema.get("description", ""))) else: fields[name] = (python_type | None, Field(default=None, description=schema.get("description", "")))
InputModel = create_model(f"{action['name']}_input", **fields)
def send_to_inbox(**kwargs): payload = { "from": {"agent": "langchain-agent"}, "action": action["name"], "parameters": {k: v for k, v in kwargs.items() if v is not None} } resp = httpx.post( INBOX_URL, json=payload, headers={"Authorization": f"Bearer {TOKEN}"} ) return resp.json()
return StructuredTool.from_function( func=send_to_inbox, name=action["name"], description=action["description"], args_schema=InputModel )
# Generate all toolstools = [make_inbox_tool(a) for a in discovery["actions"]]2. Use with a chat model
Section titled “2. Use with a chat model”from langchain_openai import ChatOpenAIfrom langchain_core.messages import HumanMessage
llm = ChatOpenAI(model="gpt-4o").bind_tools(tools)
result = llm.invoke([ HumanMessage("I need a refund for order #1234, the item was damaged.")])
# Process tool callsfor call in result.tool_calls: tool = next(t for t in tools if t.name == call["name"]) output = tool.invoke(call["args"]) print(f"Sent to inbox: {output}")LangGraph agent
Section titled “LangGraph agent”For a full agent loop that can send messages and poll for responses:
from langgraph.prebuilt import create_react_agentfrom langchain_openai import ChatOpenAI
# Add a poll tooldef check_inbox_response(message_id: str) -> dict: """Check if the website has responded to a message.""" resp = httpx.get( f"{INBOX_URL}/{message_id}", headers={"Authorization": f"Bearer {TOKEN}"} ) return resp.json()
poll_tool = StructuredTool.from_function( func=check_inbox_response, name="check_inbox_response", description="Check if the website has responded to a previously sent message. Pass the message ID.")
all_tools = tools + [poll_tool]
agent = create_react_agent( ChatOpenAI(model="gpt-4o"), tools=all_tools, prompt="You help customers interact with the website. " "Send requests via inbox tools and check for responses when needed.")
# Run the agentresult = agent.invoke({ "messages": [("user", "Request a refund for order ORD-789, reason: damaged. " "Then check if they've responded.")]})
for msg in result["messages"]: print(msg.pretty_print())Auto-discovery utility
Section titled “Auto-discovery utility”You can create a reusable utility that generates LangChain tools from any agent.json endpoint:
def discover_inbox_tools(base_url: str, token: str) -> list[StructuredTool]: """Auto-discover and create LangChain tools from an agent.json endpoint.""" discovery = httpx.get(f"{base_url}/.well-known/agent.json").json() endpoint = discovery["message_endpoint"]
tools = [] for action in discovery["actions"]: # ... same as make_inbox_tool above, but with endpoint and token in closure tools.append(make_inbox_tool(action))
return tools
# Usage: give an agent tools for any websitetools = discover_inbox_tools("https://agent-json.com", "token123")This means any LangChain agent can interact with any agent.json website with a single function call.