diff --git a/.gitea/workflows/cicd.yml b/.gitea/workflows/cicd.yml index d5526a3..1f348c2 100644 --- a/.gitea/workflows/cicd.yml +++ b/.gitea/workflows/cicd.yml @@ -51,7 +51,7 @@ jobs: with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} - password: ${{ secrets.MY_BUILDTOKEN }} + password: ${{ secrets.GITEA_TOKEN }} - name: Extract metadata (tags, labels) for Docker id: meta @@ -88,3 +88,37 @@ jobs: labels: ${{ steps.meta.outputs.labels }} cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache 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 diff --git a/TODO.md b/TODO.md index e3e1020..7d6cbee 100644 --- a/TODO.md +++ b/TODO.md @@ -23,3 +23,8 @@ - [x] Callback-Endpoint `/auth/callback` im FastMCP-Server ergänzen - [x] `STRAVA_REFRESH_TOKEN` automatisch in `.env` zurückschreiben nach Token-Rotation - [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. \ No newline at end of file diff --git a/src/strava_mcp_server/main.py b/src/strava_mcp_server/main.py index 52c2a3b..8f0f910 100644 --- a/src/strava_mcp_server/main.py +++ b/src/strava_mcp_server/main.py @@ -16,7 +16,6 @@ def validate_credentials() -> None: required = { "STRAVA_CLIENT_ID": os.getenv("STRAVA_CLIENT_ID"), "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] if missing: @@ -25,6 +24,10 @@ def validate_credentials() -> None: print(f" - {key}") print("\nCopy .env.example to .env and fill in your Strava API credentials.") 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: @@ -39,6 +42,7 @@ def main() -> None: mcp = FastMCP( "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, port=port, streamable_http_path="/mcp", diff --git a/src/strava_mcp_server/strava_client.py b/src/strava_mcp_server/strava_client.py index c321db5..8c7f2c7 100644 --- a/src/strava_mcp_server/strava_client.py +++ b/src/strava_mcp_server/strava_client.py @@ -36,6 +36,9 @@ class StravaClient: async def get_valid_token(self) -> str: """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: await self._refresh_access_token() return self.access_token