Skip to content

Instantly share code, notes, and snippets.

@paulyuk
Last active August 7, 2025 20:10
Show Gist options
  • Save paulyuk/ff7c3d45f19a2b3739bbf249798a5140 to your computer and use it in GitHub Desktop.
Save paulyuk/ff7c3d45f19a2b3739bbf249798a5140 to your computer and use it in GitHub Desktop.
MCP Batch PR Propagation Spec for AZD Functions Templates

MCP Batch PR Propagation Spec for AZD Functions Templates

Purpose

  • Propagate a change from a source PR in an Azure Functions AZD sample to related AZD Gallery templates (Functions service templates) via batch PRs.
  • Ensure user-in-the-loop validation of targets and dry-run previews before creating PRs.

Scope

  • Source PR: URL provided by user at runtime (example: Azure-Samples/functions-quickstart-dotnet-azd#18).
  • Target repositories: AZD Gallery templates filtered as:
    • Service type: Functions service templates
    • Author: Microsoft* OR paulyuk
  • Operations: Discover targets, confirm with user, create branches, apply equivalent change, open PRs, and report results.

Prerequisites

  • MCP servers configured and reachable:
    • AZD Template discovery server (e.g., mcp-azd-template) with capability to search/filter AZD Gallery templates by service type and author. Repo: https://github.com/spboyer/mcp-azd-template. Start it with: npx -y mcp-azd-template@latest, which registers in the IDE as the MCP server azd-template-helper.
    • GitHub MCP with permissions to read repos, fork/create branches (if needed), and open pull requests in the target repositories.
  • Auth:
    • GitHub access token with repo scope for relevant orgs/repos.
  • Local environment optional for dry-run diffs (cloning): git available.

Inputs (at runtime)

  • SOURCE_PR_URL: The source PR to propagate.
  • FILTERS:
    • serviceType = "Functions"
    • authors = ["Microsoft", "paulyuk"] (match by owner or author metadata)
    • optional: languages (e.g., dotnet, node, python, java), triggers (http, queue, timer, blob, service bus, event grid, etc.)
  • EXECUTION_MODE:
    • discover-only | dry-run | create-prs
  • BATCH_LIMIT: Maximum PRs to create in a single run (default 10).

High-level Workflow

  1. Read and analyze SOURCE_PR_URL
    • Fetch PR metadata: title, body, state, commits, changed files, labels, linked issues.
    • Retrieve patch/diff for changed files.
    • Summarize the intent of change and categorize file types (code, infra, docs, CI, azd metadata).
  2. Discover candidate target templates
    • Query AZD Gallery templates with filters: serviceType=Functions and author in {Microsoft, paulyuk}.
    • Collect repository metadata (name, owner, default branch, languages, triggers/tags).
    • Present the list to the user for validation before proceeding.
  3. User validation checkpoint (REQUIRED)
    • Show a paginated list with repo name, owner, template description, language, trigger(s).
    • Allow the user to:
      • Approve all, or
      • Deselect specific repos, or
      • Edit filters and re-run discovery.
  4. Prepare change mapping
    • Infer change type per file from source PR (e.g., csproj flag, host.json setting, infra main.bicep tweak, README section, CI matrix changes).
    • Define cross-language/trigger mapping rules if applicable. Examples:
      • host.json or local.settings.json: similar location across languages; adjust syntax if needed.
      • infra/ (Bicep/Terraform): mirror property names; verify API versions.
      • README: propagate wording consistently; keep language-specific code blocks.
      • CI/CD: adapt job names, paths, and language tooling versions.
    • If exact mapping is ambiguous, mark repo as “manual review needed” and skip for auto PR.
  5. Dry-run (optional but recommended)
    • For each approved target repo up to BATCH_LIMIT:
      • Clone or fetch a shallow copy of the default branch.
      • Create a working branch: chore/propagate-from--pr-.
      • Apply mapped changes to corresponding files.
      • Produce a diff summary and file list; do not push.
    • Present consolidated dry-run results to user for final approval.
  6. Create PRs
    • For each target in scope (after approval):
      • Ensure repository permissions and branch protection rules are respected.
      • (Fork Mode) If you lack direct push permission to Azure-Samples/:
        • Ensure a fork exists under the user account (e.g., paulyuk/); create one if absent.
        • Sync fork default branch with upstream (fast-forward) before creating the feature branch.
        • Create / update feature branch in the fork and push changes there.
        • Open a pull request with base: Azure-Samples/@main and head: paulyuk:.
      • (Direct Mode) If you have push permission, create/update the feature branch in the upstream and open the PR normally.
      • Commit with a standardized message.
      • Open a pull request targeting the upstream default branch (always Azure-Samples main as base for consistency).
    • Respect rate limits and backoff; stop at BATCH_LIMIT in a single run.
  7. Reporting
    • Summarize successes (PR URLs) and failures with reasons.
    • Provide a CSV/JSON artifact of results for tracking.

Standardized Artifacts

  • Branch name
    • chore/propagate-from--pr-
  • Commit message
    • chore: propagate changes from #

      Source PR: <SOURCE_PR_URL> Summary: Notes: Applied equivalent updates across AZD Functions templates.

  • Pull request title
    • Propagate: (from #)
  • Pull request body (template)
    • This PR propagates changes from <SOURCE_PR_URL> into this AZD Functions template.

      Summary of upstream change:

      Applied updates here:

      Validation:

      • Build/CI passes
      • Local azd provision/deploy (optional)

      Notes:

      • Generated via MCP batch propagation workflow.

Safety and Guardrails

  • Do not proceed beyond discovery without explicit user approval.
  • Skip repositories where mapping is ambiguous or conflicting.
  • Respect existing open PRs touching the same files: add comments or update instead of duplicating.
  • Obey CODEOWNERS and required labels when creating PRs.
  • BATCH_LIMIT to avoid spamming.
  • Add a label: area:automation or propagation-bot if available.

Error Handling & Retries

  • If cloning fails: retry once with backoff; otherwise skip and log.
  • If PR creation fails due to permissions: report and continue.
  • If merge conflicts occur: convert to draft PR and note manual intervention required.

Execution Modes

  • discover-only: Only list candidate repos for approval.
  • dry-run: Prepare local diffs and present a preview without pushing.
  • create-prs: Execute branch creation and PR opening after approval.

User Interaction Checkpoints

  • After discovery: show target list for approval/edit.
  • After dry-run: show diff summaries for approval.
  • After PR creation: show results and links.

Reusable Prompt Blocks (copy/paste into your MCP orchestrator)

Prompt: Discover AZD Functions templates

  • Goal: Return AZD Gallery templates filtered by Functions service type and authors (Microsoft* or paulyuk)

  • Tooling: AZD Template discovery server (mcp-azd-template)

  • Variables:

    • SOURCE_PR_URL:
    • AUTHORS: ["Microsoft", "paulyuk"]
    • SERVICE_TYPE: "Functions"
    • LANGUAGES: [] (optional)
    • TRIGGERS: [] (optional)
    • LIMIT: <int, optional>
  • Instruction: """ Discover AZD Gallery templates using these filters:

    • serviceType: {SERVICE_TYPE}
    • authors: {AUTHORS}
    • languages: {LANGUAGES}
    • triggers: {TRIGGERS}

    Return a JSON array of candidates with fields: [ { "name": string, "owner": string, "repo": string, // owner/repo "description": string, "defaultBranch": string, "languages": string[], "triggers": string[], "tags": string[], "url": string } ]

    Do not proceed beyond discovery. No side effects. """

Prompt: Dry-run mapping and diff preview

  • Goal: For approved targets, compute equivalent changes from SOURCE_PR_URL and produce diffs without pushing
  • Tooling: GitHub MCP (read-only clone/fetch), optional local git
  • Variables:
    • SOURCE_PR_URL:
    • TARGETS: ["owner/repo", ...] (approved subset)
    • BRANCH_NAME: chore/propagate-from--pr-
    • LIMIT:
  • Instruction: """
    1. Fetch SOURCE_PR_URL metadata and unified diff.
    2. For each TARGET in TARGETS (up to LIMIT):
      • Shallow clone default branch.
      • Analyze mapping for each changed file (code/infra/docs/CI). If ambiguous, mark target as manual_review_required and SKIP.
      • Apply changes in a temporary working tree.
      • Produce a diff summary: { "repo": "owner/repo", "manual_review_required": boolean, "files": [ { "path": string, "changeSummary": string } ], "diff": string // patch text }
    3. Return an array of these results. Do not push or open PRs. """

Prompt: Create PRs

  • Goal: Create branches, commit changes, and open PRs with standardized messages
  • Tooling: GitHub MCP (write)
  • Variables:
    • SOURCE_PR_URL:
    • TARGETS: ["owner/repo", ...] (approved subset)
    • BRANCH_NAME: chore/propagate-from--pr-
    • PR_TITLE_TEMPLATE: "Propagate: (from #)"
    • PR_BODY_TEMPLATE: see Standardized Artifacts
    • LABELS: ["propagation", "automation"] (if allowed)
    • LIMIT:
    • FORK_USER: paulyuk (the user account to host forks when direct push is unavailable)
  • Instruction: """ Using SOURCE_PR_URL metadata and previously computed mappings:
    • For each TARGET (up to LIMIT):
      • Check if write permission to upstream (Azure-Samples/) exists.
        • If not: ensure fork FORK_USER/ exists (create if missing) and is synchronized with upstream default branch.
        • Create or update branch {BRANCH_NAME} in the fork (or upstream if direct write allowed).
      • Commit changes with message: "chore: propagate changes from #\n\nSource PR: <SOURCE_PR_URL>\nSummary: \nNotes: Applied equivalent updates across AZD Functions templates."
      • Open a PR with: base: Azure-Samples/@defaultBranch head: (FORK_USER or upstream owner):{BRANCH_NAME} using PR_TITLE_TEMPLATE and PR_BODY_TEMPLATE.
      • Apply LABELS if permissions allow.
      • If conflicts arise, open as draft and note manual intervention.
    • Return JSON results: [ { "repo": "owner/repo", "prUrl": string, "branch": string, "status": "created"|"skipped"|"failed", "reason"?: string } ] """

Fork Workflow Variant (Summary)

  • Purpose: Operate safely without upstream write access by using user forks (paulyuk) as the PR head source.
  • Steps per repo:
    1. Fork existence check / creation.
    2. Upstream default branch fetch & fork sync (fast-forward only; if diverged, create a sync commit in fork).
    3. Feature branch creation in fork: {BRANCH_NAME}.
    4. Apply mapped changes & commit.
    5. Open PR: base=Azure-Samples/:main head=paulyuk:{BRANCH_NAME}.
    6. Apply labels (best-effort) and add propagation run ID comment.
    7. Record result.

Git CLI Reference (optional manual fallback)

upstream=Azure-Samples/functions-quickstart-javascript-azd
fork_user=paulyuk
branch=chore/propagate-from-functions-quickstart-dotnet-azd-pr-18
git clone https://github.com/$fork_user/${upstream##*/}.git || git clone https://github.com/$upstream.git
cd ${upstream##*/}
git remote add upstream https://github.com/$upstream.git 2>/dev/null || true
git fetch upstream main
git checkout -B main upstream/main
git push origin main
git checkout -B $branch
# (apply edits)
git commit -am "chore: propagate changes from functions-quickstart-dotnet-azd#18"
git push -u origin $branch
gh pr create --base main --head $fork_user:$branch --title "Propagate: <title> (from functions-quickstart-dotnet-azd#18)" --body-file pr_body.md

Output Contracts

  • discovery.results.json [ { name, owner, repo, description, defaultBranch, languages, triggers, tags, url } ]
  • dryrun.results.json [ { repo, manual_review_required, files: [ { path, changeSummary } ], diff } ]
  • createprs.results.json [ { repo, prUrl, branch, status, reason? } ]

Consent Gates

  • Gate 1: After discovery.results.json, require explicit user approval and allow deselection.
  • Gate 2: After dryrun.results.json, require explicit user approval before PR creation.
  • Gate 3: After createprs.results.json, present summary and next steps.

Configuration Parameters

  • filters.serviceType: "Functions"
  • filters.authors: ["Microsoft", "paulyuk"]
  • filters.languages: [optional]
  • filters.triggers: [optional]
  • batch.limit: default 10
  • branchPrefix: chore/propagate-from
  • labels: ["propagation", "automation"] (if allowed)

Minimal Pseudo-Flow

  • getSourcePr(SOURCE_PR_URL) -> {title, body, files[], patch[]}
  • discoverTemplates({serviceType:"Functions", authors:["Microsoft","paulyuk"], languages?, triggers?}) -> repos[]
  • promptUserApprove(repos)
  • if dry-run:
    • for repo in approved[:BATCH_LIMIT]:
      • planChanges = mapChanges(sourcePatch, repo)
      • diffPreview = applyInMemory(planChanges)
    • promptUserApprove(diffPreviews)
  • if create-prs:
    • for repo in approved[:BATCH_LIMIT]:
      • branch = createBranch(repo, branchName)
      • applyChanges(repo, plan)
      • commitAndPush(repo, branch)
      • openPR(repo, branch, title, body)
    • reportSummary()

Acceptance Criteria

  • Shows a filtered list of AZD Functions templates by Microsoft or paulyuk for user confirmation.
  • Supports a dry-run with clear diff previews before creating PRs.
  • Creates PRs with standardized naming and links back to the source PR.
  • Produces a success/failure summary.

Appendix A: Mapping Guidance Examples

  • host.json changes: replicate equivalent settings across languages; ensure schema correctness.
  • Bicep (infra): verify apiVersion compatibility; update outputs/params consistently; run a linter if available.
  • README: keep language-specific commands/tools accurate (dotnet/npm/pip/gradle).
  • CI workflows: align tooling versions; matrix may differ per language.

Appendix B: Rate Limiting & Idempotency

  • Include a unique propagation run ID in PR body comments.
  • Detect and update existing PRs from the same run.

Appendix C: Consent Gates

  • The workflow must pause and await user confirmation at discovery and dry-run stages before proceeding to PR creation.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment