The GitHub Blog https://github.blog/ Updates, ideas, and inspiration from GitHub to help developers build and design software. Mon, 04 Aug 2025 16:28:13 +0000 en-US hourly 1 https://wordpress.org/?v=6.8.2 https://github.blog/wp-content/uploads/2019/01/cropped-github-favicon-512.png?fit=32%2C32 The GitHub Blog https://github.blog/ 32 32 153214340 Automate your project with GitHub Models in Actions https://github.blog/ai-and-ml/generative-ai/automate-your-project-with-github-models-in-actions/ Mon, 04 Aug 2025 16:00:00 +0000 https://github.blog/?p=89874 Learn how to integrate AI features with GitHub Models directly in GitHub Actions workflows.

The post Automate your project with GitHub Models in Actions appeared first on The GitHub Blog.

]]>

GitHub Models brings AI into your GitHub Actions workflows, helping you automate triage, summarize, and more — right where your project lives. 

Let’s explore three ways to integrate and automate the use of GitHub Models in GitHub Actions workflows, from the most straightforward to the most powerful.

But first: Add the right permissions

Before you can use GitHub Models in your Actions workflows, you need to grant your workflow access to AI models. Without the correct permissions, any step that tries to call an AI model will fail.

Giving permissions to use GitHub Models is one line in your permissions block:

permissions:
  contents: read
  issues: write
  models: read

These permissions will give your workflow the ability to read repository content; to read, create, or update issues and comments; and, most importantly for this tutorial, to enable access to GitHub Models. 

Example one: Request more information in bug reports 

This example will show you how to use the AI inference action and how to use AI to create branching logic. You can find the full workflow in this repo.

One of the most time-consuming and menial parts of our work as developers is triaging new issues that often contain too little information to reproduce. 

Instead of having to spend time assessing and responding to these issues, you can use the AI inference action lets you call leading AI models to analyze or generate text as part of your workflow. The workflow below, for example, will automatically check if new bug reports have enough information to be actionable, and respond if they’re not.

To set up the workflow, create a new file in your repository’s .github/workflows directory called bug-reproduction-instructions.yml (create the directory if it doesn’t exist). It will trigger whenever a new issue is opened and then fetch the issue’s title and body for future steps. 

name: Bug Report Reproduction Check

on:
  issues:
    types: [opened]

permissions:
  contents: read
  issues: write
  models: read

jobs:
  reproduction-steps-check:
    runs-on: ubuntu-latest
    steps:
      - name: Fetch Issue
        id: issue
        uses: actions/github-script@v7
        with:
          script: |
            const issue = await github.rest.issues.get({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number
            })
            core.setOutput('title', issue.data.title)
            core.setOutput('body', issue.data.body)

Now that your workflow has the necessary context, create a new step. This step should only execute if the issue is tagged with a bug label. This step will use the AI inference action, configured with a system prompt that outlines the characteristics of effective reproduction instructions, and provide the value from the issue.

- name: Analyze Issue For Reproduction
  if: contains(join(github.event.issue.labels.*.name, ','), 'bug')
  id: analyze-issue
  uses: actions/ai-inference@v1
  with:
  model: mistral-ai/ministral-3b
  system-prompt: |
    Given a bug report title and text for an application, return 'pass' if there is enough information to reliably reproduce the issue, meaning the report clearly describes the steps to reproduce the problem, specifies the expected and actual behavior, and includes environment details such as browser and operating system; if any of these elements are missing or unclear, return a brief description of what is missing in a friendly response to the author instead of 'pass'. Consider the following title and body:
  prompt: |
    Title: ${{ steps.issue.outputs.title }}
    Body: ${{ steps.issue.outputs.body }}

This step will either return a pass if there is enough information provided (more on why we’re doing this in a moment), or return a response detailing what is missing. 

You can use over 40 AI models available in the GitHub Models catalog. Just swap out the model value with the identifier on each model’s page. 

Next, add one final step, which will post the comment only if the value returned was not pass

- name: Comment On Issue
  if: contains(join(github.event.issue.labels.*.name, ','), 'bug') && steps.analyze-issue.outputs.response != 'pass'
  uses: actions/github-script@v7
  env:
    AI_RESPONSE: steps.analyze-issue.outputs.response
    with:
      script: |
        await github.rest.issues.createComment({
          owner: context.repo.owner,
          repo: context.repo.repo,
          issue_number: context.issue.number,
          body: process.env.AI_RESPONSE
        })

By prompting the AI model to return a fixed string if certain criteria are met (in this case, a good bug report was filed with enough reproduction information), we can create AI-powered conditional logic in our workflows.

An issue on GitHub named "Doesn't work on firefox" with no description and a bug label. The github-actions bot responds asking for more information - specifically reproduction steps, expected and actual behavior, and browser and operating system details.

Example two: Creating release notes from merged pull requests

This example will show you how to use the gh CLI with the gh-models extension. You can find the full workflow in this repo.

Generating thorough release notes with new versions of a project can take time, between collating what’s changed and finding a succinct way to explain it to users.

But you can actually trigger GitHub Actions workflow steps  when pull requests are merged and use the GitHub CLI to gather information and take action, including calling models. The workflow below, for example, will summarize merged pull requests and add them to a release notes issue — showing how you can save time and energy with each pull request.

To set up this workflow, create a new label called release, and create one issue with this label called Publish next release changelog. Then, create a new file in your repository’s .github/workflows directory called release-notes.yml. It will trigger whenever a new pull request is closed, and its single job conditionally will run only if its merged status is true. 

name: Add to Changelog

on:
  pull_request:
    types:
      - closed

permissions:
  pull-requests: read
  issues: write
  contents: read
  models: read

jobs:
  add_to_changelog:
    if: github.event.pull_request.merged == true
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

Install the gh-models extension with a new step, providing your workflow’s token which now has permissions to use GitHub Models:

- name: Install gh-models extension
  run: gh extension install https://github.com/github/gh-models
  env:
    GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

The rest of the steps will take place in one step:

- name: Summarize pull request and append to release issue
  env:
    GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  run: |-
    PR_NUMBER="${{ github.event.pull_request.number }}"

    # Fetch PR and save to a file
    gh pr view "$PR_NUMBER" --json title,body,comments,reviews > pr.json
    
    # Generate a summary using the model by reading from file
    cat pr.json | gh models run xai/grok-3-mini \
      "Given the following pull request information, generate a single, clear, and concise one-line changelog entry that summarizes the main change (feature, fix, or bug) introduced by this PR. Use neutral, user-facing language and avoid technical jargon or internal references. Only write the line, with no additional introduction or explanation text." > summary.md

    # Fetch release issue number
    RELEASE_ISSUE=$(gh issue list --label release --limit 1 --json number --jq '.[0].number')

    # Fetch current release issue body
    RELEASE_ISSUE_BODY=$(gh issue view "$RELEASE_ISSUE" --json body --jq '.body')

    # Append summary to release issue body
    FORMATTED_LINE="- $(cat summary.md) (#$PR_NUMBER)"
    NEW_BODY="${RELEASE_ISSUE_BODY}"$'\n'"$FORMATTED_LINE"

    # Update the release issue with the new body
    gh issue edit "$RELEASE_ISSUE" --body "$NEW_BODY"

The pull request’s title, body, comments, and reviews are grabbed and passed to a model using the gh models run command. The release issue is fetched and updated with the summarized line.

A pull request named Publish Next Release Changelog. The description has two bullet list items - each one describing a change in 8-12 words with a link to the merged pull request.

Example three: summarizing and prioritizing issues

This example demonstrates how to use the ⁠GitHub CLI with the ⁠gh-models extension and a prompt file to automate a more complex, scheduled workflow. Review the full workflow file and prompt file.

It’s easy to lose track of new activity, especially as your project grows. And even then, actually keeping track of repeated issues and themes requires a surprising amount of time. To open a weekly issue to summarize, thematize, and prioritize newly opened issues, you can trigger GitHub Actions on a schedule. 

To set up the workflow, create a new file in your repository’s .github/workflows directory called weekly-issue-summary.yml. It will trigger every Monday at 9 a.m. 

name: Weekly Issue Summary

on:
  workflow_dispatch:
  schedule:
    - cron: '0 9 * * 1'

permissions:
  issues: write
  contents: read
  models: read

jobs:
  create_weekly_summary:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Install gh-models extension
        run: gh extension install https://github.com/github/gh-models
        env:
          GH_TOKEN: ${{ github.token }}

Create a new step to get open issues from the last week and save them to a file:

 - name: Get issues from the past week and summarize
  id: get_issues
    run: |-
      LAST_WEEK=$(date -d "7 days ago" +"%Y-%m-%d")
      gh search issues "created:>$LAST_WEEK" --state=open --json title,body,url --repo ${{ github.repository }} > issues.json

      # further code will go here
    env:
      GH_TOKEN: ${{ github.token }}

Pass in the week’s worth of issues to a gh models run call:

cat issues.json | gh models run --file prompts/issue-summary.prompt.yml > summary.md

Unlike the previous example, a separate prompt file is being used by this command. Create a prompts directory in your repository and, within it, a issue-summary.prompt.yml file:

name: Issue summarizer
description: Summarizes weekly issues
model: openai/gpt-4.1
messages:
  - role: system
    content: You are a helpful issue summarizer. When given issue content, respond in markdown format.
  - role: user
    content: "Please summarize the following issues into a few short bullet points. Include links if provided. If possible, pull out general themes and help the team prioritize based on impact. Issues begin here:\n {{input}}"

This file contains all of the required information: the model, the system and user prompts, and, optionally, parameters used to tune your response. By using a .prompt.yml file, you can also leverage the GitHub Models’ repository integration to iterate on the prompt with a rich UI.

Back in the workflow file, straight under the gh models run command, create the issue with the summary:

ISSUE_TITLE="Issue Summary - $(date -d '7 days ago' '+%B %d') to $(date '+%B %d')"
gh issue create --title "$ISSUE_TITLE" --label summary --body-file summary.md
An issue with the title "Issue Summary - June 16 to June 23". It has three sections - an issue summary which details and links each issue that has been opened, general themes which contains three groupings for the issues, and suggested prioritization. The top issue is on data integrity - issue 37.

Whether you start simple with the AI inference action, use the gh-models CLI with inline prompts, or create full-featured, prompt-driven workflows, GitHub Models makes it easy to scale your processes with AI. 

Just add the right permissions, pick an example above, and try out GitHub Models in your next workflow.

The post Automate your project with GitHub Models in Actions appeared first on The GitHub Blog.

]]>
89874
Onboarding your AI peer programmer: Setting up GitHub Copilot coding agent for success https://github.blog/ai-and-ml/github-copilot/onboarding-your-ai-peer-programmer-setting-up-github-copilot-coding-agent-for-success/ Thu, 31 Jul 2025 17:12:43 +0000 https://github.blog/?p=89858 Learn how to configure Copilot coding agent’s environment, optimize project structure, use custom instructions, and extend its capabilities with MCP servers.

The post Onboarding your AI peer programmer: Setting up GitHub Copilot coding agent for success appeared first on The GitHub Blog.

]]>

We often describe GitHub Copilot as an AI peer programmer, or an AI member of the team. With agentic features like coding agent, you can assign issues to Copilot, and it will diligently get to work behind the scenes, creating a proposed solution to the problem, all without even asking for a cup of coffee.

Much of the initial setup for Copilot coding agent is similar to onboarding a new developer – like providing good documentation and streamlining the setup process. But since it’s AI, there are a few things that make Copilot unique as a team member (aside from it not needing caffeine).

So let’s explore how this is done. We’ll start by examining the flow Copilot coding agent follows, and key strategies to ensure Copilot has the resources it needs to generate the best possible pull request.

Inside Copilot coding agent’s workflow: From issue to ready‑to‑review pull request

When you assign an issue to Copilot, it follows a set pattern:

  1. Creates a branch for the code it will create.
  2. Creates a pull request to track its work and communicate with the team.
  3. Creates a contained environment for its work (running inside GitHub Actions).
  4. Reads the issue or prompt to understand the requested task.
  5. Explores the project to determine the best approach to tackle the problem.
  6. Works iteratively toward a solution.
  7. Finalizes its work, updates the pull request, and notifies the team the pull request is ready to be reviewed.

