Overview
CrewAI’s tool system is designed to be extended. If you’ve built a tool that could benefit others, you can package it as a standalone Python library, publish it to PyPI, and make it available to any CrewAI user — no PR to the CrewAI repo required. This guide walks through the full process: implementing the tools contract, structuring your package, and publishing to PyPI.If you just need a custom tool for your own project, see the Create Custom Tools guide instead.
The Tools Contract
Every CrewAI tool must satisfy one of two interfaces:Option 1: Subclass BaseTool
Subclass crewai.tools.BaseTool and implement the _run method. Define name, description, and optionally an args_schema for input validation.
Option 2: Use the @tool Decorator
For simpler tools, the @tool decorator turns a function into a CrewAI tool. The function must have a docstring (used as the tool description) and type annotations.
Key Requirements
Regardless of which approach you use, your tool must:- Have a
name— a short, descriptive identifier. - Have a
description— tells the agent when and how to use the tool. This directly affects how well agents use your tool, so be clear and specific. - Implement
_run(BaseTool) or provide a function body (@tool) — the synchronous execution logic. - Use type annotations on all parameters and return values.
- Return a string result, or define an optional Pydantic output schema for structured results.
Optional: Async Support
If your tool performs I/O-bound work, implement_arun for async execution:
Optional: Input Validation with args_schema
Define a Pydantic model as your args_schema to get automatic input validation and clear error messages. If you don’t provide one, CrewAI will infer it from your _run method’s signature.
Optional: Typed Outputs with result_schema
If your tool returns structured data, define a Pydantic output model. This is a good default for published tools because users and agents can rely on named fields.
Direct Python calls still receive the value your tool returns. When an agent uses the tool, CrewAI sends the agent JSON based on the output model.
CrewAI can infer the output schema from a Pydantic return annotation:
result_schema explicitly when your tool returns a dictionary:
format_output_for_agent on your BaseTool subclass.
tool.run(...).
Optional: Environment Variables
If your tool requires API keys or other configuration, declare them withenv_vars so users know what to set:
Package Structure
Structure your project as a standard Python package. Here’s a recommended layout:pyproject.toml
crewai as a dependency so users get a compatible version automatically.
__init__.py
Re-export your tool classes so users can import them directly:
Naming Conventions
- Package name: Use the prefix
crewai-(e.g.,crewai-geolocate). This makes your tool discoverable when users search PyPI. - Module name: Use underscores (e.g.,
crewai_geolocate). - Tool class name: Use PascalCase ending in
Tool(e.g.,GeolocateTool).
