Skip to content

Commit 4f98e0a

Browse files
authored
Merge pull request #1 from modelcontextprotocol/chore/scaffolding
Initial project structure for MCP variants
1 parent 4c989fd commit 4f98e0a

30 files changed

Lines changed: 855 additions & 3 deletions
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
name: Comment Trigger
2+
3+
on:
4+
issue_comment:
5+
types: [created]
6+
7+
permissions:
8+
contents: read
9+
pull-requests: write
10+
actions: write
11+
12+
jobs:
13+
trigger-checks:
14+
name: Trigger Checks from Comment
15+
if: |
16+
github.event.issue.pull_request &&
17+
(github.event.comment.body == '/test all' ||
18+
github.event.comment.body == '/test-all' ||
19+
github.event.comment.body == '/run-all-checks') &&
20+
(github.event.comment.author_association == 'OWNER' ||
21+
github.event.comment.author_association == 'MEMBER' ||
22+
github.event.comment.author_association == 'COLLABORATOR')
23+
runs-on: ubuntu-latest
24+
steps:
25+
- name: Get PR branch
26+
uses: actions/github-script@v7
27+
id: get-pr
28+
with:
29+
script: |
30+
const pr = await github.rest.pulls.get({
31+
owner: context.repo.owner,
32+
repo: context.repo.repo,
33+
pull_number: context.issue.number
34+
});
35+
return pr.data.head.ref;
36+
37+
- name: Add reaction to comment
38+
uses: actions/github-script@v7
39+
with:
40+
script: |
41+
await github.rest.reactions.createForIssueComment({
42+
owner: context.repo.owner,
43+
repo: context.repo.repo,
44+
comment_id: context.payload.comment.id,
45+
content: 'rocket'
46+
});
47+
48+
- name: Trigger Python CI
49+
uses: actions/github-script@v7
50+
with:
51+
script: |
52+
await github.rest.actions.createWorkflowDispatch({
53+
owner: context.repo.owner,
54+
repo: context.repo.repo,
55+
workflow_id: 'python.yml',
56+
ref: '${{ fromJSON(steps.get-pr.outputs.result) }}'
57+
});
58+
59+
- name: Trigger Go CI
60+
uses: actions/github-script@v7
61+
with:
62+
script: |
63+
await github.rest.actions.createWorkflowDispatch({
64+
owner: context.repo.owner,
65+
repo: context.repo.repo,
66+
workflow_id: 'go.yml',
67+
ref: '${{ fromJSON(steps.get-pr.outputs.result) }}'
68+
});
69+
70+
- name: Trigger TypeScript CI
71+
uses: actions/github-script@v7
72+
with:
73+
script: |
74+
await github.rest.actions.createWorkflowDispatch({
75+
owner: context.repo.owner,
76+
repo: context.repo.repo,
77+
workflow_id: 'typescript.yml',
78+
ref: '${{ fromJSON(steps.get-pr.outputs.result) }}'
79+
});
80+
81+
- name: Comment on PR
82+
uses: actions/github-script@v7
83+
with:
84+
script: |
85+
await github.rest.issues.createComment({
86+
owner: context.repo.owner,
87+
repo: context.repo.repo,
88+
issue_number: context.issue.number,
89+
body: '🚀 All CI checks triggered! Check the Actions tab for progress.'
90+
});

