Create a new MCP tool following project conventions. Use $ARGUMENTS for the tool name and description.
Steps
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
IsConfiguredcheck — return error result if required service not configured
- Static class with
Add models to the appropriate models file if needed
- Request/response records
Add service interface method in the service interface if the tool needs business logic beyond direct API calls
Implement service method in the implementation class
Update DI registration in
Program.csif new services are neededWrite tests following existing test patterns
Patterns to Follow
[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_TOOLSinpython/lightning-enable-mcp/tests/test_server.pyandFreeToolsindotnet/tests/LightningEnable.Mcp.Tests/ToolInventoryTests.cs— tools that work with just a wallet (no license).API_KEY_TOOLS/ApiKeyToolsin the same files — tools that require an Agentic Commerce subscription +LIGHTNING_ENABLE_API_KEY(e.g. the producer toolscreate_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