Agent frameworks / LangChain
LangChain
Give a LangChain or LangGraph agent the AIX tools through the MCP server, or define the two tools in code, with the timing rules the model needs.
LangChain agents take a list of tools. An AIX integration adds two: submit_intent after any turn that states or changes what the shopper wants to buy, and report_handoff before the shopper is sent to a store. Both run on your server with your key.
Through the MCP server
LangChain 1.4 and later ship an MCP adapter in the langchain.mcp namespace (beta). It delegates the connection to FastMCP's client, so the key is passed as the client's auth, which becomes the Authorization: Bearer header. The MCP submit_intent tool takes one argument, intent, with the same body as POST /intents (its turn input is reserved for Brambles-managed publishers; the model must send exactly one of the two).
pip install "langchain[mcp]>=1.4.0"import osfrom fastmcp.client import Clientfrom langchain.agents import create_agentfrom langchain.mcp import MCPAdapter
AIX_MCP = "https://aix.brambles.ai/api/aix/mcp"
async def run(user_message: str) -> str: async with MCPAdapter(Client(AIX_MCP, auth=os.environ["AIX_PUBLISHER_KEY"])) as adapter: tools = await adapter.list_tools() agent = create_agent(model, tools, system_prompt=AIX_RULES) # see below result = await agent.ainvoke({"messages": [("user", user_message)]}) return result["messages"][-1].contentBefore 1.4, the langchain-mcp-adapters package does the same with a headers field:
from langchain_mcp_adapters.client import MultiServerMCPClient
client = MultiServerMCPClient({ "aix": { "transport": "streamable_http", "url": "https://aix.brambles.ai/api/aix/mcp", "headers": {"Authorization": f"Bearer {os.environ['AIX_PUBLISHER_KEY']}"}, }})tools = await client.get_tools()Defined in code
Two tools and one request helper with a three-second timeout. Every failure returns a skipped result so AIX can never slow down or break the shopper's experience. submit_intent takes the same intent argument as the MCP tool, so one prompt works whichever way the tools arrive.
import osfrom typing import Literal
import httpxfrom langchain_core.tools import toolfrom pydantic import BaseModel, Field
AIX = "https://aix.brambles.ai/api/aix"
class Budget(BaseModel): currency: str = Field(min_length=3, max_length=3) max_cents: int
class Fact(BaseModel): attribute: Literal["brand", "width", "size", "department", "use_case", "feature", "merchant", "deal"] value: str strength: Literal["required", "preferred", "excluded"]
class Task(BaseModel): category: str summary: str = Field(max_length=1600) budget: Budget | None = None facts: list[Fact] = []
class Intent(BaseModel): session_id: str = Field(min_length=1, max_length=128) country: str = Field(min_length=2, max_length=2) task: Task
async def _aix(path: str, body: dict) -> dict: key = os.environ.get("AIX_PUBLISHER_KEY") if not key: return {"status": "skipped", "reason": "no_key"} try: async with httpx.AsyncClient(timeout=3) as client: r = await client.post(f"{AIX}/{path}", json=body, headers={"Authorization": f"Bearer {key}"}) return r.json() if r.is_success else {"status": "skipped", "reason": f"http_{r.status_code}"} except httpx.HTTPError: return {"status": "skipped", "reason": "timeout"} # never block the shopper
@toolasync def submit_intent(intent: Intent) -> dict: """Report the shopper's current shopping task to AIX. Call after any turn that states or changes what they want to buy, with intent: session_id, country and the task. Shopping requirements only, never personal data.""" return await _aix("intents", intent.model_dump(exclude_none=True))
@toolasync def report_handoff(session_id: str, destination_url: str, consent: str | None = None) -> dict: """Report that the shopper is being sent to a store or product page (the store's own URL). Use the returned landing_url as that page's URL, inside your affiliate link if you use one.""" body: dict = {"session_id": session_id, "destination_url": destination_url} if consent: body["consent"] = consent return await _aix("handoffs", body)
agent = create_agent(model, [submit_intent, report_handoff], system_prompt=AIX_RULES)The rules the model needs
Put this in the system prompt:
You can send shopping intent to the Agentic Intent Exchange (AIX).- After any user turn that states or changes what they want to buy, call submit_intent with one argument, intent: an object holding the conversation's session_id, the shopper's two-letter country, and the task: a category, a one-line summary, the budget when they gave one, and facts with attribute, value and strength (required, preferred or excluded). Send only shopping requirements: never names, emails, phone numbers, addresses, account or order numbers, or the conversation itself.- Before you give the user a link to a store or product page, call report_handoff with the same session_id and the store's page URL, then use the returned landing_url as that page's URL (inside your own affiliate or ad link, if you use one).- If either tool fails or is slow, carry on without it. Never ask the user for a key.Set country on the server from your host's geolocation header rather than asking the shopper. Shoppers in the EEA, the UK or Switzerland are shared only with consent: show one line under your assistant, "Clicking a store link shares your shopping request with that store", and pass consent: "granted" on handoffs from those clicks. Sensitive topics are suppressed by AIX on arrival; never reword a task to get it through.
Receiving side
A store's agent uses the same connection with AIX_RECEIVER_KEY; the tools then list deliveries (subscribe_intents), read one receipt (get_intent_context), acknowledge it (acknowledge_delivery) and redeem a handoff id from a landing or a checkout (redeem_handoff; with a sandbox key it returns a free test delivery for any well-formed id). Verification and acknowledgment belong on your server; see Receiving agents.
Test it
- Create a free sending agent in the AIX console and store the sandbox key as
AIX_PUBLISHER_KEY. - Run one conversation that names a product and ends with a store link. The intent answers
accepted; the handoff answerstest_deliveredwith areceiver_preview. GET /activitywith the same key, or the AIX console, shows the test. Create the production key there and set it in production.