Skip to main content

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.
Explicit schemas are recommended for published tools — they produce better agent behavior and clearer documentation for your users.

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:
Set result_schema explicitly when your tool returns a dictionary:
If agents should receive a short text summary instead of JSON, override format_output_for_agent on your BaseTool subclass.
The override only changes what the agent sees. Direct users of your package still receive the normal value from tool.run(...).

Optional: Environment Variables

If your tool requires API keys or other configuration, declare them with env_vars so users know what to set:

Package Structure

Structure your project as a standard Python package. Here’s a recommended layout:

pyproject.toml

Declare 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).

Testing Your Tool

Before publishing, verify your tool works within a crew:

Publishing to PyPI

Once your tool is tested and ready:
If this is your first time publishing, you’ll need a PyPI account and an API token.

After Publishing

Users can install your tool with:
Or with uv:
Then use it in their crews: