Skip to main content

ftl-sdk (Python)

Python SDK for building Model Context Protocol (MCP) tools that compile to WebAssembly.

PyPI Version Python Versions License GitHub Actions

Installation

Latest Stable Version

pip install ftl-sdk

Specific Version

pip install ftl-sdk==0.1.0

Development Version

pip install git+https://github.com/fastertools/ftl-cli.git#subdirectory=sdk/python

From TestPyPI (Pre-releases)

pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ ftl-sdk

Overview

This SDK provides:

  • Decorator-based API for easy tool creation
  • Automatic JSON Schema generation from type hints
  • Support for both sync and async functions
  • Automatic return value conversion to MCP format
  • Zero-dependency implementation (only requires spin-sdk)
  • Full compatibility with Spin WebAssembly components
  • Seamless deployment to Fermyon Cloud

Requirements

  • Python 3.10 or later
  • componentize-py for building WebAssembly components
  • spin-sdk for Spin runtime integration

Quick Start

1. Create a new Python tool

from ftl_sdk import FTL

# Create FTL application instance
ftl = FTL()

@ftl.tool
def echo(message: str) -> str:
    """Echo back the input."""
    return f"Echo: {message}"

# Create the Spin handler
Handler = ftl.create_handler()

3. Build and Deploy

# Create virtual environment
python3 -m venv venv
source venv/bin/activate

# Install dependencies
pip install componentize-py spin-sdk ftl-sdk

# Build
ftl build

# Deploy to Fermyon Cloud
ftl deploy

API Reference

Decorator-based API

FTL Class

ftl = FTL()

Creates an FTL application instance for registering tools.

@ftl.tool Decorator

@ftl.tool
def my_tool(param: str) -> str:
    """Tool description."""
    return result

# With custom name and annotations
@ftl.tool(name="custom_name", annotations={"priority": "high"})
def another_tool(data: dict) -> dict:
    return {"processed": data}

The decorator:

  • Automatically generates JSON Schema from type hints
  • Extracts docstring as tool description
  • Handles both sync and async functions
  • Validates output against return type annotation

ftl.create_handler()

Creates a Spin HTTP handler that:

  • Returns tool metadata on GET / requests
  • Routes to specific tools on POST /{tool_name} requests
  • Handles async/await for async tool functions
  • Automatically converts return values to MCP format

ToolResponse Helper Methods

# Simple text response
ToolResponse.text("Hello, world!")

# Error response
ToolResponse.error("Something went wrong")

# Response with structured content
ToolResponse.with_structured("Operation complete", {"result": 42})

ToolContent Helper Methods

# Text content
ToolContent.text("Some text", {"priority": 0.8})

# Image content
ToolContent.image(base64_data, "image/png")

# Audio content
ToolContent.audio(base64_data, "audio/wav")

# Resource reference
ToolContent.resource({"uri": "file:///example.txt"})

Type Guards

# Check content types
if is_text_content(content):
    print(content["text"])

Examples

Basic Tools

from ftl_sdk import FTL

ftl = FTL()

@ftl.tool
def echo(message: str) -> str:
    """Echo the input."""
    return f"Echo: {message}"

@ftl.tool
def reverse_text(text: str) -> str:
    """Reverse the input text."""
    return text[::-1]

@ftl.tool
def word_count(text: str) -> dict:
    """Count words in text."""
    count = len(text.split())
    return {"text": text, "word_count": count}

Handler = ftl.create_handler()

Async Tools

import asyncio
from ftl_sdk import FTL

ftl = FTL()

@ftl.tool
async def fetch_data(url: str) -> dict:
    """Fetch data from URL asynchronously."""
    # Simulate async HTTP request
    await asyncio.sleep(0.1)
    return {
        "url": url,
        "status": "success",
        "data": {"example": "data"}
    }

@ftl.tool
async def process_items(items: list[str]) -> dict:
    """Process items with async operations."""
    results = []
    for item in items:
        # Simulate async processing
        await asyncio.sleep(0.01)
        results.append(item.upper())
    
    return {
        "original": items,
        "processed": results,
        "count": len(results)
    }

# Mix sync and async tools
@ftl.tool
def sync_add(a: int, b: int) -> int:
    """Add two numbers synchronously."""
    return a + b

Handler = ftl.create_handler()

Error Handling

from ftl_sdk import FTL

ftl = FTL()

@ftl.tool
def divide(a: float, b: float) -> float:
    """Divide two numbers."""
    if b == 0:
        raise ValueError("Cannot divide by zero")
    return a / b

# Async error handling
@ftl.tool
async def validate_data(data: dict) -> dict:
    """Validate data asynchronously."""
    if "required_field" not in data:
        raise KeyError("Missing required field: required_field")
    
    # Simulate async validation
    await asyncio.sleep(0.05)
    
    if not isinstance(data["required_field"], str):
        raise TypeError("required_field must be a string")
    
    return {"status": "valid", "data": data}

Handler = ftl.create_handler()

The FTL framework automatically catches exceptions and returns them as error responses.

Development

Setting Up Development Environment

  1. Clone the repository:

    git clone https://github.com/fastertools/ftl-cli.git
    cd ftl-cli/sdk/python
    
  2. Create virtual environment:

    python -m venv venv
    source venv/bin/activate  # On Windows: venv\Scripts\activate
    
  3. Install development dependencies:

    make install-dev
    # or manually:
    pip install -e ".[dev]"
    pip install componentize-py
    