By understanding this flow, we can work to ensure Copilot is set up for success.

The first two steps — creating the pull request and branch — are self-contained, and there’s no additional work for us to do to help Copilot. 

So, let’s skip right to the third step — the environment — where we can configure everything Copilot might need in the environment where it’ll write the code and run tasks as it generates the pull request.

Configure Copilot’s environment with GitHub Actions

In keeping with the analogy of onboarding a new developer, let’s consider the environment in which GitHub Copilot — or really any developer — does its work. Before you’re able to be productive, you need specific services, libraries, and frameworks installed.

Copilot is the exact same. In order for Copilot to add a new feature and run the necessary tests to ensure everything works, it needs access to all the tooling the rest of your team has. We’ll do this with a custom workflow file.

Coding agent uses a container running inside GitHub Actions. If you’re not already familiar with Actions, it’s our automation platform, and is configured using YAML files, which describe the necessary tasks that need to be completed. 

Actions is often used for CI/CD, so tasks like testing, deployment, etc. In this case, Actions hosts the container coding agent will use for its work. And we can take advantage of the ability to script tasks in YAML to ensure said container is set up correctly!

💡Pro tip: There’s a good chance you already have a workflow for creating an environment, which could be used for development — say like the one used when running various tests or validation scripts. You can absolutely reuse those workflows for Copilot coding agent’s environment!

Example Copilot setup workflow file

To do this, create a new workflow file located at .github/workflows/copilot-setup-steps.yml with a job titled copilot-setup-steps. Inside the job, you’ll list all of the steps to install the necessary requirements for the environment. Let’s say, for example, we’re building a Python app that uses SQLite. We could have a workflow file like the following, which will be run to set up the environment for Copilot:

name: "Copilot Setup Steps"

# Automatically run the setup steps when they are changed
# Allows for streamlined validation,
# and allow manual testing through the repository's "Actions" tab

on:
  workflow_dispatch:
  push:
    paths:
      - .github/workflows/copilot-setup-steps.yml
  pull_request:
    paths:
      - .github/workflows/copilot-setup-steps.yml

jobs:
  # The job MUST be called `copilot-setup-steps`
  # otherwise it will not be picked up by Copilot.
  copilot-setup-steps:
    runs-on: ubuntu-latest

    # Permissions set just for the setup steps
    # Copilot has permissions to its branch
    
    permissions:
      # To allow us to clone the repo for setup
      contents: read

    # The setup steps - install Python and our dependencies
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: "3.13"
          cache: "pip"

      - name: Install Python dependencies
        run: pip install -r requirements.txt

      - name: Install SQLite
        run: sudo apt update && sudo apt install sqlite3

Whenever an issue is assigned to Copilot, it will run this workflow to configure its environment so it’ll have everything it needs!

💡 Pro tip: If you know something should be done a particular way, tell Copilot! In our above example, Copilot could install the requisite services on its own. However, doing so may lead to unexpected versions or other mistakes. As I always like to joke, don’t be passive aggressive with Copilot. 😀

Set Copilot up for success with well-written issues and prompts

Speaking of not being passive aggressive, now’s the perfect time to focus on the next step Copilot follows: reading the issue. This will be Copilot’s entry point into creating the pull request you’ll later review. Remember that the more clearly defined the issue, the better quality the pull request. 

The best approach is to think about how you’d like to see the first issue you’re assigned on a new project. Chances are, you’d appreciate the following:

  • Clearly defined problem statement or user story
  • If it’s a bug, the full error message, stack trace, or output, and steps to reproduce the problem
  • Any relevant history or approaches that have been tried previously
  • Suggestions on how to approach the issue

The same holds true with Copilot. Let’s say you needed to migrate a set of tests from unittest to pytest. Sure,Copilot could likely figure out the best approach on its own, but taking a couple of minutes to write out a good issue goes a long way to ensuring Copilot’s PR will be accepted and merged into your codebase.

Here’s an example of a good issue (for developers and Copilot, alike!): 

Title: Migrate server tests from unittest to pytest

Body:

We are looking to migrate from unittest to pytest to take advantage of some pytest specific features.

Requirements:

- A new folder called `migrated_tests` will be created with the new pytest tests.
- All existing unittests are rewritten using pytest style in the `migrated_tests` folder, keeping the exact same functionality and code coverage.
- Documentation is updated, highlighting the migration and steps required to run the new tests.
- All new tests pass.

Existing resources:

- All existing tests exist in `server/tests`
- There is a script at `scripts/run-server-tests.sh` which is used to run tests and generate code coverage reports

Recommended approach:

- Explore existing tests to determine their functionality
- Read the coverage reports to determine existing code coverage
- Recreate the tests one by one, testing along the way, to ensure compatibility
- Run all tests at the end to ensure everything passes
- Generate a code coverage report to demonstrate code coverage has been maintained
- Generate documentation of the migration and how to run the new tests

Make your repository welcoming (for developers and AI)

Let’s stick with the analogy of onboarding a developer to a new team and project, something I’ve done a handful of times throughout my career. 

When I am onboarding somewhere new, I get my laptop set up and try to overcome my first-day-of-school butterflies — because I know there’s a lot of work to be done. Setting aside a conversation about my anxiety, let’s explore everything I need to do in order to be productive.

First, I need to figure out where, and how, my code should be created. What’s the project structure? What are the rules and guidelines that need to be followed? Are we using tabs or spaces? (The right answer, of course, is spaces.)

GitHub Copilot needs to know these same things! Fortunately, standard best practices around documentation and project structure will help Copilot the same way it helps developers.

💡Pro tip: Understanding how Copilot tackles problems can help you improve how you use it. Here’s how to do that: On the PR Copilot created you’ll see a View session button that shows you everything Copilot did (or is doing if the session is currently active). This is both a great way to validate Copilot’s work and see how it approaches tasks. You can then use this information to further refine your approach to assigning tasks and configuring Copilot’s environment.

Optimize project structure and docs so Copilot finds the right info fast

Let’s say we assign an issue to Copilot, and ask it to add search functionality to an app. When Copilot takes on an issue, the first thing it does is explore the codebase. It’ll look for README files, and, unlike this developer, actually reads the documentation to learn about the project before writing code. It’ll perform searches in the codebase for anything related to interacting with the database, and read through the files it discovers. Then it’ll get to work.

This is the same approach you’d likely take as a developer if you were assigned the task. So ensuring the project structure has the resources and entities to make it as welcoming to new developers as possible sets up everyone (including your AI teammates) for success.

This includes having a robust and up-to-date README for the project and services, comments in code to describe what and how operations are performed, and good practices followed in naming classes, functions and variables. Additionally, having a logical project structure that follows accepted best practices in folder names and entity groupings will provide a more predictable environment for Copilot (and the rest of your team).

Document institutional knowledge with Copilot custom instructions

One of the best ways to provide guidance to Copilot is through the use of custom instructions. Custom instructions are just like they sound: a set of instructions specifically for Copilot. They can be about the various rules and guidelines you have around formatting code, or the institutional knowledge that all developers “inherently know,” but isn’t written down anywhere.

Copilot coding agent supports two types of instructions files: copilot-instructions.md, which are repository-wide and applied to all requests, and <file-name>.instructions.md, which can be targeted at specific types of files.

Repository level instructions files

Repository level instructions filed, stored in .github/copilot-instructions.md in the codebase, house notes which are generally relevant to all requests made to Copilot. Some key pieces of information to include would be:

  • An overview of what you’re building, and how you’re building it
  • Any overarching user stories
  • Frameworks and libraries in use
  • The project structure, highlighting key files and folders
  • Global coding guidelines and rules

In the example below, note how we’ve started with a quick overview of the app, the expected flow for the user, frameworks and rules, and the resources available.

# Classic arcade

This project hosts a classic arcade, themed after the 1980s 8-bit games.

## Standard player flow

1. Player opens app and sees list of games.
2. Player selects game to play.
3. Player sees a splash screen with the message "Insert quarter".
4. Player presses space to start game and plays game
6. After game ends, the "Game over" message is displayed.
7. The player score is checked against high scores. If the score is in top 10, user is prompted for their initials (3 initials).
8. High scores are displayed, and an option to return to the main menu to start over again.

## Frameworks

- Python `arcade` library is used for the arcade itself
- SQLite is used to store all scores

## Coding guidelines

- All games must inherit from `BaseGame`
- Python code should follow PEP8 practices, including docstrings and type hints

## Project structure

- `data`: Stores data abstraction layer and SQLite database
- `games`: Stores collection of games and `BaseGame`
- `app`: Stores core app components including menuing system

Everything documented in the Copilot instructions document above could likely be figured out by Copilot as it does its investigation. But listing your requirements and resources helps ensure it has the right information, especially since there’s likely code that deviates from the accepted best practices of your organization.

> Note: This author’s code is always perfect, so that isn’t applicable to me, of course. 😉

Targeted instructions files

Obviously the code that resides in a unit test is very different from code in a data abstraction layer, which is very different from … While having repository-wide instructions is powerful, we typically have rules around specific types of files as well. Copilot coding agent supports this through the use of <file-name>.instructions.md files, which reside in the codebase in the .github/instructions/ folder (or subfolders inside of there).

