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__)