Running Tests

# Run all tests
make test

# Run tests with coverage
make test-cov

# Run specific test
pytest tests/test_ftl_sdk.py::test_tool_response_text

Code Quality

# Format code
make format

# Run linting
make lint

# Type checking
make type-check

# Run all quality checks
make quality

Available Make Commands

make help         # Show all available commands
make install      # Install SDK
make install-dev  # Install with dev dependencies
make format       # Format code with black
make lint         # Run linting with ruff
make type-check   # Run type checking with mypy
make test         # Run tests
make test-cov     # Run tests with coverage
make clean        # Clean build artifacts
make build        # Build distribution packages
make publish      # Publish to PyPI

Building to WebAssembly

Tools must be compiled to WebAssembly to run on Spin:

  1. Install dependencies:

    pip install componentize-py spin-sdk ftl-sdk
    
  2. Build with componentize-py:

    componentize-py -w spin-http componentize app -o app.wasm
    
  3. Or use FTL CLIs build command:

    ftl build
    

Best Practices

Type Hints

Always use type hints for better code clarity and IDE support:

from typing import Dict, Any
from ftl_sdk import ToolResponse

def my_handler(input_data: Dict[str, Any]) -> Dict[str, Any]:
    message: str = input_data.get("message", "")
    return ToolResponse.text(f"Received: {message}")

Error Handling

Handle errors gracefully and return informative error messages:

def safe_handler(input_data: Dict[str, Any]) -> Dict[str, Any]:
    try:
        # Validate required fields
        if "required_field" not in input_data:
            return ToolResponse.error("Missing required field: required_field")
        
        # Process input
        result = process_data(input_data["required_field"])
        return ToolResponse.text(f"Success: {result}")
        
    except ValueError as e:
        return ToolResponse.error(f"Invalid value: {e}")
    except Exception as e:
        return ToolResponse.error(f"Unexpected error: {e}")

Testing Your Tools

Write comprehensive tests for your tools:

import pytest
from your_module import your_handler

def test_handler_success():
    result = your_handler({"message": "test"})
    assert result["content"][0]["text"] == "Expected output"

def test_handler_missing_field():
    result = your_handler({})
    assert result.get("isError") is True
    assert "Missing required field" in result["content"][0]["text"]

Important Notes

  1. Python Version: Requires Python 3.10 or later. Python 3.11+ recommended.

  2. Zero Dependencies: This SDK has no external dependencies beyond spin-sdk, keeping the WASM bundle size minimal.

  3. Input Validation: The FTL gateway handles input validation against your JSON Schema. Your handler can assume inputs are valid.

  4. Virtual Environments: Always use a virtual environment to ensure consistent builds.

  5. WASM Size: Python WASM components are larger than TypeScript/Rust equivalents (~37MB), but this is acceptable for cloud deployment.

  6. Type Safety: Use type hints and mypy for better code quality and fewer runtime errors.

  7. Code Quality: The SDK includes development tools (black, ruff, mypy, pytest) to maintain high code quality standards.

Deployment

Deploy to FTL:

# Deploy with auto-generated name
ftl deploy

Development

Contributions are welcome! Please feel free to submit a Pull Request.

Setting Up Development Environment

# Clone the repository
git clone https://github.com/fastertools/ftl-cli.git
cd ftl-cli/sdk/python

# Create virtual environment
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

# Install development dependencies
pip install -e ".[dev]"
pip install tox

Running Tests

# Run tests for all Python versions
tox

# Run tests for specific Python version
tox -e py311

# Run linting and type checking
tox -e lint,type

# Run tests with coverage
tox -e py311 -- --cov-report=html

Code Quality

# Format code
black src tests

# Run linter
ruff check src tests

# Type checking
mypy src

Changelog

See CHANGELOG.md for a list of changes in each release.

License

Apache-2.0 - see LICENSE for details.

Metadata

Release files for ftl-sdk 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ftl-sdk 0.1.0
File Size Uploaded
ftl_sdk-0.1.0.tar.gz 22.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ftl-sdk 0.1.0
File Interpreter ABI Platform
ftl_sdk-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 36.2 kB

Release files / ftl_sdk-0.1.0.tar.gz

Download URL ftl_sdk-0.1.0.tar.gz
Size 22.0 kB
Tags Source
SHA-256 checksum
How to use checksums
beec6090e1cf5940be808ef8552458a679a17beb692f783977adbbec59c799a4
BLAKE2b-256 checksum
How to use checksums
a938de3cf931134c01d5dc4ff34890503faf2ad3d9c393a3fb82453dceca2f99
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.12.9

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 4, 2025.

Transparency log

Release files / ftl_sdk-0.1.0-py3-none-any.whl

Download URL ftl_sdk-0.1.0-py3-none-any.whl
Size 14.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
849d020e988542b17dc4007a83b3a491cc497d8b7b33ea0b0feeb97aff959670
BLAKE2b-256 checksum
How to use checksums
73ffdd6383c48ab71f043b3084c03eab6d8d8086183f59ea32e0d440b50782d8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.12.9

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 4, 2025.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page