Available Activities
+Loading activities...
+From 40aac4d0dc3f02eadf4130425194213cfa8fbe51 Mon Sep 17 00:00:00 2001
From: Aleksander Fidelus <63016446+FidelusAleksander@users.noreply.github.com>
Date: Thu, 27 Mar 2025 09:51:11 +0000
Subject: [PATCH] feat: initial draft of the exercise
---
.devcontainer/devcontainer.json | 21 ++++
.github/steps/1-step.md | 72 +++++++++++
.github/steps/2-step.md | 60 +++++++++
.github/steps/3-step.md | 29 +++++
.github/steps/4-step.md | 24 ++++
.github/steps/x-review.md | 18 +++
.github/workflows/0-start-exercise.yml | 74 +++++++++++
.github/workflows/1-step.yml | 166 +++++++++++++++++++++++++
.github/workflows/2-step.yml | 117 +++++++++++++++++
.github/workflows/3-step.yml | 106 ++++++++++++++++
.github/workflows/4-step.yml | 88 +++++++++++++
.gitignore | 41 ++++++
.vscode/launch.json | 19 +++
README.md | 62 +++++++++
requirements.txt | 2 +
src/README.md | 50 ++++++++
src/app.py | 67 ++++++++++
src/static/app.js | 86 +++++++++++++
src/static/index.html | 50 ++++++++
src/static/styles.css | 144 +++++++++++++++++++++
20 files changed, 1296 insertions(+)
create mode 100644 .devcontainer/devcontainer.json
create mode 100644 .github/steps/1-step.md
create mode 100644 .github/steps/2-step.md
create mode 100644 .github/steps/3-step.md
create mode 100644 .github/steps/4-step.md
create mode 100644 .github/steps/x-review.md
create mode 100644 .github/workflows/0-start-exercise.yml
create mode 100644 .github/workflows/1-step.yml
create mode 100644 .github/workflows/2-step.yml
create mode 100644 .github/workflows/3-step.yml
create mode 100644 .github/workflows/4-step.yml
create mode 100644 .gitignore
create mode 100644 .vscode/launch.json
create mode 100644 README.md
create mode 100644 requirements.txt
create mode 100644 src/README.md
create mode 100644 src/app.py
create mode 100644 src/static/app.js
create mode 100644 src/static/index.html
create mode 100644 src/static/styles.css
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
new file mode 100644
index 0000000..608b221
--- /dev/null
+++ b/.devcontainer/devcontainer.json
@@ -0,0 +1,21 @@
+{
+ "name": "Python 3",
+ "image": "mcr.microsoft.com/vscode/devcontainers/python:3.13",
+ "features": {
+ "ghcr.io/devcontainers/features/node:1": {
+ "version": "latest"
+ }
+ },
+ "forwardPorts": [8000],
+ "postCreateCommand": "pip install -r requirements.txt",
+ "customizations": {
+ "vscode": {
+ "extensions": [
+ "GitHub.copilot",
+ "ms-python.python",
+ "ms-python.debugpy",
+ "dbaeumer.vscode-eslint"
+ ]
+ }
+ }
+}
diff --git a/.github/steps/1-step.md b/.github/steps/1-step.md
new file mode 100644
index 0000000..a415c4d
--- /dev/null
+++ b/.github/steps/1-step.md
@@ -0,0 +1,72 @@
+## Step 1: Introduction to MCP and environment setup
+
+Welcome to the **"Integrate Model Context Protocol with GitHub Copilot"** exercise! :robot:
+
+In this exercise, you'll learn how Model Context Protocol (MCP) enhances the way you use GitHub Copilot.
+
+> [!IMPORTANT]
+> This exercise may not explain the basics that were taught in the [Getting Started with Copilot](https://github.com/skills/getting-started-with-github-copilot) exercise. If you are new to Copilot we recommend starting with that one.
+
+
+### What is Model Context Protocol (MCP)?
+
+[Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) is an open standard that bridges AI models with external data sources and tools. It provides a universal interface for connecting AI assistants like GitHub Copilot to various system allowing them to access real-time data, perform actions in external systems, and leverage specialized tools beyond their built-in capabilities.
+### :keyboard: Activity: Get to know your environment
+
+Let's start up our development environment and familiarize with the environment.
+
+We are using the same web application as in the [Getting Started with Copilot](https://github.com/skills/getting-started-with-github-copilot) exercise - the Mergington High School's extracurricular activities website.
+
+1. Right-click the below button to open the **Create Codespace** page in a new tab. Use the default configuration.
+
+ [](https://codespaces.new/{{full_repo_name}}?quickstart=1)
+
+1. Validate the Copilot Chat extension is installed
+1. In the left sidebar, select the `Run and Debug` tab and then press the **Start Debugging** icon.
+
+
+
+1. Throughout the exercise, you can access the website link from the `ports` tab on port `8000`.
+
+### :keyboard: Activity: Set up a MCP server for your project
+
+1. Inside your codespace, create a new file named `mcp.json` in the `.vscode` directory and paste the following contents:
+
+```json
+// .vscode/mcp.json
+{
+ "servers": {
+ "github": {
+ "command": "npx",
+ "args": ["-y", "@modelcontextprotocol/server-github"],
+ "envFile": "${workspaceFolder}/.env"
+ }
+ }
+}
+```
+
+1. Save the file and you should see `Start` button show up like so:
+
+
+
+1. Validate the MCP Server is running.
+ 1. The `.vscode/mcp.json` file should show if the server you started is running
+
+ 1. You should see additional tools available in Copilot Agent Mode
+
+ 1. You can use the VSCode command palette `Ctrl+Shift+P` or `Command+Shift+P` on Mac.
+ Start typing `> MCP` to see different MCP commands, such as listing active servers.
+
+
+1. Commit and push the `.vscode/mcp.json` file to the `main` branch
+
+
+
Having trouble?
+
+Make sure you:
+
+- Properly uncommented the contents of `.vscode/mcp.json` file
+- Pushed your changes to the `main` branch
+
+ **Prompt**
+ >
+ > ```prompt
+ > Are there any open bug report issues on my repository ({{{full_repo_name}}}) ?
+ > ```
+
+ > 🪧 **Note:** We explicitly include the repository name to add it to Copilot's session context. For subsequent prompts, this context will be preserved in the conversation.
+
+ > ✨ **Bonus:** You are welcome to try the prompt without it and if Copilot chooses to list issues in a different repository, guide it your way.
+
+1. Once Copilot identifies a bug report, ask it to implement a fix:
+
+ >
**Prompt**
+ >
+ > ```prompt
+ > Okay, let's start working on the bug report.
+ > Comment on the issue that I will take a look at the issue and try to fix it.
+ > Create a new branch, introduce the changes and raise a pull request to the `main` branch
+ > ```
+
+ > ⚠️ **Warning:** Always verify the information that Copilot passes to the MCP server before accepting.
+
+1. Follow Copilot's guidance to create a pull request with the fix.
+
+ > 🪧 **Note:** Remember that Copilot is conversational, and you are power of guiding the AI assistant to implement what's on your mind.
+
+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!
+
+
Having trouble?
+
+If you encounter issues:
+
+- Make sure your MCP configuration is properly set up from Step 1
+- Verify that the tools are executed on your repository ({{{full_repo_name}}}). Whenever a MCP tool is invoked you can inspect what Copilot passes to the MCP Server.
+
+Having trouble?
+
+If you encounter issues:
+
+- Make sure the PR was created correctly in the previous step
+- If needed, you can navigate directly to your repository on GitHub.com to find the PR
+- Remember that while MCP helps Copilot understand your repo better, human review is still essential
+
+ **Prompt**
+ >
+ > ```prompt
+ > Add a closing comment on the bug report issue that the issue has been resolved.
+ > Include a sneak peek of what to expect in the extracurricular GitHub Skills activity (top 5 most starred repositories in GitHub `skills` organization)
+ > ```
+
+
Having trouble? 🤷
+
+ Some things to check
+ - Is your MCP Server still running?
+ - Check what information is passed to the MCP server calls - is Copilot using the correct repository?
+ - Did Copilot comment on the bug report?
+
+
+Here's a recap of your accomplishments:
+
+
+### What's next?
+
+
+Check out these resources to learn more or get involved:
+
+- [Take another GitHub Skills exercise](https://skills.github.com).
+_
+
+__
diff --git a/.github/workflows/0-start-exercise.yml b/.github/workflows/0-start-exercise.yml
new file mode 100644
index 0000000..68442c6
--- /dev/null
+++ b/.github/workflows/0-start-exercise.yml
@@ -0,0 +1,74 @@
+name: Step 0 # Start Exercise
+
+on:
+ push:
+ branches:
+ - main
+
+permissions:
+ contents: write # Update Readme
+ actions: write # Disable/enable workflows
+ issues: write # Create issue and comment on issues
+
+
+env:
+ STEP_1_FILE: ".github/steps/1-step.md"
+
+jobs:
+ start_exercise:
+ if: |
+ !github.event.repository.is_template
+ name: Start Exercise
+ uses: skills/exercise-toolkit/.github/workflows/start-exercise.yml@v0.1.0
+ with:
+ exercise-title: "Integrate MCP with Copilot"
+ intro-message: "Welcome to the exercise! This exercise will help you learn how to integrate the Model Context Protocol (MCP) with GitHub Copilot."
+
+
+ post_next_step_content:
+ name: Post next step content
+ runs-on: ubuntu-latest
+ needs: [start_exercise]
+ env:
+ ISSUE_URL: ${{ needs.start_exercise.outputs.issue-url }}
+
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Get response templates
+ uses: actions/checkout@v4
+ with:
+ repository: skills/exercise-toolkit
+ path: exercise-toolkit
+ ref: v0.1.0
+
+ - name: Build comment - add step content
+ id: build-comment
+ uses: skills/action-text-variables@v1
+ with:
+ template-file: ${{ env.STEP_1_FILE }}
+ template-vars: |
+ full_repo_name=${{ github.repository }}
+
+ - name: Create comment - add step content
+ run: |
+ gh issue comment "$ISSUE_URL" \
+ --body "$ISSUE_BODY"
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ ISSUE_BODY: ${{ steps.build-comment.outputs.updated-text }}
+
+ - name: Create comment - watching for progress
+ run: |
+ gh issue comment "$ISSUE_URL" \
+ --body-file exercise-toolkit/markdown-templates/step-feedback/watching-for-progress.md
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Disable current workflow and enable next one
+ run: |
+ gh workflow enable "Step 1"
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/1-step.yml b/.github/workflows/1-step.yml
new file mode 100644
index 0000000..6974118
--- /dev/null
+++ b/.github/workflows/1-step.yml
@@ -0,0 +1,166 @@
+name: Step 1
+
+on:
+ push:
+ paths:
+ - ".vscode/mcp.json"
+
+permissions:
+ contents: read
+ actions: write
+ issues: write
+
+env:
+ STEP_2_FILE: ".github/steps/2-step.md"
+
+jobs:
+ find_exercise:
+ name: Find Exercise Issue
+ uses: skills/exercise-toolkit/.github/workflows/find-exercise-issue.yml@v0.1.0
+
+ check_step_work:
+ name: Check step work
+ runs-on: ubuntu-latest
+ needs: find_exercise
+ env:
+ ISSUE_URL: ${{ needs.find_exercise.outputs.issue-url }}
+
+ steps:
+ - name: Get response templates
+ uses: actions/checkout@v4
+ with:
+ repository: skills/exercise-toolkit
+ path: exercise-toolkit
+ ref: v0.1.0
+
+ - name: Update comment - checking work
+ run: |
+ gh issue comment "$ISSUE_URL" \
+ --body-file exercise-toolkit/markdown-templates/step-feedback/checking-work.md \
+ --edit-last
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ # TODO: Check for keywords (github, server)?
+ - name: Build message - step finished
+ id: build-message-step-finish
+ uses: skills/action-text-variables@v1
+ with:
+ template-file: exercise-toolkit/markdown-templates/step-feedback/step-finished-prepare-next-step.md
+ template-vars: |
+ next_step_number=2
+
+ - name: Update comment - step finished
+ run: |
+ gh issue comment "$ISSUE_URL" \
+ --body "$ISSUE_BODY" \
+ --edit-last
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ ISSUE_BODY: ${{ steps.build-message-step-finish.outputs.updated-text }}
+
+ create_bug_report:
+ name: Create bug report
+ needs: [check_step_work]
+ runs-on: ubuntu-latest
+
+ outputs:
+ bug-report-url: ${{ steps.create-bug-issue.outputs.bug_report_url }}
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Create bug issue
+ id: create-bug-issue
+ uses: actions/github-script@v6
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ script: |
+ const bugReport = `
+ # 🚨 Missing GitHub Skills Activity
+
+ ## 🐛 Description of the Issue
+ The GitHub Skills activity announced by our principal is missing from the school activities signup page.
+
+ 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, it's nowhere to be found on the website.
+
+ I can see the following activities:
+ - ✅ Chess Club
+ - ✅ Programming Class
+ - ✅ Gym Class
+
+ But there is:
+ - ❌ NO GitHub Skills activity
+
+ ## ⏱️ Timeline
+ This is time-sensitive as the announcement mentioned registrations would close by the end of this week. Many students are eager to join as it may help with college applications.
+
+ ## 💡 Expected Outcome
+ The GitHub Skills activity should be added to the system and available for registration like other activities
+
+ Mona
+ 11th Grade Student
+ mona@mergington.edu
+ `;
+
+ const response = await github.rest.issues.create({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ title: '🔍 Missing GitHub Skills Activity on School Website',
+ body: bugReport,
+ labels: ['bug']
+ });
+
+ console.log(`Bug report created: ${response.data.html_url}`);
+ core.setOutput('bug_report_url', response.data.html_url);
+
+ post_next_step_content:
+ name: Post next step content
+ needs: [find_exercise, check_step_work, create_bug_report]
+ runs-on: ubuntu-latest
+ env:
+ ISSUE_URL: ${{ needs.find_exercise.outputs.issue-url }}
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Get response templates
+ uses: actions/checkout@v4
+ with:
+ repository: skills/exercise-toolkit
+ path: exercise-toolkit
+ ref: v0.1.0
+
+ - name: Build comment - add step content
+ id: build-comment
+ uses: skills/action-text-variables@v1
+ with:
+ template-file: ${{ env.STEP_2_FILE }}
+ template-vars: |
+ full_repo_name=${{ github.repository }}
+ bug_report_url=${{ needs.create_bug_report.outputs.bug-report-url }}
+
+ - name: Create comment - add step content
+ run: |
+ gh issue comment "$ISSUE_URL" \
+ --body "$ISSUE_BODY"
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ ISSUE_BODY: ${{ steps.build-comment.outputs.updated-text }}
+
+
+ - name: Create comment - watching for progress
+ run: |
+ gh issue comment "$ISSUE_URL" \
+ --body-file exercise-toolkit/markdown-templates/step-feedback/watching-for-progress.md
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Disable current workflow and enable next one
+ run: |
+ gh workflow disable "Step 1"
+ gh workflow enable "Step 2"
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/2-step.yml b/.github/workflows/2-step.yml
new file mode 100644
index 0000000..44c45be
--- /dev/null
+++ b/.github/workflows/2-step.yml
@@ -0,0 +1,117 @@
+name: Step 2
+
+
+on:
+ pull_request:
+ branches:
+ - main
+ paths:
+ - "src/app.py"
+
+permissions:
+ contents: read
+ actions: write
+ issues: write
+
+env:
+ STEP_3_FILE: ".github/steps/3-step.md"
+
+
+jobs:
+ find_exercise:
+ name: Find Exercise Issue
+ uses: skills/exercise-toolkit/.github/workflows/find-exercise-issue.yml@v0.1.0
+
+ check_step_work:
+ name: Check step work
+ runs-on: ubuntu-latest
+ needs: find_exercise
+ if: |
+ !github.event.repository.is_template
+ env:
+ ISSUE_URL: ${{ needs.find_exercise.outputs.issue-url }}
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Get response templates
+ uses: actions/checkout@v4
+ with:
+ repository: skills/exercise-toolkit
+ path: exercise-toolkit
+ ref: v0.1.0
+
+
+ - name: Update comment - checking work
+ run: |
+ gh issue comment "$ISSUE_URL" \
+ --body-file exercise-toolkit/markdown-templates/step-feedback/checking-work.md \
+ --edit-last
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Build message - step finished
+ id: build-message-step-finish
+ uses: skills/action-text-variables@v1
+ with:
+ template-file: exercise-toolkit/markdown-templates/step-feedback/step-finished-prepare-next-step.md
+ template-vars: |
+ next_step_number=3
+
+ - name: Update comment - step finished
+ run: |
+ gh issue comment "$ISSUE_URL" \
+ --body "${{ steps.build-message-step-finish.outputs.updated-text }}" \
+ --edit-last
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ post_next_step_content:
+ name: Post next step content
+ needs: [find_exercise, check_step_work]
+ runs-on: ubuntu-latest
+ env:
+ ISSUE_URL: ${{ needs.find_exercise.outputs.issue-url }}
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Get response templates
+ uses: actions/checkout@v4
+ with:
+ repository: skills/exercise-toolkit
+ path: exercise-toolkit
+ ref: v0.1.0
+
+ - name: Build comment - add step content
+ id: build-comment
+ uses: skills/action-text-variables@v1
+ with:
+ template-file: ${{ env.STEP_3_FILE }}
+ template-vars: |
+ pull_request_url=${{ github.event.pull_request.html_url }}
+
+ - name: Create comment - add step content
+ run: |
+ gh issue comment "$ISSUE_URL" \
+ --body "$ISSUE_BODY"
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ ISSUE_BODY: ${{ steps.build-comment.outputs.updated-text }}
+
+
+ - name: Create comment - watching for progress
+ run: |
+ gh issue comment "$ISSUE_URL" \
+ --body-file exercise-toolkit/markdown-templates/step-feedback/watching-for-progress.md
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Disable current workflow and enable next one
+ run: |
+ gh workflow disable "Step 2"
+ gh workflow enable "Step 3"
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/3-step.yml b/.github/workflows/3-step.yml
new file mode 100644
index 0000000..8c96caa
--- /dev/null
+++ b/.github/workflows/3-step.yml
@@ -0,0 +1,106 @@
+name: Step 3
+on:
+ pull_request:
+ branches:
+ - main
+ types:
+ - closed
+
+
+permissions:
+ contents: read
+ actions: write
+ issues: write
+
+env:
+ STEP_4_FILE: ".github/steps/4-step.md"
+
+jobs:
+ find_exercise:
+ name: Find Exercise Issue
+ uses: skills/exercise-toolkit/.github/workflows/find-exercise-issue.yml@v0.1.0
+
+ check_step_work:
+ name: Check step work
+ runs-on: ubuntu-latest
+ needs: find_exercise
+ if: |
+ !github.event.repository.is_template &&
+ github.event.pull_request.merged == true
+ env:
+ ISSUE_URL: ${{ needs.find_exercise.outputs.issue-url }}
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Get response templates
+ uses: actions/checkout@v4
+ with:
+ repository: skills/exercise-toolkit
+ path: exercise-toolkit
+ ref: v0.1.0
+
+ - name: Update comment - checking work
+ run: |
+ gh issue comment "$ISSUE_URL" \
+ --body-file exercise-toolkit/markdown-templates/step-feedback/checking-work.md \
+ --edit-last
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Build message - step finished
+ id: build-message-step-finish
+ uses: skills/action-text-variables@v1
+ with:
+ template-file: exercise-toolkit/markdown-templates/step-feedback/step-finished-prepare-next-step.md
+ template-vars: |
+ next_step_number=4
+
+ - name: Update comment - step finished
+ run: |
+ gh issue comment "$ISSUE_URL" \
+ --body "${{ steps.build-message-step-finish.outputs.updated-text }}" \
+ --edit-last
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ post_next_step_content:
+ name: Post next step content
+ needs: [find_exercise, check_step_work]
+ runs-on: ubuntu-latest
+ env:
+ ISSUE_URL: ${{ needs.find_exercise.outputs.issue-url }}
+
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Get response templates
+ uses: actions/checkout@v4
+ with:
+ repository: skills/exercise-toolkit
+ path: exercise-toolkit
+ ref: v0.1.0
+
+ - name: Create comment - add step content
+ run: |
+ gh issue comment "$ISSUE_URL" \
+ --body-file ${{ env.STEP_4_FILE }}
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Create comment - watching for progress
+ run: |
+ gh issue comment "$ISSUE_URL" \
+ --body-file exercise-toolkit/markdown-templates/step-feedback/watching-for-progress.md
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Disable current workflow and enable next one
+ run: |
+ gh workflow disable "Step 3"
+ gh workflow enable "Step 4"
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/4-step.yml b/.github/workflows/4-step.yml
new file mode 100644
index 0000000..db4a719
--- /dev/null
+++ b/.github/workflows/4-step.yml
@@ -0,0 +1,88 @@
+name: Step 4
+
+on:
+ issue_comment:
+ types: [created]
+
+permissions:
+ contents: write
+ actions: write
+ issues: write
+
+# concurrency:
+# group: ${{ github.workflow }}
+# cancel-in-progress: true
+
+env:
+ REVIEW_FILE: ".github/steps/x-review.md"
+
+jobs:
+ find_exercise:
+ name: Find Exercise Issue
+ uses: skills/exercise-toolkit/.github/workflows/find-exercise-issue.yml@v0.1.0
+
+ check_step_work:
+ name: Check step work
+ needs: find_exercise
+ runs-on: ubuntu-latest
+ if: |
+ !github.event.repository.is_template
+ env:
+ ISSUE_URL: ${{ needs.find_exercise.outputs.issue-url }}
+
+ steps:
+ - name: Get response templates
+ uses: actions/checkout@v4
+ with:
+ repository: skills/exercise-toolkit
+ path: exercise-toolkit
+ ref: v0.1.0
+
+ - name: Update comment - step finished - final review next
+ run: |
+ gh issue comment "$ISSUE_URL" \
+ --body-file exercise-toolkit/markdown-templates/step-feedback/lesson-review.md \
+ --edit-last
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ post_review_content:
+ name: Post review content
+ needs: [find_exercise, check_step_work]
+ runs-on: ubuntu-latest
+ if: |
+ !github.event.repository.is_template
+ env:
+ ISSUE_URL: ${{ needs.find_exercise.outputs.issue-url }}
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Create comment - add review content
+ run: |
+ gh issue comment "$ISSUE_URL" \
+ --body-file ${{ env.REVIEW_FILE }}
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ finish_exercise:
+ name: Finish Exercise
+ needs: [find_exercise, post_review_content]
+ uses: skills/exercise-toolkit/.github/workflows/finish-exercise.yml@v0.1.0
+ with:
+ issue-url: ${{ needs.find_exercise.outputs.issue-url }}
+
+ disable_workflow:
+ name: Disable this workflow
+ needs: [find_exercise, post_review_content]
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ - name: Disable current workflow
+ run: gh workflow disable "${{github.workflow}}"
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..0eace22
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,41 @@
+# Compiled source #
+###################
+*.com
+*.class
+*.dll
+*.exe
+*.o
+*.so
+
+# Packages #
+############
+# it's better to unpack these files and commit the raw source
+# git has its own built in compression methods
+*.7z
+*.dmg
+*.gz
+*.iso
+*.jar
+*.rar
+*.tar
+*.zip
+
+# Logs and databases #
+######################
+*.log
+*.sql
+*.sqlite
+
+# OS generated files #
+######################
+.DS_Store
+.DS_Store?
+._*
+.Spotlight-V100
+.Trashes
+ehthumbs.db
+Thumbs.db
+
+
+# Environment variables
+.env
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..b349f44
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,19 @@
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "Launch Mergington WebApp",
+ "type": "debugpy",
+ "request": "launch",
+ "module": "uvicorn",
+ "args": [
+ "src.app:app",
+ "--reload"
+ ],
+ "jinja": true
+ }
+ ]
+}
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..07e5acb
--- /dev/null
+++ b/README.md
@@ -0,0 +1,62 @@
+# Integrate MCP with GitHub Copilot
+
+
+
+
+
+
+
+
+_Learn how to integrate Model Context Protocol (MCP) with GitHub Copilot in less than an hour._
+
+## Welcome
+
+The Model Context Protocol (MCP) provides powerful ways to enhance AI interactions in your development workflow. By integrating MCP with GitHub Copilot, you can leverage context-aware AI assistance to build more sophisticated applications. This exercise guides you through everything you need to start using MCP with GitHub Copilot in less than an hour.
+
+- **Who is this for**: Developers looking to enhance their AI-assisted workflows, GitHub Copilot users, and AI enthusiasts.
+- **What you'll learn**: We'll introduce MCP basics, GitHub MCP server setup, and integration with Copilot Agent Mode.
+
+- **Prerequisites**: [Getting Started with Copilot Exercise](https://github.com/skills/getting-started-with-github-copilot)
+- **How long**: This exercise takes less than one hour to complete.
+
+In this exercise, you will:
+
+1. Learn the basics of Model Context Protocol (MCP)
+2. Set up a GitHub MCP server
+3. Integrate MCP with GitHub Copilot Agent Mode
+4. Create a sample application showcasing the integration
+
+### How to start this exercise
+
+1. Right-click **Copy Exercise** and open the link in a new tab.
+
+
+
+
+
+2. In the new tab, most of the prompts will automatically fill in for you.
+
+ - For owner, choose your personal account or an organization to host the repository.
+ - We recommend creating a public repository, as private repositories will [use Actions minutes](https://docs.github.com/en/billing/managing-billing-for-github-actions/about-billing-for-github-actions).
+ - Scroll down and click the **Create repository** button at the bottom of the form.
+
+3. After your new repository is created, wait about 20 seconds for the exercise to be prepared and buttons updated. You will continue working from your copy of the exercise.
+
+ - The **Copy Exercise** button will deactivate, changing to gray.
+ - The **Start Exercise** button will activate, changing to green.
+ - You will likely need to refresh the page.
+
+4. Click **Start Exercise**. Follow the step-by-step instructions and feedback will be provided as you progress.
+
+
+
+
+
+> [!IMPORTANT]
+> The **Start Exercise** button will activate after copying the repository. You will probably need to refresh the page.
+
+---
+
+Get help: [Post in our discussion board](https://github.com/orgs/skills/discussions/categories/introduction-to-github) • [Review the GitHub status page](https://www.githubstatus.com/)
+
+© 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)
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..97dc7cd
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,2 @@
+fastapi
+uvicorn
diff --git a/src/README.md b/src/README.md
new file mode 100644
index 0000000..a90534b
--- /dev/null
+++ b/src/README.md
@@ -0,0 +1,50 @@
+# Mergington High School Activities API
+
+A super simple FastAPI application that allows students to view and sign up for extracurricular activities.
+
+## Features
+
+- View all available extracurricular activities
+- Sign up for activities
+
+## Getting Started
+
+1. Install the dependencies:
+
+ ```
+ pip install fastapi uvicorn
+ ```
+
+2. Run the application:
+
+ ```
+ python app.py
+ ```
+
+3. Open your browser and go to:
+ - API documentation: http://localhost:8000/docs
+ - Alternative documentation: http://localhost:8000/redoc
+
+## API Endpoints
+
+| Method | Endpoint | Description |
+| ------ | ----------------------------------------------------------------- | ------------------------------------------------------------------- |
+| GET | `/activities` | Get all activities with their details and current participant count |
+| POST | `/activities/{activity_name}/signup?email=student@mergington.edu` | Sign up for an activity |
+
+## Data Model
+
+The application uses a simple data model with meaningful identifiers:
+
+1. **Activities** - Uses activity name as identifier:
+
+ - Description
+ - Schedule
+ - Maximum number of participants allowed
+ - List of student emails who are signed up
+
+2. **Students** - Uses email as identifier:
+ - Name
+ - Grade level
+
+All data is stored in memory, which means data will be reset when the server restarts.
diff --git a/src/app.py b/src/app.py
new file mode 100644
index 0000000..4ebb1d9
--- /dev/null
+++ b/src/app.py
@@ -0,0 +1,67 @@
+"""
+High School Management System API
+
+A super simple FastAPI application that allows students to view and sign up
+for extracurricular activities at Mergington High School.
+"""
+
+from fastapi import FastAPI, HTTPException
+from fastapi.staticfiles import StaticFiles
+from fastapi.responses import RedirectResponse
+import os
+from pathlib import Path
+
+app = FastAPI(title="Mergington High School API",
+ description="API for viewing and signing up for extracurricular activities")
+
+# Mount the static files directory
+current_dir = Path(__file__).parent
+app.mount("/static", StaticFiles(directory=os.path.join(Path(__file__).parent,
+ "static")), name="static")
+
+# In-memory activity database
+activities = {
+ "Chess Club": {
+ "description": "Learn strategies and compete in chess tournaments",
+ "schedule": "Fridays, 3:30 PM - 5:00 PM",
+ "max_participants": 12,
+ "participants": ["michael@mergington.edu", "daniel@mergington.edu"]
+ },
+ "Programming Class": {
+ "description": "Learn programming fundamentals and build software projects",
+ "schedule": "Tuesdays and Thursdays, 3:30 PM - 4:30 PM",
+ "max_participants": 20,
+ "participants": ["emma@mergington.edu", "sophia@mergington.edu"]
+ },
+ "Gym Class": {
+ "description": "Physical education and sports activities",
+ "schedule": "Mondays, Wednesdays, Fridays, 2:00 PM - 3:00 PM",
+ "max_participants": 30,
+ "participants": ["john@mergington.edu", "olivia@mergington.edu"]
+ }
+}
+
+
+@app.get("/")
+def root():
+ return RedirectResponse(url="/static/index.html")
+
+
+@app.get("/activities")
+def get_activities():
+ return activities
+
+
+@app.post("/activities/{activity_name}/signup")
+def signup_for_activity(activity_name: str, email: str):
+ """Sign up a student for an activity"""
+ # Validate activity exists
+ if activity_name not in activities:
+ raise HTTPException(status_code=404, detail="Activity not found")
+
+ # Get the specific activity
+ activity = activities[activity_name]
+
+ # Add student
+ activity["participants"].append(email)
+ return {"message": f"Signed up {email} for {activity_name}"}
diff --git a/src/static/app.js b/src/static/app.js
new file mode 100644
index 0000000..dcc1e38
--- /dev/null
+++ b/src/static/app.js
@@ -0,0 +1,86 @@
+document.addEventListener("DOMContentLoaded", () => {
+ const activitiesList = document.getElementById("activities-list");
+ const activitySelect = document.getElementById("activity");
+ const signupForm = document.getElementById("signup-form");
+ const messageDiv = document.getElementById("message");
+
+ // Function to fetch activities from API
+ async function fetchActivities() {
+ try {
+ const response = await fetch("/activities");
+ const activities = await response.json();
+
+ // Clear loading message
+ activitiesList.innerHTML = "";
+
+ // Populate activities list
+ Object.entries(activities).forEach(([name, details]) => {
+ const activityCard = document.createElement("div");
+ activityCard.className = "activity-card";
+
+ const spotsLeft = details.max_participants - details.participants.length;
+
+ activityCard.innerHTML = `
+
${details.description}
+Schedule: ${details.schedule}
+Availability: ${spotsLeft} spots left
+ `; + + activitiesList.appendChild(activityCard); + + // Add option to select dropdown + const option = document.createElement("option"); + option.value = name; + option.textContent = name; + activitySelect.appendChild(option); + }); + } catch (error) { + activitiesList.innerHTML = "Failed to load activities. Please try again later.
"; + console.error("Error fetching activities:", error); + } + } + + // Handle form submission + signupForm.addEventListener("submit", async (event) => { + event.preventDefault(); + + const email = document.getElementById("email").value; + const activity = document.getElementById("activity").value; + + try { + const response = await fetch( + `/activities/${encodeURIComponent(activity)}/signup?email=${encodeURIComponent(email)}`, + { + method: "POST", + } + ); + + const result = await response.json(); + + if (response.ok) { + messageDiv.textContent = result.message; + messageDiv.className = "success"; + signupForm.reset(); + } else { + messageDiv.textContent = result.detail || "An error occurred"; + messageDiv.className = "error"; + } + + messageDiv.classList.remove("hidden"); + + // Hide message after 5 seconds + setTimeout(() => { + messageDiv.classList.add("hidden"); + }, 5000); + } catch (error) { + messageDiv.textContent = "Failed to sign up. Please try again."; + messageDiv.className = "error"; + messageDiv.classList.remove("hidden"); + console.error("Error signing up:", error); + } + }); + + // Initialize app + fetchActivities(); +}); diff --git a/src/static/index.html b/src/static/index.html new file mode 100644 index 0000000..3074f6e --- /dev/null +++ b/src/static/index.html @@ -0,0 +1,50 @@ + + + + + +Loading activities...
+