Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 73 additions & 12 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ on:
branches:
- main
workflow_dispatch:
inputs:
force_publish:
description: 'Skip release-please and publish current package.json versions'
type: boolean
default: false

permissions:
contents: write
Expand Down Expand Up @@ -32,33 +37,56 @@ jobs:
with:
token: ${{ steps.generate-token.outputs.token }}

# Everything below only runs when a release PR is merged.
# Shared setup steps gate on releases_created (true if any package released).
- name: Validate force publish ref
if: ${{ inputs.force_publish == true }}
env:
GH_TOKEN: ${{ github.token }}
REF_TYPE: ${{ github.ref_type }}
REF_NAME: ${{ github.ref_name }}
run: |
set -euo pipefail
if [ "$REF_TYPE" != "tag" ]; then
echo "Select a release tag instead of a branch when running force_publish."
exit 1
fi
if gh api --silent "repos/$GITHUB_REPOSITORY/releases/tags/$REF_NAME"; then
echo "Force publishing from release tag $REF_NAME."
exit 0
fi
echo "Selected tag $REF_NAME is not associated with a GitHub Release."
exit 1

# Everything below runs when a release PR is merged, or when
# force_publish is manually enabled for retrying current package versions.
# Shared setup steps gate on releases_created (true if any package released)
# or force_publish.
# Per-package publish steps gate on <path>--release_created so only the
# released package(s) are published each run.
# released package(s) are published each run. force_publish runs all
# publish steps; already-published npm versions and MCP registry
# versions are skipped below.
# Ref: https://github.com/googleapis/release-please-action#path-outputs

- name: Checkout repository
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1
if: ${{ steps.release.outputs.releases_created }}
if: ${{ steps.release.outputs.releases_created || inputs.force_publish == true }}

- name: Setup tools
uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db # v3.6.3
if: ${{ steps.release.outputs.releases_created }}
if: ${{ steps.release.outputs.releases_created || inputs.force_publish == true }}
with:
install: true
cache: true

- name: Install dependencies
if: ${{ steps.release.outputs.releases_created }}
if: ${{ steps.release.outputs.releases_created || inputs.force_publish == true }}
run: pnpm install --frozen-lockfile

- name: Build packages
if: ${{ steps.release.outputs.releases_created }}
if: ${{ steps.release.outputs.releases_created || inputs.force_publish == true }}
run: pnpm --filter @supabase/mcp-utils --filter @supabase/mcp-server-supabase --filter @supabase/mcp-server-postgrest build

- name: Publish @supabase/mcp-utils to npm
if: ${{ steps.release.outputs['packages/mcp-utils--release_created'] }}
if: ${{ steps.release.outputs['packages/mcp-utils--release_created'] || inputs.force_publish == true }}
working-directory: packages/mcp-utils
run: |
set -euo pipefail
Expand All @@ -78,7 +106,7 @@ jobs:
pnpm publish --no-git-checks --ignore-scripts --access public --provenance

- name: Publish @supabase/mcp-server-supabase to npm
if: ${{ steps.release.outputs['packages/mcp-server-supabase--release_created'] }}
if: ${{ steps.release.outputs['packages/mcp-server-supabase--release_created'] || inputs.force_publish == true }}
working-directory: packages/mcp-server-supabase
run: |
set -euo pipefail
Expand All @@ -98,7 +126,7 @@ jobs:
pnpm publish --no-git-checks --ignore-scripts --access public --provenance

- name: Publish @supabase/mcp-server-postgrest to npm
if: ${{ steps.release.outputs['packages/mcp-server-postgrest--release_created'] }}
if: ${{ steps.release.outputs['packages/mcp-server-postgrest--release_created'] || inputs.force_publish == true }}
working-directory: packages/mcp-server-postgrest
run: |
set -euo pipefail
Expand All @@ -117,14 +145,47 @@ jobs:
rm -f "$NPM_VIEW_STDERR"
pnpm publish --no-git-checks --ignore-scripts --access public --provenance

