Tutorial: Build a Custom Tool
Build a private MCP server, publish it to your registry, and use it in chat.
Tutorial: Build a Custom Tool
In this tutorial, you'll build a custom tool that gives your AI agent access to internal product data, publish it to your organization's private registry, and use it in a chat conversation.
By the end, your team will be able to ask the AI questions like "What's the stock level for SKU-4810?" and get real answers from your systems.
What you'll need
- ToolPlex Desktop installed and signed in
- An organization with Admin or Owner access
- Node.js 18 or later
- Your Scope ID and API key (both in Org Settings)
Step 1: Clone the template
Start from our example project:
git clone https://github.com/toolplex/private-tool-example.git my-inventory-tool
cd my-inventory-tool
npm installThe template gives you a working MCP server with a product catalog — search, detail, and low-stock tools with mock data. You'll replace it with your own logic.
Step 2: Define your tools
Open src/index.ts and replace the example tools with your own. Here's a product lookup tool:
import { z } from "zod";
server.registerTool(
"check_stock",
{
description: "Check inventory levels for a product",
inputSchema: {
query: z.string().describe("Product name or SKU"),
},
},
async ({ query }) => {
const results = await yourApi.searchProducts(query);
if (results.length === 0) {
return { content: [{ type: "text", text: "No products found." }] };
}
const summary = results.map(p =>
`${p.name} (${p.sku}): ${p.stock_on_hand} units in stock`
).join("\n");
return { content: [{ type: "text", text: summary }] };
}
);A few guidelines for good tools:
- Keep them read-only when possible. AI agents can call tools repeatedly, so side-effect-free operations are safest.
- Return clear text. The AI reads the output to form its response, so structured plain text works better than raw JSON.
- Use descriptive names and descriptions. The AI uses these to decide which tool to call and when.
Step 3: Connect to your data
How you fetch data is up to you. Common patterns:
- REST API — Call your internal service with
fetchor a client library - Database — Query directly with a driver like
pg,mysql2, orbetter-sqlite3 - File system — Read from CSV exports, JSON files, or local databases
Authenticating with environment variables
Never hardcode credentials in your tool. Use environment variables and validate them at startup so the server fails fast with a clear error if something is missing:
const API_URL = process.env.MY_API_URL;
const API_TOKEN = process.env.MY_API_TOKEN;
if (!API_URL) throw new Error("MY_API_URL environment variable is required");
if (!API_TOKEN) throw new Error("MY_API_TOKEN environment variable is required");Then use them when making requests:
async function fetchFromApi(path: string) {
const res = await fetch(`${API_URL}${path}`, {
headers: {
Authorization: `Bearer ${API_TOKEN}`,
Accept: "application/json",
},
});
if (!res.ok) throw new Error(`API error: ${res.status}`);
return res.json();
}Setting environment variables
Set these in two places:
- Locally — Create a
.envfile or export vars in your shell for development - In ToolPlex — Go to Org Settings > Environment variables to add them for cloud execution. All organization environment variables are automatically available to your cloud tools at runtime.
See Environment variables for details on managing org-level secrets.
Step 4: Update package.json
Replace the package name with your organization's scope:
{
"name": "@YOUR_SCOPE_ID/inventory",
"version": "1.0.0",
"toolplex": {
"server_name": "Inventory Lookup",
"description": "Check product stock levels across warehouses",
"keywords": ["inventory", "stock", "warehouse"]
}
}Find your Scope ID in the Org Settings panel in ToolPlex Desktop.
Step 5: Test locally
Run your tool to make sure it starts without errors:
npm run build
node dist/index.jsThe MCP server communicates over stdio, so you won't see output in the terminal — it's waiting for input from an AI agent. If it starts without crashing, you're good.
Step 6: Publish
Log in to your organization's private registry and publish:
npm login --registry=YOUR_REGISTRY_URL
npm publish --registry=YOUR_REGISTRY_URLUse the credentials from your Org Settings panel. Find your registry URL there as well.
Your tool will appear in ToolPlex Desktop within about 30 minutes.
Step 7: Install and use
- In ToolPlex Desktop, go to the Servers panel
- Click the Private tab
- Find your tool and click Install
Now open a chat and try it:
"What's the current stock for athletic socks?"
The AI will call your check_stock tool and return the results from your system.
Step 8: Add more tools
Most useful tools expose 3-6 related capabilities. For an inventory system, you might add:
search_products— Find products by name, SKU, or categorycheck_stock— Stock levels across warehousesget_low_stock_items— Products below reorder pointget_inventory_summary— High-level metrics
Each tool is a separate server.registerTool() call in your src/index.ts.
Publishing updates
When you add features or fix bugs, bump the version and publish again:
npm version patch
npm publish --registry=YOUR_REGISTRY_URLTeam members get the update automatically on their next install.
Next steps
- Automate a workflow using your custom tool
- Set up your team with approved tools and roles
- Add human oversight for sensitive operations