← docs

Use Bazaar MCP Tools with CrewAI

Give your CrewAI multi-agent crews access to Agent Bazaar's paid tool marketplace. Every tool call is priced, metered, and receipted — each crew member pays only for what it uses.

Prerequisites

1. Install Dependencies

pip install crewai

Bazaar runs each provider's MCP server for you behind one HTTPS proxy, so your crew needs no MCP adapter or extra packages.

2. Set Environment Variables

export NOUI_API_KEY="bz_your_key_here"
export OPENAI_API_KEY="sk-..."   # CrewAI default LLM

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 Crew

Save this as crew.py next to the client and run it. Only the researcher gets paid tools; the writer just reasons:

from crewai import Agent, Crew, Task
from crewai.tools import BaseTool

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


class BazaarTool(BaseTool):
    tool_id: str

    def _run(self, arguments: dict) -> str:
        return call_bazaar_tool(self.tool_id, arguments)


bazaar_tools = [
    BazaarTool(
        name=tool_function_name(t),
        description=tool_description(t),
        tool_id=t["id"],
    )
    for t in list_bazaar_tools()
]
print(f"Loaded {len(bazaar_tools)} Bazaar tools")

researcher = Agent(
    role="Research Analyst",
    goal="Gather data using the available Bazaar tools",
    backstory="You call paid tools through Agent Bazaar and report raw results.",
    tools=bazaar_tools,
    verbose=True,
)

writer = Agent(
    role="Report Writer",
    goal="Turn research into a clear summary",
    backstory="You turn raw data into actionable insights.",
    verbose=True,
)

research_task = Task(
    description="Use the available tools to get the current weather in Paris.",
    expected_output="Raw data from tool calls",
    agent=researcher,
)

report_task = Task(
    description="Write a 3-sentence summary of the findings.",
    expected_output="A concise summary report",
    agent=writer,
)

crew = Crew(agents=[researcher, writer], tasks=[research_task, report_task], verbose=True)
result = crew.kickoff()
print(result)

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.

Selective Tool Assignment

You don't have to give every agent every tool. Filter by catalog name to control costs and scope:

# Only give the researcher specific tools
allowed = {"weather_forecast", "web_search"}
filtered_tools = [t for t in bazaar_tools if t.name in allowed]

researcher = Agent(
    role="Research Analyst",
    goal="Gather weather and search data",
    backstory="You have access to specific Bazaar tools.",
    tools=filtered_tools,
)

5. How Billing Works

Every tool call through Bazaar is metered transparently:

What happens on each tool call:

  1. A crew member 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 to the agent
  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

Budget per Crew Run

Check balance before and after each crew.kickoff(). Multi-agent crews can make many tool calls — monitor costs during development.

Tool Scoping

Assign only the tools each agent needs. A report writer rarely needs API tools — restrict expensive tools to specialized agents.

Verbose Logging

Enable verbose=True on agents during development to see which tools are called and how often. Helps catch runaway tool usage.

See Also