--- title: "How do I create a custom tool?" slug: "how-do-i-create-a-custom-tool" updated: 2026-04-29T15:20:58Z published: 2026-04-29T15:20:58Z canonical: "support.lusid.com/how-do-i-create-a-custom-tool" --- > ## Documentation Index > Fetch the complete documentation index at: https://support.lusid.com/llms.txt > Use this file to discover all available pages before exploring further. # How do I create a custom tool? Custom tools extend Candela with capabilities specific to your organisation - no code required for your end-users. A tool wraps either of the following and exposes it as a named tool that your Candela [agents](/v1/docs/understanding-candela-s-system-agents) can call: - A [Luminesce SQL query](/v1/docs/understanding-the-luminesce-sql-query-syntax) - A [Scheduler](/v1/docs/scheduler) job For example, you could create a `GetPortfolioProperties` tool that returns all custom metadata attached to a portfolio, then assign it to a [specialist agent](/v1/docs/how-do-i-create-a-custom-agent) so your team can retrieve that data through a simple conversation prompt. This article explains how to create and assign custom tools via the [LUSID Identity API](https://www.lusid.com/docs/api/identity/intro). > [!WARNING] > Prerequisites > > - Suitable access permissions to create MCP tools in LUSID > - For Luminesce tools: Your tested [Luminesce SQL query](/v1/docs/understanding-the-luminesce-sql-query-syntax) > - For Scheduler tools: Your [Scheduler job](/v1/docs/how-do-i-create-a-job)’s scope and code ## Step 1: Create a tool ### Understanding the fields required to create a tool All tools share the following fields: | Field | Description | | --- | --- | | `name` | A tool name that’s unique within your domain. | | `title` | A friendly title to show in tool listings. | | `description` | A specific, action-oriented description for the AI to use to decide when to call the tool. | | `destructive` | Set to `true` to require user confirmation before executing. [Read more.](/v1/docs/monitoring-candela-ai-activity) | | `readOnly` | Set to `false` to have an agent confirm with a user before calling the tool. | | `parameters` | A list of parameters that the tool can pass into the underlying Luminesce query or scheduler job. [See parameters below.](/v1/docs/how-do-i-create-a-custom-tool#parameters) | | [luminescePayload](/v1/docs/how-do-i-create-a-custom-tool#luminescepowered-tools) or [schedulerPayload](/v1/docs/how-do-i-create-a-custom-tool#schedulerpowered-tools) | The query or job this tool executes; [more information below](/v1/docs/how-do-i-create-a-custom-tool#luminescepowered-tools). | > [!NOTE] > Note > > The `idempotent` and `openWorld` fields are currently reference-only. In future, they will be used to govern how tools are executed and what external services they can access. #### `parameters` Each parameter declared in the `parameters` array can be referenced in your [luminescePayload](/v1/docs/how-do-i-create-a-custom-tool#luminescepowered-tools) query or [schedulerPayload](/v1/docs/how-do-i-create-a-custom-tool#schedulerpowered-tools) arguments using triple curly brace `{{{<parameter>}}}` syntax. When called, Candela substitutes each placeholder with the value provided in the conversation. Each parameter requires the following fields: | Field | Description | | --- | --- | | `name` | The parameter name, which you can subsequently reference in the payload as `{{{<parameter>}}}`. | | `dataType` | The expected data type. | | `description` | A specific description of the parameter for the agent to use to determine what value to pass. For example, `"The LUSID scope of the portfolio, for example 'acme'"` is more effective than `"The portfolio scope"`. | ### Luminesce-powered tools Imagine you want to create a tool that can run the following [Luminesce query](/v1/docs/understanding-the-luminesce-sql-query-syntax): ```sql select [PropertyScope], [PropertyCode], [Value] from [Lusid.Portfolio.Property] where [PortfolioScope] = '{{{portfolioScope}}}' and [PortfolioCode] = '{{{portfolioCode}}}' ``` You can call the [CreateMcpTool API](https://www.lusid.com/docs/api/identity/endpoints/mcp-tools/CreateMcpTool), passing in the fields from the table above, plus the following `luminescePayload`: ```json curl -X POST 'https://.lusid.com/identity/api/mcptools/Finbourne-Examples/GetPortfolioProperties'  -H 'Accept: application/json'  -H 'Authorization: Bearer '  -H 'Content-Type: application/json-patch+json'  -d '{    "name": "GetPortfolioProperties",    "title": "Get custom properties for a portfolio",    "description": "Returns all custom properties attached to a portfolio. Use when the user asks about portfolio metadata, tags, or custom attributes.",    "destructive": false,    "idempotent": true,    "openWorld": false,    "readOnly": true,    "parameters": [      { "name": "portfolioScope", "dataType": "String", "description": "The LUSID scope of the portfolio" },      { "name": "portfolioCode", "dataType": "String", "description": "The LUSID code of the portfolio" }    ],    "luminescePayload": {      "query": "select [PropertyScope], [PropertyCode], [Value] from [Lusid.Portfolio.Property] where [PortfolioScope] = '\''{{{portfolioScope}}}'\'' and [PortfolioCode] = '\''{{{portfolioCode}}}'\''"    }  } ' ``` ### Scheduler-powered tools To create a tool that can trigger a scheduled job, you can call the [CreateMcpTool API](https://www.lusid.com/docs/api/identity/endpoints/mcp-tools/CreateMcpTool), passing in the fields [from the table above](/v1/docs/how-do-i-create-a-custom-tool#understanding-the-fields-required-to-create-a-tool), plus the following `schedulerPayload`: ```json curl -X POST 'https://.lusid.com/identity/api/mcptools/Finbourne-Examples/RunComplianceJob'  -H 'Accept: application/json'  -H 'Authorization: Bearer '  -H 'Content-Type: application/json-patch+json'  -d '{  "name": "RunComplianceJob",  "title": "Run a compliance scheduler job",  "description": "Triggers the nightly compliance job for a given set of rules.",  "destructive": false,  "idempotent": false,  "readOnly": false,  "parameters": [    {      "name": "ruleScope",      "dataType": "String",      "description": "The rules scope to run compliance on"    },        {      "name": "runScope",      "dataType": "String",      "description": "The scope to run compliance for"    }  ],  "schedulerPayload": {    "jobScope": "Finbourne-Examples",    "jobCode": "RunCompliance",    "arguments": {      "ruleScope": "{{{ruleScope}}}",      "runScope": "{{{runScope}}}"    }  } }' ``` ## Step 2: Assign the tool to an agent Agents only call tools that you explicitly list in their `toolNames` array. [See how to create or update an agent.](/v1/docs/how-do-i-create-a-custom-agent)