How this skill is triggered — by the user, by Claude, or both
Slash command
/forge-mcp:mcp-add-toolThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Walk through adding a single, well-designed tool to an existing MCP server.
Walk through adding a single, well-designed tool to an existing MCP server.
Ask the user:
If the user is vague, help them refine:
A good MCP tool does one thing well. Instead of "manage users", consider separate tools:
search-users— Find users by criteriaget-user— Get a single user by IDcreate-user— Create a new user record
Before writing any code, search the project's existing documentation for context about the feature this tool wraps. This step directly improves the quality of tool descriptions and parameter descriptions.
Search for relevant docs:
docs/, wiki/, README.md, or any documentation directoryExtract and note:
get-user to verify the user exists before calling assign-role")Apply what you find:
description in Step 5 (registration) — not just "what it does" but "when to use it, what to expect, and what to do next".describe() strings on Zod fields in Step 2 — include valid values, formats, and domain contextIf no relevant documentation is found, note this and write the best descriptions you can from the code. Flag to the user that adding docs would improve the AI agent experience.
Design the Zod input schema following the security baseline:
.max(N) — ask what reasonable max is (default: 1000).min() and .max() — ask for valid range.max(N) — ask for max items (default: 100).describe("clear description for AI consumption").default() for optional fields with sensible defaultsz.enum() instead of free-form strings when values are known.optional() for truly optional fieldsShow the user the schema before generating code:
z.object({
query: z.string().min(1).max(200).describe("Search term"),
limit: z.number().int().min(1).max(100).default(20).describe("Max results"),
})
If the tool needs external services:
src/index.ts for this service.provide({
key: "serviceName",
factory: async () => initializeService(process.env.SERVICE_URL!),
dispose: async (svc) => svc.close(),
})
Create src/tools/<tool-name>.ts with:
import { z } from "zod";
import type { CallToolResult } from "@modelcontextprotocol/server";
export const <toolName>Schema = z.object({
// ... designed schema from Step 2
});
export async function <toolName>Handler(
args: z.infer<typeof <toolName>Schema>,
ctx: { mcpReq: { log: (level: string, data: string) => Promise<void> } }
): Promise<CallToolResult> {
await ctx.mcpReq.log("info", "<tool-name> called");
try {
// Implementation
const result = /* ... */;
return {
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
};
} catch (err) {
await ctx.mcpReq.log("error", `<tool-name> failed: ${err instanceof Error ? err.message : String(err)}`);
return {
content: [{ type: "text", text: "Failed to <action>. Please try again." }],
isError: true,
};
}
}
Update src/index.ts to import and register:
import { <toolName>Schema, <toolName>Handler } from "./tools/<tool-name>.js";
server.registerTool(
"<tool-name>",
{
description: "<description for AI consumption>",
inputSchema: <toolName>Schema,
},
<toolName>Handler
);
Create tests/tools/<tool-name>.test.ts:
import { describe, it, expect } from "vitest";
import { <toolName>Schema, <toolName>Handler } from "../src/tools/<tool-name>.js";
const mockCtx = { mcpReq: { log: async () => {} } };
describe("<tool-name>", () => {
it("accepts valid input", () => {
expect(<toolName>Schema.safeParse({ /* valid input */ }).success).toBe(true);
});
it("rejects missing required fields", () => {
expect(<toolName>Schema.safeParse({}).success).toBe(false);
});
it("returns expected result", async () => {
const result = await <toolName>Handler({ /* valid input */ }, mockCtx);
expect(result.content.length).toBeGreaterThan(0);
expect(result.isError).toBeFalsy();
});
});
Run the security checklist from agents/security.md on the new tool:
Fix any issues found before presenting the result.
npm run typecheck to verify compilationnpm test to verify all tests passTell the user what was created:
Added tool
<tool-name>:
- Handler:
src/tools/<tool-name>.ts- Tests:
tests/tools/<tool-name>.test.ts- Registered in
src/index.tsThe tool has N input parameters, validates all inputs, and has tests for happy path, validation, and edge cases.
npx claudepluginhub randyquaye/forge-mcp --plugin forge-mcpGuides building MCP servers in TypeScript from research to evaluation. Covers design principles, SDK usage, and hosting patterns.
Interactively adds a new tool to an existing FastMCP server by prompting for name, Zod parameters, return type, features like logging and streaming, then generates and integrates the code.
Scaffolds new MCP tool definitions for a TypeScript MCP server project. Use when adding new server capabilities or implementing tool endpoints.