├── requirements.txt ├── .github ├── steps │ ├── 1-step-issues │ │ ├── enhancement │ │ │ ├── activities-file.md │ │ │ ├── prettier-interface.md │ │ │ ├── add-filters.md │ │ │ ├── admin-mode.md │ │ │ └── missing-activity.md │ │ └── bug │ │ │ └── school-pride.md │ ├── x-review.md │ ├── 4-step.md │ ├── 3-step.md │ ├── 2-step.md │ └── 1-step.md └── workflows │ ├── 0-start-exercise.yml │ ├── 4-step.yml │ ├── 2-step.yml │ ├── 1-step.yml │ └── 3-step.yml ├── .vscode └── launch.json ├── .gitignore ├── .devcontainer └── devcontainer.json ├── LICENSE ├── src ├── static │ ├── index.html │ ├── styles.css │ └── app.js ├── README.md └── app.py └── README.md /requirements.txt: -------------------------------------------------------------------------------- 1 | fastapi 2 | uvicorn 3 | -------------------------------------------------------------------------------- /.github/steps/1-step-issues/enhancement/activities-file.md: -------------------------------------------------------------------------------- 1 | # Hard to change activities 2 | 3 | Teachers are afraid to modify the program since they think they might break it. Move the list of activities out of the python file into a dedicated `activities.json` file. 4 | -------------------------------------------------------------------------------- /.github/steps/1-step-issues/bug/school-pride.md: -------------------------------------------------------------------------------- 1 | # Missing School Pride 2 | 3 | The website is blue, but our school colors are white and lime green. Please fix this. 4 | 5 | Also, why are none of our mascots on the page? 6 | Please use the various options from https://octodex.github.com/ 7 | 8 | Oh one more idea, I think it would look cool if the background had various Git-style branch lines slowly animating! That's easy, right? 9 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Launch Mergington WebApp", 9 | "type": "debugpy", 10 | "request": "launch", 11 | "module": "uvicorn", 12 | "args": [ 13 | "src.app:app", 14 | "--reload" 15 | ], 16 | "jinja": true 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /.github/steps/1-step-issues/enhancement/prettier-interface.md: -------------------------------------------------------------------------------- 1 | # Prettier Interface 2 | 3 | Now that we have many activities, the list on the left is too long so it is hard to navigate. And the add dialog is far away from the activity. 4 | 5 | - Move the cards to the bottom 6 | 7 | - Remove the registration form and replace it with a "register student" button on each activity card. 8 | 9 | - Make sure it looks good on desktop and phone. 10 | 11 | ----- COMMENTS ----- 12 | I second this idea. I'm having trouble finding my activity. 13 | 100% support this. Nice idea! Looking forward to the update. 14 | Don't forget about tablet's too. 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled source # 2 | ################### 3 | *.com 4 | *.class 5 | *.dll 6 | *.exe 7 | *.o 8 | *.so 9 | 10 | # Packages # 11 | ############ 12 | # it's better to unpack these files and commit the raw source 13 | # git has its own built in compression methods 14 | *.7z 15 | *.dmg 16 | *.gz 17 | *.iso 18 | *.jar 19 | *.rar 20 | *.tar 21 | *.zip 22 | 23 | # Logs and databases # 24 | ###################### 25 | *.log 26 | *.sql 27 | *.sqlite 28 | 29 | # OS generated files # 30 | ###################### 31 | .DS_Store 32 | .DS_Store? 33 | ._* 34 | .Spotlight-V100 35 | .Trashes 36 | ehthumbs.db 37 | Thumbs.db 38 | 39 | # Python files 40 | __pycache__ 41 | 42 | # Env files 43 | .env 44 | -------------------------------------------------------------------------------- /.github/steps/1-step-issues/enhancement/add-filters.md: -------------------------------------------------------------------------------- 1 | # Add filters 2 | 3 | There seems to be no order to the activities. Please fix this. 4 | 5 | Here are my ideas, maybe in a toolbar above the activity cards. 6 | 7 | - Add some filters, for example by category. If needed, add a field to the JSON. 8 | - Add options to sort, for example by name or time. If needed, add a date field but leave the textual description version of the time. 9 | - Add a free text search. 10 | 11 | Obviously, make sure it still looks good on desktop and phone. 12 | 13 | ----- COMMENTS ----- 14 | This will be so useful. We should be proactive and do this before the list gets even longer. 15 | Let's do it! I would love to help out. I just took a coding class. 🤓 16 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Python 3", 3 | "image": "mcr.microsoft.com/vscode/devcontainers/python:3.13-bookworm", 4 | "features": { 5 | "ghcr.io/devcontainers/features/node:1": { 6 | "version": "latest" 7 | }, 8 | "ghcr.io/devcontainers/features/docker-in-docker:2": { 9 | "moby": false 10 | } 11 | }, 12 | "forwardPorts": [8000], 13 | "postCreateCommand": "pip install -r requirements.txt", 14 | "customizations": { 15 | "vscode": { 16 | "extensions": [ 17 | "GitHub.copilot", 18 | "ms-python.python", 19 | "ms-python.debugpy", 20 | "dbaeumer.vscode-eslint" 21 | ], 22 | "settings": { 23 | "chat.agent.enabled": true, 24 | "chat.mcp.enabled": true 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /.github/steps/1-step-issues/enhancement/admin-mode.md: -------------------------------------------------------------------------------- 1 | # Admin Mode 2 | 3 | ## Problem 4 | 5 | Students are removing each other to free up space for themselves in the activities. 6 | 7 | ## Recommended Solution 8 | 9 | Add a user icon in the top right. When clicked it shows a login button. When the login button is clicked, it presents a window to enter a username and password. 10 | 11 | - Only the teachers (logged in) have the ability to register and unregister students to activities. 12 | 13 | - The students (not logged in) can still view who is registered. 14 | 15 | - There is no need for an account maintenance page. Teachers will be assigned passwords. 16 | 17 | ## Context 18 | 19 | Since there is no database yet, please store the teacher usernames and passwords in a `json` file that is checked by the backend. 20 | -------------------------------------------------------------------------------- /.github/steps/x-review.md: -------------------------------------------------------------------------------- 1 | ## Review 2 | 3 | _Congratulations, you've completed this exercise and learned how to integrate MCP with GitHub Copilot!_ 4 | 5 | celebrate 6 | 7 | Here's a recap of what you learned: 8 | 9 | - **MCP Server Configuration**: Setting up and connecting the GitHub MCP server to Copilot 10 | - **Agent Mode with MCP**: Using natural language to interact with external services through MCP tools 11 | - **GitHub Repository Research**: Searching for and analyzing similar projects using MCP capabilities 12 | - **Issue Management & Implementation**: Triaging, creating, and managing GitHub issues through Copilot, then having Copilot solve issues for you 13 | 14 | ### What's next? 15 | 16 | Check out these resources to learn more or get involved: 17 | 18 | - [Take another GitHub Skills exercise](https://learn.github.com/skills). 19 | - Learn more about [Model Context Protocol](https://modelcontextprotocol.io/introduction) 20 | - Explore the [GitHub MCP Registry](https://github.com/mcp) and try out other servers! -------------------------------------------------------------------------------- /.github/steps/1-step-issues/enhancement/missing-activity.md: -------------------------------------------------------------------------------- 1 | # 🚨 Missing Activity: GitHub Skills 2 | 3 | The GitHub Skills activity announced by our principal is missing from the school activities signup page. 4 | 5 | Yesterday in the school assembly, the principal announced a new partnership with GitHub to teach students practical coding and collaboration skills. However, when I try to sign up for this activity, I can't find it on the website. 6 | 7 | I can see several other activities, like these, so I think I have access. 8 | 9 | - ✅ Chess Club 10 | - ✅ Programming Class 11 | - ✅ Gym Class 12 | 13 | ## ⏱️ Timeline 14 | 15 | This is time-sensitive as the announcement mentioned registrations would close by the end of this week. Many students are eager to join. It's the first part of our [GitHub Certifications program](https://resources.github.com/learn/certifications/), which will help with college applications. 16 | 17 | ## 💡 Expected Outcome 18 | 19 | The GitHub Skills activity should be added to the system and available for registration like other activities 20 | 21 | Hewbie C. 22 | 11th Grade Student 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 GitHub Skills 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Mergington High School Activities 7 | 8 | 9 | 10 |
11 |

Mergington High School

12 |

Extracurricular Activities

13 |
14 | 15 |
16 |
17 |

Available Activities

18 |
19 | 20 |

Loading activities...

21 |
22 |
23 | 24 |
25 |

Sign Up for an Activity

26 |
27 |
28 | 29 | 30 |
31 |
32 | 33 | 37 |
38 | 39 |
40 | 41 |
42 |
43 | 44 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/README.md: -------------------------------------------------------------------------------- 1 | # Mergington High School Activities API 2 | 3 | A super simple FastAPI application that allows students to view and sign up for extracurricular activities. 4 | 5 | ## Features 6 | 7 | - View all available extracurricular activities 8 | - Sign up for activities 9 | 10 | ## Getting Started 11 | 12 | 1. Install the dependencies: 13 | 14 | ``` 15 | pip install fastapi uvicorn 16 | ``` 17 | 18 | 2. Run the application: 19 | 20 | ``` 21 | python app.py 22 | ``` 23 | 24 | 3. Open your browser and go to: 25 | - API documentation: http://localhost:8000/docs 26 | - Alternative documentation: http://localhost:8000/redoc 27 | 28 | ## API Endpoints 29 | 30 | | Method | Endpoint | Description | 31 | | ------ | ----------------------------------------------------------------- | ------------------------------------------------------------------- | 32 | | GET | `/activities` | Get all activities with their details and current participant count | 33 | | POST | `/activities/{activity_name}/signup?email=student@mergington.edu` | Sign up for an activity | 34 | 35 | ## Data Model 36 | 37 | The application uses a simple data model with meaningful identifiers: 38 | 39 | 1. **Activities** - Uses activity name as identifier: 40 | 41 | - Description 42 | - Schedule 43 | - Maximum number of participants allowed 44 | - List of student emails who are signed up 45 | 46 | 2. **Students** - Uses email as identifier: 47 | - Name 48 | - Grade level 49 | 50 | All data is stored in memory, which means data will be reset when the server restarts. 51 | -------------------------------------------------------------------------------- /.github/workflows/0-start-exercise.yml: -------------------------------------------------------------------------------- 1 | name: Step 0 # Start Exercise 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | permissions: 9 | contents: write # Update Readme 10 | actions: write # Disable/enable workflows 11 | issues: write # Create issue and comment on issues 12 | 13 | env: 14 | STEP_1_FILE: ".github/steps/1-step.md" 15 | 16 | jobs: 17 | start_exercise: 18 | if: | 19 | !github.event.repository.is_template 20 | name: Start Exercise 21 | uses: skills/exercise-toolkit/.github/workflows/start-exercise.yml@v0.7.3 22 | with: 23 | exercise-title: "Integrate MCP with Copilot" 24 | intro-message: "This exercise will help you learn how to expand GitHub Copilot's capabilities with Model Context Protocol (MCP)." 25 | 26 | post_next_step_content: 27 | name: Post next step content 28 | runs-on: ubuntu-latest 29 | needs: [start_exercise] 30 | env: 31 | ISSUE_NUMBER: ${{ needs.start_exercise.outputs.issue-number }} 32 | ISSUE_REPOSITORY: ${{ github.repository }} 33 | 34 | steps: 35 | - name: Checkout 36 | uses: actions/checkout@v5 37 | 38 | - name: Get response templates 39 | uses: actions/checkout@v5 40 | with: 41 | repository: skills/exercise-toolkit 42 | path: exercise-toolkit 43 | ref: v0.7.0 44 | 45 | - name: Create comment - add step content 46 | uses: GrantBirki/comment@v2.1.1 47 | with: 48 | repository: ${{ env.ISSUE_REPOSITORY }} 49 | issue-number: ${{ env.ISSUE_NUMBER }} 50 | file: ${{ env.STEP_1_FILE }} 51 | vars: | 52 | full_repo_name: ${{ github.repository }} 53 | 54 | - name: Create comment - watching for progress 55 | uses: GrantBirki/comment@v2.1.1 56 | with: 57 | repository: ${{ env.ISSUE_REPOSITORY }} 58 | issue-number: ${{ env.ISSUE_NUMBER }} 59 | file: exercise-toolkit/markdown-templates/step-feedback/watching-for-progress.md 60 | 61 | - name: Enable next step workflow 62 | run: | 63 | gh workflow enable "Step 1" 64 | env: 65 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 66 | -------------------------------------------------------------------------------- /.github/workflows/4-step.yml: -------------------------------------------------------------------------------- 1 | name: Step 4 2 | 3 | on: 4 | issue_comment: 5 | types: [created] 6 | 7 | permissions: 8 | contents: write 9 | actions: write 10 | issues: write 11 | 12 | # Prevent running multiple times if multiple comments are created 13 | concurrency: 14 | group: ${{ github.workflow }} 15 | cancel-in-progress: true 16 | 17 | env: 18 | REVIEW_FILE: ".github/steps/x-review.md" 19 | 20 | jobs: 21 | find_exercise: 22 | name: Find Exercise Issue 23 | uses: skills/exercise-toolkit/.github/workflows/find-exercise-issue.yml@v0.7.0 24 | 25 | 26 | post_review_content: 27 | name: Post review content 28 | needs: [find_exercise] 29 | runs-on: ubuntu-latest 30 | if: | 31 | !github.event.repository.is_template 32 | env: 33 | ISSUE_REPOSITORY: ${{ github.repository }} 34 | ISSUE_NUMBER: ${{ needs.find_exercise.outputs.issue-number }} 35 | 36 | steps: 37 | - name: Checkout 38 | uses: actions/checkout@v5 39 | 40 | - name: Get response templates 41 | uses: actions/checkout@v5 42 | with: 43 | repository: skills/exercise-toolkit 44 | path: exercise-toolkit 45 | ref: v0.7.0 46 | 47 | - name: Create comment - step finished - final review next 48 | uses: GrantBirki/comment@v2.1.1 49 | with: 50 | repository: ${{ env.ISSUE_REPOSITORY }} 51 | issue-number: ${{ env.ISSUE_NUMBER }} 52 | file: exercise-toolkit/markdown-templates/step-feedback/lesson-review.md 53 | 54 | - name: Create comment - add review content 55 | uses: GrantBirki/comment@v2.1.1 56 | with: 57 | repository: ${{ env.ISSUE_REPOSITORY }} 58 | issue-number: ${{ env.ISSUE_NUMBER }} 59 | file: ${{ env.REVIEW_FILE }} 60 | 61 | - name: Disable current workflow 62 | run: gh workflow disable "${{github.workflow}}" 63 | env: 64 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 65 | 66 | finish_exercise: 67 | name: Finish Exercise 68 | needs: [find_exercise, post_review_content] 69 | uses: skills/exercise-toolkit/.github/workflows/finish-exercise.yml@v0.7.1 70 | with: 71 | issue-url: ${{ needs.find_exercise.outputs.issue-url }} 72 | exercise-title: "Integrate MCP with GitHub Copilot" -------------------------------------------------------------------------------- /.github/steps/4-step.md: -------------------------------------------------------------------------------- 1 | ## Step 4: Validating AI-generated code 2 | 3 | Great work on implementing that issue! Our extracurricular activities site is getting better every day! 💚 4 | 5 | While AI assistants like GitHub Copilot can dramatically improve productivity, it's essential to remember that **_you_** are responsible for reviewing and validating all work, generated or not. 6 | 7 | > [!tip] 8 | > In real projects, many teams use [GitHub Actions](https://github.com/features/actions) to setup automated testing. 9 | 10 | ### :keyboard: Activity: Review and merge the AI solution 11 | 12 | 1. Open the new pull request created by Copilot in a new tab. 13 | 14 | [![Examine the pull request](https://img.shields.io/badge/-Open%20Pull%20Request-1f883d?logo=github)]({{pull_request_url}}) 15 | 16 | > ✨ **Bonus:** If your Copilot subscription provides it, you can also use a specialised version of Copilot to [review the changes](https://docs.github.com/en/copilot/using-github-copilot/code-review/using-copilot-code-review?tool=webui). 17 | 18 | 1. Review the changes. When you are satisfied, merge the pull request. 19 | 20 | 1. Return to VS code and the active **Copilot Chat** session. 21 | 22 | > 🚨 **Important:** If you previously clicked Done and need to return to a previous conversation, use the **Show Chats** button at the top of the Copilot Chat panel to restore it. 23 | 24 | 1. Ask Copilot to add a comment to the issue we just finished, and to say thanks for the comments and ideas. 25 | 26 | > ![Static Badge](https://img.shields.io/badge/-Prompt-text?style=social&logo=github%20copilot) 27 | > 28 | > ```prompt 29 | > Add a closing comment to the issue we just finished. Provide a 1 sentence description 30 | > of the implemented solution and thank the commenters for their ideas and feedback. 31 | > ``` 32 | 33 |
34 | Having trouble? 🤷
35 | 36 | Some things to check 37 | 38 | - Is your MCP Server still running? 39 | - Check what information is passed to the MCP server calls - is Copilot using the correct repository? 40 | - Did Copilot comment on the bug report? 41 |
42 | 43 | 1. Once the comment has been created, Mona will start checking your work. Give her a moment to provide feedback or share the final review. Nice work! You're all done! 🎉 44 | -------------------------------------------------------------------------------- /.github/workflows/2-step.yml: -------------------------------------------------------------------------------- 1 | name: Step 2 2 | 3 | on: 4 | issues: 5 | types: [opened] 6 | 7 | # Prevent running multiple times if multiple issues are created quickly 8 | concurrency: 9 | group: ${{ github.workflow }} 10 | cancel-in-progress: true 11 | 12 | permissions: 13 | contents: read 14 | actions: write 15 | issues: write 16 | 17 | env: 18 | STEP_3_FILE: ".github/steps/3-step.md" 19 | 20 | jobs: 21 | find_exercise: 22 | name: Find Exercise Issue 23 | uses: skills/exercise-toolkit/.github/workflows/find-exercise-issue.yml@v0.7.0 24 | 25 | post_next_step_content: 26 | name: Post next step content 27 | needs: [find_exercise] 28 | runs-on: ubuntu-latest 29 | env: 30 | ISSUE_REPOSITORY: ${{ github.repository }} 31 | ISSUE_NUMBER: ${{ needs.find_exercise.outputs.issue-number }} 32 | 33 | steps: 34 | - name: Checkout 35 | uses: actions/checkout@v5 36 | 37 | - name: Get response templates 38 | uses: actions/checkout@v5 39 | with: 40 | repository: skills/exercise-toolkit 41 | path: exercise-toolkit 42 | ref: v0.7.0 43 | 44 | - name: Create comment - step finished 45 | uses: GrantBirki/comment@v2.1.1 46 | with: 47 | repository: ${{ env.ISSUE_REPOSITORY }} 48 | issue-number: ${{ env.ISSUE_NUMBER }} 49 | file: exercise-toolkit/markdown-templates/step-feedback/step-finished-prepare-next-step.md 50 | vars: | 51 | next_step_number: 3 52 | 53 | - name: Create comment - add step content 54 | uses: GrantBirki/comment@v2.1.1 55 | with: 56 | repository: ${{ env.ISSUE_REPOSITORY }} 57 | issue-number: ${{ env.ISSUE_NUMBER }} 58 | file: ${{ env.STEP_3_FILE }} 59 | 60 | - name: Create comment - watching for progress 61 | uses: GrantBirki/comment@v2.1.1 62 | with: 63 | repository: ${{ env.ISSUE_REPOSITORY }} 64 | issue-number: ${{ env.ISSUE_NUMBER }} 65 | file: exercise-toolkit/markdown-templates/step-feedback/watching-for-progress.md 66 | 67 | - name: Disable current workflow and enable next one 68 | run: | 69 | gh workflow disable "${{github.workflow}}" 70 | gh workflow enable "Step 3" 71 | env: 72 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Integrate MCP with GitHub Copilot 2 | 3 | _Learn how to give GitHub Copilot more tools to expand the capabilities of your development workflow. All in less than an hour!_ 4 | 5 | ## Welcome 6 | 7 | - **Who is this for**: Developers looking to enhance their AI-assisted workflows, GitHub Copilot users, and AI enthusiasts. 8 | - **What you'll learn**: We'll introduce MCP basics, a GitHub MCP server setup, and integration with Copilot Agent Mode. 9 | - **What you'll build**: A mixed development workflow that uses GitHub Copilot to manage issues while upgrading the extracurricular activities website for Mergington High School. 10 | - **Prerequisites**: [Getting Started with Copilot](https://github.com/skills/getting-started-with-github-copilot) Exercise 11 | - **How long**: This exercise takes less than one hour to complete. 12 | 13 | In this exercise, you will: 14 | 15 | 1. Integrate a GitHub MCP server with GitHub Copilot. 16 | 2. Delegate Copilot to research similar projects and open issues. 17 | 3. Ask Copilot to find an important issue and implement it from idea to pull request. 18 | 4. Add comments to a recently closed issue. 19 | 20 | ### How to start this exercise 21 | 22 | > [!IMPORTANT] 23 | > This exercise assumes basic knowledge of [GitHub Copilot](https://github.com/features/copilot). If you are unfamiliar, we recommend the [Getting Started with Copilot](https://github.com/skills/getting-started-with-github-copilot) exercise. 24 | 25 | Simply copy the exercise to your account, then give your favorite Octocat (Mona) **about 20 seconds** to prepare the first lesson, then **refresh the page**. 26 | 27 | [![](https://img.shields.io/badge/Copy%20Exercise-%E2%86%92-1f883d?style=for-the-badge&logo=github&labelColor=197935)](https://github.com/new?template_owner=skills&template_name=integrate-mcp-with-copilot&owner=%40me&name=skills-integrate-mcp-with-copilot&description=Exercise:+Integrate+Model+Context+Protocol+with+GitHub+Copilot&visibility=public) 28 | 29 |
30 | Having trouble? 🤷
31 | 32 | When copying the exercise, we recommend the following settings: 33 | 34 | - For owner, choose your personal account or an organization to host the repository. 35 | 36 | - We recommend creating a public repository, since private repositories will use Actions minutes. 37 | 38 | If the exercise isn't ready in 20 seconds, please check the [Actions](../../actions) tab. 39 | 40 | - Check to see if a job is running. Sometimes it simply takes a bit longer. 41 | 42 | - If the page shows a failed job, please submit an issue. Nice, you found a bug! 🐛 43 | 44 |
45 | 46 | --- 47 | 48 | © 2025 GitHub • [Code of Conduct](https://www.contributor-covenant.org/version/2/1/code_of_conduct/code_of_conduct.md) • [MIT License](https://gh.io/mit) 49 | -------------------------------------------------------------------------------- /.github/steps/3-step.md: -------------------------------------------------------------------------------- 1 | ## Step 3: Solve issues with Agent Mode and GitHub MCP Server 2 | 3 | Great work doing that research and finding a potential collaboration opportunity. 4 | Not only did we find some new ideas to help organize extracurricular activities, but we did all that quickly too. 5 | 6 | Now, let's use our MCP server's tools and Copilot to do a bit of triage and get some work done. 7 | 8 | ### :keyboard: Activity: Easily implement an important issue 9 | 10 | The issue backlog is piling up. Let’s finally tackle one, but which deserves our attention first? 11 | 12 | 1. Ensure the **Copilot Chat** panel is open and **Agent** mode is selected. Verify the MCP server tools are also still available. 13 | 14 | 1. Ask Copilot about the open issues on this repository. 15 | 16 | > ![Static Badge](https://img.shields.io/badge/-Prompt-text?style=social&logo=github%20copilot) 17 | > 18 | > ```prompt 19 | > How many open issues are there on my repository? 20 | > ``` 21 | 22 | > 🪧 **Note:** Check that the List Issues tool is called with proper parameters. 23 | 24 | 1. Ask Copilot to summarize the important issues. 25 | 26 | > ![Static Badge](https://img.shields.io/badge/-Prompt-text?style=social&logo=github%20copilot) 27 | > 28 | > ```prompt 29 | > Oh no. That's too many for me! Please get the list of issues, 30 | > review the descriptions and comments, and pick the top 3 most important. 31 | > ``` 32 | 33 |
34 | 💡 Tip: Pre-authorize tool usage
35 | 36 | If Copilot uses a tool often, you can proactively grant permission for the rest of the conversation session. 37 | 38 | 39 | 40 |
41 | 42 | 1. Review the suggested issues. If Copilot didn't give a specific recommendation, try providing some feedback to narrow the results. 43 | 44 | 1. With the list narrowed, ask Copilot to implement an issue. **Mona won't grade if the changes work, just that an attempt was made.** 45 | 46 | > ![Static Badge](https://img.shields.io/badge/-Prompt-text?style=social&logo=github%20copilot) 47 | > 48 | > ```prompt 49 | > #codebase Let's do the first one. Follow these steps: 50 | > 1. Checkout a new local branch for making our changes. 51 | > 2. Make the changes then confirm with me that they look correct. 52 | > 3. Push the changes and create a pull request. 53 | > ``` 54 | 55 | > ⚠️ **Warning:** Always verify the the actions Copilot is asking to perform, especially with the external abilities provided by an MCP server, which probably have no undo option. 56 | 57 | 1. Once the pull request is created, Mona will start checking your work. Give her a moment and keep watch of the comments. You will see her respond with progress info and the next step! 58 | 59 |
60 | Having trouble?
61 | 62 | - If tools are not being requested, verify your MCP configuration is correct. 63 | - If Copilot cannot retrieve results, verify you are using this Codespace's token or a Personal Access Token (PAT) with appropriate permissions. By default, the codespace token we are using only has access to this repository. 64 | 65 |
66 | -------------------------------------------------------------------------------- /src/static/styles.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | margin: 0; 4 | padding: 0; 5 | font-family: Arial, sans-serif; 6 | } 7 | 8 | body { 9 | font-family: Arial, sans-serif; 10 | line-height: 1.6; 11 | color: #333; 12 | max-width: 1200px; 13 | margin: 0 auto; 14 | padding: 20px; 15 | background-color: #f5f5f5; 16 | } 17 | 18 | header { 19 | text-align: center; 20 | padding: 20px 0; 21 | margin-bottom: 30px; 22 | background-color: #1a237e; 23 | color: white; 24 | border-radius: 5px; 25 | } 26 | 27 | header h1 { 28 | margin-bottom: 10px; 29 | } 30 | 31 | main { 32 | display: flex; 33 | flex-wrap: wrap; 34 | gap: 30px; 35 | justify-content: center; 36 | } 37 | 38 | @media (min-width: 768px) { 39 | main { 40 | grid-template-columns: 2fr 1fr; 41 | } 42 | } 43 | 44 | section { 45 | background-color: white; 46 | padding: 20px; 47 | border-radius: 5px; 48 | box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); 49 | width: 100%; 50 | max-width: 500px; 51 | } 52 | 53 | section h3 { 54 | margin-bottom: 20px; 55 | padding-bottom: 10px; 56 | border-bottom: 1px solid #ddd; 57 | color: #1a237e; 58 | } 59 | 60 | .activity-card { 61 | margin-bottom: 15px; 62 | padding: 15px; 63 | border: 1px solid #ddd; 64 | border-radius: 5px; 65 | background-color: #f9f9f9; 66 | } 67 | 68 | .activity-card h4 { 69 | margin-bottom: 10px; 70 | color: #0066cc; 71 | } 72 | 73 | .activity-card p { 74 | margin-bottom: 8px; 75 | } 76 | 77 | /* New styles for participants section */ 78 | .participants-container { 79 | margin-top: 15px; 80 | padding-top: 12px; 81 | border-top: 1px dashed #ccc; 82 | } 83 | 84 | .participants-section h5 { 85 | margin-bottom: 8px; 86 | color: #1a237e; 87 | font-size: 16px; 88 | } 89 | 90 | .participants-section ul { 91 | list-style-type: none; 92 | padding-left: 5px; 93 | } 94 | 95 | .participants-section ul li { 96 | padding: 4px 0; 97 | position: relative; 98 | display: flex; 99 | align-items: center; 100 | justify-content: space-between; 101 | } 102 | 103 | /* Remove the bullet point pseudo-element */ 104 | .participants-section ul li::before { 105 | display: none; 106 | } 107 | 108 | .participant-email { 109 | flex-grow: 1; 110 | margin-right: 8px; 111 | } 112 | 113 | .delete-btn { 114 | background: none; 115 | border: none; 116 | color: #c62828; 117 | cursor: pointer; 118 | font-size: 14px; 119 | padding: 2px 5px; 120 | transition: all 0.2s; 121 | border-radius: 3px; 122 | } 123 | 124 | .delete-btn:hover { 125 | background-color: #ffebee; 126 | } 127 | 128 | .participants-section p { 129 | color: #777; 130 | font-style: italic; 131 | } 132 | 133 | .form-group { 134 | margin-bottom: 15px; 135 | } 136 | 137 | .form-group label { 138 | display: block; 139 | margin-bottom: 5px; 140 | font-weight: bold; 141 | } 142 | 143 | .form-group input, 144 | .form-group select { 145 | width: 100%; 146 | padding: 10px; 147 | border: 1px solid #ddd; 148 | border-radius: 4px; 149 | font-size: 16px; 150 | } 151 | 152 | button { 153 | background-color: #1a237e; 154 | color: white; 155 | border: none; 156 | padding: 10px 15px; 157 | font-size: 16px; 158 | border-radius: 5px; 159 | cursor: pointer; 160 | transition: background-color 0.2s; 161 | } 162 | 163 | button:hover { 164 | background-color: #3949ab; 165 | } 166 | 167 | .message { 168 | margin-top: 20px; 169 | padding: 10px; 170 | border-radius: 4px; 171 | } 172 | 173 | .success { 174 | background-color: #e8f5e9; 175 | color: #2e7d32; 176 | border: 1px solid #a5d6a7; 177 | } 178 | 179 | .error { 180 | background-color: #ffebee; 181 | color: #c62828; 182 | border: 1px solid #ef9a9a; 183 | } 184 | 185 | .info { 186 | background-color: #d1ecf1; 187 | color: #0c5460; 188 | border: 1px solid #bee5eb; 189 | } 190 | 191 | .hidden { 192 | display: none; 193 | } 194 | 195 | footer { 196 | text-align: center; 197 | margin-top: 30px; 198 | padding: 20px; 199 | color: #666; 200 | } 201 | -------------------------------------------------------------------------------- /.github/steps/2-step.md: -------------------------------------------------------------------------------- 1 | ## Step 2: Agent Mode and an MCP Server for GitHub 2 | 3 | Great work! You just connected your first MCP server to GitHub Copilot! 🎉 4 | 5 | 🚨 The teachers have been busy opening new issues in your repository with bugs and feature requests! Go [take a look](https://github.com/{{full_repo_name}}/issues) - so many good ideas! 6 | 7 | We should probably look into them and start researching for other upgrades. Fortunately, with an MCP server for GitHub, triaging these and even doing some research to get ahead should be pretty quick! 🕵️ 8 | 9 | ### 📖 Theory: How MCP Tool Calling Works in Agent Mode 10 | 11 | Now that we have the GitHub MCP connected, let's look at how **agent mode** actually uses these external tools. 12 | 13 | With every prompt you send, Copilot also includes the catalog (list + schema) of available tools. Copilot can then plan and decide: 14 | 15 | - Is any tool needed for this request? 16 | - Which tool(s) best match the intent? 17 | - What arguments (per each tool's input schema) should be passed? 18 | 19 | Copilot then executes the chosen tool call(s) and streams results back to the LLM. 20 | 21 | ![Flowchart diagram illustrating how a user interacts with Copilot Agent Mode](https://github.blog/wp-content/uploads/2025/05/how-it-works.png) 22 | 23 | > [!TIP] 24 | > You can also explicitly nudge Copilot to call a specific tool by including `#` in your prompt (e.g `#create_pull_request`, `#codebase`). 25 | 26 | From here, Copilot can use a set of GitHub‑aware tools to do more than just read or edit code in your repo. Here are a few things you can ask it to do: 27 | 28 | - Discover similar public projects to get inspiration. 29 | - Search issues considering description, comments, and likes. 30 | - Turn the new ideas you like into issues right away so you don’t lose them. 31 | - Retrieve an issue, make changes on a branch, and start a pull request. 32 | 33 | Isn't that cool?! Now let's do it! 👩‍🚀 34 | 35 | ### :keyboard: Activity: Quickly find and save ideas 36 | 37 | Let's put the GitHub MCP server to use by researching, comparing, and capturing enhancement ideas! 38 | 39 | 1. Close any open files inside your codespace. This will help reduce unnecessary context. 40 | 41 | 1. Ensure the **Copilot Chat** panel is open and **Agent** mode is selected. Verify the MCP server tools are also still available. 42 | 43 | 1. Ask Copilot to search GitHub for projects similar to this one. 44 | 45 | > ![Static Badge](https://img.shields.io/badge/-Prompt-text?style=social&logo=github%20copilot) 46 | > 47 | > ```prompt 48 | > Search for any other repositories for organizing extra curricular activities 49 | > ``` 50 | 51 | 1. When an MCP tool is required, Copilot may ask for permission. **Verify the request** and modify if necessary, then click **Continue**. 52 | 53 | request permission dialog 54 | 55 | 1. Ask Copilot to describe one of the projects. Explore until you find something you like. 56 | 57 | > ![Static Badge](https://img.shields.io/badge/-Prompt-text?style=social&logo=github%20copilot) 58 | > 59 | > ```prompt 60 | > Please look at the code for the 3rd option and give me a detailed description of the features. 61 | > ``` 62 | 63 | 1. Use Copilot to compare and generate ideas for enhancements. 64 | 65 | > ![Static Badge](https://img.shields.io/badge/-Prompt-text?style=social&logo=github%20copilot) 66 | > 67 | > ```prompt 68 | > Please compare these features to our project. Which would be new? 69 | > ``` 70 | 71 | 1. Nice! Let's have Copilot create issues to save these ideas. 72 | 73 | > ![Static Badge](https://img.shields.io/badge/-Prompt-text?style=social&logo=github%20copilot) 74 | > 75 | > ```prompt 76 | > I like it. Let's create issues for these in my repository. 77 | > ``` 78 | 79 | 1. Copilot will ask for permission to create issues on your repository. Click **Continue** for each new issue. Reminder: **verify the request** before running. 80 | 81 | request permission dialog 82 | 83 | 1. Since we are done researching, let's finish this chat session to clear the context. At the top of the **Copilot Chat** panel, click the **New Chat** icon (plus sign). 84 | 85 | 1. With the new issues created, Mona should already be busy checking your work. Give her a moment and keep watch in the comments. You will see her respond with progress info and the next lesson. 86 | 87 | > [!NOTE] 88 | > The Model Context Protocol (MCP) landscape is quickly evolving. Many servers, including the [Official GitHub MCP server](https://github.com/github/github-mcp-server) are in active development and do not have full parity with their stable APIs. 89 | -------------------------------------------------------------------------------- /src/app.py: -------------------------------------------------------------------------------- 1 | """ 2 | High School Management System API 3 | 4 | A super simple FastAPI application that allows students to view and sign up 5 | for extracurricular activities at Mergington High School. 6 | """ 7 | 8 | from fastapi import FastAPI, HTTPException 9 | from fastapi.staticfiles import StaticFiles 10 | from fastapi.responses import RedirectResponse 11 | import os 12 | from pathlib import Path 13 | 14 | app = FastAPI(title="Mergington High School API", 15 | description="API for viewing and signing up for extracurricular activities") 16 | 17 | # Mount the static files directory 18 | current_dir = Path(__file__).parent 19 | app.mount("/static", StaticFiles(directory=os.path.join(Path(__file__).parent, 20 | "static")), name="static") 21 | 22 | # In-memory activity database 23 | activities = { 24 | "Chess Club": { 25 | "description": "Learn strategies and compete in chess tournaments", 26 | "schedule": "Fridays, 3:30 PM - 5:00 PM", 27 | "max_participants": 12, 28 | "participants": ["michael@mergington.edu", "daniel@mergington.edu"] 29 | }, 30 | "Programming Class": { 31 | "description": "Learn programming fundamentals and build software projects", 32 | "schedule": "Tuesdays and Thursdays, 3:30 PM - 4:30 PM", 33 | "max_participants": 20, 34 | "participants": ["emma@mergington.edu", "sophia@mergington.edu"] 35 | }, 36 | "Gym Class": { 37 | "description": "Physical education and sports activities", 38 | "schedule": "Mondays, Wednesdays, Fridays, 2:00 PM - 3:00 PM", 39 | "max_participants": 30, 40 | "participants": ["john@mergington.edu", "olivia@mergington.edu"] 41 | }, 42 | "Soccer Team": { 43 | "description": "Join the school soccer team and compete in matches", 44 | "schedule": "Tuesdays and Thursdays, 4:00 PM - 5:30 PM", 45 | "max_participants": 22, 46 | "participants": ["liam@mergington.edu", "noah@mergington.edu"] 47 | }, 48 | "Basketball Team": { 49 | "description": "Practice and play basketball with the school team", 50 | "schedule": "Wednesdays and Fridays, 3:30 PM - 5:00 PM", 51 | "max_participants": 15, 52 | "participants": ["ava@mergington.edu", "mia@mergington.edu"] 53 | }, 54 | "Art Club": { 55 | "description": "Explore your creativity through painting and drawing", 56 | "schedule": "Thursdays, 3:30 PM - 5:00 PM", 57 | "max_participants": 15, 58 | "participants": ["amelia@mergington.edu", "harper@mergington.edu"] 59 | }, 60 | "Drama Club": { 61 | "description": "Act, direct, and produce plays and performances", 62 | "schedule": "Mondays and Wednesdays, 4:00 PM - 5:30 PM", 63 | "max_participants": 20, 64 | "participants": ["ella@mergington.edu", "scarlett@mergington.edu"] 65 | }, 66 | "Math Club": { 67 | "description": "Solve challenging problems and participate in math competitions", 68 | "schedule": "Tuesdays, 3:30 PM - 4:30 PM", 69 | "max_participants": 10, 70 | "participants": ["james@mergington.edu", "benjamin@mergington.edu"] 71 | }, 72 | "Debate Team": { 73 | "description": "Develop public speaking and argumentation skills", 74 | "schedule": "Fridays, 4:00 PM - 5:30 PM", 75 | "max_participants": 12, 76 | "participants": ["charlotte@mergington.edu", "henry@mergington.edu"] 77 | } 78 | } 79 | 80 | 81 | @app.get("/") 82 | def root(): 83 | return RedirectResponse(url="/static/index.html") 84 | 85 | 86 | @app.get("/activities") 87 | def get_activities(): 88 | return activities 89 | 90 | 91 | @app.post("/activities/{activity_name}/signup") 92 | def signup_for_activity(activity_name: str, email: str): 93 | """Sign up a student for an activity""" 94 | # Validate activity exists 95 | if activity_name not in activities: 96 | raise HTTPException(status_code=404, detail="Activity not found") 97 | 98 | # Get the specific activity 99 | activity = activities[activity_name] 100 | 101 | # Validate student is not already signed up 102 | if email in activity["participants"]: 103 | raise HTTPException( 104 | status_code=400, 105 | detail="Student is already signed up" 106 | ) 107 | 108 | # Add student 109 | activity["participants"].append(email) 110 | return {"message": f"Signed up {email} for {activity_name}"} 111 | 112 | 113 | @app.delete("/activities/{activity_name}/unregister") 114 | def unregister_from_activity(activity_name: str, email: str): 115 | """Unregister a student from an activity""" 116 | # Validate activity exists 117 | if activity_name not in activities: 118 | raise HTTPException(status_code=404, detail="Activity not found") 119 | 120 | # Get the specific activity 121 | activity = activities[activity_name] 122 | 123 | # Validate student is signed up 124 | if email not in activity["participants"]: 125 | raise HTTPException( 126 | status_code=400, 127 | detail="Student is not signed up for this activity" 128 | ) 129 | 130 | # Remove student 131 | activity["participants"].remove(email) 132 | return {"message": f"Unregistered {email} from {activity_name}"} 133 | -------------------------------------------------------------------------------- /.github/workflows/1-step.yml: -------------------------------------------------------------------------------- 1 | name: Step 1 2 | 3 | on: 4 | push: 5 | paths: 6 | - ".vscode/mcp.json" 7 | 8 | permissions: 9 | contents: read 10 | actions: write 11 | issues: write 12 | 13 | env: 14 | STEP_2_FILE: ".github/steps/2-step.md" 15 | 16 | jobs: 17 | find_exercise: 18 | name: Find Exercise Issue 19 | uses: skills/exercise-toolkit/.github/workflows/find-exercise-issue.yml@v0.7.0 20 | 21 | create_issues: 22 | name: Create issues 23 | runs-on: ubuntu-latest 24 | 25 | steps: 26 | - name: Checkout repository 27 | uses: actions/checkout@v5 28 | 29 | # TODO: replace with https://github.com/marketplace/actions/create-an-issue 30 | - name: Create issues 31 | uses: actions/github-script@v6 32 | with: 33 | github-token: ${{ secrets.GITHUB_TOKEN }} 34 | script: | 35 | const fs = require('fs'); 36 | const path = require('path'); 37 | 38 | async function createIssuesFromMarkdownFiles(dir, label) { 39 | // Get list of markdown files 40 | const files = fs.readdirSync(dir); 41 | console.log(`Creating ${files.length} issues with '${label}' label from '${dir}' folder.`); 42 | 43 | // Create the issue 44 | for (const file of files) { 45 | 46 | // Load the file content 47 | const fullPath = path.join(dir, file); 48 | const fileContent = fs.readFileSync(fullPath, 'utf8'); 49 | 50 | // Split the file content into title, body, and comments 51 | const title = fileContent.split('\n')[0].replace('#', '').trim(); 52 | const body = fileContent.split('\n').slice(1).join('\n').split('----- COMMENTS -----')[0].trim(); 53 | let comments = fileContent.split('----- COMMENTS -----').slice(1).join('\n').trim().split('\n') 54 | comments = comments.filter(comment => comment.trim() !== ''); 55 | 56 | // Log the content 57 | // console.log(`\n\Title: ${title}`); 58 | // console.log(`Body:\n${body}`); 59 | // for (const comment of comments) { 60 | // console.log(`Comment: '${comment.trim()}'`); 61 | // } 62 | // console.log(`\n`); 63 | 64 | // Create the issue 65 | const issue = await github.rest.issues.create({ 66 | owner: context.repo.owner, 67 | repo: context.repo.repo, 68 | title: title, 69 | body: body, 70 | labels: [label], 71 | }); 72 | 73 | // Add comments 74 | for (const comment of comments) { 75 | await github.rest.issues.createComment({ 76 | owner: context.repo.owner, 77 | repo: context.repo.repo, 78 | issue_number: issue.data.number, 79 | body: comment, 80 | }); 81 | } 82 | 83 | console.log(`Created issue: ${title}, URL: ${issue.data.html_url} with ${comments.length} comments.`); 84 | } 85 | }; 86 | 87 | // Load issues from both folders 88 | await createIssuesFromMarkdownFiles('.github/steps/1-step-issues/bug/', 'bug'); 89 | await createIssuesFromMarkdownFiles('.github/steps/1-step-issues/enhancement/', 'enhancement'); 90 | 91 | post_next_step_content: 92 | name: Post next step content 93 | needs: [find_exercise] 94 | runs-on: ubuntu-latest 95 | env: 96 | ISSUE_REPOSITORY: ${{ github.repository }} 97 | ISSUE_NUMBER: ${{ needs.find_exercise.outputs.issue-number }} 98 | 99 | steps: 100 | - name: Checkout 101 | uses: actions/checkout@v5 102 | 103 | - name: Get response templates 104 | uses: actions/checkout@v5 105 | with: 106 | repository: skills/exercise-toolkit 107 | path: exercise-toolkit 108 | ref: v0.7.0 109 | 110 | - name: Create comment - step finished 111 | uses: GrantBirki/comment@v2.1.1 112 | with: 113 | repository: ${{ env.ISSUE_REPOSITORY }} 114 | issue-number: ${{ env.ISSUE_NUMBER }} 115 | file: exercise-toolkit/markdown-templates/step-feedback/step-finished-prepare-next-step.md 116 | vars: | 117 | next_step_number: 2 118 | 119 | - name: Create comment - add step content 120 | uses: GrantBirki/comment@v2.1.1 121 | with: 122 | repository: ${{ env.ISSUE_REPOSITORY }} 123 | issue-number: ${{ env.ISSUE_NUMBER }} 124 | file: ${{ env.STEP_2_FILE }} 125 | vars: | 126 | full_repo_name: ${{ github.repository }} 127 | 128 | - name: Create comment - watching for progress 129 | uses: GrantBirki/comment@v2.1.1 130 | with: 131 | repository: ${{ env.ISSUE_REPOSITORY }} 132 | issue-number: ${{ env.ISSUE_NUMBER }} 133 | file: exercise-toolkit/markdown-templates/step-feedback/watching-for-progress.md 134 | 135 | - name: Disable current workflow and enable next one 136 | run: | 137 | gh workflow disable "${{github.workflow}}" 138 | gh workflow enable "Step 2" 139 | env: 140 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 141 | -------------------------------------------------------------------------------- /src/static/app.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded", () => { 2 | const activitiesList = document.getElementById("activities-list"); 3 | const activitySelect = document.getElementById("activity"); 4 | const signupForm = document.getElementById("signup-form"); 5 | const messageDiv = document.getElementById("message"); 6 | 7 | // Function to fetch activities from API 8 | async function fetchActivities() { 9 | try { 10 | const response = await fetch("/activities"); 11 | const activities = await response.json(); 12 | 13 | // Clear loading message 14 | activitiesList.innerHTML = ""; 15 | 16 | // Populate activities list 17 | Object.entries(activities).forEach(([name, details]) => { 18 | const activityCard = document.createElement("div"); 19 | activityCard.className = "activity-card"; 20 | 21 | const spotsLeft = 22 | details.max_participants - details.participants.length; 23 | 24 | // Create participants HTML with delete icons instead of bullet points 25 | const participantsHTML = 26 | details.participants.length > 0 27 | ? `
28 |
Participants:
29 | 37 |
` 38 | : `

No participants yet

`; 39 | 40 | activityCard.innerHTML = ` 41 |

${name}

42 |

${details.description}

43 |

Schedule: ${details.schedule}

44 |

Availability: ${spotsLeft} spots left

45 |
46 | ${participantsHTML} 47 |
48 | `; 49 | 50 | activitiesList.appendChild(activityCard); 51 | 52 | // Add option to select dropdown 53 | const option = document.createElement("option"); 54 | option.value = name; 55 | option.textContent = name; 56 | activitySelect.appendChild(option); 57 | }); 58 | 59 | // Add event listeners to delete buttons 60 | document.querySelectorAll(".delete-btn").forEach((button) => { 61 | button.addEventListener("click", handleUnregister); 62 | }); 63 | } catch (error) { 64 | activitiesList.innerHTML = 65 | "

Failed to load activities. Please try again later.

"; 66 | console.error("Error fetching activities:", error); 67 | } 68 | } 69 | 70 | // Handle unregister functionality 71 | async function handleUnregister(event) { 72 | const button = event.target; 73 | const activity = button.getAttribute("data-activity"); 74 | const email = button.getAttribute("data-email"); 75 | 76 | try { 77 | const response = await fetch( 78 | `/activities/${encodeURIComponent( 79 | activity 80 | )}/unregister?email=${encodeURIComponent(email)}`, 81 | { 82 | method: "DELETE", 83 | } 84 | ); 85 | 86 | const result = await response.json(); 87 | 88 | if (response.ok) { 89 | messageDiv.textContent = result.message; 90 | messageDiv.className = "success"; 91 | 92 | // Refresh activities list to show updated participants 93 | fetchActivities(); 94 | } else { 95 | messageDiv.textContent = result.detail || "An error occurred"; 96 | messageDiv.className = "error"; 97 | } 98 | 99 | messageDiv.classList.remove("hidden"); 100 | 101 | // Hide message after 5 seconds 102 | setTimeout(() => { 103 | messageDiv.classList.add("hidden"); 104 | }, 5000); 105 | } catch (error) { 106 | messageDiv.textContent = "Failed to unregister. Please try again."; 107 | messageDiv.className = "error"; 108 | messageDiv.classList.remove("hidden"); 109 | console.error("Error unregistering:", error); 110 | } 111 | } 112 | 113 | // Handle form submission 114 | signupForm.addEventListener("submit", async (event) => { 115 | event.preventDefault(); 116 | 117 | const email = document.getElementById("email").value; 118 | const activity = document.getElementById("activity").value; 119 | 120 | try { 121 | const response = await fetch( 122 | `/activities/${encodeURIComponent( 123 | activity 124 | )}/signup?email=${encodeURIComponent(email)}`, 125 | { 126 | method: "POST", 127 | } 128 | ); 129 | 130 | const result = await response.json(); 131 | 132 | if (response.ok) { 133 | messageDiv.textContent = result.message; 134 | messageDiv.className = "success"; 135 | signupForm.reset(); 136 | 137 | // Refresh activities list to show updated participants 138 | fetchActivities(); 139 | } else { 140 | messageDiv.textContent = result.detail || "An error occurred"; 141 | messageDiv.className = "error"; 142 | } 143 | 144 | messageDiv.classList.remove("hidden"); 145 | 146 | // Hide message after 5 seconds 147 | setTimeout(() => { 148 | messageDiv.classList.add("hidden"); 149 | }, 5000); 150 | } catch (error) { 151 | messageDiv.textContent = "Failed to sign up. Please try again."; 152 | messageDiv.className = "error"; 153 | messageDiv.classList.remove("hidden"); 154 | console.error("Error signing up:", error); 155 | } 156 | }); 157 | 158 | // Initialize app 159 | fetchActivities(); 160 | }); 161 | -------------------------------------------------------------------------------- /.github/workflows/3-step.yml: -------------------------------------------------------------------------------- 1 | name: Step 3 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | 8 | permissions: 9 | contents: read 10 | actions: write 11 | issues: write 12 | 13 | env: 14 | STEP_4_FILE: ".github/steps/4-step.md" 15 | 16 | jobs: 17 | find_exercise: 18 | name: Find Exercise Issue 19 | uses: skills/exercise-toolkit/.github/workflows/find-exercise-issue.yml@v0.7.0 20 | 21 | check_step_work: 22 | name: Check step work 23 | runs-on: ubuntu-latest 24 | needs: [find_exercise] 25 | if: | 26 | !github.event.repository.is_template 27 | env: 28 | ISSUE_REPOSITORY: ${{ github.repository }} 29 | ISSUE_NUMBER: ${{ needs.find_exercise.outputs.issue-number }} 30 | 31 | steps: 32 | - name: Checkout 33 | uses: actions/checkout@v5 34 | 35 | - name: Get response templates 36 | uses: actions/checkout@v5 37 | with: 38 | repository: skills/exercise-toolkit 39 | path: exercise-toolkit 40 | ref: v0.7.0 41 | 42 | - name: Find last comment 43 | id: find-last-comment 44 | uses: peter-evans/find-comment@v3 45 | with: 46 | repository: ${{ env.ISSUE_REPOSITORY }} 47 | issue-number: ${{ env.ISSUE_NUMBER }} 48 | direction: last 49 | 50 | - name: Update comment - checking work 51 | uses: GrantBirki/comment@v2.1.1 52 | with: 53 | repository: ${{ env.ISSUE_REPOSITORY }} 54 | issue-number: ${{ env.ISSUE_NUMBER }} 55 | comment-id: ${{ steps.find-last-comment.outputs.comment-id }} 56 | file: exercise-toolkit/markdown-templates/step-feedback/checking-work.md 57 | edit-mode: replace 58 | 59 | # START: Check practical exercise 60 | 61 | - name: Get changed files 62 | id: changed-files 63 | continue-on-error: true 64 | uses: tj-actions/changed-files@v46.0.3 65 | 66 | - name: Check for changes in src folder 67 | id: check-src-changes 68 | continue-on-error: true 69 | env: 70 | ALL_CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }} 71 | run: | 72 | # Show the list of all changed files 73 | echo "All changed files: ${ALL_CHANGED_FILES}" 74 | 75 | # Initialize flag 76 | has_src_changed=false 77 | 78 | # Check each changed file 79 | for file in ${ALL_CHANGED_FILES}; do 80 | if [[ $file == src/* ]]; then 81 | has_src_changed=true 82 | break 83 | fi 84 | done 85 | 86 | # Set step message based on results 87 | if ! $has_src_changed; then 88 | echo "No changes found in src directory" 89 | echo "STEP_MESSAGE=Use Copilot to implement changes in the src directory" >> $GITHUB_OUTPUT 90 | exit 1 91 | fi 92 | 93 | echo "Changes found in src directory" 94 | echo "STEP_MESSAGE=Great work! Changes detected in src directory" >> $GITHUB_OUTPUT 95 | 96 | - name: Update comment - step results 97 | uses: GrantBirki/comment@v2.1.1 98 | with: 99 | repository: ${{ env.ISSUE_REPOSITORY }} 100 | issue-number: ${{ env.ISSUE_NUMBER }} 101 | comment-id: ${{ steps.find-last-comment.outputs.comment-id }} 102 | edit-mode: replace 103 | file: exercise-toolkit/markdown-templates/step-feedback/step-results-table.md 104 | vars: | 105 | step_number: 3 106 | results_table: 107 | - description: ${{ steps.check-src-changes.outputs.STEP_MESSAGE }} 108 | passed: ${{ steps.check-src-changes.outcome == 'success' }} 109 | 110 | # END: Check practical exercise 111 | 112 | - name: Fail job if not all checks passed 113 | if: contains(steps.*.outcome, 'failure') 114 | run: exit 1 115 | 116 | post_next_step_content: 117 | name: Post next step content 118 | needs: [find_exercise, check_step_work] 119 | runs-on: ubuntu-latest 120 | env: 121 | ISSUE_REPOSITORY: ${{ github.repository }} 122 | ISSUE_NUMBER: ${{ needs.find_exercise.outputs.issue-number }} 123 | 124 | steps: 125 | - name: Checkout 126 | uses: actions/checkout@v5 127 | 128 | - name: Get response templates 129 | uses: actions/checkout@v5 130 | with: 131 | repository: skills/exercise-toolkit 132 | path: exercise-toolkit 133 | ref: v0.7.0 134 | 135 | - name: Create comment - step finished 136 | uses: GrantBirki/comment@v2.1.1 137 | with: 138 | repository: ${{ env.ISSUE_REPOSITORY }} 139 | issue-number: ${{ env.ISSUE_NUMBER }} 140 | file: exercise-toolkit/markdown-templates/step-feedback/step-finished-prepare-next-step.md 141 | vars: | 142 | next_step_number: 4 143 | 144 | - name: Create comment - add step content 145 | uses: GrantBirki/comment@v2.1.1 146 | with: 147 | repository: ${{ env.ISSUE_REPOSITORY }} 148 | issue-number: ${{ env.ISSUE_NUMBER }} 149 | file: ${{ env.STEP_4_FILE }} 150 | vars: | 151 | pull_request_url: ${{ github.event.pull_request.html_url }} 152 | 153 | - name: Create comment - watching for progress 154 | uses: GrantBirki/comment@v2.1.1 155 | with: 156 | repository: ${{ env.ISSUE_REPOSITORY }} 157 | issue-number: ${{ env.ISSUE_NUMBER }} 158 | file: exercise-toolkit/markdown-templates/step-feedback/watching-for-progress.md 159 | 160 | - name: Disable current workflow and enable next one 161 | run: | 162 | gh workflow disable "${{github.workflow}}" 163 | gh workflow enable "Step 4" 164 | env: 165 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 166 | -------------------------------------------------------------------------------- /.github/steps/1-step.md: -------------------------------------------------------------------------------- 1 | ## Step 1: Introduction to MCP and environment setup 2 | 3 | copilot logo 4 | 5 | In the [Getting Started with GitHub Copilot](https://github.com/skills/getting-started-with-github-copilot) exercise, we were introduced to the Mergington High School's extracurricular activities website, which allowed students to sign up for events. 6 | 7 | And now we have a problem... but.. it's a good one! More teachers are asking to use it! 🎉 8 | 9 | Our fellow teachers have lots of ideas but we can't seem to keep up with all the requests! 😮 To fix this issue, lets give GitHub Copilot an upgrade by enabling Model Context Protocol (MCP). To be more specific, we will add the GitHub MCP server, which will enable a combined workflow of issue management and website upgrades. 🧑‍🚀 10 | 11 | Let's get started! 12 | 13 | ### 📖 Theory: What is Model Context Protocol (MCP)? 14 | 15 | [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) is often referred to as "USB-C for AI" - a universal connector that allows GitHub Copilot (and other AI tools) to seamlessly interact with other services. 16 | 17 | Essentially, it is a way to describe the capabilities and requirements of a service, so AI tools can easily determine what methods to use and to accurately provide the parameters. An MCP server is providing that interface. 18 | 19 | ```mermaid 20 | graph LR 21 | A[Developer] -->|Uses| B[GitHub Copilot] 22 | B -->|Unified API| MCP[Model Context Protocol] 23 | 24 | MCP <-->|Unique API| C[(GitHub)] 25 | MCP <-->|Unique API| D[(Slack)] 26 | MCP <-->|Unique API| E[(Figma)] 27 | 28 | style B fill:#4CAF50,stroke:#333,stroke-width:2px 29 | 30 | subgraph "Less Context Switching, More Coding" 31 | B 32 | MCP 33 | C 34 | D 35 | E 36 | 37 | end 38 | ``` 39 | 40 | ### :keyboard: Activity: Get to know your environment 41 | 42 | Before we dive into MCP, let's start up our development environment and refamiliarize ourself with the extracurricular activity application. 43 | 44 | 1. Right-click the below button to open the **Create Codespace** page in a new tab. Use the default configuration. 45 | 46 | [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/{{full_repo_name}}?quickstart=1) 47 | 48 | 1. Validate the **Copilot Chat** and **Python** extensions are installed and enabled. 49 | 50 | copilot extension for VS Code
51 | python extension for VS Code 52 | 53 | 1. Verify our application runs before modification. In the left sidebar, select the **Run and Debug** tab and then press the **Start Debugging** icon. 54 | 55 |
56 | 📸 Show screenshot
57 | 58 | run and debug 59 | 60 |
61 | 62 |
63 | 🤷 Having trouble?
64 | 65 | If the **Run and Debug** area is empty, try reloading VS Code: Open the command palette (`Ctrl`+`Shift`+`P`) and search for `Developer: Reload Window`. 66 | 67 | empty run and debug panel 68 | 69 |
70 | 71 | 1. Use the **Ports** tab to find the webpage address, open it, and verify it is running. 72 | 73 |
74 | 📸 Show screenshot
75 | 76 | ports tab 77 | 78 | ![Screenshot of Mergington High School WebApp](https://github.com/user-attachments/assets/5cb88d53-d948-457e-9f4b-403d697fa93a) 79 | 80 |
81 | 82 | ### :keyboard: Activity: Add the GitHub MCP server 83 | 84 | 1. Inside your codespace, open the **Copilot Chat** panel and verify **Agent** mode is selected. 85 | 86 | image 87 | 88 |
89 | Agent mode missing?
90 | 91 | - Verify VS Code is at least `v1.99.0`. 92 | - Verify the Copilot extension is at least `v1.296.0`. 93 | - Check if Agent mode is enabled in your [user or workspace settings](https://code.visualstudio.com/docs/configure/settings#_workspace-settings). 94 | 95 | image 96 | 97 |
98 | 99 | 1. Inside your codespace, navigate to the `.vscode` folder, and create a new file named `mcp.json`. Paste the following contents: 100 | 101 | 📄 **.vscode/mcp.json** 102 | 103 | ```json 104 | { 105 | "servers": { 106 | "github": { 107 | "type": "http", 108 | "url": "https://api.githubcopilot.com/mcp/" 109 | } 110 | } 111 | } 112 | ``` 113 | 114 | 1. In the `.vscode/mcp.json` file, click the **Start** button and accept the prompt to authenticate with GitHub. This has just informed GitHub Copilot of the MCP server's capabilities. 115 | 116 | mcp.json file showing start button 117 | 118 | allow authentication prompt
119 | 120 | mcp.json file showing running server 121 | 122 | 1. In the Copilot side panel, click the **🛠️ icon** to show the additional capabilities. 123 | 124 | image 125 | 126 | image 127 | 128 | 1. **Commit** and **push** the `.vscode/mcp.json` file to the `main` branch. 129 | 130 | > 🪧 **Note:** Pushing directly to `main` is not a recommended practice. It is only to simplify this exercise. 131 | 132 | 1. Now that your MCP server configuration is pushed to GitHub, Mona should already be busy checking your work. Give her a moment and keep watch in the comments. You will see her respond with progress info and the next lesson. 133 | 134 | > [!NOTE] 135 | > The next steps will involve creating GitHub issues. If you would like to avoid notification emails, you can unwatch the repository. 136 | 137 |
138 | Having trouble?
139 | 140 | Make sure: 141 | 142 | - Your `.vscode/mcp.json` file is similar to the example provided. 143 | - You pushed the changes to the `main` branch. 144 | 145 |
146 | --------------------------------------------------------------------------------