airbyte_ops_mcp.mcp.prerelease
MCP tools for triggering connector pre-release workflows.
This module provides MCP tools for triggering the publish-connectors-prerelease workflow in the airbytehq/airbyte repository (for OSS connectors) or the publish_enterprise_connectors workflow in airbytehq/airbyte-enterprise (for enterprise connectors) via GitHub's workflow dispatch API.
MCP reference
MCP primitives registered by the prerelease module of the airbyte-internal-ops server: 1 tool(s), 0 prompt(s), 0 resource(s).
Tools (1)
publish_connector_to_airbyte_registry
Hints: open-world
Publish a connector to the Airbyte registry.
Currently only supports pre-release publishing. This tool triggers the publish-connectors-prerelease workflow in the airbytehq/airbyte repository (for OSS connectors) or the publish_enterprise_connectors workflow in airbytehq/airbyte-enterprise (for enterprise connectors), which publishes a pre-release version of the specified connector from the PR branch.
Pre-release versions are tagged with the format: {version}-preview.{7-char-git-sha} These versions are available for version pinning via the scoped_configuration API.
Requires GITHUB_CONNECTOR_PUBLISHING_PAT or GITHUB_TOKEN environment variable with 'actions:write' permission.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
connector_name |
string |
yes | — | The connector name to publish (e.g., 'source-github', 'destination-postgres') |
pr_number |
integer |
yes | — | The pull request number containing the connector changes |
repo |
enum("airbyte", "airbyte-enterprise") |
no | "airbyte" |
Repository where the connector PR is located. Use 'airbyte' for OSS connectors (default) or 'airbyte-enterprise' for enterprise connectors. |
prerelease |
boolean |
no | true |
Must be True. Only prerelease publishing is supported at this time. |
Show input JSON schema
{
"additionalProperties": false,
"properties": {
"connector_name": {
"description": "The connector name to publish (e.g., 'source-github', 'destination-postgres')",
"type": "string"
},
"pr_number": {
"description": "The pull request number containing the connector changes",
"type": "integer"
},
"repo": {
"description": "Repository where the connector PR is located. Use 'airbyte' for OSS connectors (default) or 'airbyte-enterprise' for enterprise connectors.",
"enum": [
"airbyte",
"airbyte-enterprise"
],
"type": "string",
"default": "airbyte"
},
"prerelease": {
"const": true,
"default": true,
"description": "Must be True. Only prerelease publishing is supported at this time.",
"type": "boolean"
}
},
"required": [
"connector_name",
"pr_number"
],
"type": "object"
}
Show output JSON schema
{
"description": "Response model for publish_connector_to_airbyte_registry MCP tool.",
"properties": {
"success": {
"type": "boolean"
},
"message": {
"type": "string"
},
"workflow_url": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null
},
"connector_name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null
},
"pr_number": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null
},
"docker_image": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null
},
"docker_image_tag": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null
}
},
"required": [
"success",
"message"
],
"type": "object"
}
1# Copyright (c) 2025 Airbyte, Inc., all rights reserved. 2"""MCP tools for triggering connector pre-release workflows. 3 4This module provides MCP tools for triggering the publish-connectors-prerelease 5workflow in the airbytehq/airbyte repository (for OSS connectors) or the 6publish_enterprise_connectors workflow in airbytehq/airbyte-enterprise 7(for enterprise connectors) via GitHub's workflow dispatch API. 8 9## MCP reference 10 11.. include:: ../../../docs/mcp-generated/prerelease.md 12 :start-line: 2 13""" 14 15from __future__ import annotations 16 17__all__: list[str] = [] 18 19import base64 20from enum import StrEnum 21from typing import Annotated, Literal 22 23import requests 24import yaml 25from fastmcp import FastMCP 26from fastmcp_extensions import mcp_tool, register_mcp_tools 27from pydantic import BaseModel, Field 28 29from airbyte_ops_mcp.airbyte_repo.bump_version import strip_prerelease_suffix 30from airbyte_ops_mcp.github_actions import trigger_workflow_dispatch 31from airbyte_ops_mcp.github_api import ( 32 GITHUB_API_BASE, 33 get_pr_head_ref, 34 resolve_ci_trigger_github_token, 35) 36 37 38class ConnectorRepo(StrEnum): 39 """Repository where connector code is located.""" 40 41 AIRBYTE = "airbyte" 42 AIRBYTE_ENTERPRISE = "airbyte-enterprise" 43 44 45DEFAULT_REPO_OWNER = "airbytehq" 46DEFAULT_REPO_NAME = ConnectorRepo.AIRBYTE 47DEFAULT_BRANCH = "master" 48PRERELEASE_WORKFLOW_FILE = "publish-connectors-prerelease-command.yml" 49CONNECTOR_PATH_PREFIX = "airbyte-integrations/connectors" 50 51# Enterprise repository constants 52ENTERPRISE_REPO_NAME = ConnectorRepo.AIRBYTE_ENTERPRISE 53ENTERPRISE_DEFAULT_BRANCH = "main" 54ENTERPRISE_PRERELEASE_WORKFLOW_FILE = "publish_enterprise_connectors.yml" 55 56# Token env vars for prerelease publishing (in order of preference) 57PRERELEASE_TOKEN_ENV_VARS = [ 58 "GITHUB_CONNECTOR_PUBLISHING_PAT", 59 "GITHUB_CI_WORKFLOW_TRIGGER_PAT", 60 "GITHUB_TOKEN", 61] 62 63# ============================================================================= 64# Pre-release Version Tag Constants 65# ============================================================================= 66 67PRERELEASE_TAG_PREFIX = "preview" 68"""The prefix used for pre-release version tags (e.g., '1.2.3-preview.abcde12').""" 69 70PRERELEASE_SHA_LENGTH = 7 71"""The number of characters from the git SHA to include in pre-release tags.""" 72 73 74def compute_prerelease_docker_image_tag(base_version: str, sha: str) -> str: 75 """Compute the pre-release docker image tag. 76 77 This is the SINGLE SOURCE OF TRUTH for pre-release version format. 78 All other code should receive this value as a parameter, not recompute it. 79 80 The format is: {base_version}-preview.{short_sha} 81 82 Where: 83 - base_version: The base version from metadata.yaml (e.g., "1.2.3"), 84 which may already contain a pre-release suffix (e.g., "2.23.16-rc.1"). 85 Any existing pre-release suffix is stripped before applying the preview tag. 86 - short_sha: The first 7 characters of the git commit SHA 87 88 Examples: 89 >>> compute_prerelease_docker_image_tag("1.2.3", "abcdef1234567890") 90 '1.2.3-preview.abcdef1' 91 >>> compute_prerelease_docker_image_tag("0.1.0", "1234567") 92 '0.1.0-preview.1234567' 93 >>> compute_prerelease_docker_image_tag("2.23.16-rc.1", "abcdef1234567890") 94 '2.23.16-preview.abcdef1' 95 96 Args: 97 base_version: The base version from metadata.yaml (e.g., "1.2.3" or "2.23.16-rc.1") 98 sha: The full git commit SHA (or at least 7 characters) 99 100 Returns: 101 Pre-release version tag (e.g., "1.2.3-preview.abcde12") 102 """ 103 short_sha = sha[:PRERELEASE_SHA_LENGTH] 104 clean_version = strip_prerelease_suffix(base_version) 105 return f"{clean_version}-{PRERELEASE_TAG_PREFIX}.{short_sha}" 106 107 108class PrereleaseWorkflowResult(BaseModel): 109 """Response model for publish_connector_to_airbyte_registry MCP tool.""" 110 111 success: bool 112 message: str 113 workflow_url: str | None = None 114 connector_name: str | None = None 115 pr_number: int | None = None 116 docker_image: str | None = None 117 docker_image_tag: str | None = None 118 119 120def _get_connector_metadata( 121 owner: str, 122 repo: str, 123 connector_name: str, 124 ref: str, 125 token: str, 126) -> dict | None: 127 """Fetch and parse connector metadata.yaml from the repository. 128 129 Args: 130 owner: Repository owner (e.g., "airbytehq") 131 repo: Repository name (e.g., "airbyte") 132 connector_name: Connector name (e.g., "source-github") 133 ref: Git ref to fetch from (branch name or SHA) 134 token: GitHub API token 135 136 Returns: 137 Parsed metadata dictionary, or None if not found. 138 """ 139 metadata_path = f"{CONNECTOR_PATH_PREFIX}/{connector_name}/metadata.yaml" 140 url = f"{GITHUB_API_BASE}/repos/{owner}/{repo}/contents/{metadata_path}" 141 headers = { 142 "Authorization": f"Bearer {token}", 143 "Accept": "application/vnd.github+json", 144 "X-GitHub-Api-Version": "2022-11-28", 145 } 146 params = {"ref": ref} 147 148 response = requests.get(url, headers=headers, params=params, timeout=30) 149 150 # Guard: Return None if metadata file not found 151 if response.status_code == 404: 152 return None 153 154 response.raise_for_status() 155 156 content_data = response.json() 157 158 # Guard: Return None if content is not base64 encoded 159 if content_data.get("encoding") != "base64": 160 return None 161 162 content = base64.b64decode(content_data["content"]).decode("utf-8") 163 return yaml.safe_load(content) 164 165 166@mcp_tool( 167 read_only=False, 168 destructive=False, 169 idempotent=False, 170 open_world=True, 171) 172def publish_connector_to_airbyte_registry( 173 connector_name: Annotated[ 174 str, 175 Field( 176 description="The connector name to publish (e.g., 'source-github', 'destination-postgres')" 177 ), 178 ], 179 pr_number: Annotated[ 180 int, 181 Field(description="The pull request number containing the connector changes"), 182 ], 183 repo: Annotated[ 184 ConnectorRepo, 185 Field( 186 default=ConnectorRepo.AIRBYTE, 187 description="Repository where the connector PR is located. " 188 "Use 'airbyte' for OSS connectors (default) or 'airbyte-enterprise' for enterprise connectors.", 189 ), 190 ], 191 prerelease: Annotated[ 192 Literal[True], 193 Field( 194 default=True, 195 description="Must be True. Only prerelease publishing is supported at this time.", 196 ), 197 ], 198) -> PrereleaseWorkflowResult: 199 """Publish a connector to the Airbyte registry. 200 201 Currently only supports pre-release publishing. This tool triggers the 202 publish-connectors-prerelease workflow in the airbytehq/airbyte repository 203 (for OSS connectors) or the publish_enterprise_connectors workflow in 204 airbytehq/airbyte-enterprise (for enterprise connectors), which publishes 205 a pre-release version of the specified connector from the PR branch. 206 207 Pre-release versions are tagged with the format: {version}-preview.{7-char-git-sha} 208 These versions are available for version pinning via the scoped_configuration API. 209 210 Requires GITHUB_CONNECTOR_PUBLISHING_PAT or GITHUB_TOKEN environment variable 211 with 'actions:write' permission. 212 """ 213 # Guard: Only prerelease publishing is supported 214 if prerelease is not True: 215 raise NotImplementedError( 216 "Non-prerelease publishing is not implemented yet. Set prerelease=True." 217 ) 218 219 # Guard: Check for required token 220 token = resolve_ci_trigger_github_token(PRERELEASE_TOKEN_ENV_VARS) 221 222 # Determine repo-specific settings 223 is_enterprise = repo == ConnectorRepo.AIRBYTE_ENTERPRISE 224 target_repo_name = ENTERPRISE_REPO_NAME if is_enterprise else DEFAULT_REPO_NAME 225 target_branch = ENTERPRISE_DEFAULT_BRANCH if is_enterprise else DEFAULT_BRANCH 226 target_workflow = ( 227 ENTERPRISE_PRERELEASE_WORKFLOW_FILE 228 if is_enterprise 229 else PRERELEASE_WORKFLOW_FILE 230 ) 231 232 # Get the PR's head SHA for computing the docker image tag 233 # Note: We no longer pass gitref to the workflow - it derives the ref from PR number 234 head_info = get_pr_head_ref(DEFAULT_REPO_OWNER, target_repo_name, pr_number, token) 235 236 # Prepare workflow inputs 237 workflow_inputs = { 238 "repo": f"{DEFAULT_REPO_OWNER}/{target_repo_name}", 239 "pr": str(pr_number), 240 "connector": connector_name, 241 } 242 243 # Trigger the workflow on the default branch 244 # The workflow will checkout the PR branch via inputs.gitref 245 dispatch_result = trigger_workflow_dispatch( 246 owner=DEFAULT_REPO_OWNER, 247 repo=target_repo_name, 248 workflow_file=target_workflow, 249 ref=target_branch, 250 inputs=workflow_inputs, 251 token=token, 252 find_run=True, 253 ) 254 # Use the specific run URL if found, otherwise fall back to the workflow URL 255 workflow_url = dispatch_result.run_url or dispatch_result.workflow_url 256 257 # Try to compute docker_image and docker_image_tag from connector metadata 258 docker_image: str | None = None 259 docker_image_tag: str | None = None 260 metadata = _get_connector_metadata( 261 DEFAULT_REPO_OWNER, 262 target_repo_name, 263 connector_name, 264 head_info.sha, 265 token, 266 ) 267 if metadata and "data" in metadata: 268 data = metadata["data"] 269 docker_image = data.get("dockerRepository") 270 base_version = data.get("dockerImageTag") 271 if base_version: 272 docker_image_tag = compute_prerelease_docker_image_tag( 273 base_version, head_info.sha 274 ) 275 276 repo_info = f" from {repo}" if is_enterprise else "" 277 return PrereleaseWorkflowResult( 278 success=True, 279 message=f"Successfully triggered pre-release workflow for {connector_name}{repo_info} from PR #{pr_number}", 280 workflow_url=workflow_url, 281 connector_name=connector_name, 282 pr_number=pr_number, 283 docker_image=docker_image, 284 docker_image_tag=docker_image_tag, 285 ) 286 287 288def register_prerelease_tools(app: FastMCP) -> None: 289 """Register pre-release workflow tools with the FastMCP app. 290 291 Args: 292 app: FastMCP application instance 293 """ 294 register_mcp_tools(app, mcp_module=__name__)