# Create Tool

### Build Custom MCP Tools

OBTO's built-in tools cover the standard development lifecycle. But your workflows are unique. The **Create Tool** feature lets you define custom MCP tools that extend the platform with your own logic.

Custom tools are stored as records in the `MCPToolModel` collection. Once created, they're automatically registered on your MCP server and available to any connected AI client.

***

### When to Create a Custom Tool

Create a custom tool when you need the AI to:

* **Interact with a third-party API** — e.g., send a Slack notification, create a Jira ticket, query an external database
* **Run domain-specific logic** — e.g., calculate shipping rates, validate business rules, generate reports
* **Automate multi-step workflows** — e.g., deploy to staging, run tests, promote to production
* **Access internal services** — e.g., query your CRM, fetch inventory data, trigger email campaigns

***

### Tool Anatomy

Every custom MCP tool has four parts:

#### 1. Metadata

```json
{
  "name": "my_custom_tool",
  "title": "My Custom Tool",
  "description": "What this tool does — the AI reads this to decide when to use it",
  "domain": "your-domain"
}
```

* **`name`** — Machine-readable identifier (snake\_case). This is what the AI calls.
* **`title`** — Human-readable display name.
* **`description`** — Critical. The AI uses this to decide when and how to invoke the tool. Be specific and descriptive.
* **`domain`** — Scope the tool to your domain, or set to `"global"` for all environments.

#### 2. Input Schema

Defines the parameters your tool accepts. Uses JSON Schema format:

```json
{
  "properties": {
    "projectName": {
      "type": "string",
      "description": "Name of the project to query"
    },
    "limit": {
      "type": "number",
      "description": "Maximum results to return"
    }
  },
  "required": ["projectName"]
}
```

**Supported types:** `string`, `number`, `boolean`, `array`, `object`

> 💡 **Pro tip:** Write detailed `description` fields for each parameter. The AI reads these to understand what values to pass. Vague descriptions lead to hallucinated values.

#### 3. Handler Function

The JavaScript function that executes when the AI calls the tool:

```javascript
async function handler(args) {
  const { projectName, limit = 10 } = args;
  
  // Your custom logic here
  const results = await someExternalAPI.query(projectName, limit);
  
  return {
    content: [
      {
        type: "text",
        text: JSON.stringify(results)
      }
    ]
  };
}
```

**Rules:**

* Must return an object with a `content` array containing `{ type: "text", text: "..." }` objects
* Can use `ob.require()` to load npm packages available on the platform
* Can use `xe.` to call OBTO server scripts
* Can use `ob.db` for direct database queries
* For errors, return `{ isError: true, content: [...] }` so the AI knows the call failed

#### 4. Annotations

Hints that help the AI understand the tool's behavior:

```json
{
  "readOnlyHint": false,
  "destructiveHint": false,
  "idempotentHint": true,
  "openWorldHint": false
}
```

| Annotation        | What It Tells the AI                                                         |
| ----------------- | ---------------------------------------------------------------------------- |
| `readOnlyHint`    | This tool only reads data, never modifies anything                           |
| `destructiveHint` | This tool can permanently delete or alter data                               |
| `idempotentHint`  | Calling this tool multiple times with the same args produces the same result |
| `openWorldHint`   | This tool interacts with external systems outside OBTO                       |

***

### Best Practices

#### Write Descriptive Descriptions

The AI decides whether to call your tool based on the `description` field. Be specific:

```
❌ "Sends a message"
✅ "Send a Slack notification to the #deployments channel with the app name and deployment status"
```

#### Handle Errors Gracefully

Always return structured error responses:

```javascript
if (!result) {
  return {
    isError: true,
    content: [
      { type: "text", text: "Error: Project not found. Check the project name and try again." }
    ]
  };
}
```

#### Keep Tools Focused

One tool = one capability. Don't create a mega-tool that does everything. The AI performs better when it can pick from focused, well-described single-purpose tools.

#### Test Before Deploying

Create the tool in your staging domain first. Connect an AI client and test whether the AI correctly identifies when to use the tool and passes the right parameters.

***

### Next Steps

* **Dev Zone** — Explore your development workspace
* **MCP Tools - OOB** — Review the built-in tools your custom tools can complement