.github/workflows/go.yml

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
name: Go CI
2+
on:
3+
push:
4+
branches: [main]
5+
paths:
6+
- 'go/**'
7+
- '.github/workflows/go.yml'
8+
pull_request:
9+
paths:
10+
- 'go/**'
11+
- '.github/workflows/go.yml'
12+
workflow_dispatch:
13+
14+
permissions:
15+
contents: read
16+
17+
jobs:
18+
go-lint:
19+
name: "Linting"
20+
runs-on: ubuntu-latest
21+
steps:
22+
- name: Check out code
23+
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
24+
- name: Set up Go
25+
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
26+
with:
27+
go-version: "^1.25"
28+
- name: Check formatting
29+
run: |
30+
cd go/sdk
31+
unformatted=$(gofmt -l .)
32+
if [ -n "$unformatted" ]; then
33+
echo "The following files are not properly formatted:"
34+
echo "$unformatted"
35+
exit 1
36+
fi
37+
echo "All Go files are properly formatted"
38+
- name: Run Go vet
39+
run: |
40+
cd go/sdk
41+
go vet ./...
42+
- name: Run staticcheck
43+
uses: dominikh/staticcheck-action@288b4e28bae83c59f35f73651aeb5cab746a06fc # v1.4.0
44+
with:
45+
install-go: false
46+
version: "v0.6.1"
47+
working-directory: go/sdk
48+
49+
go-test:
50+
name: "Unit Tests"
51+
runs-on: ubuntu-latest
52+
strategy:
53+
matrix:
54+
go: ["1.23", "1.24", "1.25"]
55+
steps:
56+
- name: Check out code
57+
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
58+
- name: Set up Go
59+
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
60+
with:
61+
go-version: ${{ matrix.go }}
62+
- name: Test
63+
run: |
64+
cd go/sdk
65+
go test -v ./...
66+
67+
go-race-test:
68+
name: "Race Detection"
69+
runs-on: ubuntu-latest
70+
steps:
71+
- name: Check out code
72+
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
73+
- name: Set up Go
74+
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
75+
with:
76+
go-version: "1.24"
77+
- name: Test with -race
78+
run: |
79+
cd go/sdk
80+
go test -v -race ./...

.github/workflows/python.yml

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
name: Python CI
2+
on:
3+
push:
4+
branches: [main]
5+
paths:
6+
- 'python/**'
7+
- '.github/workflows/python.yml'
8+
pull_request:
9+
paths:
10+
- 'python/**'
11+
- '.github/workflows/python.yml'
12+
workflow_dispatch:
13+
14+
permissions:
15+
contents: read
16+
17+
jobs:
18+
python-lint:
19+
name: "Linting"
20+
runs-on: ubuntu-latest
21+
steps:
22+
- name: Check out code
23+
uses: actions/checkout@v4
24+
- name: Set up Python
25+
uses: actions/setup-python@v5
26+
with:
27+
python-version: "3.11"
28+
- name: Install dependencies
29+
run: |
30+
cd python/sdk
31+
pip install -e .
32+
pip install ruff mypy
33+
- name: Run Ruff formatter check
34+
run: |
35+
cd python/sdk
36+
ruff format --check .
37+
- name: Run Ruff linter
38+
run: |
39+
cd python/sdk
40+
ruff check .
41+
- name: Run mypy
42+
run: |
43+
cd python/sdk
44+
mypy src/mcp_ext_variants --ignore-missing-imports
45+
46+
python-test:
47+
name: "Unit Tests"
48+
runs-on: ubuntu-latest
49+
strategy:
50+
matrix:
51+
python-version: ["3.10", "3.11", "3.12"]
52+
steps:
53+
- name: Check out code
54+
uses: actions/checkout@v4
55+
- name: Set up Python
56+
uses: actions/setup-python@v5
57+
with:
58+
python-version: ${{ matrix.python-version }}
59+
- name: Install dependencies
60+
run: |
61+
cd python/sdk
62+
pip install -e .
63+
pip install pytest pytest-cov
64+
- name: Run tests
65+
run: |
66+
cd python/sdk
67+
pytest -v --cov=src/mcp_ext_variants

