feat: enable unauthenticated server startup with runtime OAuth and update CI/CD to append Docker pull instructions to release notes
CI/CD Pipeline / Lint & Check (push) Successful in 54s
CI/CD Pipeline / Build & Push Docker Image (push) Failing after 11s

This commit is contained in:
2026-05-09 05:19:16 +02:00
parent a3305b162d
commit 6dd70c29aa
4 changed files with 48 additions and 2 deletions
+35 -1
View File
@@ -51,7 +51,7 @@ jobs:
with: with:
registry: ${{ env.REGISTRY }} registry: ${{ env.REGISTRY }}
username: ${{ github.actor }} username: ${{ github.actor }}
password: ${{ secrets.MY_BUILDTOKEN }} password: ${{ secrets.GITEA_TOKEN }}
- name: Extract metadata (tags, labels) for Docker - name: Extract metadata (tags, labels) for Docker
id: meta id: meta
@@ -88,3 +88,37 @@ jobs:
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache
cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache,mode=max cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache,mode=max
- name: Update Gitea Release Notes
if: startsWith(github.ref, 'refs/tags/v')
run: |
TAG_NAME=${GITHUB_REF#refs/tags/}
# Fetch the current release
RELEASE_JSON=$(curl -s -H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \
${{ github.api_url }}/repos/${{ github.repository }}/releases/tags/${TAG_NAME})
# Extract Release ID (if it exists)
RELEASE_ID=$(echo "$RELEASE_JSON" | jq -r '.id // empty')
if [ -n "$RELEASE_ID" ] && [ "$RELEASE_ID" != "null" ]; then
OLD_BODY=$(echo "$RELEASE_JSON" | jq -r '.body // ""')
# Check if Docker Image section already exists
if [[ "$OLD_BODY" != *"## 🐳 Docker Image"* ]]; then
NEW_BODY="${OLD_BODY}\n\n## 🐳 Docker Image\n\`\`\`bash\ndocker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${TAG_NAME}\n\`\`\`"
jq -n --arg body "$NEW_BODY" '{body: $body}' | \
curl -s -X PATCH \
-H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \
-H "Content-Type: application/json" \
-d @- \
${{ github.api_url }}/repos/${{ github.repository }}/releases/${RELEASE_ID}
echo "Successfully updated Release Notes for $TAG_NAME"
else
echo "Release Notes already contain the Docker pull command."
fi
else
echo "No associated release found for tag $TAG_NAME. Skipping."
fi
+5
View File
@@ -23,3 +23,8 @@
- [x] Callback-Endpoint `/auth/callback` im FastMCP-Server ergänzen - [x] Callback-Endpoint `/auth/callback` im FastMCP-Server ergänzen
- [x] `STRAVA_REFRESH_TOKEN` automatisch in `.env` zurückschreiben nach Token-Rotation - [x] `STRAVA_REFRESH_TOKEN` automatisch in `.env` zurückschreiben nach Token-Rotation
- [x] Optionaler Hinweis beim Start falls kein Token vorhanden ist - [x] Optionaler Hinweis beim Start falls kein Token vorhanden ist
## Bugs
- [x] Server startet nicht ohne Refresh Token. Brauche Möglichkeit das ich Auth über Agentgateway machen kann, damit ich nicht jedes Mal manuell den Auth Prozess anstoßen muss. Siehe Gitea MCP Server.
- [x] Hinweise für Model wie das Datum ausgegeben wird vom MCP Server. Aktuell ist das LLM oft unsicher bzgl. datums formates.
+5 -1
View File
@@ -16,7 +16,6 @@ def validate_credentials() -> None:
required = { required = {
"STRAVA_CLIENT_ID": os.getenv("STRAVA_CLIENT_ID"), "STRAVA_CLIENT_ID": os.getenv("STRAVA_CLIENT_ID"),
"STRAVA_CLIENT_SECRET": os.getenv("STRAVA_CLIENT_SECRET"), "STRAVA_CLIENT_SECRET": os.getenv("STRAVA_CLIENT_SECRET"),
"STRAVA_REFRESH_TOKEN": os.getenv("STRAVA_REFRESH_TOKEN"),
} }
missing = [k for k, v in required.items() if not v] missing = [k for k, v in required.items() if not v]
if missing: if missing:
@@ -26,6 +25,10 @@ def validate_credentials() -> None:
print("\nCopy .env.example to .env and fill in your Strava API credentials.") print("\nCopy .env.example to .env and fill in your Strava API credentials.")
sys.exit(1) sys.exit(1)
if not os.getenv("STRAVA_REFRESH_TOKEN"):
print("️ No STRAVA_REFRESH_TOKEN found. Server starting in unauthenticated mode.")
print(" Use the 'get_new_oauth_token' tool via MCP to authenticate.")
def main() -> None: def main() -> None:
"""Entry point for the strava-mcp console script.""" """Entry point for the strava-mcp console script."""
@@ -39,6 +42,7 @@ def main() -> None:
mcp = FastMCP( mcp = FastMCP(
"Strava MCP Server", "Strava MCP Server",
instructions="Dates returned by this server are generally in ISO-8601 (UTC) or formatted as DD.MM.YYYY HH:MM. Always present dates, times, and durations to the user in a natural, human-readable format appropriate for their language.",
host=host, host=host,
port=port, port=port,
streamable_http_path="/mcp", streamable_http_path="/mcp",
+3
View File
@@ -36,6 +36,9 @@ class StravaClient:
async def get_valid_token(self) -> str: async def get_valid_token(self) -> str:
"""Returns a valid access token, refreshing it if necessary.""" """Returns a valid access token, refreshing it if necessary."""
if not self.refresh_token:
raise ValueError("No Strava refresh token found. Please run the 'get_new_oauth_token' MCP tool to authenticate first.")
if not self.access_token or time.time() > self.expires_at - 60: if not self.access_token or time.time() > self.expires_at - 60:
await self._refresh_access_token() await self._refresh_access_token()
return self.access_token return self.access_token