> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tai42.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Author a connector

> Build an OAuth connector plugin.

Author an OAuth connector plugin — a pure descriptor the connector engine drives.

A connector provider is a pure-data plugin. It declares one `ProviderDescriptor` — the OAuth endpoints, the per-sub-service MCP servers, and the environment-variable names that hold the client credentials — and registers it through the `tai42_app` handle. It carries no OAuth, probe, or launch code: the connector engine drives all of that generically from the descriptor. It depends on `tai42-contract` only and never imports the skeleton.

## Build the descriptor

Build a `ProviderDescriptor` naming the provider, its OAuth endpoints, the client-credential env vars, and one `SubServiceDescriptor` per sub-service. Each sub-service is a pkg-launched stdio MCP server named by its `entry_point`; the engine synthesizes the launch command from the provider's `pkg_manager`.

```python examples/connector/weather_provider.py theme={null}
"""A minimal fictional OAuth connector: a ``weather`` provider.

A connector provider is pure data. It declares one ``ProviderDescriptor`` — the
OAuth endpoints, the per-sub-service MCP servers, and the environment-variable
names that hold the client credentials — and registers it through the ``tai42_app``
handle at import. It carries no OAuth, probe, or launch code: the connector
engine drives all of that generically from the descriptor.
"""

from tai42_contract.app import tai42_app
from tai42_contract.connectors.providers import (
    OAuthEndpoints,
    ProviderDescriptor,
    SubServiceDescriptor,
)


def build_descriptor() -> ProviderDescriptor:
    return ProviderDescriptor(
        id="weather",
        kind="oauth",
        origin="system",
        category="productivity",
        display_name="Weather",
        description="Connect forecasts and severe-weather alerts.",
        icon_url="/static/connector-icons/weather.svg",
        oauth=OAuthEndpoints(
            authorize="https://auth.example-weather.test/oauth/authorize",
            token="https://auth.example-weather.test/oauth/token",
            revoke="https://auth.example-weather.test/oauth/revoke",
        ),
        client_id_env="WEATHER_CLIENT_ID",
        client_secret_env="WEATHER_CLIENT_SECRET",
        pkg_manager="uvx",
        sub_services={
            "forecast": SubServiceDescriptor(
                id="forecast",
                display_name="Forecast",
                description="Read daily and hourly forecasts.",
                scopes=["openid", "forecast.read"],
                entry_point="example-weather-mcp-forecast",
            ),
        },
        # Authorize-URL parameters this provider requires. The client credentials
        # are named, never stored: the ``*_env`` fields hold env-var names the
        # engine resolves from the process environment at connect time.
        extra_authorize_params={"audience": "https://api.example-weather.test"},
    )


# Manifest-load registration: importing this module registers the provider. A
# connector ships pure data, so this is a plain call, not a decorator.
tai42_app.connectors.register_connector(build_descriptor())
```

The client credentials are named, never stored: `client_id_env` / `client_secret_env` hold the environment-variable names, which the engine resolves from the process environment at connect time. Use `extra_authorize_params` for authorize-URL parameters a provider requires — anything the provider's OAuth server expects beyond the standard set.

## Register on import

Register the descriptor through the handle at module import, as the last line of the example above shows. A connector ships pure data, so this is a plain call — `tai42_app.connectors.register_connector(build_descriptor())` — not a decorator. Importing the module registers the provider.

## Package layout

* Ship each provider in its own package and repository.
* Depend on `tai42-contract` only; a clone needs nothing private.
* Document the OAuth app the operator must register and the two credential env vars in your repository's README — that impl-specific setup lives in your repo, not on this site.

The host loads the provider by naming the module under `lifecycle_modules` — see [Connect an OAuth provider](/guides/connect-an-oauth-provider).

## Shipped implementations

* [`tai42-connector-google`](https://github.com/tai42ai/tai-connector-google) — Gmail, Calendar, Drive.
* [`tai42-connector-atlassian`](https://github.com/tai42ai/tai-connector-atlassian) — Jira, Confluence, Compass.

## See also

* [Connectors](/concepts/connectors) — the connector model and the engine that drives it.
* [Connect an OAuth provider](/guides/connect-an-oauth-provider) — using a connector.
* [Python SDK reference](/reference/python-sdk) — `ProviderDescriptor` and the `tai42_app.connectors` surface.
* [Ecosystem catalog](/reference/catalog) — every shipped connector.