.github/workflows/status-check.yml

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
name: Status Check
2+
3+
# This workflow enforces that all relevant CI checks pass based on which files changed.
4+
# It's the only required status check in branch protection settings.
5+
6+
on:
7+
pull_request:
8+
types: [opened, synchronize, reopened]
9+
workflow_run:
10+
workflows: ["Python CI", "Go CI", "TypeScript CI"]
11+
types: [completed]
12+
13+
permissions:
14+
contents: read
15+
statuses: write
16+
checks: write
17+
pull-requests: read
18+
19+
jobs:
20+
verify-required-checks:
21+
name: Verify Required Checks
22+
runs-on: ubuntu-latest
23+
if: github.event_name == 'pull_request' || github.event.workflow_run.conclusion != 'cancelled'
24+
steps:
25+
- name: Check out code
26+
uses: actions/checkout@v4
27+
28+
- name: Get PR number
29+
id: pr
30+
run: |
31+
if [ "${{ github.event_name }}" == "workflow_run" ]; then
32+
PR_NUMBER=$(gh pr list --head "${{ github.event.workflow_run.head_branch }}" --json number --jq '.[0].number')
33+
echo "number=$PR_NUMBER" >> $GITHUB_OUTPUT
34+
else
35+
echo "number=${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT
36+
fi
37+
env:
38+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
39+
40+
- name: Get changed files
41+
id: changed-files
42+
uses: dorny/paths-filter@v3
43+
with:
44+
filters: |
45+
python:
46+
- 'python/**'
47+
- '.github/workflows/python.yml'
48+
go:
49+
- 'go/**'
50+
- '.github/workflows/go.yml'
51+
typescript:
52+
- 'typescript/**'
53+
- '.github/workflows/typescript.yml'
54+
55+
- name: Check required statuses
56+
uses: actions/github-script@v7
57+
with:
58+
script: |
59+
const owner = context.repo.owner;
60+
const repo = context.repo.repo;
61+
const ref = context.payload.pull_request?.head.sha || context.payload.workflow_run?.head_sha;
62+
63+
// Define required checks per language
64+
const requiredChecks = {
65+
python: [
66+
'Python CI / Linting',
67+
'Python CI / Unit Tests (3.10)',
68+
'Python CI / Unit Tests (3.11)',
69+
'Python CI / Unit Tests (3.12)'
70+
],
71+
go: [
72+
'Go CI / Linting',
73+
'Go CI / Unit Tests (1.23)',
74+
'Go CI / Unit Tests (1.24)',
75+
'Go CI / Unit Tests (1.25)',
76+
'Go CI / Race Detection'
77+
],
78+
typescript: [
79+
'TypeScript CI / Linting',
80+
'TypeScript CI / Unit Tests (20)',
81+
'TypeScript CI / Unit Tests (22)'
82+
]
83+
};
84+
85+
// Get changed files from previous step
86+
const changedFiles = {
87+
python: ${{ steps.changed-files.outputs.python }} === 'true',
88+
go: ${{ steps.changed-files.outputs.go }} === 'true',
89+
typescript: ${{ steps.changed-files.outputs.typescript }} === 'true'
90+
};
91+
92+
// Collect all required checks based on changes
93+
let allRequiredChecks = [];
94+
for (const [lang, changed] of Object.entries(changedFiles)) {
95+
if (changed) {
96+
allRequiredChecks = allRequiredChecks.concat(requiredChecks[lang]);
97+
}
98+
}
99+
100+
if (allRequiredChecks.length === 0) {
101+
console.log('No language files changed, no checks required');
102+
return;
103+
}
104+
105+
// Get all check runs for this commit
106+
const { data: checkRuns } = await github.rest.checks.listForRef({
107+
owner,
108+
repo,
109+
ref
110+
});
111+
112+
// Verify all required checks have passed
113+
const checkStatuses = {};
114+
for (const check of checkRuns.check_runs) {
115+
checkStatuses[check.name] = check.conclusion;
116+
}
117+
118+
let allPassed = true;
119+
let failureMessage = '';
120+
121+
for (const requiredCheck of allRequiredChecks) {
122+
const status = checkStatuses[requiredCheck];
123+
if (!status) {
124+
allPassed = false;
125+
failureMessage += `❌ ${requiredCheck}: Not started\\n`;
126+
} else if (status !== 'success') {
127+
allPassed = false;
128+
failureMessage += `❌ ${requiredCheck}: ${status}\\n`;
129+
} else {
130+
failureMessage += `✅ ${requiredCheck}: ${status}\\n`;
131+
}
132+
}
133+
134+
if (!allPassed) {
135+
core.setFailed(`Required checks have not passed:\\n${failureMessage}`);
136+
} else {
137+
console.log(`All required checks passed:\\n${failureMessage}`);
138+
}

0 commit comments

Comments
 (0)