Error while using MySQLSearchTool

I am on crewai version 0.80.0

using this command to connect to my db

sql_tool = MySQLSearchTool(
db_uri=‘mysql://:@:3306/<db_name>’,
table_name=‘tbl_arena_transactions’
)

my db is in gcp cloud I am able to connect to it with mysqlworkbench

the error which i am facing is

raise AttributeError(f"Unsupported argument ‘{key}’") from None
AttributeError: Unsupported argument ‘url’
An error occurred while running the flow: Command ‘[‘uv’, ‘run’, ‘kickoff’]’ returned non-zero exit status 1.

I agree there needs to be a lot more info from MySQL RAG Search - CrewAI to get this running. I have mysql setup and working with other python code and still get

import mysql.connector as sqlconnector
ModuleNotFoundError: No module named ‘mysql’

Maybe add a list of dependencies needed along with a ‘poem’ like example so we can debug our environments.

I have run into this issue as well and found that there is an open issue (MySQLSearchTool Error · Issue #122 · crewAIInc/crewAI-tools · GitHub) that explains what the error is all about and even suggests a fix, unfortunately there hasn’t been any movement on the open issue for what looks like almost two years. :frowning:
Not sure why as the fix seems pretty straightforward - maybe crewai is moving so fast no one has time? Or maybe mysql usage with crewai is not very popular? I’m brand new to crewai so I’m getting familiar with the culture…

@user1024, the MySQLSearchTool in its current version is useless. It doesn’t even work.

In :backhand_index_pointing_right: this issue, you’ll find my proposal with a working version of the tool.

Given the complete lack of interest from the CrewAI devs (as usual), feel free to use it on your own. I honestly hope this version helps you with what you need.

@maxmoura, thanks! Your new version is making a lot more progress - looks like now I just need to learn how to set it up correctly. I was surprised to see that the issue where you proposed the updated version has been closed as “not planned”. :frowning:

I wonder if maybe the thinking is to use an MCP server to access the database rather than a crewai tool…

1 Like

@maxmoura, I can’t find any docs on how to use MySQLSearchTool. So far the new version you provided seems to be working well but I’m having trouble figuring out how to use it.

It looks to me like it expects “table_name” and “db_uri” as inputs and then there’s the MySQLSearchToolSchema that looks like it expects a “search_query”. I tried providing all of these as inputs to my crew().kickoff but I end up with this error -

I encountered an error while trying to use the tool. This was the error: Arguments
 validation failed: 1 validation error for 
   MySQLSearchToolSchema                                                                                                           
   search_query

   Field required [type=missing, input_value={'query': 'SELECT notes F...0610', 
'metadata': {}}}}, input_type=dict] 
      For further information visit https://errors.pydantic.dev/2.11/v/missing.                                                   

    Tool Search MySQL Database Table Content accepts these inputs: Performs
    semantic search on the 'entry_detail' table in the
   specified MySQL database. Input is the search query..  

Do you have any examples that outline the configuration for MySQLSearchTool (and MySQLSearchToolSchema)?

  1. Follow the MySQL Getting Started tutorial. By the end, you’ll have a running MySQL instance with a database named pets and a table called cats. Keep your <USER> and <PASSWORD> handy.
  2. Save the version I proposed in that issue as alternative_mysql_search_tool.py.
  3. In the same directory as the previous file, create a new file, for instance, main.py. I’m using Gemini here, but feel free to adapt it to your needs:
from alternative_mysql_search_tool import MySQLSearchTool
import os

# Satisfy both LiteLLM and Embedchain
os.environ["GEMINI_API_KEY"] = "<YOUR_KEY>"
os.environ["GOOGLE_API_KEY"] = os.environ["GEMINI_API_KEY"]

embedchain_config = {
    "embedder": {
        "provider": "google",
        "config": {
            "model": "models/gemini-embedding-001",
            "task_type": "RETRIEVAL_DOCUMENT"
        }
    }
}

mysql_tool = MySQLSearchTool(
    db_uri="mysql://<USER>:<PASSWORD>@localhost:3306/pets",  # 👈
    table_name="cats",
    config=embedchain_config
)

#
# Test if `MySQLSearchTool.run()` works standalone
#

user_question = "Who owns Cookie?"

relevant_chunks = mysql_tool.run(user_question)

print("--- MySQLSearchTool.run() Chunks ---")
print(relevant_chunks)
print("------------------------------------")

If everything runs smoothly (i.e., if it prints out any chunks), you can then use mysql_tool (or whatever you’ve named the instance) as a tool for your Agent.

Thanks @maxmoura ! I followed your instructions with a little modification and everything worked as you outlined though there was some extra output from an earlier crew run as well.

Here’s my output -

$ uv run main.py
/home/mre/dox/repos/timebillcrew/.venv/lib/python3.10/site-packages/pydantic/fields.py:1093: PydanticDeprecatedSince20: Using extra keyword arguments on `Field` is deprecated and will be removed. Use `json_schema_extra` instead. (Extra keys: 'required'). Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.11/migration/
  warn(
/home/mre/dox/repos/timebillcrew/.venv/lib/python3.10/site-packages/embedchain/embedder/ollama.py:27: LangChainDeprecationWarning: The class `OllamaEmbeddings` was deprecated in LangChain 0.3.1 and will be removed in 1.0.0. An updated version of the class exists in the :class:`~langchain-ollama package and should be used instead. To use it run `pip install -U :class:`~langchain-ollama` and import as `from :class:`~langchain_ollama import OllamaEmbeddings``.
  embeddings = OllamaEmbeddings(model=self.config.model, base_url=config.base_url)
/home/mre/dox/repos/timebillcrew/.venv/lib/python3.10/site-packages/alembic/config.py:592: DeprecationWarning: No path_separator found in configuration; falling back to legacy splitting on spaces, commas, and colons for prepend_sys_path.  Consider adding path_separator=os to Alembic config.
  util.warn_deprecated(
Using Tool: Search MySQL Database Table Content
/home/mre/dox/repos/timebillcrew/.venv/lib/python3.10/site-packages/chromadb/types.py:144: PydanticDeprecatedSince211: Accessing the 'model_fields' attribute on the instance is deprecated. Instead, you should access this attribute from the model class. Deprecated in Pydantic V2.11 to be removed in V3.0.
  return self.model_fields  # pydantic 2.x
--- MySQLSearchTool.run() Chunks ---
Relevant Content:

Relevant Content:
(2, 'Cookie', 'Casey', datetime.date(2013, 11, 13)

(191, datetime.date(2025, 1, 21), 'Jane Doe', 'Johnson', ', 'Design Development', 'Review lighting for presentation. Review schemes and add dog kennel furniture', Decimal('1.25'), datetime.timedelta(seconds=51300), datetime.timedelta(seconds=55800), 1, 0, 0, 'Mary', 'Jane', ', 1, Decimal('0.00'), Decimal('0.00'), Decimal('0.00'), Decimal('0.00'), 'USD', ')

(172, datetime.date(2025, 1, 13), 'Jane Doe', 'Johnson', ', 'Selections', 'shop for more lighting options for the dining area and kitchen, look for any more chest ideas, put on power point , go over fabrics with mary', Decimal('3.25'), datetime.timedelta(seconds=37800), datetime.timedelta(seconds=49500), 1, 0, 0, 'Bobby', 'Sue', 'Designer', 1, Decimal('0.00'), Decimal('0.00'), Decimal('50.00'), Decimal('162.50'), 'USD', ')

The “extra” relevant content looks like it came from my earlier crew runs where I’m trying to build a crew to create some billing reports. I tried running

$ uv run crewai reset-memories --all
[2025-08-28 14:33:04][INFO]: [Crew (e818fcc9-c987-4fe7-9914-59f9e4ab1158)] Task Output memory has been reset
[Crew (e818fcc9-c987-4fe7-9914-59f9e4ab1158)] Reset memories command has been completed.

but the pets relevant output continues to display the “remembered” billing data but it does consistently find the owner for Cookie (Casey).

And then I’m going to have to figure out how to get rid of those irritating warnings … :slight_smile:

For completeness, here is my modified main.py -

from alternative_mysql_search_tool import MySQLSearchTool
import os

# # Satisfy both LiteLLM and Embedchain
# os.environ["GEMINI_API_KEY"] = "<YOUR_KEY>"
# os.environ["GOOGLE_API_KEY"] = os.environ["GEMINI_API_KEY"]
# using local models and local mysql database

embedchain_config = {
    "embedder": {
        "provider": "ollama",
        "config": {
            "model": "nomic-embed-text",
#            "task_type": "ENHANCEMENT_DOCUMENT"
        }
    }
}

mysql_tool = MySQLSearchTool(
    db_uri="mysql://vet:******@localhost:3306/pets",
    table_name="cats",
    config=embedchain_config
)

#
# Test if `MySQLSearchTool.run()` works standalone
#

user_question = "Who owns Cookie?"

relevant_chunks = mysql_tool.run(user_question)

print("--- MySQLSearchTool.run() Chunks ---")
print(relevant_chunks)
print("------------------------------------")

where the only real modifications were to comment out the api keys since I am using a local ollama model and local database; and then to configure the embedder as my local ollama nomic-embed-text model. (I had to comment out the task_type as it generates a fatal error regardless of what value it is set to).

But when I transfer this knowledge/learning/example to my billing app I consistently get that search_query error -


🚀 Crew: crew
└── 📋 Task: 2658bfdb-93c9-4c35-b9fe-4a3445ec3256
    Status: Executing Task...
    └── 🔧 Failed Search MySQL Database Table Content (1)
╭─────────────────────────────────────────────────────────── Tool Error ───────────────────────────────────────────────────────────╮
│                                                                                                                                  │
│  Tool Usage Failed                                                                                                               │
│  Name: Search MySQL Database Table Content                                                                                       │
│  Error: Arguments validation failed: 1 validation error for MySQLSearchToolSchema                                                │
│  search_query                                                                                                                    │
│    Field required [type=missing, input_value={'query': 'SELECT project...4564', 'metadata': {}}}}, input_type=dict]              │
│      For further information visit https://errors.pydantic.dev/2.11/v/missing                                                    │
│  Tool Args:                                                                                                                      │
│                                                                                                                                  │
│                                                                                                                                  │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

which is why I asked how to provide the search_query for MySQLSearchToolSchema. My current thinking is that you don’t provide the search_query, instead the crewai framework fills it in based on the goals and expected outputs mentioned in the agents and tasks - but that isn’t working.

Modify the beginning of your script to:

import warnings
warnings.filterwarnings("ignore", module="pydantic")
warnings.filterwarnings("ignore", module="langchain")
warnings.filterwarnings("ignore", module="chromadb")
warnings.filterwarnings("ignore", module="alembic")

from crewai.utilities.paths import db_storage_path

print(f"\n>>> Please remove the '{db_storage_path()}' directory\n")

from alternative_mysql_search_tool import MySQLSearchTool
import os

# ... rest of your code ...

And then you’ll get a message telling you which directory to delete to get rid of the past memories.

Modify the beginning of your script to:

import warnings
warnings.filterwarnings("ignore", module="pydantic")
warnings.filterwarnings("ignore", module="langchain")
warnings.filterwarnings("ignore", module="chromadb")
warnings.filterwarnings("ignore", module="alembic")

from crewai.utilities.paths import db_storage_path

print(f"\n>>> Please remove the '{db_storage_path()}' directory\n")

from alternative_mysql_search_tool import MySQLSearchTool
import os

# ... rest of your code ...

And then you’ll get a message about which directory you should delete to get rid of past memories.

The issue here is related to how the tool is being used. As I mentioned in my original comment, my version is simply a functional implementation of the MySQLSearchTool that adheres to the official documentation. This means it’s a RAG tool. In other words, you point it to a database and a table, and it transforms the data from that specific table into a data source. It then breaks this data into chunks, applies an embedding model, and stores the results in a vector database. So, when you (or your agent) make a query, a semantic search is performed, and the most relevant chunks are injected into the prompt.

However, it looks like you’re trying to execute arbitrary SQL against a database, which is a completely different use case. If that’s the situation, there’s another tool in CrewAI called NL2SQLTool which, in theory, is designed for that purpose. I’ve seen some complaints that the tool only works with certain types of databases and not others. Hopefully, it works for you. I don’t have a fixed or improved version of this tool, as I completely lost interest in submitting issues with suggestions for improvement after the “warm welcome” my MySQLSearchTool version received (you know what I mean).

I really hope the NL2SQLTool meets your needs. If it doesn’t, feel free to come back here and open a new thread about it, and you’ll certainly get help from the community. Good luck with your projects!

@maxmoura, super thanks as always for the detailed feedback!

I have understood the aspect you discussed where MySQLSearchTool “determines” the SQL to use against the embedded vector database and I’m specifically trying to embrace that approach and avoid me authoring SQL directly so I don’t have any SQL anywhere in my crew (sounds like I did a poor job of conveying that), just my agent and task prompt instructions but no matter what I do I seem to consistently run into that error -

🚀 Crew: crew
└── 📋 Task: 2658bfdb-93c9-4c35-b9fe-4a3445ec3256
    Status: Executing Task...
    └── 🔧 Failed Search MySQL Database Table Content (1)
╭─────────────────────────────────────────────────────────── Tool Error ───────────────────────────────────────────────────────────╮
│                                                                                                                                  │
│  Tool Usage Failed                                                                                                               │
│  Name: Search MySQL Database Table Content                                                                                       │
│  Error: Arguments validation failed: 1 validation error for MySQLSearchToolSchema                                                │
│  search_query                                                                                                                    │
│    Field required [type=missing, input_value={'query': 'SELECT project...4564', 'metadata': {}}}}, input_type=dict]              │
│      For further information visit https://errors.pydantic.dev/2.11/v/missing                                                    │
│  Tool Args:                                                                                                                      │
│                                                                                                                                  │
│                                                                                                                                  │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

