airbyte_ops_mcp.mcp.connector_registry
MCP tools for the connector registry and monorepo catalog: registry reads/yank plus repo connector listing and version bumps.
MCP reference
MCP primitives registered by the connector_registry module of the airbyte-internal-ops server: 9 tool(s), 0 prompt(s), 0 resource(s).
Tools (9)
get_connector_registry_entry
Read a connector's metadata from the GCS registry.
Returns the full metadata.yaml content for a connector at the specified version. Requires GCS_CREDENTIALS environment variable to be set.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
connector_name |
string |
yes | — | The connector name (e.g., 'source-faker', 'destination-postgres') |
version |
string |
no | "latest" |
Version to read (e.g., 'latest', '1.2.3'). Defaults to 'latest'. |
Show input JSON schema
{
"additionalProperties": false,
"properties": {
"connector_name": {
"description": "The connector name (e.g., 'source-faker', 'destination-postgres')",
"type": "string"
},
"version": {
"default": "latest",
"description": "Version to read (e.g., 'latest', '1.2.3'). Defaults to 'latest'.",
"type": "string"
}
},
"required": [
"connector_name"
],
"type": "object"
}
Show output JSON schema
{
"description": "Result of reading a registry entry from GCS.\n\nThis model wraps the raw metadata dictionary with additional context.",
"properties": {
"connector_name": {
"description": "The connector technical name",
"type": "string"
},
"version": {
"description": "The version that was read",
"type": "string"
},
"bucket_name": {
"description": "The GCS bucket name",
"type": "string"
},
"gcs_path": {
"description": "The GCS path that was read",
"type": "string"
},
"metadata": {
"additionalProperties": true,
"description": "The raw metadata dictionary",
"type": "object"
}
},
"required": [
"connector_name",
"version",
"bucket_name",
"gcs_path",
"metadata"
],
"type": "object"
}
get_connector_registry_spec
Read a connector's spec from the GCS registry.
Returns the spec.json content for a connector at the specified version. Requires GCS_CREDENTIALS environment variable to be set.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
connector_name |
string |
yes | — | The connector name (e.g., 'source-faker', 'destination-postgres') |
version |
string |
no | "latest" |
Version to read (e.g., 'latest', '1.2.3'). Defaults to 'latest'. |
Show input JSON schema
{
"additionalProperties": false,
"properties": {
"connector_name": {
"description": "The connector name (e.g., 'source-faker', 'destination-postgres')",
"type": "string"
},
"version": {
"default": "latest",
"description": "Version to read (e.g., 'latest', '1.2.3'). Defaults to 'latest'.",
"type": "string"
}
},
"required": [
"connector_name"
],
"type": "object"
}
Show output JSON schema
{
"description": "Result of reading a connector spec from GCS.",
"properties": {
"connector_name": {
"description": "The connector technical name",
"type": "string"
},
"version": {
"description": "The version that was read",
"type": "string"
},
"bucket_name": {
"description": "The GCS bucket name",
"type": "string"
},
"gcs_path": {
"description": "The GCS path that was read",
"type": "string"
},
"spec": {
"additionalProperties": true,
"description": "The connector spec dictionary",
"type": "object"
}
},
"required": [
"connector_name",
"version",
"bucket_name",
"gcs_path",
"spec"
],
"type": "object"
}
get_connector_version_release
Read release attribution for one connector version.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
connector_name |
string |
yes | — | The connector name (e.g., 'source-faker', 'destination-postgres'). |
version |
string |
yes | — | The connector version to inspect (e.g., '7.2.1'). |
store |
string |
no | "coral:prod" |
Store target to read (e.g. 'coral:prod', 'coral:dev'). Defaults to 'coral:prod'. |
Show input JSON schema
{
"additionalProperties": false,
"properties": {
"connector_name": {
"description": "The connector name (e.g., 'source-faker', 'destination-postgres').",
"type": "string"
},
"version": {
"description": "The connector version to inspect (e.g., '7.2.1').",
"type": "string"
},
"store": {
"default": "coral:prod",
"description": "Store target to read (e.g. 'coral:prod', 'coral:dev'). Defaults to 'coral:prod'.",
"type": "string"
}
},
"required": [
"connector_name",
"version"
],
"type": "object"
}
Show output JSON schema
{
"description": "Result of resolving attribution for one connector version.",
"properties": {
"connector_name": {
"type": "string"
},
"version": {
"type": "string"
},
"status": {
"enum": [
"found",
"unattributed",
"not_found",
"error"
],
"type": "string"
},
"lookup_path": {
"enum": [
"index",
"metadata",
"changelog",
"none"
],
"type": "string"
},
"attribution": {
"anyOf": [
{
"description": "Attribution metadata for one published connector version.",
"properties": {
"pr_number": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null
},
"pr_url": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null
},
"pr_author_id": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null
},
"pr_author_login": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null
},
"pr_author_type": {
"default": "Unknown",
"enum": [
"User",
"Bot",
"Unknown"
],
"type": "string"
},
"pr_author_association": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null
},
"attributed_to": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null
},
"attributed_to_kind": {
"anyOf": [
{
"enum": [
"maintainer",
"bot",
"other"
],
"type": "string"
},
{
"type": "null"
}
],
"default": null
},
"pr_merged_by_login": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null
},
"pr_merged_by_type": {
"default": "Unknown",
"enum": [
"User",
"Bot",
"Unknown"
],
"type": "string"
},
"merge_commit_sha": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null
},
"merged_at": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"default": null
},
"released_at": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"default": null
},
"source": {
"enum": [
"publish",
"git-backfill",
"prerelease",
"changelog"
],
"type": "string"
}
},
"required": [
"source"
],
"type": "object"
},
{
"type": "null"
}
],
"default": null
},
"error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null
}
},
"required": [
"connector_name",
"version",
"status",
"lookup_path"
],
"type": "object"
}
get_connector_version_yank_detail
Read the active yank marker for a single connector version.
Returns yanked=True with the marker's yanked_at, reason, and
approval_url when the version currently has an active version-yank.yml
marker, or yanked=False with empty fields when it is not yanked.
Historical version-unyanked-*.yml audit markers are ignored.
Requires GCS_CREDENTIALS environment variable to be set.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
connector_name |
string |
yes | — | The connector name (e.g., 'source-faker', 'destination-postgres'). |
version |
string |
yes | — | Version to inspect (e.g., '1.2.3'). |
store |
string |
no | "coral:prod" |
Store target to read (e.g. 'coral:prod', 'coral:dev'). Defaults to 'coral:prod'. |
Show input JSON schema
{
"additionalProperties": false,
"properties": {
"connector_name": {
"description": "The connector name (e.g., 'source-faker', 'destination-postgres').",
"type": "string"
},
"version": {
"description": "Version to inspect (e.g., '1.2.3').",
"type": "string"
},
"store": {
"default": "coral:prod",
"description": "Store target to read (e.g. 'coral:prod', 'coral:dev'). Defaults to 'coral:prod'.",
"type": "string"
}
},
"required": [
"connector_name",
"version"
],
"type": "object"
}
Show output JSON schema
{
"description": "Active yank-marker detail for a single connector version.",
"properties": {
"connector_name": {
"description": "The connector technical name",
"type": "string"
},
"version": {
"description": "The version that was checked",
"type": "string"
},
"store": {
"description": "The store target that was read",
"type": "string"
},
"bucket_name": {
"description": "The resolved GCS bucket name",
"type": "string"
},
"yanked": {
"description": "True when an active `version-yank.yml` marker exists",
"type": "boolean"
},
"yanked_at": {
"description": "When the version was yanked, if recorded",
"type": "string"
},
"reason": {
"description": "Reason recorded in the yank marker, if any",
"type": "string"
},
"approval_url": {
"description": "Approval evidence URL, if recorded",
"type": "string"
}
},
"required": [
"connector_name",
"version",
"store",
"bucket_name",
"yanked",
"yanked_at",
"reason",
"approval_url"
],
"type": "object"
}
list_connector_version_releases
List release attribution for a connector's versions, newest first.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
connector_name |
string |
yes | — | The connector name (e.g., 'source-faker', 'destination-postgres'). |
limit |
integer |
no | 50 |
Maximum number of versions to return, newest first. |
with_metadata_fallback |
boolean |
no | false |
When True, read metadata for index entries without attribution. |
store |
string |
no | "coral:prod" |
Store target to read (e.g. 'coral:prod', 'coral:dev'). Defaults to 'coral:prod'. |
Show input JSON schema
{
"additionalProperties": false,
"properties": {
"connector_name": {
"description": "The connector name (e.g., 'source-faker', 'destination-postgres').",
"type": "string"
},
"limit": {
"default": 50,
"description": "Maximum number of versions to return, newest first.",
"type": "integer"
},
"with_metadata_fallback": {
"default": false,
"description": "When `True`, read metadata for index entries without attribution.",
"type": "boolean"
},
"store": {
"default": "coral:prod",
"description": "Store target to read (e.g. 'coral:prod', 'coral:dev'). Defaults to 'coral:prod'.",
"type": "string"
}
},
"required": [
"connector_name"
],
"type": "object"
}
Show output JSON schema
{
"description": "Attribution lookup results for one connector's versions.",
"properties": {
"connector_name": {
"type": "string"
},
"items": {
"items": {
"description": "Result of resolving attribution for one connector version.",
"properties": {
"connector_name": {
"type": "string"
},
"version": {
"type": "string"
},
"status": {
"enum": [
"found",
"unattributed",
"not_found",
"error"
],
"type": "string"
},
"lookup_path": {
"enum": [
"index",
"metadata",
"changelog",
"none"
],
"type": "string"
},
"attribution": {
"anyOf": [
{
"description": "Attribution metadata for one published connector version.",
"properties": {
"pr_number": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null
},
"pr_url": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null
},
"pr_author_id": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null
},
"pr_author_login": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null
},
"pr_author_type": {
"default": "Unknown",
"enum": [
"User",
"Bot",
"Unknown"
],
"type": "string"
},
"pr_author_association": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null
},
"attributed_to": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null
},
"attributed_to_kind": {
"anyOf": [
{
"enum": [
"maintainer",
"bot",
"other"
],
"type": "string"
},
{
"type": "null"
}
],
"default": null
},
"pr_merged_by_login": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null
},
"pr_merged_by_type": {
"default": "Unknown",
"enum": [
"User",
"Bot",
"Unknown"
],
"type": "string"
},
"merge_commit_sha": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null
},
"merged_at": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"default": null
},
"released_at": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"default": null
},
"source": {
"enum": [
"publish",
"git-backfill",
"prerelease",
"changelog"
],
"type": "string"
}
},
"required": [
"source"
],
"type": "object"
},
{
"type": "null"
}
],
"default": null
},
"error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null
}
},
"required": [
"connector_name",
"version",
"status",
"lookup_path"
],
"type": "object"
},
"type": "array"
},
"error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null
}
},
"required": [
"connector_name",
"items"
],
"type": "object"
}
list_connector_versions_in_registry
List all versions of a connector in the GCS registry.
Returns all published versions for a connector (excluding 'latest' and 'release_candidate'). Requires GCS_CREDENTIALS environment variable to be set.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
connector_name |
string |
yes | — | The connector name (e.g., 'source-faker', 'destination-postgres') |
Show input JSON schema
{
"additionalProperties": false,
"properties": {
"connector_name": {
"description": "The connector name (e.g., 'source-faker', 'destination-postgres')",
"type": "string"
}
},
"required": [
"connector_name"
],
"type": "object"
}
Show output JSON schema
{
"description": "Result of listing versions for a connector.",
"properties": {
"connector_name": {
"description": "The connector technical name",
"type": "string"
},
"bucket_name": {
"description": "The GCS bucket name",
"type": "string"
},
"version_count": {
"description": "Number of versions found",
"type": "integer"
},
"versions": {
"description": "List of version strings",
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"connector_name",
"bucket_name",
"version_count",
"versions"
],
"type": "object"
}
list_connectors_in_registry
List connectors in the production registry, with optional filtering.
Filters can be combined; name_contains is a case-insensitive substring
match on the connector name (leading/trailing whitespace is ignored). To
inspect a single known connector, prefer get_connector_registry_entry
(metadata) or list_connector_versions_in_registry (versions) instead.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
certified |
boolean |
no | false |
When True, return only certified connectors. Shorthand for support_level='certified'. |
support_level |
string |
no | "" |
Exact support level to match (e.g., certified, community, archived). Empty string means no filter. |
min_support_level |
string |
no | "" |
Minimum support level threshold (inclusive). Levels: archived < community < certified. Empty string means no filter. |
connector_type |
string |
no | "" |
Filter by connector type: source or destination. Empty string means no filter. |
language |
string |
no | "" |
Filter by implementation language (e.g., python, java, manifest-only). Empty string means no filter. |
name_contains |
string |
no | "" |
Case-insensitive substring to match against connector names (e.g., github). Empty string means no filter. |
Show input JSON schema
{
"additionalProperties": false,
"properties": {
"certified": {
"default": false,
"description": "When `True`, return only certified connectors. Shorthand for `support_level='certified'`.",
"type": "boolean"
},
"support_level": {
"default": "",
"description": "Exact support level to match (e.g., `certified`, `community`, `archived`). Empty string means no filter.",
"type": "string"
},
"min_support_level": {
"default": "",
"description": "Minimum support level threshold (inclusive). Levels: `archived` < `community` < `certified`. Empty string means no filter.",
"type": "string"
},
"connector_type": {
"default": "",
"description": "Filter by connector type: `source` or `destination`. Empty string means no filter.",
"type": "string"
},
"language": {
"default": "",
"description": "Filter by implementation language (e.g., `python`, `java`, `manifest-only`). Empty string means no filter.",
"type": "string"
},
"name_contains": {
"default": "",
"description": "Case-insensitive substring to match against connector names (e.g., `github`). Empty string means no filter.",
"type": "string"
}
},
"type": "object"
}
Show output JSON schema
{
"description": "Result of listing connectors in the registry.",
"properties": {
"bucket_name": {
"description": "The GCS bucket name",
"type": "string"
},
"connector_count": {
"description": "Number of connectors found",
"type": "integer"
},
"connectors": {
"description": "List of connector names",
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"bucket_name",
"connector_count",
"connectors"
],
"type": "object"
}
list_yanked_connector_versions
List every yanked connector version in a registry store.
Returns one entry per active version-yank.yml marker, sorted by connector
name then version, with each marker's yanked_at, reason, and
approval_url populated. Historical version-unyanked-*.yml audit markers
are ignored — only live markers count.
Requires GCS_CREDENTIALS environment variable to be set.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
store |
string |
no | "coral:prod" |
Store target to read (e.g. 'coral:prod', 'coral:dev'). Defaults to 'coral:prod'. |
Show input JSON schema
{
"additionalProperties": false,
"properties": {
"store": {
"default": "coral:prod",
"description": "Store target to read (e.g. 'coral:prod', 'coral:dev'). Defaults to 'coral:prod'.",
"type": "string"
}
},
"type": "object"
}
Show output JSON schema
{
"description": "Result of listing yanked connector versions in a registry store.",
"properties": {
"store": {
"description": "The store target that was read",
"type": "string"
},
"bucket_name": {
"description": "The resolved GCS bucket name",
"type": "string"
},
"count": {
"description": "Number of yanked versions found",
"type": "integer"
},
"yanked_versions": {
"description": "Yanked versions, sorted by connector name then version",
"items": {
"description": "A single yanked connector version discovered from its marker file.",
"properties": {
"connector_name": {
"description": "The connector technical name",
"type": "string"
},
"version": {
"description": "The yanked version tag",
"type": "string"
},
"yanked_at": {
"description": "When the version was yanked, if recorded",
"type": "string"
},
"reason": {
"description": "Reason recorded in the yank marker, if any",
"type": "string"
},
"approval_url": {
"description": "Approval evidence URL, if recorded",
"type": "string"
}
},
"required": [
"connector_name",
"version",
"yanked_at",
"reason",
"approval_url"
],
"type": "object"
},
"type": "array"
}
},
"required": [
"store",
"bucket_name",
"count",
"yanked_versions"
],
"type": "object"
}
yank_connector_version
Yank or unyank a connector version after Slack/HITL approval.
This MCP tool requires approval for all stores, including dev/test stores,
so the safety behavior is consistent and prod-impacting coral:prod
requests cannot dispatch without approval.
Without approval_comment_url, returns the exact approval request summary
and Slack message to send via escalate_to_human; no GitHub Actions
workflow is triggered. With an approved Slack record URL, validates the
approver and then triggers a workflow that marks the version as yanked
(or unyanked) and recompiles the registry to update indexes and latest
pointers.
Requires GITHUB_CI_WORKFLOW_TRIGGER_PAT or GITHUB_TOKEN environment variable with 'actions:write' permission.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
connector_name |
string |
yes | — | Connector name (e.g., 'source-faker', 'destination-postgres'). |
version |
string |
yes | — | Version to yank (e.g., '1.2.3'). |
store |
string |
yes | — | Store target (e.g., 'coral:dev', 'coral:prod'). |
reason |
string |
no | "" |
Reason for yanking this version. |
unyank |
boolean |
no | false |
Set to true to unyank (restore) the version instead of yanking it. |
approval_comment_url |
string | null |
no | null |
Slack approval record URL. Obtain this by calling escalate_to_human with approval_requested=True using the approval request details returned by this tool. The backend validates the approval record and resolves the approver's @airbyte.io email before dispatching the registry workflow. |
Show input JSON schema
{
"additionalProperties": false,
"properties": {
"connector_name": {
"description": "Connector name (e.g., 'source-faker', 'destination-postgres').",
"type": "string"
},
"version": {
"description": "Version to yank (e.g., '1.2.3').",
"type": "string"
},
"store": {
"description": "Store target (e.g., 'coral:dev', 'coral:prod').",
"type": "string"
},
"reason": {
"default": "",
"description": "Reason for yanking this version.",
"type": "string"
},
"unyank": {
"default": false,
"description": "Set to true to unyank (restore) the version instead of yanking it.",
"type": "boolean"
},
"approval_comment_url": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Slack approval record URL. Obtain this by calling `escalate_to_human` with `approval_requested=True` using the approval request details returned by this tool. The backend validates the approval record and resolves the approver's `@airbyte.io` email before dispatching the registry workflow."
}
},
"required": [
"connector_name",
"version",
"store"
],
"type": "object"
}
Show output JSON schema
{
"description": "Response from triggering a yank connector version workflow.",
"properties": {
"approval_required": {
"default": false,
"description": "Whether the operation still requires Slack/HITL approval before dispatch.",
"type": "boolean"
},
"message": {
"description": "Human-readable status message",
"type": "string"
},
"approval_request_summary": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Short approval summary to pass to `escalate_to_human` when approval is required."
},
"approval_request_message": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Detailed Slack message to pass to `escalate_to_human` when approval is required."
},
"approved_by": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Resolved `@airbyte.io` email for the Slack approver."
},
"workflow_url": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "URL to view the GitHub Actions workflow file"
},
"github_run_id": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null,
"description": "GitHub Actions workflow run ID (use with check_ci_workflow_status)"
},
"github_run_url": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Direct URL to the GitHub Actions workflow run"
}
},
"required": [
"message"
],
"type": "object"
}
1# Copyright (c) 2025 Airbyte, Inc., all rights reserved. 2"""MCP tools for the connector registry and monorepo catalog: registry reads/yank plus repo connector listing and version bumps. 3 4## MCP reference 5 6.. include:: ../../../docs/mcp-generated/connector_registry.md 7 :start-line: 2 8""" 9 10from __future__ import annotations 11 12__all__: list[str] = [] 13 14from typing import Annotated, Any, Literal 15 16from fastmcp import FastMCP 17from fastmcp_extensions import mcp_tool, register_mcp_tools 18from pydantic import BaseModel, Field 19 20from airbyte_ops_mcp.airbyte_repo.bump_version import bump_connector_version 21from airbyte_ops_mcp.airbyte_repo.list_connectors import list_connectors 22from airbyte_ops_mcp.airbyte_repo.utils import resolve_diff_range 23from airbyte_ops_mcp.approval_resolution import ( 24 ApprovalResolutionError, 25 resolve_admin_email_from_approval, 26) 27from airbyte_ops_mcp.github_actions import trigger_workflow_dispatch 28from airbyte_ops_mcp.github_api import resolve_ci_trigger_github_token 29from airbyte_ops_mcp.human_in_the_loop import APPROVAL_REQUEST_SUMMARY_MAX_LENGTH 30from airbyte_ops_mcp.registry import ( 31 PROD_METADATA_SERVICE_BUCKET_NAME, 32 ConnectorListResult, 33 RegistryEntryResult, 34 VersionListResult, 35 resolve_registry_store, 36) 37from airbyte_ops_mcp.registry._enums import ( 38 ConnectorLanguage, 39 ConnectorType, 40 SupportLevel, 41) 42from airbyte_ops_mcp.registry.operations import ( 43 get_registry_entry, 44 get_registry_spec, 45 list_connector_versions, 46 list_registry_connectors, 47 list_registry_connectors_filtered, 48) 49from airbyte_ops_mcp.registry.registry_store_base import get_registry 50from airbyte_ops_mcp.registry.release_attribution import ( 51 ReleaseAttributionListResult, 52 ReleaseAttributionLookupResult, 53 list_release_attribution, 54 lookup_release_attribution, 55) 56 57 58class RegistrySpecResult(BaseModel): 59 """Result of reading a connector spec from GCS.""" 60 61 connector_name: str = Field(description="The connector technical name") 62 version: str = Field(description="The version that was read") 63 bucket_name: str = Field(description="The GCS bucket name") 64 gcs_path: str = Field(description="The GCS path that was read") 65 spec: dict[str, Any] = Field(description="The connector spec dictionary") 66 67 68@mcp_tool( 69 read_only=True, 70 idempotent=True, 71 open_world=True, 72) 73def get_connector_registry_entry( 74 connector_name: Annotated[ 75 str, 76 "The connector name (e.g., 'source-faker', 'destination-postgres')", 77 ], 78 version: Annotated[ 79 str, 80 "Version to read (e.g., 'latest', '1.2.3'). Defaults to 'latest'.", 81 ] = "latest", 82) -> RegistryEntryResult: 83 """Read a connector's metadata from the GCS registry. 84 85 Returns the full metadata.yaml content for a connector at the specified version. 86 Requires GCS_CREDENTIALS environment variable to be set. 87 """ 88 bucket_name = PROD_METADATA_SERVICE_BUCKET_NAME 89 metadata = get_registry_entry( 90 connector_name=connector_name, 91 bucket_name=bucket_name, 92 version=version, 93 ) 94 gcs_path = f"metadata/airbyte/{connector_name}/{version}/metadata.yaml" 95 return RegistryEntryResult( 96 connector_name=connector_name, 97 version=version, 98 bucket_name=bucket_name, 99 gcs_path=gcs_path, 100 metadata=metadata, 101 ) 102 103 104@mcp_tool( 105 read_only=True, 106 idempotent=True, 107 open_world=True, 108) 109def get_connector_registry_spec( 110 connector_name: Annotated[ 111 str, 112 "The connector name (e.g., 'source-faker', 'destination-postgres')", 113 ], 114 version: Annotated[ 115 str, 116 "Version to read (e.g., 'latest', '1.2.3'). Defaults to 'latest'.", 117 ] = "latest", 118) -> RegistrySpecResult: 119 """Read a connector's spec from the GCS registry. 120 121 Returns the spec.json content for a connector at the specified version. 122 Requires GCS_CREDENTIALS environment variable to be set. 123 """ 124 bucket_name = PROD_METADATA_SERVICE_BUCKET_NAME 125 spec = get_registry_spec( 126 connector_name=connector_name, 127 bucket_name=bucket_name, 128 version=version, 129 ) 130 gcs_path = f"metadata/airbyte/{connector_name}/{version}/spec.json" 131 return RegistrySpecResult( 132 connector_name=connector_name, 133 version=version, 134 bucket_name=bucket_name, 135 gcs_path=gcs_path, 136 spec=spec, 137 ) 138 139 140@mcp_tool( 141 read_only=True, 142 idempotent=True, 143 open_world=True, 144) 145def list_connectors_in_registry( 146 certified: Annotated[ 147 bool, 148 "When `True`, return only certified connectors. Shorthand for `support_level='certified'`.", 149 ] = False, 150 support_level: Annotated[ 151 str, 152 "Exact support level to match (e.g., `certified`, `community`, `archived`). Empty string means no filter.", 153 ] = "", 154 min_support_level: Annotated[ 155 str, 156 "Minimum support level threshold (inclusive). Levels: `archived` < `community` < `certified`. Empty string means no filter.", 157 ] = "", 158 connector_type: Annotated[ 159 str, 160 "Filter by connector type: `source` or `destination`. Empty string means no filter.", 161 ] = "", 162 language: Annotated[ 163 str, 164 "Filter by implementation language (e.g., `python`, `java`, `manifest-only`). Empty string means no filter.", 165 ] = "", 166 name_contains: Annotated[ 167 str, 168 "Case-insensitive substring to match against connector names (e.g., `github`). Empty string means no filter.", 169 ] = "", 170) -> ConnectorListResult: 171 """List connectors in the production registry, with optional filtering. 172 173 Filters can be combined; `name_contains` is a case-insensitive substring 174 match on the connector name (leading/trailing whitespace is ignored). To 175 inspect a single known connector, prefer `get_connector_registry_entry` 176 (metadata) or `list_connector_versions_in_registry` (versions) instead. 177 """ 178 bucket_name = PROD_METADATA_SERVICE_BUCKET_NAME 179 180 # Normalise empty strings to typed enums or `None` for downstream logic. 181 eff_support_level: SupportLevel | None = ( 182 SupportLevel.parse(support_level) if support_level else None 183 ) 184 eff_min_support_level: SupportLevel | None = ( 185 SupportLevel.parse(min_support_level) if min_support_level else None 186 ) 187 eff_connector_type: ConnectorType | None = ( 188 ConnectorType.parse(connector_type) if connector_type else None 189 ) 190 eff_language: ConnectorLanguage | None = ( 191 ConnectorLanguage.parse(language) if language else None 192 ) 193 194 # `certified=True` is sugar for `support_level="certified"`. 195 if certified: 196 if eff_support_level and eff_support_level != SupportLevel.CERTIFIED: 197 raise ValueError( 198 "`certified=True` conflicts with `support_level=" 199 f"{eff_support_level!r}`. Use one or the other." 200 ) 201 eff_support_level = SupportLevel.CERTIFIED 202 203 has_filters = any( 204 [eff_support_level, eff_min_support_level, eff_connector_type, eff_language] 205 ) 206 207 if has_filters: 208 connectors = list_registry_connectors_filtered( 209 bucket_name=bucket_name, 210 support_level=eff_support_level, 211 min_support_level=eff_min_support_level, 212 connector_type=eff_connector_type, 213 language=eff_language, 214 ) 215 else: 216 connectors = list_registry_connectors(bucket_name=bucket_name) 217 218 needle = name_contains.strip().lower() 219 if needle: 220 connectors = [c for c in connectors if needle in c.lower()] 221 222 return ConnectorListResult( 223 bucket_name=bucket_name, 224 connector_count=len(connectors), 225 connectors=connectors, 226 ) 227 228 229@mcp_tool( 230 read_only=True, 231 idempotent=True, 232 open_world=True, 233) 234def list_connector_versions_in_registry( 235 connector_name: Annotated[ 236 str, 237 "The connector name (e.g., 'source-faker', 'destination-postgres')", 238 ], 239) -> VersionListResult: 240 """List all versions of a connector in the GCS registry. 241 242 Returns all published versions for a connector (excluding 'latest' and 'release_candidate'). 243 Requires GCS_CREDENTIALS environment variable to be set. 244 """ 245 bucket_name = PROD_METADATA_SERVICE_BUCKET_NAME 246 versions = list_connector_versions( 247 connector_name=connector_name, 248 bucket_name=bucket_name, 249 ) 250 return VersionListResult( 251 connector_name=connector_name, 252 bucket_name=bucket_name, 253 version_count=len(versions), 254 versions=versions, 255 ) 256 257 258@mcp_tool( 259 read_only=True, 260 idempotent=True, 261 open_world=True, 262) 263def get_connector_version_release( 264 connector_name: Annotated[ 265 str, 266 "The connector name (e.g., 'source-faker', 'destination-postgres').", 267 ], 268 version: Annotated[ 269 str, 270 "The connector version to inspect (e.g., '7.2.1').", 271 ], 272 store: Annotated[ 273 str, 274 "Store target to read (e.g. 'coral:prod', 'coral:dev'). Defaults to 'coral:prod'.", 275 ] = "coral:prod", 276) -> ReleaseAttributionLookupResult: 277 """Read release attribution for one connector version.""" 278 return lookup_release_attribution( 279 resolve_registry_store(store=store), 280 connector_name, 281 version, 282 ) 283 284 285@mcp_tool( 286 read_only=True, 287 idempotent=True, 288 open_world=True, 289) 290def list_connector_version_releases( 291 connector_name: Annotated[ 292 str, 293 "The connector name (e.g., 'source-faker', 'destination-postgres').", 294 ], 295 limit: Annotated[ 296 int, 297 "Maximum number of versions to return, newest first.", 298 ] = 50, 299 with_metadata_fallback: Annotated[ 300 bool, 301 "When `True`, read metadata for index entries without attribution.", 302 ] = False, 303 store: Annotated[ 304 str, 305 "Store target to read (e.g. 'coral:prod', 'coral:dev'). Defaults to 'coral:prod'.", 306 ] = "coral:prod", 307) -> ReleaseAttributionListResult: 308 """List release attribution for a connector's versions, newest first.""" 309 return list_release_attribution( 310 resolve_registry_store(store=store), 311 connector_name, 312 limit=limit, 313 with_metadata_fallback=with_metadata_fallback, 314 ) 315 316 317class YankedVersionEntry(BaseModel): 318 """A single yanked connector version discovered from its marker file.""" 319 320 connector_name: str = Field(description="The connector technical name") 321 version: str = Field(description="The yanked version tag") 322 yanked_at: str = Field(description="When the version was yanked, if recorded") 323 reason: str = Field(description="Reason recorded in the yank marker, if any") 324 approval_url: str = Field(description="Approval evidence URL, if recorded") 325 326 327class YankedVersionsResult(BaseModel): 328 """Result of listing yanked connector versions in a registry store.""" 329 330 store: str = Field(description="The store target that was read") 331 bucket_name: str = Field(description="The resolved GCS bucket name") 332 count: int = Field(description="Number of yanked versions found") 333 yanked_versions: list[YankedVersionEntry] = Field( 334 description="Yanked versions, sorted by connector name then version" 335 ) 336 337 338class YankDetailResult(BaseModel): 339 """Active yank-marker detail for a single connector version.""" 340 341 connector_name: str = Field(description="The connector technical name") 342 version: str = Field(description="The version that was checked") 343 store: str = Field(description="The store target that was read") 344 bucket_name: str = Field(description="The resolved GCS bucket name") 345 yanked: bool = Field( 346 description="True when an active `version-yank.yml` marker exists" 347 ) 348 yanked_at: str = Field(description="When the version was yanked, if recorded") 349 reason: str = Field(description="Reason recorded in the yank marker, if any") 350 approval_url: str = Field(description="Approval evidence URL, if recorded") 351 352 353@mcp_tool( 354 read_only=True, 355 idempotent=True, 356 open_world=True, 357) 358def list_yanked_connector_versions( 359 store: Annotated[ 360 str, 361 "Store target to read (e.g. 'coral:prod', 'coral:dev'). Defaults to 'coral:prod'.", 362 ] = "coral:prod", 363) -> YankedVersionsResult: 364 """List every yanked connector version in a registry store. 365 366 Returns one entry per active `version-yank.yml` marker, sorted by connector 367 name then version, with each marker's `yanked_at`, `reason`, and 368 `approval_url` populated. Historical `version-unyanked-*.yml` audit markers 369 are ignored — only live markers count. 370 371 Requires GCS_CREDENTIALS environment variable to be set. 372 """ 373 registry = get_registry(resolve_registry_store(store=store)) 374 yanked = registry.list_yanked_versions() 375 return YankedVersionsResult( 376 store=store, 377 bucket_name=registry.bucket_name, 378 count=len(yanked), 379 yanked_versions=[ 380 YankedVersionEntry( 381 connector_name=item.connector_name, 382 version=item.version, 383 yanked_at=item.yanked_at, 384 reason=item.reason, 385 approval_url=item.approval_url, 386 ) 387 for item in yanked 388 ], 389 ) 390 391 392@mcp_tool( 393 read_only=True, 394 idempotent=True, 395 open_world=True, 396) 397def get_connector_version_yank_detail( 398 connector_name: Annotated[ 399 str, 400 "The connector name (e.g., 'source-faker', 'destination-postgres').", 401 ], 402 version: Annotated[ 403 str, 404 "Version to inspect (e.g., '1.2.3').", 405 ], 406 store: Annotated[ 407 str, 408 "Store target to read (e.g. 'coral:prod', 'coral:dev'). Defaults to 'coral:prod'.", 409 ] = "coral:prod", 410) -> YankDetailResult: 411 """Read the active yank marker for a single connector version. 412 413 Returns `yanked=True` with the marker's `yanked_at`, `reason`, and 414 `approval_url` when the version currently has an active `version-yank.yml` 415 marker, or `yanked=False` with empty fields when it is not yanked. 416 Historical `version-unyanked-*.yml` audit markers are ignored. 417 418 Requires GCS_CREDENTIALS environment variable to be set. 419 """ 420 registry = get_registry(resolve_registry_store(store=store)) 421 marker = registry.get_yank_marker(connector_name=connector_name, version=version) 422 return YankDetailResult( 423 connector_name=connector_name, 424 version=version, 425 store=store, 426 bucket_name=registry.bucket_name, 427 yanked=marker is not None, 428 yanked_at=marker.yanked_at if marker else "", 429 reason=marker.reason if marker else "", 430 approval_url=marker.approval_url if marker else "", 431 ) 432 433 434# ============================================================================= 435# Yank Workflow Configuration 436# ============================================================================= 437 438YANK_WORKFLOW_REPO_OWNER = "airbytehq" 439 440YANK_WORKFLOW_REPO_NAME = "airbyte" 441 442YANK_WORKFLOW_DEFAULT_BRANCH = "master" 443 444YANK_WORKFLOW_FILE = "version-yank-command.yml" 445 446 447class YankConnectorVersionResponse(BaseModel): 448 """Response from triggering a yank connector version workflow.""" 449 450 approval_required: bool = Field( 451 default=False, 452 description=( 453 "Whether the operation still requires Slack/HITL approval before dispatch." 454 ), 455 ) 456 message: str = Field(description="Human-readable status message") 457 approval_request_summary: str | None = Field( 458 default=None, 459 description=( 460 "Short approval summary to pass to `escalate_to_human` when approval is required." 461 ), 462 ) 463 approval_request_message: str | None = Field( 464 default=None, 465 description=( 466 "Detailed Slack message to pass to `escalate_to_human` when approval is required." 467 ), 468 ) 469 approved_by: str | None = Field( 470 default=None, 471 description="Resolved `@airbyte.io` email for the Slack approver.", 472 ) 473 workflow_url: str | None = Field( 474 default=None, 475 description="URL to view the GitHub Actions workflow file", 476 ) 477 github_run_id: int | None = Field( 478 default=None, 479 description="GitHub Actions workflow run ID (use with check_ci_workflow_status)", 480 ) 481 github_run_url: str | None = Field( 482 default=None, 483 description="Direct URL to the GitHub Actions workflow run", 484 ) 485 486 487def _format_yank_action(unyank: bool) -> str: 488 """Return the registry action label for a yank tool call.""" 489 return "unyank" if unyank else "yank" 490 491 492def _sanitize_approval_request_summary_text(value: str) -> str: 493 """Return text safe for Slack approval request formatting.""" 494 return value.replace("`", "'") 495 496 497def _build_yank_approval_request_summary( 498 *, 499 connector_name: str, 500 version: str, 501 store: str, 502 reason: str, 503 unyank: bool, 504) -> str: 505 """Build a Slack confirmation summary for registry yank approval.""" 506 action = _format_yank_action(unyank) 507 sanitized_connector_name = _sanitize_approval_request_summary_text(connector_name) 508 sanitized_version = _sanitize_approval_request_summary_text(version) 509 sanitized_store = _sanitize_approval_request_summary_text(store) 510 summary = ( 511 f"{action} {sanitized_connector_name}@{sanitized_version} in " 512 f"{sanitized_store}; registry will be recompiled" 513 ) 514 if reason: 515 sanitized_reason = _sanitize_approval_request_summary_text(reason) 516 summary = f"{summary}; reason: {sanitized_reason}" 517 if len(summary) <= APPROVAL_REQUEST_SUMMARY_MAX_LENGTH: 518 return summary 519 return f"{summary[: APPROVAL_REQUEST_SUMMARY_MAX_LENGTH - 3].rstrip()}..." 520 521 522def _build_yank_approval_request_message( 523 *, 524 connector_name: str, 525 version: str, 526 store: str, 527 reason: str, 528 unyank: bool, 529) -> str: 530 """Build the Slack message body for registry yank approval.""" 531 action = _format_yank_action(unyank) 532 sanitized_connector_name = _sanitize_approval_request_summary_text(connector_name) 533 sanitized_version = _sanitize_approval_request_summary_text(version) 534 sanitized_store = _sanitize_approval_request_summary_text(store) 535 reason_text = ( 536 _sanitize_approval_request_summary_text(reason) if reason else "(none provided)" 537 ) 538 return ( 539 "Approval requested for an MCP registry connector-version operation.\n\n" 540 f"- Action: `{action}`\n" 541 f"- Connector: `{sanitized_connector_name}`\n" 542 f"- Version: `{sanitized_version}`\n" 543 f"- Store: `{sanitized_store}`\n" 544 f"- Reason: {reason_text}\n" 545 "- Consequence: after approval, the MCP tool will dispatch " 546 "`airbyte/.github/workflows/version-yank-command.yml`; that workflow " 547 "will update the yank marker and run `airbyte-ops registry store compile`, " 548 "recompiling registry indexes and latest pointers.\n\n" 549 "After Slack approval, copy the Slack approval record URL into " 550 "`approval_comment_url` and call `yank_connector_version` again with " 551 "the same connector name, version, store, reason, and unyank values." 552 ) 553 554 555@mcp_tool( 556 read_only=False, 557 idempotent=False, 558 open_world=True, 559) 560def yank_connector_version( 561 connector_name: Annotated[ 562 str, 563 "Connector name (e.g., 'source-faker', 'destination-postgres').", 564 ], 565 version: Annotated[ 566 str, 567 "Version to yank (e.g., '1.2.3').", 568 ], 569 store: Annotated[ 570 str, 571 "Store target (e.g., 'coral:dev', 'coral:prod').", 572 ], 573 reason: Annotated[ 574 str, 575 "Reason for yanking this version.", 576 ] = "", 577 unyank: Annotated[ 578 bool, 579 "Set to true to unyank (restore) the version instead of yanking it.", 580 ] = False, 581 approval_comment_url: Annotated[ 582 str | None, 583 Field( 584 description=( 585 "Slack approval record URL. Obtain this by calling " 586 "`escalate_to_human` with `approval_requested=True` using the " 587 "approval request details returned by this tool. The backend " 588 "validates the approval record and resolves the approver's " 589 "`@airbyte.io` email before dispatching the registry workflow." 590 ), 591 default=None, 592 ), 593 ] = None, 594) -> YankConnectorVersionResponse: 595 """Yank or unyank a connector version after Slack/HITL approval. 596 597 This MCP tool requires approval for all stores, including dev/test stores, 598 so the safety behavior is consistent and prod-impacting `coral:prod` 599 requests cannot dispatch without approval. 600 601 Without `approval_comment_url`, returns the exact approval request summary 602 and Slack message to send via `escalate_to_human`; no GitHub Actions 603 workflow is triggered. With an approved Slack record URL, validates the 604 approver and then triggers a workflow that marks the version as yanked 605 (or unyanked) and recompiles the registry to update indexes and latest 606 pointers. 607 608 Requires GITHUB_CI_WORKFLOW_TRIGGER_PAT or GITHUB_TOKEN environment variable 609 with 'actions:write' permission. 610 """ 611 action = _format_yank_action(unyank) 612 action_title = action.capitalize() 613 614 approval_request_summary = _build_yank_approval_request_summary( 615 connector_name=connector_name, 616 version=version, 617 store=store, 618 reason=reason, 619 unyank=unyank, 620 ) 621 approval_request_message = _build_yank_approval_request_message( 622 connector_name=connector_name, 623 version=version, 624 store=store, 625 reason=reason, 626 unyank=unyank, 627 ) 628 629 if not approval_comment_url: 630 return YankConnectorVersionResponse( 631 approval_required=True, 632 message=( 633 f"Slack/HITL approval is required before dispatching the {action} " 634 f"workflow for {connector_name}@{version} on {store}. Call " 635 "`escalate_to_human` with `approval_requested=True`, " 636 "`request_type='approval'`, the returned " 637 "`approval_request_summary`, and the returned " 638 "`approval_request_message`. After approval, call this tool " 639 "again with the Slack approval record URL as `approval_comment_url`." 640 ), 641 approval_request_summary=approval_request_summary, 642 approval_request_message=approval_request_message, 643 ) 644 645 try: 646 approved_by = resolve_admin_email_from_approval( 647 approval_comment_url=approval_comment_url, 648 ) 649 except ApprovalResolutionError as e: 650 return YankConnectorVersionResponse( 651 approval_required=True, 652 message=str(e), 653 approval_request_summary=approval_request_summary, 654 approval_request_message=approval_request_message, 655 ) 656 657 try: 658 token = resolve_ci_trigger_github_token() 659 except ValueError as e: 660 return YankConnectorVersionResponse( 661 message=str(e), 662 approved_by=approved_by, 663 ) 664 665 workflow_inputs: dict[str, str] = { 666 "connector-name": connector_name, 667 "version": version, 668 "store": store, 669 "unyank": str(unyank).lower(), 670 "approval-url": approval_comment_url, 671 } 672 if reason: 673 workflow_inputs["reason"] = reason 674 675 dispatch_result = trigger_workflow_dispatch( 676 owner=YANK_WORKFLOW_REPO_OWNER, 677 repo=YANK_WORKFLOW_REPO_NAME, 678 workflow_file=YANK_WORKFLOW_FILE, 679 ref=YANK_WORKFLOW_DEFAULT_BRANCH, 680 inputs=workflow_inputs, 681 token=token, 682 ) 683 684 view_url = dispatch_result.run_url or dispatch_result.workflow_url 685 reason_info = f" (reason: {reason})" if reason else "" 686 return YankConnectorVersionResponse( 687 message=( 688 f"{action_title} workflow triggered for {connector_name}@{version} " 689 f"on {store}{reason_info} after approval by {approved_by}. " 690 f"View progress at: {view_url}" 691 ), 692 approved_by=approved_by, 693 workflow_url=dispatch_result.workflow_url, 694 github_run_id=dispatch_result.run_id, 695 github_run_url=dispatch_result.run_url, 696 ) 697 698 699class ConnectorListResponse(BaseModel): 700 """Response model for list_connectors MCP tool.""" 701 702 connectors: list[str] 703 count: int 704 705 706class BumpVersionResponse(BaseModel): 707 """Response model for bump_connector_version MCP tool.""" 708 709 connector: str 710 previous_version: str 711 new_version: str 712 files_modified: list[str] 713 dry_run: bool 714 715 716@mcp_tool( 717 read_only=True, 718 idempotent=True, 719 open_world=False, 720 requires_client_filesystem=True, 721) 722def list_connectors_in_repo( 723 repo_path: Annotated[str, "Absolute path to the Airbyte monorepo"], 724 certified: Annotated[ 725 bool | None, 726 "Filter by certification: True=certified only, False=non-certified only, None=all", 727 ] = None, 728 modified: Annotated[ 729 bool | None, 730 "Filter by modification: True=modified only, False=not-modified only, None=all", 731 ] = None, 732 language_filter: Annotated[ 733 set[str] | None, 734 "Set of languages to include (python, java, low-code, manifest-only)", 735 ] = None, 736 language_exclude: Annotated[ 737 set[str] | None, 738 "Set of languages to exclude (mutually exclusive with language_filter)", 739 ] = None, 740 connector_type: Annotated[ 741 Literal["source", "destination"] | None, 742 "Filter by connector type: 'source' or 'destination', None=all", 743 ] = None, 744 connector_subtype: Annotated[ 745 Literal["api", "database", "file", "custom"] | None, 746 "Filter by connector subtype: 'api', 'database', 'file', 'custom', None=all", 747 ] = None, 748 pr_num_or_url: Annotated[ 749 str | None, 750 "PR number (e.g., '123'), GitHub URL, or None to auto-detect from GITHUB_REF environment variable", 751 ] = None, 752 gh_token: Annotated[ 753 str | None, 754 "GitHub API token. When provided together with pr_num_or_url, the GitHub API is used " 755 "to detect modified files instead of local git diff (avoids shallow-clone issues).", 756 ] = None, 757) -> ConnectorListResponse: 758 """List connectors in the Airbyte monorepo with flexible filtering. 759 760 Filters can be combined to narrow results. PR context (if provided or auto-detected) 761 determines the git diff range for modification detection. 762 """ 763 # Resolve PR info to base_ref and head_ref (MCP-specific: supports PR URL/number input) 764 base_ref, head_ref, pr_number, pr_owner, pr_repo = resolve_diff_range(pr_num_or_url) 765 766 # Delegate to capability function 767 result = list_connectors( 768 repo_path=repo_path, 769 certified=certified, 770 modified=modified, 771 language_filter=language_filter, 772 language_exclude=language_exclude, 773 connector_type=connector_type, 774 connector_subtype=connector_subtype, 775 base_ref=base_ref, 776 head_ref=head_ref, 777 pr_number=pr_number, 778 pr_owner=pr_owner, 779 pr_repo=pr_repo, 780 gh_token=gh_token, 781 ) 782 783 return ConnectorListResponse( 784 connectors=result.connectors, 785 count=result.count, 786 ) 787 788 789@mcp_tool( 790 read_only=False, 791 idempotent=False, 792 open_world=False, 793 requires_client_filesystem=True, 794) 795def bump_version_in_repo( 796 repo_path: Annotated[str, "Absolute path to the Airbyte monorepo"], 797 connector_name: Annotated[str, "Connector technical name (e.g., 'source-github')"], 798 bump_type: Annotated[ 799 Literal[ 800 "patch", 801 "minor", 802 "major", 803 "patch_rc", 804 "minor_rc", 805 "major_rc", 806 "rc", 807 "promote", 808 ] 809 | None, 810 "Version bump type. Standard: 'patch', 'minor', 'major'. " 811 "RC: 'patch_rc', 'minor_rc', 'major_rc' (create RC for next version), " 812 "'rc' (smart default: minor_rc if not RC, else bump RC number). " 813 "'promote' (strip RC suffix to finalize release).", 814 ] = None, 815 new_version: Annotated[ 816 str | None, 817 "Explicit new version (overrides bump_type if provided)", 818 ] = None, 819 changelog_message: Annotated[ 820 str | None, 821 "Message to add to changelog (optional)", 822 ] = None, 823 pr_number: Annotated[ 824 int | None, 825 "PR number for changelog entry (optional)", 826 ] = None, 827 dry_run: Annotated[ 828 bool, 829 "If True, show what would be changed without modifying files", 830 ] = False, 831) -> BumpVersionResponse: 832 """Bump a connector's version across all relevant files. 833 834 Updates version in metadata.yaml (always), pyproject.toml (if exists), 835 and documentation changelog (if changelog_message provided). 836 837 Either bump_type or new_version must be provided. 838 839 RC bump types (patch_rc, minor_rc, major_rc) only work on non-RC versions. 840 If the version is already an RC, use 'rc' to bump the RC number or 'promote' to finalize. 841 """ 842 # Delegate to capability function (validation happens there) 843 result = bump_connector_version( 844 repo_path=repo_path, 845 connector_name=connector_name, 846 bump_type=bump_type, 847 new_version=new_version, 848 changelog_message=changelog_message, 849 pr_number=pr_number, 850 dry_run=dry_run, 851 ) 852 853 return BumpVersionResponse( 854 connector=result.connector, 855 previous_version=result.previous_version, 856 new_version=result.new_version, 857 files_modified=result.files_modified, 858 dry_run=result.dry_run, 859 ) 860 861 862def register_connector_registry_tools(app: FastMCP) -> None: 863 """Register connector_registry tools with the FastMCP app.""" 864 register_mcp_tools(app, mcp_module=__name__)