feat: enable unauthenticated server startup with runtime OAuth and update CI/CD to append Docker pull instructions to release notes
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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.
|
||||||
@@ -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:
|
||||||
@@ -25,6 +24,10 @@ def validate_credentials() -> None:
|
|||||||
print(f" - {key}")
|
print(f" - {key}")
|
||||||
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:
|
||||||
@@ -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",
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user