which is why I keep asking about MySQLSearchToolSchema where I see that “search_query” but I’ve come to the conclusion that it will be populated automatically and I’m not supposed to provide anything for it directly as it’s used internally.

The only “input” I’m providing is my agents.yaml and tasks.yaml descriptions.

My agent that comes closest to providing any SQL is my data_engineer agent -

data_engineer:
  role: >
    {topic} SQL Data Engineer
  goal: >
    Fetch grouped work log entries from MySQL for summarization.
    Using data in a mysql database in table {table_name},
    put together grouped notes for {topic} Authors to report against.
    The data needs to be grouped by project, entry_date, and person
    (first_name + last_name) and should include hours worked
    and most importantly the grouped notes.
  backstory: >
    You are experienced with querying mysql tables.
    The {topic} Author will further enhance and clean up the notes
    after you have grouped them.

with a task for the agent defined as -

query_task:
  description: >
    Query employee time reporting data from a mysql database.
  expected_output: >
    Query the {table_name} table and group the results by
    project, entry_date, person (first_name + last_name).
    The {topic} Author will use this grouped data to write their
    customer-facing reports.
  agent: data_engineer

And my inputs to kickoff are just -

    inputs = {
        'topic': 'Time Billing',
        'current_year': str(datetime.now().year),
        'table_name': 'entry_detail',
        'database': 'timebills',
        'db_uri': 'mysql://timebill:******@localhost:3306/timebills',
    }