These targeted instructions files can contain an applyTo section, which allows you to set a glob pattern to identify the files to which the rules should apply. Sticking with the scenario from above — building out a classic arcade — we might have all games in a games folder as Python files. The pattern we’d use would be **/games/*.py. Within that section, you can add instructions specific to these files, such as which base class to inherit from and any testing requirements.. An example .github/instructions/game.instructions.py might look like the following:

---
applyTo: **/games/*.py
---

## Resources and requirements

- All games inherit from `BaseGame`
- Unit tests are required for all games, focused on core functionality
- When adding a new game to the arcade ensure sample high scores are added to the database

## Arcade framework notes

- `rectangle` is always abbreviated as `rect` in the framework
- The `BaseGame` class contains numerous abstractions to streamline game creation

Notice how we’re listing requirements and resources. We also added a note about rectangle being abbreviated as rect, which is there to help Copilot with common mistakes it might make.

💡Pro tip: Instructions files are a great way to guide Copilot in the right direction when you see it making particular types of mistakes.

A closing thought on instructions files

Investing time in creating a robust set of instructions files will both aid Copilot when you use it in the IDE and when you assign tasks to Copilot coding agent. In fact, there’s a good chance you’re already familiar with the concepts in this section if you’re experienced with Copilot. Because these become artifacts in the project, they’ll continue to pay dividends in both productivity and suggestion quality.

Extend Copilot with MCP to give it more context and tools

All developers need a helping hand at some point. It might be retrieving a specific discussion from your GitHub repository to learn more about the history of a feature, or looking up the syntax for implementing a particular algorithm or block of code.

AI agents can perform these tasks by using MCP, or Model Context Protocol. MCP is an open standard from Anthopic designed to help AI connect to key services and tools. This helps AI agents execute tasks on your behalf — but it also allows you to give the model more context by connecting it to more sources of data and information (like GitHub!). 

Here’s why this matters: GitHub Copilot can use MCP servers! By default, two MCP servers are available when you use its coding agent: GitHub and Playwright. The former allows Copilot to interact with your repository, searching for issues and other information while the latter allows Copilot to generate Playwright tests for end-to-end or acceptance testing.

Example: Azure MCP server for Bicep generation

Let’s take Azure Bicep as an example, which is a domain-specific language (DSL) for defining Azure resources. To do its best work with a DSL, like Azure Bicep, Copilot benefits from a virtual helping hand in generating the code. Fortunately, there’s an Azure MCP server available that Copilot can use to get a bit of support.

If your team is already using MCP servers for the project in VS Code, the existing .vscode/mcp.json file in your project can be used by Copilot to identify MCP servers! Otherwise, you can configure MCP servers specifically for Copilot coding agent in the Settings tab of your project, under Copilot then Coding agent, where you’ll have a textbox to paste in the JSON.

Keeping with our example of wanting to better support Bicep creation, the JSON below enables the Azure MCP server while specifying we only want Bicep schema support. 

{
  "mcpServers": {
    "AzureBicep": {
      "type": "local",
      "command": "npx",
      "args": [
        "-y",
        "@azure/mcp@latest",
        "server",
        "start",
        "--namespace",
        "bicepschema",
        "--read-only"
      ]
    }
  }
}

Manage internet access and data exfiltration risks with Copilot’s firewall

You may have noticed the type option in the previous MCP example is set to local. This means that the server will be accessed inside the container without Copilot needing to contact an external service. But this also implies the possibility of a remote server, which begs the question: Is Copilot allowed to access the internet? And if so, how can we control it?

Copilot coding agent has a default firewall, which effectively limits Copilot’s access to core services, such as package hosting services like npm and pip. This helps you manage data exfiltration risks. For instance, if malicious instructions are somehow given to GitHub Copilot, it could lead to code or other sensitive information being leaked to remote locations.

If you are adding a remote MCP server, or need to allow Copilot to access internet resources, you will need to update the firewall, which you can do by updating the allow list. This is available under your repository’s settings, inside Copilot, then Coding agent (conveniently, that’s the same screen as configuring your MCP servers!). 

Welcome to the team, Copilot!

Just like any good teammate, GitHub Copilot coding agent thrives when it’s set up for success! By investing a little time upfront to configure its environment, craft clear issues, optimize your project, and leverage custom instructions and MCP servers, you’ll empower Copilot to deliver its best work.

With these tips in your arsenal, you’ll be well on your way to getting higher quality pull requests from Copilot coding agent, and a more productive development experience. 

Ready to see the magic happen? Learn more about GitHub Copilot!

As for me, I need to refill my coffee cup.

Learn how to assign and complete issues with coding agent in GitHub Copilot >

The post Onboarding your AI peer programmer: Setting up GitHub Copilot coding agent for success appeared first on The GitHub Blog.

]]>
89858
A practical guide on how to use the GitHub MCP server https://github.blog/ai-and-ml/generative-ai/a-practical-guide-on-how-to-use-the-github-mcp-server/ Wed, 30 Jul 2025 16:00:00 +0000 https://github.blog/?p=89799 Upgrade from a local MCP Docker image to GitHub’s hosted server and automate pull requests, continuous integration, and security triage in minutes — no tokens required.

The post A practical guide on how to use the GitHub MCP server appeared first on The GitHub Blog.

]]>

Running the Model Context Protocol (MCP) server locally works, but managing Docker, rotating access tokens, and pulling updates is a hassle. GitHub’s managed MCP endpoint eliminates these infrastructure headaches, letting you focus on what you love — shipping code.

In this 201-level tutorial, we’ll walk through upgrading from the local MCP setup to GitHub’s managed endpoint. You’ll get OAuth authentication, automatic updates, and access to toolsets that open the door to richer AI workflows you simply can’t pull off with a bare‑bones local runtime.

You’ll also learn how to customize tool access with read-only modes, streamline your AI workflows with dynamic toolsets, and get ready for agent-to-agent collaboration using GitHub Copilot.

But first, why switch to our hosted server? 

Running the open source MCP server locally works, but it carries hidden costs. Here’s what changes when you go remote:

Local Docker serverHosted MCP endpoint
Maintain a Docker image, upgrade manuallyGitHub patches and upgrades automatically
Manage personal‑access tokens (PATs)Sign in once with OAuth; scopes handled for you
Expose the server on localhost onlyReachable from any IDE or remote‑dev box
Full write access unless you customise the binaryBuilt-in read‑only switch and per‑toolset flags

If you need an air‑gapped environment, stick with local. For most teams, the hosted server eliminates infrastructure work and lets you focus on automation. With that, let’s dive in.

A few things you need before you get started:

  • GitHub Copilot or Copilot Enterprise seat
  • VS Code 1.92+ (or another MCP‑capable client)
  • Network access to https://api.githubcopilot.com
  • A test repository to experiment with

Step 1: Install the remote MCP server

Setting up GitHub’s remote MCP server server is a breeze compared to local Docker-based installations. Hosted by GitHub, it eliminates the need for managing Docker containers or manually handling updates, offering a streamlined, cloud-native experience.

How to install the remote server on VS Code or VS Code Insiders:

  1. Open the command palette and run:
    > GitHub MCP: Install Remote Server
  2. Complete the OAuth flow to connect your GitHub account.
  3. Restart the server to finish setup.

For any other client

Set the server URL to: https://api.githubcopilot.com/mcp/

Then authenticate when prompted.

Validate your connection with a quick check

curl -I https://api.githubcopilot.com/mcp/_ping
# HTTP/1.1 200 OK

If you see 200 OK, you’re good to go.

Once installed, the remote server replaces the local one, and you’re ready to roll. That means no more Docker or tokens, just a simple integration.

Step 2: Configure access controls

Use read-only mode for safe exploration.

Working in a sensitive environment? Testing in production? Demoing to stakeholders? Flip the server to read-only mode:

{
  "servers": {
    "github": {
      "type": "http",
      "url": "https://api.githubcopilot.com/mcp/",
      "headers": {
        "X-MCP-Readonly": "true"
      }
    }
  }
}

The agent can read issues, pull requests, and code but can’t push changes. Perfect for code reviews where you want context without risk.

Use case: Pull request viewer

Need to review pull requests without modifying anything? This setup gives you safe, read-only access — perfect for browsing changes, leaving comments, or gathering context without risk of altering code.

  1. Go to the GitHub MCP server repo.
  2. Navigate to the “Remote Server” section.
  3. Choose the pull request read-only variant.
  4. Click Install Read Only.

You’ll now see tools like listPullRequests, getPullRequest, and searchPullRequests, but no write access. And since these tools don’t make changes, VS Code skips the permission prompts for a seamless experience.

Step 3: Try it out with these three hands-on examples

Want to see how Copilot agent mode works in practice? These real-world examples show how the agent can handle everyday developer tasks — like managing pull requests, debugging workflows, and triaging security alerts — without needing local setup or manual digging. Just prompt and go.

Example 1: Add a CODEOWNERS file and open a pull request

  1. Open your repo Ask Copilot Agent.
  2. Prompt your agent: "Add a CODEOWNERS file for /api/** assigning @backend-team, then open a draft pull request."
  3. The agent will:
  • Use repos.create_file to add the CODEOWNERS file.
  • Call pull_requests.open to create the pull request.
  • Execute pull_requests.request_reviewers to assign reviewers.

No local cloning, no manual file creation. Just prompt and ship.

Example 2: Debug a failed workflow

Prompt: “Why did the release.yml job fail last night?”

The agent pulls logs with actions.get_workflow_run_logs, analyzes the stack trace, and suggests fixes. It’s like having a senior engineer review your CI/CD failures.

Example 3: Triage security alerts

Prompt: “List critical Dependabot alerts across all my repos and create issues for each.” 

The server returns alerts via dependabot.list_dependabot_alerts, then the agent creates focused issues only where needed.

Step 4: Troubleshooting tips with the GitHub remote MCP server
 

SymptomLikely causeFix
401 Unauthorized on installLeft‑over GITHUB_TOKEN env varUnset the var and rerun OAuth flow
Tools don’t appearCorporate proxy blocks api.githubcopilot.comAdd proxy settings or allowlist the domain
Model times outLarge toolset enabledRestrict to needed toolsets only

Step 5: What’s next with security and agentic workflows

The GitHub MCP server is actively evolving. Here’s what’s coming next:

Secret scanning in MCP

Soon, the MCP server will detect and block AI-generated secrets, just like GitHub prevents you from pushing secrets in pull requests. You can override if needed, but the default protects your data, whether from a prompt injection or by accident.

Assign issues to Copilot

Direct integration with Copilot’s coding agent means you’ll be able to:

  • Assign issues directly to Copilot.
  • Trigger completions from VS Code.
  • Watch as agent-to-agent workflows unfold across tools.

The future is agents collaborating with agents, and GitHub MCP is the foundation.

Want to contribute?

The GitHub MCP project is fully open source and growing fast.

📌 Explore the repo: See how tools are built and contribute your own.
📌 File issues: Help shape the protocol and tooling.
📌 Join discussions: Connect with other builders on GitHub and Discord.

Whether you’re building tools, providing feedback, or exploring AI-powered development, there’s a place for you in the MCP ecosystem.

Ready to Ship?

The GitHub remote MCP server removes infrastructure overhead so you can focus on building better automations. No more Docker babysitting, no more token rotation, just OAuth once and start shipping.

Remember: the best infrastructure is the infrastructure you don’t have to manage.

Read the full documentation to get started, or dive into the examples above and start experimenting today.

Read our guide to building secure and scalable remote MCP servers >

The post A practical guide on how to use the GitHub MCP server appeared first on The GitHub Blog.

]]>
89799
From first commits to big ships: Tune into our new open source podcast https://github.blog/open-source/maintainers/from-first-commits-to-big-ships-tune-into-our-new-open-source-podcast/ Tue, 29 Jul 2025 16:31:29 +0000 https://github.blog/?p=89807 Introducing the brand new GitHub Podcast: A show dedicated to the topics, trends, stories, and culture in and around the open source developer community on GitHub.

The post From first commits to big ships: Tune into our new open source podcast appeared first on The GitHub Blog.

]]>

What makes open source work, and why do so many of us keep showing up to build together? On the GitHub Podcast, we dive into the stories behind the code: the projects, the people, and the ideas shaping the open source ecosystem.

At GitHub, we know open source has always been the launchpad for what’s next. But 2025 feels different. Everything new in software from AI agents to edge runtimes to climate-tech dashboards starts life in a public repository where anyone can fork, remix, and improve it overnight. When you invest in that commons, you’re not just sponsoring code; you’re underwriting the world’s R&D engine. 

And that’s what we want to explore in our latest podcast with an eye towards everything that makes open source what it is today. 

(And yes, we also answer essential questions like: how exactly do you do a hackathon on a plane?)

Meet the core contributors

I’m joined by an amazing crew of rotating hosts including Cassidy Williams, Kedasha Kerr, Andrea Griffiths, and me, Abby Cabunoc Mayes — all of us long-time contributors to different parts of the open source world. Together, we’ll explore what’s exciting, challenging, and evolving in open source today. Whether it’s community building, open science, developer education, or building in public, we each bring a unique perspective to the conversation.

In today’s episode, we introduce ourselves, share how we got involved in open source, and reflect on what keeps us going. We talk about the importance of creating beginner content in a world seemingly saturated with beginner developer content with Kedasha, and Cassidy talks about how overhearing a conversation as a teenager sparked her love of code. 

Plus, we spotlight some of our favorite open source projects that have caught our eyes this week. Here’s a sneak peek:

  • Anime.JS, a visually stunning JavaScript animation library that sparks creativity.
  • Docs, a collaborative open source document editor developed by the French and German governments.
  • CSS Zero, a no-build frontend starter kit that simplifies web development.

What’s in the build?

Every two weeks we’ll share a new episode with stories from maintainers, contributors, and builders across the open source ecosystem. We’ll talk about tools, standards, and the side projects that spark joy (and sometimes chaos). You’ll also hear from special guests like Jason Lengstorf, who makes TV for developers, and Keeley Hammond, a core maintainer of Electron, who’ll share their own journeys and insights. Whether you’re just getting started, or you’ve been maintaining projects for years, there’s something here for you.

Coming up next: we dive into the Model Context Protocol (MCP), what it is, why it matters, and how it’s helping make AI tools more transparent and interoperable. We’ll explore how MCP builds on the long history of open standards, and what it unlocks for developers today.

Don’t want to miss out? Subscribe now to stay up to date on our latest episodes.

The post From first commits to big ships: Tune into our new open source podcast appeared first on The GitHub Blog.

]]>
89807
Scaling for impact: How GitHub Copilot supercharges smallholder farmers https://github.blog/open-source/social-impact/scaling-for-impact-how-github-copilot-supercharges-smallholder-farmers/ Mon, 28 Jul 2025 19:53:32 +0000 https://github.blog/?p=89763 Empowering 10 million farm families by 2030 to generate $1 billion in new revenue. How GitHub helps One Acre Fund’s mission — driving real impact across Africa.

The post Scaling for impact: How GitHub Copilot supercharges smallholder farmers appeared first on The GitHub Blog.

]]>

What started in 2006 with just 40 farm families in western Kenya has grown into a powerful movement. Today, One Acre Fund serves 5 million farm families across ten countries in eastern and southern Africa. Their ambitious goal? By 2030, they aim to support 10 million farm families annually. How? By using open source technology and AI, aiming to generate an astounding $1 billion in new revenue for these communities.

Cultivating impact with technology

For smallholder farmers — those typically working with an acre or less of land — intensifying agriculture is crucial for their prosperity. This process of producing more food with the same amount of land, not only brings higher crop yields, but stimulates the economy, strengthens community, and enables farmers to scale. One Acre Fund’s core mission is to empower these farmers, providing a direct pathway out of poverty. But unlike traditional microfinance, they don’t just loan cash. Instead, they provide vital farm resources like fertilizer and seed, plus training and services, directly equipping farmers with the tools they need to succeed. They also help the farmers they serve to improve their soil health and plant trees to not only increase yields but also help farmers be more resilient to weather changes due to climate change.

In the past, farmers used to fear using technology. But, as we provide training to them, they’re now eager to use it.

Blaise Murame, Regional Lead, One Acre Fund

Technology is at the heart of One Acre Fund’s rapid growth. They’ve transitioned from an entirely analog approach — meeting farmers in the field with paper records — to a highly digitized system. This transformation has revolutionized their operations, making everything from logistics and delivery to farmer registration and the development of training materials more efficient. Farmers, initially hesitant, are now eager to embrace this tech, after receiving resources and tools on time and achieving their goals faster than ever before.

Growing products to empower farmers

A significant part of One Acre Fund’s tech leap comes from their adoption of GitHub Copilot

Since the coming of GitHub Copilot, the time it used to take us three weeks, that development work can be finished within a week. That’s affecting our goals – we’re able to set more goals than last year.

Yididiya Gebredingel, Developer, One Acre Fund

By introducing GitHub Copilot, One Acre Fund has been able to move much faster on their development, and they can focus on the pieces that are actually creating impact in the field. This acceleration has enabled them to set and achieve more goals, with developers completing projects three times faster and over 30% of their work being assisted by AI.

As a nonprofit, working with some of the world’s poorest populations means operating on razor-thin margins.This makes the cost-effectiveness of their solutions paramount. Open source technology provides the ideal balance, offering both “solution maturity and solution flexibility” without the burden of exponentially growing license fees as they scale. Embracing the open source community is a strategic move for One Acre Fund, as they’ve migrated most of their core operational systems to open source to leverage collaborative development and community support.

As a nonprofit, we can’t tolerate license fees that will grow exponentially as we scale. Open source gives us the right balance between solution maturity and solution flexibility.

Sarah Hylden, Global Director of Operations, One Acre Fund

Ultimately, One Acre Fund believes that if you have an intervention that works to create a sustainable pathway out of poverty for farmers, and you know it works, then you have a moral obligation to scale it. And with the help of GitHub Copilot, they are doing just that — moving faster and making a greater impact in the lives of millions of farm families.

Explore a better way of working by trying GitHub Copilot for free today, or if you’re a nonprofit organization, check out GitHub for Nonprofits for exclusive discounts.

The post Scaling for impact: How GitHub Copilot supercharges smallholder farmers appeared first on The GitHub Blog.

]]>
89763
How to build secure and scalable remote MCP servers https://github.blog/ai-and-ml/generative-ai/how-to-build-secure-and-scalable-remote-mcp-servers/ Fri, 25 Jul 2025 17:12:02 +0000 https://github.blog/?p=89756 More context can mean more attack surfaces for your projects. Be prepared for what lies ahead with this guide.

The post How to build secure and scalable remote MCP servers appeared first on The GitHub Blog.

]]>

Model Context Protocol (MCP) enables AI agents to connect to external tools and data sources without having to implement API-specific connectors. Whether you’re extracting key data from invoices, summarizing support tickets, or searching for code snippets across a large codebase, MCP provides a standardized way to connect LLMs with the context they need. 

Below we’ll dig into why security is such a crucial component to MCP usage, especially with a recent specification release, as well as how developers of both MCP clients and MCP servers can build secure integrations from the get-go.

Why security matters for MCP

Unlike traditional APIs that serve known clients in somewhat controlled environments, MCP servers act as bridges between AI agents and an unlimited number of data sources that can include sensitive enterprise resources. So, a security breach won’t just compromise data — it can give malicious actors the ability to manipulate AI behavior and access connected systems.

To help prevent common pitfalls, the MCP specification now includes security guidelines and best practices that address common attack vectors, like confused deputy problems, token passthrough vulnerabilities, and session hijacking. Following these patterns from the start can help you build systems that can handle sensitive tools and data.

Understanding the MCP authorization

The MCP specification uses OAuth 2.1 for secure authorization. This allows MCP, at the protocol level, to take advantage of many modern security capabilities, including:

  • Authorization server discovery: MCP servers implement OAuth 2.0 Protected Resource Metadata (PRM) (RFC 9728) to advertise the authorization servers that they support. When a client attempts to access a protected MCP server, the server will respond with a HTTP 401 Unauthorized and include a WWW-Authenticate header pointing to the metadata endpoint.
  • Dynamic client registration: This is automatic client registration using OAuth 2.0 Dynamic Client Registration Protocol (RFC 7591). This removes the need for manual client setup when AI agents connect to MCP servers dynamically.
  • Resource indicators: The specification also mandates RFC 8707 Resource Indicators, ensuring that tokens are bound to specific MCP servers. This prevents token reuse attacks and helps maintain clear security boundaries.

Even with the latest changes to authorization specs, like the clean split between the responsibilities of the authorization server and the resource server, developers don’t need to worry about implementing security infrastructure from scratch. (Because the requirement to follow the OAuth2.1 conventions didn’t change.) So developers can just use off-the-shelf authorization servers and identity providers. 

Because MCP requires implementers to snap to OAuth 2.1 as the default approach to authorization, this also means that developers can use existing OAuth libraries to build the authorization capabilities into their MCP servers without anything super-custom. This is a massive time and effort saver.

The complete authorization flow

When it comes to connecting to protected MCP servers, a MCP client will need to somehow find out what credentials the server needs. Luckily, because of the aforementioned discovery mechanism, this is a relatively straightforward flow:

  1. Discovery phase. MCP client attempts to access MCP server without credentials (that is a token).
  2. Server response. MCP server returns a HTTP 401 Unauthorized response with a metadata URL in the WWW-Authenticate header.
  3. Metadata retrieval. MCP client fetches Protected Resource Metadata, parses it, and then gets the authorization server endpoints.
  4. Client registration. MCP client automatically registers with authorization server (if supported). Some clients may be pre-registered.
  5. Authorization request. MCP client initiates OAuth flow with Proof Key for Code Exchange (PKCE) and the resource parameter.
  6. User consent. The user authorizes access through the authorization server.
  7. Token exchange. MCP client exchanges authorization code for access token.
  8. Authenticated requests. All subsequent requests from MCP client to MCP server include Bearer token.

Nothing in the flow here is MCP-specific, and that’s the beauty of MCP snapping to a common industry standard. There’s no need to reinvent the wheel because a robust solution already exists.

Implementing authorization in MCP

Most OAuth providers work well for MCP server authorization without any additional configuration, though one of the more challenging gaps today is the availability of Dynamic Client Registration. However, support for that feature is slowly rolling out across the identity ecosystem, and we expect it to be more common as MCP gains traction.

Aside from the authorization server, when implementing authorization for your MCP server, you will need to consider several key components and behaviors:

  • PRM endpoint. The MCP server must implement the /.well-known/oauth-protected-resource endpoint to advertise supported authorization server scopes. The MCP TypeScript SDK already integrates this capability natively, with other MCP SDK support coming very soon.
  • Token validation middleware. You need to make sure that your MCP server is only accepting tokens meant for it. Many open source solutions, like PyJWT, can help you here by:
    • Extracting Bearer tokens from Authorization headers
    • Validating token signatures using your OAuth provider’s JSON Web Key Sets (JWKS) endpoint
    • Checking token expiration and audience claims
    • Ensuring tokens were issued specifically for your MCP server (this part is critical for the security of your infrastructure)
  • Error handling. Your MCP server will need to return proper HTTP status codes (HTTP 401 Unauthorized for missing/invalid tokens, HTTP 403 Forbidden for insufficient permissions) with appropriate WWW-Authenticate headers.

Anthropic, together with the broader MCP community, is working on integrating a lot of these capabilities directly into the MCP SDKs, removing the need to implement many of the requirements from scratch. For MCP server developers, this will be the recommended path when it comes to building implementations that conform to the MCP specification and will be able to work with any MCP client out there.

Handling multi-user scenarios

Multi-tenancy in MCP servers introduces unique security challenges that go beyond simple authorization and token validation. When your MCP server handles requests from multiple users — each with their own identities, permissions, and data — you must enforce strict boundaries to prevent unauthorized access and data leakage. This is a classic “confused deputy” problem, where a legitimate user could inadvertently trick the MCP server into accessing resources they shouldn’t.

OAuth tokens are the foundation for securely identifying users. They often contain the necessary user information embedded within their claims (like the sub claim for user ID), but this data must be rigorously validated, and not blindly trusted.

As mentioned earlier in the blog post, your MCP server is responsible for:

  1. Extracting and validating user identity. After validating the token’s signature and expiration, it can extract the user identifier from the claims.
  2. Enforcing authorization policies. Map the user identifier to an internal user profile to determine their specific permissions. Just because a user is authenticated doesn’t mean they are authorized to perform every action or access every piece of data that the MCP server makes available.
  3. Ensure correct token audience: Double-check that the token was issued specifically for your MCP server by validating the audience (e.g., in a JSON Web Token this can be the aud claim). This prevents a token obtained for one MCP server from being used to access another.

With the user’s identity and permissions established, data isolation becomes the next critical layer of defense. Every database query, downstream API request, cache lookup, and log entry must be scoped to the current user. Failure to do so can lead to one user’s data being accidentally exposed to another. Adhering to the principle of least privilege — where a user can only access the data and perform the actions strictly necessary for their tasks — is paramount.

As with other security-sensitive operations, we strongly recommend you use existing, well-tested libraries and frameworks for handling user sessions and data scoping rather than implementing your own from scratch.

Scaling with AI gateways

As your MCP server gains visibility and adoption, raw performance and basic authorization capabilities won’t be enough. You’ll face challenges like traffic spikes from AI agents making rapid-fire requests, the need to transform between different protocol versions as clients evolve at different speeds, and the complexity of managing security policies consistently across multiple server instances.

An AI gateway, similar to what you might’ve seen with API gateways before, sits between your MCP client and MCP server, acting as both a shield and a traffic director. It handles the mundane but critical tasks that would otherwise clutter your business logic, such as rate limiting aggressive clients, validating JWT tokens before they reach your servers, and adding security headers that protect against common web vulnerabilities.

AI gateway configuration for MCP servers

The great thing about using an AI gateway lies in centralizing cross-cutting concerns. Rather than implementing rate limiting in every MCP server instance, you configure it once at the gateway level. The same applies to JWT validation. Let the gateway handle token verification against your OAuth provider’s requirements, then forward only validated requests with clean user context to your MCP server. This separation of concerns makes maintainability and diagnostics much easier, as you don’t need to worry about spaghetti code mixing responsibilities in one MCP server implementation.

Consider implementing these essential policies:

  • Rate limiting to prevent resource exhaustion from runaway AI agents
  • Request/response transformation to handle protocol evolution gracefully
  • Caching for expensive operations that don’t change frequently
  • Circuit breakers that fail fast when downstream services are struggling

The AI gateway also becomes your first line of defense for CORS handling and automatic security header injections.

Production-ready patterns

With the basics out of the way, you’re probably wondering what special considerations you need to keep in mind when deploying MCP servers to production. This section is all about best practices that we recommend you adopt to build secure and scalable MCP infrastructure.

Better secrets management

We cannot not talk about secrets. Chances are that your MCP server needs to handle its own collection of secrets to talk to many different services, databases, or APIs that are out of direct reach of the MCP server consumers. You wouldn’t want someone to be able to have direct access to the credentials stored on the MCP server to talk to your internal APIs, for example.

Knowing this, secrets in MCP servers present a unique challenge: They’re needed frequently for things like OAuth validation, external API calls, and database connections, which makes them prime targets for attackers. Compromising a MCP server often means gaining access to a wide array of downstream systems. Robust secrets management is a non-negotiable requirement for anything with Internet access.

What we often see is that developers default to very basic implementations that are just enough to get things working, usually based on environment variables. While these are convenient for local development, they are a security anti-pattern in production. Environment variables are difficult to rotate, often leak into logs or build artifacts, and provide a static target for attackers.

The modern approach is to move secrets out of your application’s configuration and into a dedicated secrets management service like Azure Key Vault, AWS Secrets Manager, or HashiCorp Vault. These services provide encrypted storage, fine-grained access control, detailed audit trails, and centralized management.

But the most secure way to access these vaults is by eliminating the “bootstrap secret” problem altogether using workload identities (you might’ve heard the term “secretless” or “keyless”). Different providers might have a different term or implementation of it, but the gist is that instead of storing a credential to access the vault, your application is assigned a secure identity by the cloud platform itself. This identity can then be granted specific, limited permissions (e.g., “read-only access to the database credential“) in the secrets vault. Your MCP server authenticates using this identity, retrieves the secrets it needs at runtime, and never has to handle long-lived credentials in its own configuration.

This architecture enables you to treat secrets as dynamic, short-lived resources rather than static configuration. You can implement startup validation to fail fast when required secrets are missing and builtin runtime secret rotation capabilities. All your static secrets, such as API keys, can be easily and quickly refreshed without server downtime, dramatically reducing the window of opportunity for an attacker.

Finally, the principle of least privilege is critical at scale. Each instance of your MCP server should only have access to the secrets it absolutely needs for its specific tasks. This compartmentalization limits the blast radius of any single compromised instance, containing the potential damage.

Observability and monitoring

Building scalable and secure MCP servers implies that you have full visibility into their operations. That means that you need effective observability, having full access to a combination of logs, metrics, and traces.

Structured logging forms the foundation. The key is consistency across request boundaries. When an AI agent makes a complex request that triggers multiple tool calls or external API interactions, a unique correlation ID should be attached to every log entry. This lets you trace the entire journey through your logs, from the initial request to the final response.

Beyond basic logs, distributed tracing provides a detailed, hop-by-hop view of a request’s lifecycle. Using standards like OpenTelemetry, you can visualize how a request flows through your MCP server and any downstream services it calls. This is invaluable for pinpointing performance bottlenecks, like if a specific tool invocation is taking too long.

Security event logging deserves special attention in MCP servers because they’re high-value targets. Every authentication attempt, authorization failure, and unusual access pattern should be captured with enough context for future forensic analysis. This isn’t just compliance theater; it’s your early warning system for attacks in progress.

In turn, metrics collection should focus on the signals that matter: request latency (because AI agents have short attention spans), error rates (especially for authentication and authorization), and resource utilization. You should also implement a dedicated health endpoint that provides a simple up/down status, allowing load balancers and orchestration systems to automatically manage server instances.

Finally, all this data is useless without alerting and visualization. Set up automated alerts to notify you when key metrics cross critical thresholds (e.g., a sudden spike in HTTP 500 errors). Create dashboards that provide an at-a-glance view of your MCP server’s health, performance, and security posture. The goal is to gain end-to-end visibility that helps you detect and diagnose emerging issues before they impact users at scale.

Take this with you

Building secure and scalable MCP servers requires attention to authentication, authorization, and deployment architecture. The patterns in this guide will give you a head start in creating reliable MCP servers that can handle sensitive tools and data.

When building on top of a fast-paced technology like MCP, it’s key that you start with security as a foundation, not an afterthought. The MCP specification provides basic security primitives, and modern cloud platforms provide the infrastructure to scale them.

Want to dive deeper? Check out the MCP authorization specification and recommended security best practices for complete technical details.

Want to dive deeper? Check out the MCP authorization specification and recommended security best practices for complete technical details.

The post How to build secure and scalable remote MCP servers appeared first on The GitHub Blog.

]]>
89756
How to streamline GitHub API calls in Azure Pipelines https://github.blog/enterprise-software/ci-cd/how-to-streamline-github-api-calls-in-azure-pipelines/ Thu, 24 Jul 2025 16:00:00 +0000 https://github.blog/?p=89733 Build a custom Azure DevOps extension that eliminates the complexity of JWT generation and token management, enabling powerful automation and enhanced security controls.

The post How to streamline GitHub API calls in Azure Pipelines appeared first on The GitHub Blog.

]]>

Azure Pipelines is a cloud-based continuous integration and continuous delivery (CI/CD) service that automatically builds, tests, and deploys code similarly to GitHub Actions. While it is part of Azure DevOps, Azure Pipelines has built-in support to build and deploy code stored in GitHub repositories.

Because Azure Pipelines is fully integrated into GitHub development flows, pipelines can be triggered by pushes or pull requests, and it reports the results of the job execution back to GitHub via GitHub status checks. This way, developers can easily see if a given commit is healthy or block pull request merges if the pipeline is not compliant with GitHub rulesets.

When you need additional functionality, you can use either extensions available in the marketplace  or GitHub APIs to deepen the integration with GitHub. Below, we’ll show how you can streamline the process of calling the GitHub API from Azure Pipelines by abstracting authentication with GitHub Apps and introducing a custom Azure DevOps extension, this will allow pipeline authors to easily authenticate against GitHub and call GitHub APIs without implementing authentication logic themselves. This approach provides enhanced security through centralized credential management, improved maintainability by standardizing GitHub integrations, time savings through cross-project reusability, and simplified operations with centrally managed updates for bug fixes.

Common use cases and scenarios

The GitHub API is very rich, so the possibilities for customization are almost endless. Some of the most common scenarios for GitHub calls in Azure Pipelines include:

  • Setting status checks on commits or pull requests: Report the success or failure of pipeline steps (like tests, builds, or security scans) back to GitHub, enabling rulesets utilization to enforce policies, and providing clear feedback to developers about the health of their code changes.
  • Adding comments to pull requests: Automatically post pipeline results, test coverage reports, performance metrics, or deployment information directly to pull request discussions, keeping all relevant information in one place for code reviewers.
  • Updating files in repositories: Automatically update documentation, configuration files, or version numbers as part of your CI/CD process, such as updating a CHANGELOG.md file or bumping version numbers in package files.
  • Managing GitHub Issues: Automatically create, update, or close issues based on pipeline results, such as creating bug reports when tests fail or closing issues when related features are successfully deployed.
  • Integrating with GitHub Advanced Security: Send code scanning results to GitHub’s code scanning, enabling centralized vulnerability management, security insights, and supporting DevSecOps practices across your development workflow.
  • Managing releases and assets: Automatically create GitHub releases and upload build artifacts, binaries, or documentation as release assets when deployments are successful, streamlining your release management process.
  • Tracking deployments with GitHub deployments: Integrate with GitHub’s deployment API to provide visibility into deployment history and status directly in the GitHub interface.
  • Triggering GitHub Actions workflows: Orchestrate hybrid CI/CD scenarios where Azure Pipelines handles certain build or deployment tasks and then triggers GitHub Actions workflows for additional processing or notifications.

Understanding GitHub API: REST vs. GraphQL

The GitHub API provides programmatic access to most of GitHub’s features and data, offering two distinct interfaces: REST and GraphQL. The REST API follows RESTful principles and provides straightforward HTTP endpoints for common operations like managing repositories, issues, pull requests, and workflows. It’s well documented, easy to get started with, and supports authentication via personal access tokens, GitHub Apps, or OAuth tokens.

GitHub’s GraphQL API offers a more flexible and efficient approach to data retrieval. Unlike REST, where you might need multiple requests to gather related data, GraphQL allows you to specify exactly what data you need in a single request, reducing over-fetching and under-fetching of data. This is particularly valuable when you need to retrieve complex, nested data structures or when you want to optimize network requests in your applications. You can see some examples in Exploring GitHub CLI: How to interact with GitHub’s GraphQL API endpoint.

Both APIs serve as the foundation for integrating GitHub’s functionality into external tools, automating workflows, and building custom solutions that extend GitHub’s capabilities.

How to choose the right authentication method

GitHub offers three primary authentication methods for accessing its APIs. Personal Access Tokens (PATs) are the simplest method, providing a token tied to a user account with specific permissions. OAuth tokens are designed for third-party applications that need to act on behalf of different users, implementing a standard authorization flow where users grant specific permissions to the application. 

GitHub Apps provide the most robust and scalable solution, operating as their own entities with fine-grained permissions, installation-based access, and higher rate limits — making them ideal for organizations and production applications that need to interact with multiple repositories or organizations while maintaining tight security controls.

Authentication TypeProsCons
Personal Access Tokens (PATs)– Simple to create and use
– Quick to get started
– Good for personal automation
– Can be scoped to multiple organizations
– Configurable permissions per token
– Admins can revoke organization access
– Configurable expiration dates
– Work with most GitHub API libraries
– No additional infrastructure needed
– Tied to user account lifecycle
– Limited to user’s permissions
– Classic PATs have coarse-grained permissions
– Require manual rotation
– Browser-based management only
– If compromised, expose all accessible organization(s)/repositories
OAuth Tokens– Standard OAuth 2.0 flow
– Organization admins control app access
– Can act on behalf of multiple users
– Excellent for web applications
– User-approved permissions
– Refresh token mechanism
– Widely supported by frameworks
– Good for user-facing applications
– Require storing refresh tokens securely
– Need server infrastructure
– More complex than PATs for simple automation
– Still tied to user accounts
– Require initial browser authorization
– Token management complexity
– Potential for scope creep
– User revocation affects functionality
GitHub Apps– Act as independent identity
– Fine-grained, repository-level permissions
– Installation-based access control
– Tokens can be scoped down at runtime
– Short-lived tokens (1 hour max)
– Higher rate limits
– Best security model available
– No user account dependency
– Audit trail for all actions
– Can be installed across multiple orgs
– More complex initial setup
– Require JWT implementation
– May be overkill for simple scenarios
– Require understanding of installation concept
– Private key management responsibility
– More moving parts to maintain
– Not all APIs support Apps

PATs have two flavors: classic and fine-grained. Classic PATs provide repository-wide access with coarse permissions. Fine-grained PATs offer more granular control, since they are  scoped to a single organization, allow specified permissions at the repository level, and limit access to specific repositories. Administrators can also require approval of fine-grained tokens before they can be used, making them a more secure choice for repository access management. However, they currently do not support all API calls and still have some limitations compared to classic PATs.

Because of their fine-grained permissions, security features, and higher rate limits, GitHub Apps are the ideal choice for machine-to-machine integration with Azure Pipelines. What’s more, the short-lived tokens and installation-based access model provide better security controls compared to PATs and OAuth tokens, making them particularly well-suited for automation in CI/CD scenarios.

Registering and installing a GitHub App

In order to use an application for authentication, register it as a GitHub App, and then install it on the accounts, organizations, or enterprises the application will interact with.

These are the steps to follow:

  1. Register the GitHub App in GitHub enterprise, organization, or account.
    • Make sure to select the appropriate permissions for the application. The permissions will determine what the application can do in the enterprise, organization, and repositories to which it has access.
    • Permissions may be modified at any time. Note that if the application is already installed, changes will require a new authorization from the owner administrators before they take effect.
    • Take care to understand the consequences of making the app public or private. It is very likely that you will want to make the app private, as it is only intended to be used by you or your organization. The semantics of public and private also vary depending on the  GitHub Enterprise Cloud type (Enterprise with personal accounts, with managed users, or with data residency).
    • If a private key was generated, save it in a safe place. Private keys are used to authenticate against GitHub to generate an installation token. Note that a key can be revoked or up to 20 more may be generated if desired. 
  2. Install the GitHub App on the accounts or organizations the application will interact with.
    • When an app is installed, select which repositories the app will have access to. Options include all repositories (current and future) or you can select individual repositories.

Note: An unlimited number of GitHub Apps may be installed on each account, but only 100 GitHub Apps may be registered per enterprise, organization, or account.

GitHub App authentication flow

GitHub Apps use a two-step authentication process to access the GitHub API. First, the app authenticates itself using a JSON Web Token (JWT) signed with its private key. This JWT proves the app’s identity but doesn’t provide access to any GitHub resource. To call GitHub APIs, the app needs to obtain an installation token. Installation tokens are scoped (enterprise, organization, or account) access tokens that are generated using the app’s JWT authentication. These tokens are short-lived (valid for one hour) and can only access the resources on the scope they are installed on (enterprise, organization, or repository) and use at max the permissions granted during the app’s installation.

To obtain an installation token, there are two approaches: either use a known installation ID, or retrieve the ID by calling the installations API. Once the app has the installation ID, it requests a new token using that ID. The resulting installation token inherits the app’s permissions and repository access for that installation. It can optionally request the token with reduced permissions or limited to specific repositories — a useful security feature when you don’t need the app’s full access scope.

The resulting installation token can then be used to make GitHub API calls with the returned permissions.

Note: The application can also authenticate on a user’s behalf, but it’s not an ideal scenario for CI/CD pipelines where we want to use a service account and not a user account.

Sequence diagram showing GitHub App authentication flow between Client and GitHub, including JWT generation, installation ID retrieval, and installation token creation steps.

From a pipeline perspective, generating an installation token is all that’s needed to call GitHub APIs.

Pipeline authors have three main options to generate installation tokens in Azure Pipelines:

  1. Use a command-line tool: Several tools are available that can generate installation tokens directly from a pipeline step. For example, gh-token is a popular open source tool that handles the entire token generation process.
  2. Write custom scripts: Implement the token generation process using bash/curl or PowerShell scripts following the authentication steps described above. This grants full control over the process but requires more implementation effort.
  3. Use Azure Pipeline tasks: While Azure Pipelines doesn’t provide built-in GitHub App authentication, you can either:
    • Find a suitable task in the Azure DevOps marketplace.
    • Create a custom task that implements the GitHub App authentication flow.

Next, we’ll explore creating a custom task using an Azure DevOps extension to provide an integration with GitHub App authentication and dynamically generated installation tokens.

Azure DevOps extension for GitHub App authentication

When creating an integration between Azure Pipelines and GitHub, security of the app private key should be top of mind. Possession of this key grants permissions to generate installation tokens and make API calls on behalf of the app, so it must be stored securely. Within Azure Pipelines, we have several options for storing sensitive data:

Service connections in Azure Pipelines provide several key benefits for managing external service authentication, including:

  • Centralized access control where administrators can specify which pipelines can use the connection
  • Support for multiple authentication schemes
  • Ability to share connections across multiple pipelines within a project
  • Built-in security controls for managing who can view or modify connection details
  • Keep sensitive credentials hidden from pipeline authors while still allowing usage
  • Shared connections across multiple projects, reducing duplication and management overhead

For GitHub App authentication, service connections are particularly valuable because they:

  • Securely store the app’s private key
  • Allow administrators to configure and enforce connection behaviors
  • Provide better security compared to storing secrets directly in pipelines or variable groups

For those eager to explore the sample code, check out the repository. The key components and configuration are detailed below.

Creating a custom Azure DevOps extension

Azure DevOps extensions are packages that add new capabilities to Azure DevOps services. In our case, we need to create an extension that provides two key components:

  • Custom service connection type for securely storing GitHub App credentials (and other settings)
  • Custom task that uses those credentials to generate installation tokens

An extension consists of a manifest file that describes what the extension provides, along with the actual implementation code.

The development process involves creating the extension structure, defining the service connection schema, implementing the custom task logic in PowerShell (Windows only) or JavaScript/TypeScript for cross-platform compatibility, and packaging everything into a distributable format. Once created, the extension can be published privately for your organization or shared publicly through the Azure DevOps Marketplace, making it available for others who have similar GitHub integration needs.

We are not going to do a full walkthrough of the extension creation process, but we will demonstrate the most important steps. You can find all the information here: 

Adding a custom service connection

To enable GitHub App authentication in Azure Pipelines, we need to create a custom service connection type since there isn’t a built-in one. This can be done by adding a custom endpoint contribution to our extension, which will define how the service connection stores and validates the GitHub App credentials, and provides a user-friendly UI for configuring the connection settings like App ID, private key, and other properties.

We need to add a contribution of type ms.vss-endpoint.service-endpoint-type to the extension contributions manifest. This contribution will define the service connection type and its properties, like the authentication scheme, the endpoint schema, and the input fields that will be displayed in the service connection configuration dialogue.

Something like this (see a snippet below, or explore the full contribution definition in reference implementation):

"contributions": [
  {
    "id": "github-app-service-endpoint-type",
    "description": "GitHub App Service Connection",
    "type": "ms.vss-endpoint.service-endpoint-type",
    "targets": [ "ms.vss-endpoint.endpoint-types" ],
    "properties": {
        "name": "githubappauthentication",
        "isVerifiable": false,
        "displayName": "GitHub App",
        "url": {
            "value": "https://api.github.com/",
            "displayName": "GitHub API URL",
            "isVisible": "true"
        },
        ...
  },

Once you install the extension, you can add/manage the service connection of type “GitHub App” and configure the app’s ID, private key, and other settings. The service connection will securely store the private key and can be used by custom tasks to generate installation tokens in a pipeline.

Azure DevOps new service connection dialog showing different connection types including Generic, GitHub, GitHub App (highlighted with red arrow), GitHub Enterprise Server, and Incoming WebHook options.

In addition to storing the private key, the custom service connection can also store other settings, such as the GitHub API URL and the app client ID. It can also be used to limit token permissions or scope the token to specific repositories. By optionally enforcing these settings at the service connection level, administrators can ensure consistency and security, rather than leaving configuration decisions to pipeline authors.

Azure DevOps service connection configuration form for custom GitHub App authentication, showing fields for GitHub API URL, Client ID, Private Key, Token Permissions, and Service Connection Name.

Adding a custom task

Now that we have a secure way to store the GitHub App credentials, we can create a custom task that will use the service connection to generate an installation token. The task will be a TypeScript application (cross platform) and use the Azure DevOps Extension SDK.

While I already shared the full walkthrough of creating a custom task, here is an abbreviated list to follow:

  • Create the custom task skeleton
  • Declare the inputs and outputs on the task manifest (task.json)
  • Implement the code
  • Declare the task and its assets on the extension manifest (vss-extension.json)

I have created an extension sample that contains both the service connection as well as a custom task that generates a GitHub installation token for API calls. Since the extension is not published to the marketplace, you have to (privately) publish under your account, share it with your Azure DevOps enterprise or organization, and then install it on all organizations where you want to use the custom task.

Jump to the next section If you choose this path, as you are now ready to use the custom task in your pipeline.

Note: The sample includes both a GitHub Actions workflow and an Azure Pipelines YAML pipeline that builds and packages the extension as an Azure DevOps extension that can be published in the Azure DevOps marketplace.

Using the custom task in Azure Pipelines

The task supports receiving the private key, as a string, a file (to be combined with secure files), or preferably a service connection (see input parameters).

Assuming you have a service connection named my-github-app-service-connection, let’s see how can use task to create a comment in a pull request in the GitHub repository that triggers the pipeline using the GitHub CLI to call the GitHub API:

steps:
- task: create-github-app-token@1
  displayName: create installation token
  name: getToken
  inputs:
    githubAppConnection: my-github-app-service-connection

- bash: |
    pr_number=$(System.PullRequest.PullRequestNumber)
    repo=$(Build.Repository.Name)
    echo "Creating comment in pull request #${pr_number} in repository ${repo}"
    gh api -X POST "/repos/${repo}/issues/${pr_number}/comments" -f body="Posting a comment from Azure Pipelines"
  displayName: Create comment in pull request
  condition: eq(variables['Build.Reason'], 'PullRequest')
  env:
    GH_TOKEN: $(getToken.installationToken)

Running this pipeline will result in a comment being posted in the pull request:

Screenshot of a GitHub pull request snippet showing an Azure Pipelines Status check, and comment that reads 'Posting a comment from Azure Pipelines' written by our pipeline.

Pretty simple, right? The task will create an installation token using the service connection and export it as a variable, which can be accessed as getToken.installationToken (with getToken being the identifier of the step). It can then be used to authenticate against GitHub, in this case using the GitHub CLI command, which will take care of the API call and authentication for us (we could have also used curl or any other HTTP client).

The task also exports other variables:

  • tokenExpiration: the expiration date of the generated token, in ISO 8601 format
  • installationId: the ID of the installation for which the token was generated

Unlocking powerful automation capabilities beyond basic CI/CD

By leveraging GitHub Apps for authentication, organizations can establish secure, scalable Azure Pipelines integrations that provide fine-grained permissions, short-lived tokens, and better security controls compared to traditional PATs.

The custom Azure DevOps extension approach provides a seamless integration experience that abstracts away the complexities of GitHub App authentication. Through service connections and custom tasks, pipeline authors can easily generate installation tokens without worrying about JWT generation, installation ID management, or token lifecycle concerns.

The streamlined approach also enables development teams to implement rich GitHub integrations, including automated status checks, pull request comments, issue management, security scanning integration, and deployment tracking. The result? A more cohesive development workflow where Azure Pipelines and GitHub work together seamlessly to provide comprehensive visibility and automation throughout the software development lifecycle.

Whether you’re looking to enhance your existing CI/CD processes or build entirely new automated workflows, the combination of Azure Pipelines and GitHub API through GitHub Apps provides a robust foundation for modern DevOps practices. This will allow you to enrich your existing pipelines with GitHub capabilities as you move your code from Azure Repos to GitHub.

Explore more blog posts covering a range of topics essential for enterprise software development >

The post How to streamline GitHub API calls in Azure Pipelines appeared first on The GitHub Blog.

]]>
89733
Solving the inference problem for open source AI projects with GitHub Models https://github.blog/ai-and-ml/llms/solving-the-inference-problem-for-open-source-ai-projects-with-github-models/ Wed, 23 Jul 2025 16:00:00 +0000 https://github.blog/?p=89716 How using GitHub’s free inference API can make your AI-powered open source software more accessible.

The post Solving the inference problem for open source AI projects with GitHub Models appeared first on The GitHub Blog.

]]>

AI features can make an open source project shine. At least, until setup asks for a paid inference API key.  Requiring contributors or even casual users to bring their own large language model (LLM) key stops adoption in its tracks:

$ my-cool-ai-tool
Error: OPENAI_API_KEY not found

Developers may not want to buy a paid plan just to try out your tool, and self hosting a model can be too heavy for laptops or GitHub Actions runners. 

GitHub Models solves that friction with a free, OpenAI-compatible inference API that every GitHub account can use with no new keys, consoles, or SDKs required. In this article, we’ll show you how to drop it into your project, run it in CI/CD, and scale when your community takes off.

Let’s jump in.

The hidden cost of “just add AI”

AI features feel ubiquitous today, but getting them running locally is still a challenge for a few reasons:

  • Paid APIs: The simplest path is to ask users for an OpenAI or Anthropic key. That’s a non-starter for many hobbyists and students because paid APIs are too expensive.
  • Local models: Running a 2 B-parameter LLM can work for lightweight tasks, but anything that requires more intelligence will quickly blow past typical laptop memory — let alone the 14 GB container that backs a GitHub Actions runner.
  • Docker images and weights: You can bundle a model with your app, but distributing multi-gigabyte weights balloons install size and slows CI.

Every additional requirement filters out potential users and contributors. What you need is an inference endpoint that’s:

  1. Free for public projects
  2. Compatible with existing OpenAI SDKs
  3. Available wherever your code runs, like your laptop, server, or Actions runner

That’s what GitHub Models provides.

GitHub Models in a nutshell

  • What it is: A REST endpoint that speaks the chat/completions spec you already know.
  • What you get: A curated set of models (GPT-4o, DeepSeek-R1, Llama 3, and more) hosted by GitHub.
  • Who can call it: Anyone with a GitHub Personal Access Token (PAT), or a repository’s built-in GITHUB_TOKEN when you opt-in via permissions.
  • How much it costs: Free tier for all personal accounts and OSS orgs; metered paid tier unlocks higher throughput and larger context windows.

Because the API mirrors OpenAI’s, any client that accepts a baseURL will work without code changes. This includes OpenAI-JS, OpenAI Python, LangChain, llamacpp, or your own curl script.

How to get started with GitHub Models

Since GitHub Models is compatible with the OpenAI chat/completions API, almost every inference SDK can use it. To get started, you can use the OpenAI SDK:

import OpenAI from "openai";

const openai = new OpenAI({
  baseURL: "https://models.github.ai/inference/chat/completions",
  apiKey: process.env.GITHUB_TOKEN  // or any PAT with models:read
});

const res = await openai.chat.completions.create({
  model: "openai/gpt-4o",
  messages: [{ role: "user", content: "Hi!" }]
});
console.log(res.choices[0].message.content);

If you write your AI open source software with GitHub Models as an inference provider, all GitHub users will be able to get up and running with it just by supplying a GitHub Personal Access Token (PAT).

And if your software runs in GitHub Actions, your users won’t even need to supply a PAT. By requesting the models: read permission in your workflow file, the built-in GitHub token will have permissions to make inference requests to GitHub Models. This means you can build a whole array of AI-powered Actions that can be shared and installed with a single click. For instance:

  • Code review or PR triage bots
  • Smart issue tagging workflows
  • Weekly repository activity report generators
  • And anything else that a GitHub Action can do

Plus, using GitHub Models makes it easy for your users to set up AI inference. And that has another positive effect: it’s easier for your contributors to set up AI inference as well. When anyone with a GitHub account can run your code end to end, you’ll be able to get contributions from the whole range of GitHub users, not just the ones with an OpenAI key.

Zero-configuration CI with GitHub Actions

Publishing an Action that relies on AI used to require users to add their inference API key as a GitHub Actions secret. Now you can ship a one-click install:

yaml 

# .github/workflows/triage.yml
permissions:
  contents: read
  issues: write
  models: read   # 👈 unlocks GitHub Models for the GITHUB_TOKEN

jobs:
  triage:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Smart issue triage
        run: node scripts/triage.js

The runner’s GITHUB_TOKEN carries the models:read scope, so your Action can call any model without extra setup. This makes it well suited for:

  • Automated pull request summaries
  • Issue deduplication and tagging
  • Weekly repository digests
  • Anything else you can script in an Action

Scaling when your project takes off

The GitHub Models inference API is free for everyone. But if you or your users want to do more inference than the free rate limits allow, you can turn on paid inference in your settings for significantly larger context windows and higher requests-per-minute. 

When your community grows, so will traffic. So it’s important to consider the following: 

  • Requests per minute (RPM): While the free tier offers default limits, the paid tier offers multiples higher.
  • Context window: Free tier tops out at standard model limits; paid enables 128k tokens on supported models.
  • Latency: The paid tier runs in its own separate deployment, so you’re not in the same queue as free tier users.

To get started, you can enable paid usage in Settings > Models for your org or enterprise. Your existing clients and tokens will keep working (but they’ll be faster and support bigger contexts).

Take this with you

LLMs are transforming how developers build and ship software, but requiring users to supply their own paid API key can be a barrier to entry. The magic only happens when the first npm install, cargo run, or go test just works.

If you maintain an AI-powered open source codebase, you should consider adding GitHub Models as a default inference provider. Your users already have free AI inference via GitHub, so there’s little downside to letting them use it with your code. That’s doubly true if your project is able to run in GitHub Actions. The best API key is no API key!

By making high-quality inference a free default for every developer on GitHub, GitHub Models gets rid of the biggest blocker to OSS AI adoption. And that opens the door to more contributions, faster onboarding, and happier users.

Want to give it a try? Check out the GitHub Models documentation or jump straight into the API reference and start shipping AI features that just work today.

The post Solving the inference problem for open source AI projects with GitHub Models appeared first on The GitHub Blog.

]]>
89716
We need a European Sovereign Tech Fund https://github.blog/open-source/maintainers/we-need-a-european-sovereign-tech-fund/ Wed, 23 Jul 2025 07:01:00 +0000 https://github.blog/?p=89660 Open source software is critical infrastructure, but it’s underfunded. With a new feasibility study, GitHub’s developer policy team is building a coalition of policymakers and industry to close the maintenance funding gap.

The post We need a European Sovereign Tech Fund appeared first on The GitHub Blog.

]]>

Open source software is open digital infrastructure that our economies and societies rely on. Nevertheless, open source maintenance continues to be underfunded, especially when compared to physical infrastructure like roads or bridges. So we ask: how can the public sector better support open source maintenance? 

As part of our efforts to support developers, GitHub’s developer policy team has commissioned a study from Open Forum Europe, Fraunhofer ISI and the European University Institute that explores how one of the open source world’s most successful government programs, the German Sovereign Tech Agency, can be scaled up to the European Union level. That study was published today. Here’s what it says and what you can do to help make the EU Sovereign Tech Fund (EU-STF) a reality.

The maintenance challenge

There is a profound mismatch between the importance of open source maintenance and the public attention it receives. The demand-side value of open source software to the global economy is estimated at $8.8 trillion, and the European Commission’s own research shows that OSS contributes a minimum of €65-95 billion to the EU economy annually. Basic open source technologies, such as libraries, programming languages, or software development tools, are used in all sectors of the economy, society, and public administrations.

Open source is everywhereOpen source is valuableOpen source is underfinanced
96% of all code bases contain OSS$8.8T demand-side value to global economy1/3 of OSS maintainers are unpaid
77% of a given code base is OSS€65-95M minimum contribution to annual EU GDP1/3 are the only maintainer of their OSS project

The flip side of everybody benefiting from this open digital infrastructure is that too few feel responsible for paying the tab. The Sovereign Tech Agency’s survey of over 500 OSS maintainers showed that a third of them are not paid at all for their maintenance work, but would like to be. Another third earns some income from OSS maintenance, but is not able to make a living off this work. Perhaps even more alarmingly, a third of respondents are solo maintainers, and almost three quarters of surveyed projects are maintained by three people or fewer. As prominent security incidents such as the xz backdoor or the Log4Shell vulnerability have shown in recent years, it can mean serious risks for the OSS community’s health and the security of our global software ecosystem if too much is put on the shoulders of small, overworked, and underappreciated teams.

At GitHub, we are helping address this open source sustainability challenge through GitHub Sponsors, the GitHub Secure Open Source Fund, free security tooling for maintainers, and other initiatives. Yet we recognize that there is a significant gap between the immense public value of open source software and the funding that is available to maintain it, a gap that this research is seeking to address.

Designing an impactful fund

Building on the success story of the German Sovereign Tech Agency, which has invested over €23 million in 60 OSS projects in its first two years of operation (2022-2024), the EU-STF should have five main areas of activity:

  1. Identifying the EU’s most critical open source dependencies,
  2. Investments in maintenance,
  3. Investments in security,
  4. Investments in improvement,
  5. Strengthening the open source ecosystem.

The study proposes two alternative institutional setups for the EU-STF: either the creation of a centralized EU institution (the moonshot model), or a consortium of EU member states that provide the initial funding and apply for additional resources from the EU budget (the pragmatic model). In both cases, to make the fund a success, the minimum contribution from the upcoming EU multiannual budget should be no less than €350 million. This would not be enough to meet the open source maintenance need, but it could form the basis for leveraging industry and national government co-financing that would make a lasting impact.

Equipped with the learnings from the German Sovereign Tech Agency and other government open source programs, such as the US Open Technology Fund or the EU’s Next Generation Internet initiative, the study identified seven design criteria that the EU-STF must meet:

  1. Pooled financing. To address the maintenance funding gap, industry, national governments and the EU should all be able to put money into the same pot. It is not in the interest of overworked open source maintainers to have to research and apply to dozens of separate funds, all with slightly different funding criteria. That’s why GitHub’s Secure Open Source Fund pools funding from many industry partners into one coherent program. The EU-STF should follow the same logic and be capable of collecting contributions from industry, national governments and the EU budget alike.
  2. Low bureaucracy. If you’re one of those aforementioned unpaid solo maintainers, the last thing you need is to sink several days of work into a complicated application process with an uncertain outcome that many EU funding programs are unfortunately known for. The EU-STF should combine a lightweight application process along with its own research to identify and proactively contact critical OSS infrastructure projects. Funding recipients should have limited reporting requirements to make sure that they can spend their time on improving the health of their OSS projects, not jumping through administrative hoops.
  3. Political independence. Public funding programs often follow technological trends, such as blockchain, quantum computing or AI. Open source maintenance often gets overlooked, because it is neither a new development nor limited to a particular economic sector: it is foundational to all of them. An EU-STF has to be politically independent enough to shield it from frequent pivots to new, politically salient topics, and instead keep it focused on the mission of securing and maintaining our public software infrastructure.
  4. Flexible funding. There is no one-size-fits-all model for open source maintenance. Many maintainers are hired by companies to work on OSS as part of their day jobs. Others maintain projects in their free time. Some critical OSS projects are governed by a foundation or other nonprofit, yet others are made up of a loose collective of individuals scattered across the globe. The EU-STF should be able to fund individuals, nonprofits or companies in all of those cases for their OSS maintenance work. Living in the EU should not be a requirement for receiving funding, just like the German Sovereign Tech Agency does not restrict funding to Germans. To benefit the EU economy and society, software doesn’t have to be Made in the EU, as long as it is Made Open Source.
  5. Community focus. A fund that is solely run by career public servants is going to struggle to develop the expertise and build the trust with the open source ecosystem that are necessary to make a positive impact on open source sustainability. The EU-STF should collaborate with the open source community to co-define funding priorities and design the funding process.
  6. Strategic alignment. To be attractive enough to the European Union to justify spending a budget of a minimum of €350 million on open source sustainability, the EU-STF has to demonstrate a positive impact on the EU’s strategic goals. The study lays out in detail how open source maintenance funding contributes to economic competitiveness, digital sovereignty (that is, the ability of individuals, companies and the state to use and design technology according to their own needs), and cybersecurity, for example by helping companies comply with their supply chain security obligations for open source components under the Cyber Resilience Act.
  7. Transparency. As with any case of spending taxpayer money, the EU-STF must meet the highest standards of transparency in governance and funding decisions, to ensure that it can earn the trust not just of the open source community, but also of the policymakers who approve its budget.

Making the EU Sovereign Tech Fund a reality

Right now, the European Union is ramping up the negotiations on its new multi-year budget for the period of 2028-2035, the Multiannual Financial Framework. GitHub’s developer policy team is presenting the findings of the study to EU legislators and mobilizing the support of industry partners to demonstrate the need for a novel instrument that allows the public and private sectors to work together on securing our open source infrastructure. We are delighted to partner with Mercedes-Benz, who contributed a foreword to the study and have been vocal supporters of the idea of an EU Sovereign Tech Fund from its inception.

Without sustainable funding and support, it is entirely foreseeable that ever more open source software projects will not receive the diligence and scrutiny appropriate for software of such criticality.

Magnus Östberg, Chief Software Officer, Mercedes-Benz AG; Markus Rettstatt, Vice President Software Defined Car, Tech Innovation GmbH

The first legislative proposals for the EU budget have just hit the desks of the European Parliament and the national governments in the Council of Ministers. Whether you are an individual, a member of an open source organization, or a company representative, you can voice your support for the creation of the EU-STF to the European Commission, your elected representatives in the European Parliament, and your national government. If you’re at EU Open Source Summit Europe on August 26, you can join us for a presentation of the study and community discussion.

Explore open source blog posts >

The post We need a European Sovereign Tech Fund appeared first on The GitHub Blog.

]]>
89660
Debugging UI with AI: GitHub Copilot agent mode meets MCP servers https://github.blog/ai-and-ml/github-copilot/debugging-ui-with-ai-github-copilot-agent-mode-meets-mcp-servers/ Tue, 22 Jul 2025 21:58:35 +0000 https://github.blog/?p=89676 Explore how I use agentic tools like GitHub Copilot agent mode and the Playwright MCP server to accelerate troubleshooting and debugging of UI issues, while revisiting the importance of clear requirements.

The post Debugging UI with AI: GitHub Copilot agent mode meets MCP servers appeared first on The GitHub Blog.

]]>

If you’ve ever dusted off an old project and thought, “How did I leave things in such a mess?”, you’re in good company.

On my latest Rubber Duck Thursdays stream, I dove back into my OctoArcade Next.js app, only to rediscover a host of UI gremlins. So, we experimented with something that felt like magic: letting GitHub Copilot agent mode, paired with Playwright MCP server, identify and fix UI bugs. Along the way, I learned (again) how crucial it is to provide AI tools like Copilot with clear, detailed requirements. 

Let’s walk through how I used these agentic tools to debug, test, and (mostly) solve some tricky layout issues, while covering practical tips for anyone looking to leverage Copilot’s agent workflows in real-world projects.

The setup: Revisiting OctoArcade (and its bugs)

I started by firing up OctoArcade, my collection of GitHub-themed mini-games built with Next.js and TypeScript. Within minutes, I realized I had been introducing a new game to the app, but hadn’t quite gotten around to fixing some bugs.

Here’s what we accomplished in one stream session:

  • Problem: Navigation header overlapping game content across all games
  • Solution: Copilot agent mode and Playwright MCP server identified the issue through visual inspection, and implemented a global header fix
  • Bonus: Fixed some additional UI issues (unintended gaps between the game canvas and footer) discovered during testing
  • Result: Hands-off debugging that solved problems I’d stepped away from, and had previously spent some cycles on fixing

Let me walk you through how this worked and what you can learn for your own debugging workflows.

Making sure Copilot custom instructions are set up

With my environment set up in VS Code Insiders, I checked that my Copilot custom instruction files (.github/copilot-instructions.md, *.instructions.md files) were up to date. This is usually my first step before using any agentic features, as these instructions provide important context on my expectations, coding styles, and working practices — influencing how Copilot responds and interacts with my codebase.

In my last blog post, we spent time exploring recommended practices when setting up Copilot custom instructions. We also covered how the copilot-setup-steps.yml sets up a developer environment when using Copilot coding agent. Take a look at that blog post on using GitHub Copilot coding agents to refactor and automate developer workflows to learn more.

Always keep your Copilot custom instructions current (including descriptions of your repository structure, common steps like building and testing, and any expectations before making commits). Copilot agents depend on this context to deliver relevant changes. When I think my instructions file is out of date, I typically prompt Copilot in agent mode with a prompt along the lines of:

Based on the #codebase, please can you update the custom instructions file for accuracy? Please make sure to keep the structure (i.e. headings etc.) as-is. Thanks!

In some of my instruction files, I’ve even instructed Copilot to keep key documentation (README, .github/copilot-instructions.md, etc.) up to date when it makes significant changes (like refactoring files or adding new features).

Agentic debugging: UI troubleshooting with Playwright MCP

Playwright MCP server is a powerful tool for end-to-end testing and UI automation. Since it’s an MCP server, you can access it through your favorite AI tools that support the Model Context Protocol, like Copilot agent mode and Copilot coding agent! In agent mode, Copilot can use Playwright’s structured tools to:

  • Load web pages
  • Simulate user actions (clicks, navigation)
  • Inspect rendered layouts without needing vision models

This means you can ask Copilot to “see” what a human would, spot layout issues, and even propose CSS or component fixes. To get started with Playwright, it’s as easy as adding the below to your MCP configuration:

{

  "mcpServers": {

    "playwright": {

      "command": "npx",

      "args": ["@playwright/mcp@latest"]

    }

  }

}

Once you have started the MCP server, you should see that Copilot now has access to a suite of new tools for browser interaction like:

  • browser_snapshot – Capture accessibility snapshots of pages
  • browser_navigate – Navigate to URLs
  • browser_click, browser_type, browser_hover – Interact with elements
  • browser_resize – Test different viewport sizes
  • browser_take_screenshot – Visual documentation
  • And many more: You can find the full list in the tools section of Playwright MCP server’s README

With access to a new set of tools to solve the UI challenges, it was time to point Copilot at the problem. Meaning, I now had the task of clearly defining the requirements in my initial prompt…easier said than done.

The debugging journey: Real-time fixes and lessons learned

1. Describe the problem and let agent mode work

I noticed that, in several pages, the main content was tucked behind the navigation bar. This was particularly noticeable on any pages that rendered games. On some pages (like OctoPong), I saw inconsistent spacing between game elements and the footer.

To get Copilot agent mode started, I aimed to be as explicit as possible in my prompts:

I have spotted that there is a bit of a UI error. It seems like the main content of any page "starts" behind the navigation bar. This is more evident on the games like octosnap, octopong and octobrickbreaker.

Can you take a look at the site using Playwright (you'll need to spin up an instance of the server), take a look at the pages, and then investigate? Thanks!

It loaded up the pages to configure each game, but didn’t try loading the games themselves (so missed some context). I followed up in a separate prompt:

Sorry, I wanted you to take a look when a game is actually loaded too. Can you play the game Octopong and Octosnap – I think it’s very visible in those? Do that before you build a plan.

Lesson: The more context and specifics you provide, the better Copilot performs, just like a teammate. 

After spinning up Playwright MCP, I watched Copilot:

  • Launch a browser
  • Navigate through the app’s pages
  • Diagnose where and why content was hidden or misaligned

Ultimately, we had to evolve the way that we were rendering the navigation bar. The current implementation had a separate navigation bar (DynamicHeader component) on each of the game pages with its own local state, overlaying the “main” navigation bar. Instead, Copilot suggested using the navigation bar from the root layout and passing the relevant context up, so that only one component is updated and the root layout gets updated as needed..

Hands-off debugging: At this stage, I was literally hands off, watching as Copilot tried fixes, reran the app, and checked the results visually. As it implemented the new approach with a new header-context file, Copilot recognized linting errors, and iteratively fixed them.

2. Iterating on UI requirements

Fixing bugs is rarely one-and-done. I noticed another bug, specifically for OctoPong. There was a small gap between the game board and the footer, which didn’t show up clearly on the livestream, but was noticeable on my own screen. Fortunately as developers, we’re used to small iterative and incremental improvements.

So once again, I turned to Copilot. However, as I iterated, Copilot would make changes, but they didn’t fully achieve what I needed. The problem wasn’t Copilot though; it was me and my unclear requirements.

PromptResultReflection
I’ve noticed a minor UI bug on the Octopong game page (this only happens when the game is actually live). There is a small space between the game itself and the footer. I want the game to extend all the way to the footer (not necessarily push the footer beyond the fold though). Can you use the Playwright MCP server to explore what’s going on, build a structured plan / todo list to resolve the actions? ThanksIt achieved what I had asked, but the pong paddles no longer displayed (which was a side effect of the container now being 0 height). Through no fault of Copilot, I hadn’t asked for the game components (e.g. Paddle/Ball) to be visible in the game area. The game was still playing (in a 0 height container), but the key components were not visible to me as the player.– Good clarity on tools to use.

– Good clarity on asking for a plan (as Copilot asked me to review/approve before making the changes).

– Lack of clarity on the full requirements (i.e. having the game components be visible and working).
Just to jump in, can you test again? It looks like the paddles and the ball are now missing as a result of the change?The game began working again, however it introduced the gap that we early sought to resolve.– Solved the immediate challenge of making game components visible.

– Lack of clarity that the earlier requirements were still required.
Can you check the game once again? The spacing issues are still there.

The requirements are:

1. The game is playable (i.e. balls and paddles are visible and one paddle is usable for the player).
2. The game area covers the “full space” between header and footer.

I think the space problem is back. You must meet both requirements please, thanks.
Once again, Copilot fulfilled the requirements! But this time, the game extended beyond the viewport, and so a user would have to scroll to move the paddle to prevent the ball scoring against them (which is not an ideal experience!).– Solved all of the requirements we outlined

– Lack of clarity in the actual requirements (that the game should not extend beyond the viewport).
Thanks! Sorry, I forgot to give you a third requirement. Your solution makes the game extend beyond the fold,  which makes the user have to “scroll” to play the game.

These are the requirements you must meet:

1. The game is fully functional (paddles/ball working and visible).
2. There is no space between the game and the footer.
3. The game must not extend beyond the fold (i.e. the user must not have to scroll to see any part of the game board. So the game board at maximum must end at the bottom of the screen). The footer can be below the fold.

Please feel free to reword/rewrite my requirements, as I struggled to define  them. Make sure you confirm with me the requirements are accurate.
Success! After we prompted Copilot with our full requirements, it was able to think through and iteratively approach the problem to get to the working layout.– A full set of requirements solved all of the requirements we outlined.

– While there were some minor issues in the mobile view, (a small gap between the navigation bar and game), other pages hadn’t yet been optimised for mobile. Since this isn’t a priority, it can be a task for later. 

Each prompt brought incremental improvements, but also new side effects (like games extending past the viewport or missing paddles in Pong).

Key insight: Context is important, and making sure that we clearly articulate our requirements is a key part of that. The biggest challenge wasn’t technical, but precisely describing what I wanted. Getting the requirements right took several attempts…And lots of feedback from our viewers in the livestream chat. 

Practical tips: Working with Copilot agent mode and MCP servers

Here’s what I learned (or relearned) during this session:

  • Keep Copilot custom instructions up to date: The agent relies on these files for repo context and best practices.
  • Give Copilot more power with MCP: Playwright MCP enables true end-to-end testing and UI inspection, making it invaluable for debugging complex web apps.
  • Be explicit with requirements: Like any collaborator, Copilot only knows what you tell it. List out your must-haves, expected behaviors, and edge cases.
  • Iterate in small steps: Commit changes frequently. It’s easier to roll back and diagnose issues when your history is granular.

Conclusion: Progress, not perfection

This live debugging session reminded me of two things:

  1. Agentic tools like Copilot and Playwright MCP can genuinely accelerate troubleshooting. Especially when you provide the right context.
  2. Describing requirements is hard. And that’s okay! Iteration, feedback, and even a few missteps are part of the process (both in terms of learning, and solving bugs).

If you’re navigating similar challenges, dive in, experiment, and remember: progress beats perfection.

  1. Update Copilot custom instructions files for your repo. If you’re using Copilot coding agent, make sure to configure the copilot-setup-steps.yml.
  2. Install and start the Playwright MCP server in VS Code to provide Copilot access to a browser for UI testing.
  3. Describe your bug or feature clearly in a new chat with Copilot agent mode.
  4. Let Copilot propose and apply fixes. But always review code changes and test results.
  5. Iterate on requirements based on what you see. Clarify as needed. Make sure you’re being clear in your requirements too.
  6. Commit frequently! Work in a branch and save your progress at each step.

Are you using the Playwright MCP server for UI testing? Or maybe you have another favorite MCP server? Let us know — we’d love to hear how you’re using Copilot agent mode and MCP servers as part of your development workflow!

In the meantime, mark your calendars for our next Rubber Duck Thursdays stream, subscribe to us on YouTube, and check out skills.github.com for interactive GitHub learning. See you next time!

Learn how to set Copilot coding agent up for success with custom instruction and Copilot setup steps >

The post Debugging UI with AI: GitHub Copilot agent mode meets MCP servers appeared first on The GitHub Blog.

]]>
89676