# The MCP registry rejects re-publishing an existing version.
# Probe the registry first and gate both login and publish on the result.
- name: Check MCP registry version
id: mcp-registry-check
if: ${{ steps.release.outputs['packages/mcp-server-supabase--release_created'] || inputs.force_publish == true }}
working-directory: packages/mcp-server-supabase
run: |
set -euo pipefail
ALREADY_PUBLISHED=$(node -e '
const { name, version } = require("./server.json");
const url = `https://registry.modelcontextprotocol.io/v0/servers?search=${encodeURIComponent(name)}&version=${encodeURIComponent(version)}`;
fetch(url)
.then((res) => {
if (!res.ok) throw new Error(`Registry query failed: ${res.status} ${res.statusText}`);
return res.json();
})
.then((data) => {
const exists = (data.servers ?? []).some(
(entry) => entry.server?.name === name && entry.server?.version === version
);
process.stdout.write(exists ? "true" : "false");
})
.catch((err) => {
console.error(err.message);
process.exit(1);
});
')
echo "already_published=$ALREADY_PUBLISHED" >> "$GITHUB_OUTPUT"
if [ "$ALREADY_PUBLISHED" = "true" ]; then
VERSION=$(node -p "require('./server.json').version")
echo "MCP registry version $VERSION already published, skipping."
fi

- name: Authenticate to MCP registry
if: ${{ steps.release.outputs['packages/mcp-server-supabase--release_created'] }}
if: ${{ steps.mcp-registry-check.outputs.already_published == 'false' }}
working-directory: packages/mcp-server-supabase
env:
DOMAIN_VERIFICATION_KEY: ${{ secrets.DOMAIN_VERIFICATION_KEY }}
run: pnpm registry:login

- name: Publish to MCP registry
if: ${{ steps.release.outputs['packages/mcp-server-supabase--release_created'] }}
if: ${{ steps.mcp-registry-check.outputs.already_published == 'false' }}
working-directory: packages/mcp-server-supabase
run: pnpm registry:publish
2 changes: 2 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ Most contributors don't need to do anything beyond merging the release PR and up

If the release PR gets into a bad state, close it and manually re-run the workflow from the [Actions tab](https://github.com/supabase/mcp/actions/workflows/release.yml) → **Run workflow**. release-please will recreate the PR from scratch.

If the workflow creates GitHub releases and tags but fails before publishing to npm or the MCP registry, re-run the workflow from one of the release tags created by the failed workflow run and enable `force_publish`.

## Manual MCP registry publish (optional)

This is only needed if the automated publish failed or needs to be re-run manually. The MCP registry stores metadata about the server (defined in `packages/mcp-server-supabase/server.json`) — it does not host the server itself.
Expand Down
12 changes: 9 additions & 3 deletions packages/mcp-server-supabase/src/management-api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,10 @@ export interface paths {
};
get?: never;
put?: never;
/** [Beta] Exchange auth code for user's access and refresh token */
/**
* [Beta] Exchange auth code for user's access and refresh token
* @description Supports `authorization_code`, `refresh_token`, and `urn:ietf:params:oauth:grant-type:jwt-bearer` grant types. The `jwt-bearer` grant type (IDJAG — identity-directed JWT assertion) is in beta and available on Team and Enterprise plans only.
*/
post: operations["v1-exchange-oauth-token"];
delete?: never;
options?: never;
Expand Down Expand Up @@ -2396,14 +2399,16 @@ export interface components {
* } */
OAuthTokenBody: {
/** @enum {string} */
grant_type?: "authorization_code" | "refresh_token";
grant_type?: "authorization_code" | "refresh_token" | "urn:ietf:params:oauth:grant-type:jwt-bearer";
/** Format: uuid */
client_id?: string;
client_secret?: string;
code?: string;
code_verifier?: string;
redirect_uri?: string;
refresh_token?: string;
/** @description IDJAG assertion JWT for grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer. Beta - available on Team and Enterprise plans only. */
assertion?: string;
/**
* Format: uri
* @description Resource indicator for MCP (Model Context Protocol) clients
Expand All @@ -2413,7 +2418,8 @@ export interface components {
};
OAuthTokenResponse: {
access_token: string;
refresh_token: string;
/** @description The `urn:ietf:params:oauth:grant-type:jwt-bearer` grant type issues access tokens only, no refresh token is returned and the token cannot be revoked via `/v1/oauth/revoke`. */
refresh_token?: string;
expires_in: number;
/** @enum {string} */
token_type: "Bearer";
Expand Down
Loading