Skip to main content
Endpoint Provider Registry lets you add custom server-side endpoint providers (recipe, agents-api, MCP, tools-MCP, A2A, A2U, or your own) to PraisonAI through entry points — no fork required.

Quick Start

1

Use a built-in provider

Minimal usage with a built-in provider:
from praisonai.endpoints.registry import get_provider

provider = get_provider("recipe", base_url="http://localhost:8765")
2

Register at runtime

Register a custom provider without creating a pip package:
from praisonai.endpoints.registry import register_provider
from praisonai.endpoints.providers.base import BaseProvider

class MyCustomProvider(BaseProvider):
    def __init__(self, base_url, api_key=None, **kwargs):
        self.base_url = base_url
        self.api_key = api_key

register_provider("my-custom", MyCustomProvider)
3

Distribute as a pip plugin

The recommended approach for distributable packages:
# pyproject.toml of your package
[project.entry-points."praisonai.endpoint_providers"]
my-custom = "mypkg.endpoints:MyCustomProvider"
pip install my-praisonai-endpoint
# Now anyone with your package installed gets:
from praisonai.endpoints.registry import get_provider
provider = get_provider("my-custom", base_url="http://localhost:8765")

How It Works

The registry is thread-safe and loads plugins lazily. Built-ins are discovered on first access, entry points are loaded when needed, and aliases are case-insensitive. The singleton registry is obtained via get_default_registry().

Configuration / API

Functions

Function / MethodSignatureDescription
register_provider(type, cls)(str, Type[BaseProvider]) -> NoneBackwards-compat module function; delegates to get_default_registry().register(...)
get_provider(type, base_url, api_key, **kw)(str, str, Optional[str], **Any) -> Optional[BaseProvider]Resolve + instantiate; returns None for unknown type; raises if loader fails
list_provider_types()() -> List[str]List registered + entry-point + built-in types
get_provider_class(type)(str) -> Optional[Type[BaseProvider]]Returns the class without instantiating
get_default_registry()() -> ProviderRegistryThread-safe singleton accessor

ProviderRegistry Class

MethodSignatureDescription
ProviderRegistry.get(type, base_url, api_key, **kw)identical to get_providerOOP-style interface
ProviderRegistry.list_types()() -> List[str]Back-compat alias for list_names()
ProviderRegistry.get_class(type)(str) -> Optional[Type]Back-compat alias for resolve()

Built-in Provider Types

TypeLoaded FromPurpose
recipeendpoints/providers/recipe.pyRecipe runner endpoint
agents-apiendpoints/providers/agents_api.pyOpenAI Agents-API compatible endpoint
mcpendpoints/providers/mcp.pyMCP server endpoint
tools-mcpendpoints/providers/tools_mcp.pyMCP tools-only endpoint
a2aendpoints/providers/a2a.pyA2A protocol endpoint
a2uendpoints/providers/a2u.pyA2U protocol endpoint

Common Patterns

Last-write-wins behavior lets you replace built-in providers:
from praisonai.endpoints.registry import register_provider
from praisonai.endpoints.providers.base import BaseProvider

class MyRecipeProvider(BaseProvider):
    def __init__(self, base_url, api_key=None, **kwargs):
        # Custom implementation
        pass

# Override built-in recipe provider
register_provider("recipe", MyRecipeProvider)
Use the underlying PluginRegistry for alias support:
from praisonai.endpoints.registry import get_default_registry

registry = get_default_registry()
registry.register_lazy("my-provider", lambda: MyProvider, aliases=["mp", "custom"])
Instantiate ProviderRegistry directly for isolation:
from praisonai.endpoints.registry import ProviderRegistry

# Tenant-specific registry
tenant_registry = ProviderRegistry()
tenant_registry.register("custom", TenantProvider)

Best Practices

Never import your provider class at module top-level — defeats lazy loading and breaks the no-heavy-deps-at-import-time guarantee:
# Good - lazy loader
def _load_my_provider():
    from .heavy_dependency import MyProvider
    return MyProvider

# Bad - top-level import
from .heavy_dependency import MyProvider  # Loaded immediately!
Required for type compatibility and consistent API:
from praisonai.endpoints.providers.base import BaseProvider

class MyProvider(BaseProvider):
    def __init__(self, base_url, api_key=None, **kwargs):
        super().__init__(base_url, api_key, **kwargs)
get_provider("unknown") returns None, but import failures propagate:
provider = get_provider("unknown")
if provider is None:
    print("Provider type not registered")
    
try:
    provider = get_provider("registered-but-missing-deps")
except ValueError as e:
    print(f"Provider exists but dependencies missing: {e}")
Use pyproject.toml entry points instead of register_provider() calls:
# Preferred - discoverable via pip install
[project.entry-points."praisonai.endpoint_providers"]
my-provider = "my_package.providers:MyProvider"

# Avoid - requires explicit registration
# register_provider("my-provider", MyProvider)

Integration Registry

The sibling plugin registry for CLI tools / managed agents

Framework Adapter Plugins

Third sibling plugin registry, for framework adapters