# New MCP Tool

> Scaffold a new MCP tool with models, service method, and DI registration

- Skill: `refined-element/new-mcp-tool` (Agent Skill)
- Install (CLI): `npx skillmds@latest add refined-element/new-mcp-tool`
- Raw SKILL.md: https://api.skillmd.com/api/skills/refined-element/new-mcp-tool/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: refined-element (https://skillmd.com/u/refined-element)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/refined-element/new-mcp-tool

---


Create a new MCP tool following project conventions. Use $ARGUMENTS for the tool name and description.

## Steps

1. **Create tool class** in the appropriate tools directory
   - Static class with `[McpServerToolType]` attribute
   - Static method with `[McpServerTool(Name = "snake_case_name")]` attribute
   - Add `[Description("...")]` on EVERY parameter
   - Use flat parameters (no complex objects)
   - Nullable optional service injection for wallet services
   - Include `IsConfigured` check — return error result if required service not configured

2. **Add models** to the appropriate models file if needed
   - Request/response records

3. **Add service interface method** in the service interface if the tool needs business logic beyond direct API calls

4. **Implement service method** in the implementation class

5. **Update DI registration** in `Program.cs` if new services are needed

6. **Write tests** following existing test patterns

## Patterns to Follow

```csharp
[McpServerToolType]
public static class MyNewTool
{
    [McpServerTool(Name = "my_new_tool")]
    [Description("What this tool does")]
    public static async Task<string> Execute(
        [Description("Parameter description")] string requiredParam,
        [Description("Optional parameter")] string? optionalParam = null,
        IMyService? myService = null)
    {
        if (myService is null || !myService.IsConfigured)
            return "Error: MyService is not configured. Set MY_ENV_VAR environment variable.";

        // Implementation
        return JsonSerializer.Serialize(result, new JsonSerializerOptions { WriteIndented = true });
    }
}
```

## Key Conventions
- Tool name: `snake_case` (e.g., `get_btc_price`, `check_wallet_balance`)
- Class name: PascalCase + "Tool" suffix
- Return JSON-serialized results for structured data
- Use `[Description]` on every parameter — MCP clients use these for documentation
- Wallet priority: LND > NWC > Strike > OpenNode
- L402 requires preimage — only works with LND, Strike, CoinOS NWC, CLINK NWC, Alby Hub NWC

## Free vs Paid

**When you add a tool, update the inventory guard tests — they are the single source of truth for the advertised tool count, and they fail until the code and the declared lists match:**
- `FREE_TOOLS` in `python/lightning-enable-mcp/tests/test_server.py` and `FreeTools` in `dotnet/tests/LightningEnable.Mcp.Tests/ToolInventoryTests.cs` — tools that work with just a wallet (no license).
- `API_KEY_TOOLS` / `ApiKeyTools` in the same files — tools that require an Agentic Commerce subscription + `LIGHTNING_ENABLE_API_KEY` (e.g. the producer tools `create_l402_challenge`, `verify_l402_payment`). Add license-check logic in the tool itself if it should be paid.

Public docs no longer hard-code the count (except the MCP Complete Guide's self-counting table), so there is nothing else to bump.

Suggested follow-up: `/mcp-publish-prep` when ready to publish

