← docs

Use Bazaar MCP Tools with LangChain

Connect your LangChain agents to Agent Bazaar's metered MCP tool marketplace. Every tool call is priced, metered, and receipted — your agent pays only for what it uses.

Prerequisites

1. Install Dependencies

pip install langchain langchain-openai

Bazaar runs each provider's MCP server for you behind one HTTPS proxy, so your agent needs no MCP client library. Swap langchain-openai for any LangChain chat model package.

2. Set Environment Variables

export NOUI_API_KEY="bz_your_key_here"
export OPENAI_API_KEY="sk-..."   # or any LLM provider

3. Save the Bazaar Client

Save this as bazaar_client.py. It lists tools from GET /api/bazaar/catalog and runs them through POST /api/bazaar/proxy:

# bazaar_client.py — no dependencies beyond the standard library
import json
import os
import re
import urllib.error
import urllib.request

BAZAAR_URL = "https://noui.bot/api/bazaar"
API_KEY = os.environ["NOUI_API_KEY"]


def list_bazaar_tools() -> list[dict]:
    """Every active tool in the public catalog, following pagination."""
    tools: list[dict] = []
    while True:
        url = f"{BAZAAR_URL}/catalog?limit=100&offset={len(tools)}"
        with urllib.request.urlopen(url, timeout=30) as resp:
            page = json.load(resp)
        tools += page["tools"]
        if not page["tools"] or len(tools) >= page["total"]:
            return tools


def tool_function_name(tool: dict) -> str:
    """LLM function names allow only letters, digits, _ and - (max 64)."""
    return re.sub(r"[^A-Za-z0-9_-]", "_", tool["tool_name"])[:64]


def tool_description(tool: dict) -> str:
    summary = tool["description"] or tool["display_name"]
    return (
        f"{summary} (price: {tool['pricing']['price']}). "
        "Pass the tool's parameters as a JSON object in 'arguments'."
    )


def call_bazaar_tool(tool_id: str, arguments: dict | None) -> str:
    """Run one tool through the metered proxy.

    Failures (402 balance, 429 rate limit, provider errors) come back as text
    so the agent can read them instead of crashing the run.
    """
    request = urllib.request.Request(
        f"{BAZAAR_URL}/proxy",
        data=json.dumps({"tool_id": tool_id, "input": arguments or {}}).encode(),
        headers={
            "Authorization": f"Bearer {API_KEY}",
            "Content-Type": "application/json",
        },
        method="POST",
    )
    try:
        with urllib.request.urlopen(request, timeout=30) as resp:
            body = json.load(resp)
    except urllib.error.HTTPError as err:
        try:
            error = json.load(err)
        except ValueError:
            error = {}
        return f"Bazaar error {err.code} {error.get('code', '')}: {error.get('message', err.reason)}"
    return json.dumps(body["result"])

4. Give the Tools to a LangChain Agent

Save this as agent.py next to the client and run it:

from langchain.agents import create_agent
from langchain_core.tools import StructuredTool
from langchain_openai import ChatOpenAI

from bazaar_client import (
    call_bazaar_tool,
    list_bazaar_tools,
    tool_description,
    tool_function_name,
)


def make_langchain_tool(tool: dict) -> StructuredTool:
    tool_id = tool["id"]

    def run(arguments: dict) -> str:
        return call_bazaar_tool(tool_id, arguments)

    return StructuredTool.from_function(
        func=run,
        name=tool_function_name(tool),
        description=tool_description(tool),
    )


tools = [make_langchain_tool(t) for t in list_bazaar_tools()]
print(f"Loaded {len(tools)} Bazaar tools")

agent = create_agent(
    model=ChatOpenAI(model="gpt-4o", temperature=0),
    tools=tools,
    system_prompt="Use Bazaar tools when they help. Every call is billed to your balance.",
)

result = agent.invoke(
    {"messages": [{"role": "user", "content": "What is the weather in Paris?"}]}
)
print(result["messages"][-1].content)

The catalog does not publish parameter schemas yet, so each tool takes one arguments object and the model reads the expected fields from the tool description. To limit spend, filter list_bazaar_tools() by tool_name or pricing.price_cents before building tools.

5. How Billing Works

Every tool call through Bazaar is metered transparently:

What happens on each tool call:

  1. Your agent calls a Bazaar tool through the proxy
  2. Bazaar checks your balance and the tool's per-call price
  3. The tool executes and returns results
  4. Your balance is debited and a receipt is issued
# Check your balance anytime
curl https://noui.bot/api/v1/bazaar/balance \
  -H "Authorization: Bearer bz_your_key"

# View usage and spend
curl https://noui.bot/api/v1/bazaar/usage/summary \
  -H "Authorization: Bearer bz_your_key"

6. Production Tips

Load Tools Once

Build the tool list once at startup and reuse it across agent runs. Each proxy call is a single stateless HTTPS request, so there is no session to keep open.

Error Handling

The client turns insufficient balance (402), rate limits (429) and provider failures (502/504) into text the agent can read, so one failed call never crashes the run. Failed calls are never billed.

Cost Controls

Check your balance before and after agent runs. Each tool's price is in its catalog entry and in the description the model sees.

See Also