NitroStack Logo
/python
/quick start

Quick Start

Create and run a Python MCP server in a few minutes.

1. Scaffold

Bash
pip install nitrostack
nitrostack-py init my-server --template python-starter
cd my-server

Templates:

--templateWhat you get
python-starterCalculator + @widget("calculator-result")
python-pizzazPizza shops with list/map/shop widgets
python-oauthFlight booking + OAuth 2.1 + OAUTH_SETUP.md

Omit --template to pick interactively. --port / --widget override defaults 3000 / 3001.

2. Run in development

Bash
nitrostack-py dev

Hot-reloads main.py. Transport defaults to stdio unless you set MCP_TRANSPORT_TYPE.

For MCP Inspector over HTTP (stateless):

Bash
MCP_TRANSPORT_TYPE=http MCP_STATELESS=true nitrostack-py dev --port 3000

Connect Inspector to http://localhost:3000/mcp (no trailing slash). Turn Authentication off unless you are on the OAuth template.

3. Minimal server (without the CLI)

Python
import asyncio
from pydantic import BaseModel, Field
from nitrostack import (
    tool,
    injectable,
    module,
    McpApplicationFactory,
    ExecutionContext,
)

class AddInput(BaseModel):
    a: float = Field(description="First number")
    b: float = Field(description="Second number")

@injectable(deps=[])
class CalculatorService:
    def add(self, a: float, b: float) -> float:
        return a + b

@injectable(deps=[CalculatorService])
class CalculatorController:
    def __init__(self, service: CalculatorService):
        self.service = service

    @tool(name="add", description="Add two numbers together", input_schema=AddInput)
    async def add(self, input: AddInput, context: ExecutionContext) -> float:
        context.logger.info(f"Adding {input.a} and {input.b}")
        return self.service.add(input.a, input.b)

@module(name="calculator", controllers=[CalculatorController], providers=[CalculatorService])
class CalculatorModule:
    pass

@module(name="app", imports=[CalculatorModule])
class AppModule:
    pass

async def main():
    app = await McpApplicationFactory.create(AppModule)
    await app.start()

if __name__ == "__main__":
    asyncio.run(main())

Agent skill: nitrostack-python-tools-resources-prompts — Pydantic schemas, (self, input, context: ExecutionContext), optional @widget / @initial_tool.

4. Production

Bash
nitrostack-py start          # no reload; HTTP default in production
nitrostack-py pack           # wheel under dist/ (never packs .env)
nitrostack-py validate       # lint deps and @module refs

Next steps