NitroStack Logo
/python
/sdk
/tools

Tools

Agent skill: nitrostack-python-tools-resources-prompts

Decorate async methods on an @injectable class listed in the module’s controllers. Signature is (self, input: Model, context: ExecutionContext). Use Pydantic, not Zod.

Python
from nitrostack import injectable, tool, widget, ExecutionContext
from pydantic import BaseModel, Field
from typing import Literal

class CalculateInput(BaseModel):
    operation: Literal["add", "subtract", "multiply", "divide"] = Field(description="The operation to perform")
    a: float = Field(description="First number")
    b: float = Field(description="Second number")

class CalculateOutput(BaseModel):
    result: float

@injectable()
class CalculatorTools:
    @tool(
        name="calculate",
        description="Perform basic arithmetic calculations",
        input_schema=CalculateInput,
        output_schema=CalculateOutput,
    )
    @widget("calculator-result")
    async def calculate(self, input: CalculateInput, context: ExecutionContext) -> dict:
        context.logger.info(f"{input.operation} {input.a} {input.b}")
        return {"result": input.a + input.b}

@tool keyword arguments

Required: name, description, input_schema.

Optional: title, output_schema, annotations (ToolAnnotations), task_support ("forbidden" | "optional" | "required"), visibility, examples (ToolExamples), invocation (ToolInvocation), metadata.

Stack @initial_tool (before or after @tool) to auto-invoke on client connect.

Inspector empty strings

Inspector often sends "" for unused optionals. Coerce with a Pydantic field_validator(..., mode="before") when needed.

Do not

  • Use TypeScript @Tool({ inputSchema: z.object(...) })
  • Call server.tool() manually
  • Instantiate services with SomeService() inside the controller — inject via deps

Next steps