Skip to main content
Glama

Angular Toolkit MCP

by push-based
writing-custom-tools.md3.7 kB
# Writing Custom Tools for Angular MCP Server > **Goal:** Enable developers to add new, type-safe MCP tools that can be called by LLMs or scripts. --- ## 1. Anatomy of a Tool Every tool consists of **three parts**: 1. **Schema** – JSON-schema (via `zod`) that describes the tool name, description and arguments. 2. **Handler** – an async function that receives a typed `CallToolRequest`, executes logic, and returns a `CallToolResult`. 3. **Registration** – export a `ToolsConfig` object and add it to the category list (`dsTools`, etc.). Directory convention ``` packages/angular-mcp-server/src/lib/tools/<category>/my-feature/hello-world.tool.ts ``` File name **must** end with `.tool.ts` so tests & registries can auto-discover it. --- ## 2. Boilerplate Template ```ts import { z } from 'zod'; import { ToolSchemaOptions, ToolsConfig } from '@push-based/models'; import { createHandler, RESULT_FORMATTERS } from '../shared/utils/handler-helpers.js'; // 1️⃣ Schema const helloWorldSchema: ToolSchemaOptions = { name: 'hello-world', description: 'Echo a friendly greeting', inputSchema: z.object({ name: z.string().describe('Name to greet'), }), annotations: { title: 'Hello World', }, }; // 2️⃣ Handler (business logic) const helloWorldHandler = createHandler<{ name: string }, string>( helloWorldSchema.name, async (params) => { return `Hello, ${params.name}! 👋`; }, (result) => RESULT_FORMATTERS.success(result), ); // 3️⃣ Registration export const helloWorldTools: ToolsConfig[] = [ { schema: helloWorldSchema, handler: helloWorldHandler }, ]; ``` Key points: * `createHandler` automatically validates common arguments, injects workspace paths, and formats output. * Generic parameters `<{ name: string }, string>` indicate input shape and raw result type. * Use `RESULT_FORMATTERS` helpers to produce consistent textual arrays. --- ## 3. Adding to the Registry Open the category file (e.g. `tools/ds/tools.ts`) and spread your array: ```ts import { helloWorldTools } from './my-feature/hello-world.tool'; export const dsTools: ToolsConfig[] = [ // …existing ...helloWorldTools, ]; ``` The server will now expose `hello-world` via `list_tools`. --- ## 4. Parameter Injection The server adds workspace-specific paths to every call so you don’t need to pass them manually: | Field | Injected Value | |-------|----------------| | `cwd` | Current working dir (may be overridden) | | `workspaceRoot` | `--workspaceRoot` CLI flag | | `storybookDocsRoot` | Relative path from CLI flags | | `deprecatedCssClassesPath` | Path to deprecated CSS map | | `uiRoot` | Path to DS component source | Access them inside the handler via the second argument of `createHandler`: ```ts async (params, ctx) => { console.log('Workspace root:', ctx.workspaceRoot); } ``` --- ## 5. Validation Helpers * `validateCommonInputs` – ensures `directory` is string, `componentName` matches `Ds[A-Z]…` pattern. * Custom validation: extend the Zod `inputSchema` with additional constraints. --- ## 6. Testing Your Tool 1. **Unit tests** (recommended): import the handler function directly and assert on the returned `CallToolResult`. --- ## 7. Documentation Checklist After publishing a tool: - [ ] Add an entry to `docs/tools.md` with purpose, parameters, output. --- ## 8. Common Pitfalls | Pitfall | Fix | |---------|-----| | Tool not listed via `list_tools` | Forgot to spread into `dsTools` array. | | “Unknown argument” error | Ensure `inputSchema` matches argument names exactly. | | Long-running sync FS operations | Use async `fs/promises` or worker threads to keep server responsive. | --- Happy tooling! 🎉

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/push-based/angular-toolkit-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server