It’s really unfortunate that your updated MySQLSearchTool wasn’t picked up and incorporated; I wonder if you are expected to submit a pull request and do the update yourself. Looking at the code it seems like a no-brainer to accept your update as it looks very complete (and most importantly works!), especially when compared to the original. :slight_smile:

I’ll take a look at that NL2SQLTool as I do actually have a SQL statement that accomplishes what I want - I had just hoped to avoid going there.

Thanks for all your help!

@user1024, now that you’ve provided your Agent and Task configuration, I think it’ll be easier for me to explain my point.

Imagine you have a text about the world’s super-rich, composed of four paragraphs. This text is in a PDF file, let’s say richest_people.pdf. Now, imagine the third paragraph mentions Elon Musk’s fortune (+$400B), okay? So, by using crewai_tools.PDFSearchTool, you point to this PDF file as a knowledge source. CrewAI will then chunk your text (to simplify, let’s say it generates 4 chunks, one for each paragraph), create embeddings for them, and store each chunk in a vector database. Finally, if your Task involves finding out Elon Musk’s fortune, the RAG mechanism (which is the foundation for several tools) will inject the most relevant chunk for the LLM to answer the question. In our simplified example, the third paragraph of the specified PDF file is the most relevant one. Makes sense so far, right?

Now for the important part: imagine that instead of a PDF file, this same information is available in a table within a MySQL database. For example, you have a database named curiosities, and within it, a table called richest_people. This table has four rows, and as you might guess, the third row mentions Elon Musk’s fortune. So now, it’s this row, within this table, inside a MySQL database, that needs to be retrieved by the RAG mechanism and injected into the LLM’s prompt. That’s exactly what the MySQLSearchTool does. In other words, MySQLSearchTool is to a MySQL database/table what PDFSearchTool is to a PDF.

Am I making myself clear now? Notice that the database is being treated purely as a source of knowledge, something containing information that will be partitioned into chunks, which can then be searched for their relevance to a specific context (the query formulated by your Agent).

On the other hand, based on the description of your Agent and Task, it’s clear that you intend for your Agent to execute arbitrary structured queries (SQL) against a database. This is a different use case, and the tool CrewAI provides for this purpose is NL2SQLTool. With it, your agent could (in theory) execute queries like:

SELECT 
    project,
    entry_date,
    CONCAT(first_name, ' ', last_name) AS person,
    SUM(hours_worked) AS total_hours,
    GROUP_CONCAT(notes SEPARATOR ' | ') AS grouped_notes
FROM 
    timebills.entry_detail 
GROUP BY 
    project,
    entry_date,
    first_name,
    last_name
ORDER BY 
    project,
    entry_date DESC;

And then work with the results of the query to complete the requested task.

Ah! This description really helped, thanks again!

Now I can see that NL2SQLTool is very likely the approach I need as I was “hoping for a miracle” otherwise. :smiley:

Thanks again for all your help!

1 Like