--- dimensions: type: primary: implementation detail: standard level: intermediate standard_title: Tool Plugin language: en title: Tool Plugin description: This document provides detailed instructions on how to develop tool plugins for Dify, using Google Search as an example to demonstrate a complete tool plugin development process. The content includes plugin initialization, template selection, tool provider configuration file definition, adding third-party service credentials, tool functionality code implementation, debugging, and packaging for release. --- Tools refer to third-party services that can be called by Chatflow / Workflow / Agent-type applications, providing complete API implementation capabilities to enhance Dify applications. For example, adding extra features like online search, image generation, and more. ![Tool Plugin Example](https://assets-docs.dify.ai/2024/12/7e7bcf1f9e3acf72c6917ea9de4e4613.png) In this article, **"Tool Plugin"** refers to a complete project that includes tool provider files, functional code, and other structures. A tool provider can include multiple Tools (which can be understood as additional features provided within a single tool), structured as follows: ``` - Tool Provider - Tool A - Tool B ``` ![Tool Plugin Structure](https://assets-docs.dify.ai/2025/02/60c4c86a317d865133aa460592eac079.png) This article will use `Google Search` as an example to demonstrate how to quickly develop a tool plugin. ### Prerequisites - Dify plugin scaffolding tool - Python environment, version ≥ 3.12 For detailed instructions on how to prepare the plugin development scaffolding tool, please refer to [Initializing Development Tools](/plugin-dev-en/0221-initialize-development-tools). If you are developing a plugin for the first time, it is recommended to read [Dify Plugin Development: Hello World Guide](/plugin-dev-en/0211-getting-started-dify-tool) first. ### Creating a New Project Run the scaffolding command line tool to create a new Dify plugin project. ```bash ./dify-plugin-darwin-arm64 plugin init ``` If you have renamed the binary file to `dify` and copied it to the `/usr/local/bin` path, you can run the following command to create a new plugin project: ```bash dify plugin init ``` > In the following text, `dify` will be used as a command line example. If you encounter any issues, please replace the `dify` command with the path to the command line tool. ### Choosing Plugin Type and Template All templates in the scaffolding tool provide complete code projects. In this example, select the `Tool` plugin. > If you are already familiar with plugin development and do not need to rely on templates, you can refer to the [General Specifications](/plugin-dev-en/0411-general-specifications) guide to complete the development of different types of plugins. ![Plugin Type: Tool](https://assets-docs.dify.ai/2024/12/dd3c0f9a66454e15868eabced7b74fd6.png) #### Configuring Plugin Permissions The plugin also needs permissions to read from the Dify platform. Grant the following permissions to this example plugin: - Tools - Apps - Enable persistent storage Storage, allocate default size storage - Allow registering Endpoints > Use the arrow keys in the terminal to select permissions, and use the "Tab" button to grant permissions. After checking all permission items, press Enter to complete the plugin creation. The system will automatically generate the plugin project code. ![Plugin Permissions](https://assets-docs.dify.ai/2024/12/9cf92c2e74dce55e6e9e331d031e5a9f.png) ### Developing the Tool Plugin #### 1. Creating the Tool Provider File The tool provider file is a yaml format file, which can be understood as the basic configuration entry for the tool plugin, used to provide necessary authorization information to the tool. Go to the `/provider` path in the plugin template project and rename the yaml file to `google.yaml`. This `yaml` file will contain information about the tool provider, including the provider's name, icon, author, and other details. This information will be displayed when installing the plugin. **Example Code** ```yaml identity: # Basic information of the tool provider author: Your-name # Author name: google # Name, unique, cannot have the same name as other providers label: # Label, for frontend display en_US: Google # English label zh_Hans: Google # Chinese label description: # Description, for frontend display en_US: Google # English description zh_Hans: Google # Chinese description icon: icon.svg # Tool icon, needs to be placed in the _assets folder tags: # Tags, for frontend display - search ``` Make sure the file path is in the `/tools` directory, with the complete path as follows: ```yaml plugins: tools: - 'google.yaml' ``` Where `google.yaml` needs to use its absolute path in the plugin project. In this example, it is located in the project root directory. The identity field in the YAML file is explained as follows: `identity` contains basic information about the tool provider, including author, name, label, description, icon, etc. - The icon needs to be an attachment resource and needs to be placed in the `_assets` folder in the project root directory. - Tags can help users quickly find plugins through categories. Below are all the currently supported tags. ```python class ToolLabelEnum(Enum): SEARCH = 'search' IMAGE = 'image' VIDEOS = 'videos' WEATHER = 'weather' FINANCE = 'finance' DESIGN = 'design' TRAVEL = 'travel' SOCIAL = 'social' NEWS = 'news' MEDICAL = 'medical' PRODUCTIVITY = 'productivity' EDUCATION = 'education' BUSINESS = 'business' ENTERTAINMENT = 'entertainment' UTILITIES = 'utilities' OTHER = 'other' ``` #### **2. Completing Third-Party Service Credentials** For development convenience, we choose to use the Google Search API provided by the third-party service `SerpApi`. `SerpApi` requires an API Key for use, so we need to add the `credentials_for_provider` field in the `yaml` file. The complete code is as follows: ```yaml identity: author: Dify name: google label: en_US: Google zh_Hans: Google pt_BR: Google description: en_US: Google zh_Hans: GoogleSearch pt_BR: Google icon: icon.svg tags: - search credentials_for_provider: #Add credentials_for_provider field serpapi_api_key: type: secret-input required: true label: en_US: SerpApi API key zh_Hans: SerpApi API key placeholder: en_US: Please input your SerpApi API key zh_Hans: Please enter your SerpApi API key help: en_US: Get your SerpApi API key from SerpApi zh_Hans: Get your SerpApi API key from SerpApi url: https://serpapi.com/manage-api-key tools: - tools/google_search.yaml extra: python: source: google.py ``` - The sub-level structure of `credentials_for_provider` needs to meet the requirements of [General Specifications](/plugin-dev-en/0411-general-specifications). - You need to specify which tools the provider includes. This example only includes one `tools/google_search.yaml` file. - As a provider, in addition to defining its basic information, you also need to implement some of its code logic, so you need to specify its implementation logic. In this example, we put the code file for the functionality in `google.py`, but we won't implement it yet, but instead write the code for `google_search` first. #### 3. Filling in the Tool YAML File A tool plugin can have multiple tool functions, and each tool function needs a `yaml` file for description, including basic information about the tool function, parameters, output, etc. Still using the `GoogleSearch` tool as an example, create a new `google_search.yaml` file in the `/tools` folder. ```yaml identity: name: google_search author: Dify label: en_US: GoogleSearch zh_Hans: Google Search pt_BR: GoogleSearch description: human: en_US: A tool for performing a Google SERP search and extracting snippets and webpages. Input should be a search query. zh_Hans: A tool for performing a Google SERP search and extracting snippets and webpages. Input should be a search query. pt_BR: A tool for performing a Google SERP search and extracting snippets and webpages. Input should be a search query. llm: A tool for performing a Google SERP search and extracting snippets and webpages. Input should be a search query. parameters: - name: query type: string required: true label: en_US: Query string zh_Hans: Query string pt_BR: Query string human_description: en_US: used for searching zh_Hans: used for searching web content pt_BR: used for searching llm_description: key words for searching form: llm extra: python: source: tools/google_search.py ``` - `identity` contains basic information about the tool, including name, author, label, description, etc. - `parameters` parameter list - `name` (required) parameter name, unique, cannot have the same name as other parameters. - `type` (required) parameter type, currently supports `string`, `number`, `boolean`, `select`, `secret-input` five types, corresponding to string, number, boolean, dropdown, encrypted input box. For sensitive information, please use the `secret-input` type. - `label` (required) parameter label, for frontend display. - `form` (required) form type, currently supports `llm`, `form` two types. - In Agent applications, `llm` means that the parameter is inferred by the LLM itself, `form` means that parameters can be preset in advance to use this tool. - In Workflow applications, both `llm` and `form` need to be filled in by the frontend, but `llm` parameters will be used as input variables for the tool node. - `required` whether required - In `llm` mode, if the parameter is required, the Agent will be required to infer this parameter. - In `form` mode, if the parameter is required, the user will be required to fill in this parameter on the frontend before the conversation begins. - `options` parameter options - In `llm` mode, Dify will pass all options to the LLM, and the LLM can infer based on these options. - In `form` mode, when `type` is `select`, the frontend will display these options. - `default` default value. - `min` minimum value, can be set when the parameter type is `number`. - `max` maximum value, can be set when the parameter type is `number`. - `human_description` introduction for frontend display, supports multiple languages. - `placeholder` prompt text for the input field, can be set when the form type is `form` and the parameter type is `string`, `number`, `secret-input`, supports multiple languages. - `llm_description` introduction passed to the LLM. To make the LLM better understand this parameter, please write as detailed information as possible about this parameter here, so that the LLM can understand the parameter. #### 4. Preparing Tool Code After filling in the configuration information for the tool, you can start writing the code for the tool's functionality, implementing the logical purpose of the tool. Create `google_search.py` in the `/tools` directory with the following content: ```python from collections.abc import Generator from typing import Any import requests from dify_plugin import Tool from dify_plugin.entities.tool import ToolInvokeMessage SERP_API_URL = "https://serpapi.com/search" class GoogleSearchTool(Tool): def _parse_response(self, response: dict) -> dict: result = {} if "knowledge_graph" in response: result["title"] = response["knowledge_graph"].get("title", "") result["description"] = response["knowledge_graph"].get("description", "") if "organic_results" in response: result["organic_results"] = [ { "title": item.get("title", ""), "link": item.get("link", ""), "snippet": item.get("snippet", ""), } for item in response["organic_results"] ] return result def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage]: params = { "api_key": self.runtime.credentials["serpapi_api_key"], "q": tool_parameters["query"], "engine": "google", "google_domain": "google.com", "gl": "us", "hl": "en", } response = requests.get(url=SERP_API_URL, params=params, timeout=5) response.raise_for_status() valuable_res = self._parse_response(response.json()) yield self.create_json_message(valuable_res) ``` This example means requesting `serpapi` and using `self.create_json_message` to return a formatted `json` data string. If you want to learn more about return data types, you can refer to the [Remote Debugging Plugins](/plugin-dev-en/0411-remote-debug-a-plugin) and [Persistent Storage KV](/plugin-dev-en/0411-persistent-storage-kv) documents. #### 4. Completing the Tool Provider Code Finally, you need to create an implementation code for the provider to implement the credential validation logic. If credential validation fails, a `ToolProviderCredentialValidationError` exception will be thrown. After validation succeeds, the `google_search` tool service will be correctly requested. Create a `google.py` file in the `/provider` directory with the following content: ```python from typing import Any from dify_plugin import ToolProvider from dify_plugin.errors.tool import ToolProviderCredentialValidationError from tools.google_search import GoogleSearchTool class GoogleProvider(ToolProvider): def _validate_credentials(self, credentials: dict[str, Any]) -> None: try: for _ in GoogleSearchTool.from_credentials(credentials).invoke( tool_parameters={"query": "test", "result_type": "link"}, ): pass except Exception as e: raise ToolProviderCredentialValidationError(str(e)) ``` ### Debugging the Plugin After completing plugin development, you need to test whether the plugin can function properly. Dify provides a convenient remote debugging method to help you quickly verify the plugin's functionality in a test environment. Go to the ["Plugin Management"](https://cloud.dify.ai/plugins) page to obtain the remote server address and debugging Key. ![Remote Debug Key](https://assets-docs.dify.ai/2024/12/053415ef127f1f4d6dd85dd3ae79626a.png) Return to the plugin project, copy the `.env.example` file and rename it to `.env`, then fill in the remote server address and debugging Key information you obtained. `.env` file: ```bash INSTALL_METHOD=remote REMOTE_INSTALL_URL=debug.dify.ai:5003 REMOTE_INSTALL_KEY=********-****-****-****-************ ``` Run the `python -m main` command to start the plugin. On the plugins page, you can see that the plugin has been installed in the Workspace, and other members of the team can also access the plugin. ![](https://assets-docs.dify.ai/2024/11/0fe19a8386b1234755395018bc2e0e35.png) ### Packaging the Plugin (Optional) After confirming that the plugin can run normally, you can package and name the plugin using the following command line tool. After running, you will discover a `google.difypkg` file in the current folder, which is the final plugin package. ```bash # Replace ./google with the actual path of the plugin project dify plugin package ./google ``` Congratulations, you have completed the entire process of developing, debugging, and packaging a tool-type plugin! ### Publishing the Plugin (Optional) If you want to publish the plugin to the Dify Marketplace, please ensure that your plugin follows the specifications in [Publish to Dify Marketplace](/plugin-dev-en/0322-release-to-dify-marketplace). After passing the review, the code will be merged into the main branch and automatically launched to the [Dify Marketplace](https://marketplace.dify.ai/). [Publishing Overview](/plugin-dev-en/0321-release-overview) ### Explore More #### **Quick Start:** - [Developing Extension Plugins](/plugin-dev-en/9231-extension-plugin) - [Developing Model Plugins](/plugin-dev-en/0211-getting-started-new-model) - [Bundle Plugins: Packaging Multiple Plugins](/plugin-dev-en/9241-bundle) #### **Plugin Interface Documentation:** - [General Specifications](/plugin-dev-en/0411-general-specifications) - Manifest Structure and Tool Specifications - [Endpoint](/plugin-dev-en/0432-endpoint) - Detailed Endpoint Definition - [Reverse Invocation](/plugin-dev-en/9241-reverse-invocation) - Reverse Invocation of Dify Capabilities - [Model Schema](/plugin-dev-en/0412-model-schema) - Models - [Agent Plugins](/plugin-dev-en/9232-agent) - Extending Agent Strategies ## Next Learning Steps - [Remote Debugging Plugins](/plugin-dev-en/0411-remote-debug-a-plugin) - Learn more advanced debugging techniques - [Persistent Storage](/plugin-dev-en/0411-persistent-storage-kv) - Learn how to use data storage in plugins - [Slack Bot Plugin Development Example](/plugin-dev-en/0432-develop-a-slack-bot-plugin) - View a more complex plugin development case - [Tool Plugin](/plugin-dev-en/0411-tool) - Explore advanced features of tool plugins {/* Contributing Section DO NOT edit this section! It will be automatically generated by the script. */} --- [Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/0222-tool-plugin.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml)