├── 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 |
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 |
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 | []({{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 | > 
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://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 | > 
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 | > 
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 | > 
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 | 
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 | > 
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 |
54 |
55 | 1. Ask Copilot to describe one of the projects. Explore until you find something you like.
56 |
57 | > 
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 | > 
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 | > 
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 |
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 |
30 | ${details.participants
31 | .map(
32 | (email) =>
33 | `${email} ❌ `
34 | )
35 | .join("")}
36 |
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 |
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 | [](https://codespaces.new/{{full_repo_name}}?quickstart=1)
47 |
48 | 1. Validate the **Copilot Chat** and **Python** extensions are installed and enabled.
49 |
50 |
51 |
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 |
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 |
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 |
77 |
78 | 
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 |
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 |
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 |
117 |
118 |
119 |
120 |
121 |
122 | 1. In the Copilot side panel, click the **🛠️ icon** to show the additional capabilities.
123 |
124 |
125 |
126 |
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 |
--------------------------------------------------------------------------------