@mokoconsulting/mcp-mokogitea-api 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitattributes +94 -0
- package/.gitmessage +9 -0
- package/.mokogitea/ISSUE_TEMPLATE/adr.md +110 -0
- package/.mokogitea/ISSUE_TEMPLATE/bug_report.md +48 -0
- package/.mokogitea/ISSUE_TEMPLATE/config.yml +18 -0
- package/.mokogitea/ISSUE_TEMPLATE/documentation.md +52 -0
- package/.mokogitea/ISSUE_TEMPLATE/enterprise_support.md +85 -0
- package/.mokogitea/ISSUE_TEMPLATE/feature_request.md +51 -0
- package/.mokogitea/ISSUE_TEMPLATE/firewall-request.md +190 -0
- package/.mokogitea/ISSUE_TEMPLATE/mcp_api_integration.md +48 -0
- package/.mokogitea/ISSUE_TEMPLATE/mcp_connection_issue.md +67 -0
- package/.mokogitea/ISSUE_TEMPLATE/mcp_tool_request.md +49 -0
- package/.mokogitea/ISSUE_TEMPLATE/question.md +82 -0
- package/.mokogitea/ISSUE_TEMPLATE/rfc.md +126 -0
- package/.mokogitea/ISSUE_TEMPLATE/security.md +51 -0
- package/.mokogitea/ISSUE_TEMPLATE/version.md +24 -0
- package/.mokogitea/auto-assign.yml +76 -0
- package/.mokogitea/auto-dev-issue.yml +207 -0
- package/.mokogitea/auto-release.yml +337 -0
- package/.mokogitea/branch-protection.yml +251 -0
- package/.mokogitea/changelog-validation.yml +101 -0
- package/.mokogitea/codeql-analysis.yml +115 -0
- package/.mokogitea/copilot-agent.yml +44 -0
- package/.mokogitea/deploy-demo.yml +734 -0
- package/.mokogitea/deploy-dev.yml +700 -0
- package/.mokogitea/enterprise-firewall-setup.yml +758 -0
- package/.mokogitea/manifest.xml +25 -0
- package/.mokogitea/mcp-auto-release.yml +278 -0
- package/.mokogitea/mcp-build-test.yml +65 -0
- package/.mokogitea/mcp-sdk-check.yml +109 -0
- package/.mokogitea/mcp-tool-inventory.yml +61 -0
- package/.mokogitea/pr-branch-check.yml +90 -0
- package/.mokogitea/repository-cleanup.yml +525 -0
- package/.mokogitea/standards-compliance.yml +2614 -0
- package/.mokogitea/sync-version-on-merge.yml +133 -0
- package/.mokogitea/workflows/auto-assign.yml +76 -0
- package/.mokogitea/workflows/auto-bump.yml +66 -0
- package/.mokogitea/workflows/auto-dev-issue.yml +207 -0
- package/.mokogitea/workflows/auto-release.yml +341 -0
- package/.mokogitea/workflows/branch-cleanup.yml +48 -0
- package/.mokogitea/workflows/cascade-dev.yml +10 -0
- package/.mokogitea/workflows/changelog-validation.yml +101 -0
- package/.mokogitea/workflows/ci-generic.yml +204 -0
- package/.mokogitea/workflows/cleanup.yml +87 -0
- package/.mokogitea/workflows/codeql-analysis.yml +115 -0
- package/.mokogitea/workflows/copilot-agent.yml +44 -0
- package/.mokogitea/workflows/deploy-manual.yml +126 -0
- package/.mokogitea/workflows/enterprise-firewall-setup.yml +758 -0
- package/.mokogitea/workflows/gitleaks.yml +96 -0
- package/.mokogitea/workflows/issue-branch.yml +73 -0
- package/.mokogitea/workflows/mcp-auto-release.yml +280 -0
- package/.mokogitea/workflows/mcp-build-test.yml +65 -0
- package/.mokogitea/workflows/mcp-sdk-check.yml +109 -0
- package/.mokogitea/workflows/mcp-tool-inventory.yml +61 -0
- package/.mokogitea/workflows/notify.yml +70 -0
- package/.mokogitea/workflows/npm-publish.yml +51 -0
- package/.mokogitea/workflows/pr-check.yml +508 -0
- package/.mokogitea/workflows/pre-release.yml +11 -0
- package/.mokogitea/workflows/repo-health.yml +711 -0
- package/.mokogitea/workflows/repository-cleanup.yml +525 -0
- package/.mokogitea/workflows/security-audit.yml +82 -0
- package/.mokogitea/workflows/standards-compliance.yml +2614 -0
- package/.mokogitea/workflows/sync-version-on-merge.yml +130 -0
- package/.mokogitea/workflows/update-server.yml +312 -0
- package/CHANGELOG.md +145 -0
- package/CLAUDE.md +43 -0
- package/CONTRIBUTING.md +161 -0
- package/README.md +286 -0
- package/SECURITY.md +91 -0
- package/automation/ci-issue-reporter.sh +237 -0
- package/config.example.json +13 -0
- package/dist/client.d.ts +15 -0
- package/dist/client.js +104 -0
- package/dist/config.d.ts +4 -0
- package/dist/config.js +48 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1119 -0
- package/dist/types.d.ts +20 -0
- package/dist/types.js +16 -0
- package/package.json +34 -0
- package/scripts/setup.mjs +40 -0
- package/src/client.ts +120 -0
- package/src/config.ts +58 -0
- package/src/index.ts +1712 -0
- package/src/types.ts +37 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
|
+
#
|
|
5
|
+
# FILE INFORMATION
|
|
6
|
+
# DEFGROUP: Gitea.Workflow
|
|
7
|
+
# INGROUP: MokoStandards.Security
|
|
8
|
+
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
|
|
9
|
+
# PATH: /templates/workflows/gitleaks.yml.template
|
|
10
|
+
# VERSION: 01.00.00
|
|
11
|
+
# BRIEF: Secret scanning — detect leaked credentials, API keys, and tokens
|
|
12
|
+
#
|
|
13
|
+
# +========================================================================+
|
|
14
|
+
# | SECRET SCANNING |
|
|
15
|
+
# +========================================================================+
|
|
16
|
+
# | |
|
|
17
|
+
# | Scans commits for leaked secrets using Gitleaks. |
|
|
18
|
+
# | |
|
|
19
|
+
# | - PR scan: only new commits in the PR |
|
|
20
|
+
# | - Scheduled: full repo scan weekly |
|
|
21
|
+
# | - Alerts via ntfy on findings |
|
|
22
|
+
# | |
|
|
23
|
+
# +========================================================================+
|
|
24
|
+
|
|
25
|
+
name: "Universal: Secret Scanning"
|
|
26
|
+
|
|
27
|
+
on:
|
|
28
|
+
pull_request:
|
|
29
|
+
branches:
|
|
30
|
+
- main
|
|
31
|
+
- 'dev/**'
|
|
32
|
+
schedule:
|
|
33
|
+
- cron: '0 5 * * 1' # Weekly Monday 05:00 UTC
|
|
34
|
+
workflow_dispatch:
|
|
35
|
+
|
|
36
|
+
permissions:
|
|
37
|
+
contents: read
|
|
38
|
+
|
|
39
|
+
env:
|
|
40
|
+
NTFY_URL: ${{ vars.NTFY_URL || 'https://ntfy.mokoconsulting.tech' }}
|
|
41
|
+
NTFY_TOPIC: ${{ vars.NTFY_TOPIC || 'gitea-security' }}
|
|
42
|
+
|
|
43
|
+
jobs:
|
|
44
|
+
gitleaks:
|
|
45
|
+
name: Gitleaks Secret Scan
|
|
46
|
+
runs-on: ubuntu-latest
|
|
47
|
+
|
|
48
|
+
steps:
|
|
49
|
+
- name: Checkout
|
|
50
|
+
uses: actions/checkout@v4
|
|
51
|
+
with:
|
|
52
|
+
fetch-depth: 0
|
|
53
|
+
|
|
54
|
+
- name: Install Gitleaks
|
|
55
|
+
run: |
|
|
56
|
+
GITLEAKS_VERSION="8.21.2"
|
|
57
|
+
curl -sSL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" \
|
|
58
|
+
| tar -xz -C /usr/local/bin gitleaks
|
|
59
|
+
gitleaks version
|
|
60
|
+
|
|
61
|
+
- name: Scan for secrets
|
|
62
|
+
id: scan
|
|
63
|
+
run: |
|
|
64
|
+
echo "### Secret Scanning" >> $GITHUB_STEP_SUMMARY
|
|
65
|
+
ARGS="--source . --verbose --report-format json --report-path /tmp/gitleaks-report.json"
|
|
66
|
+
|
|
67
|
+
if [ "${{ github.event_name }}" = "pull_request" ]; then
|
|
68
|
+
# Scan only PR commits
|
|
69
|
+
ARGS="$ARGS --log-opts=${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }}"
|
|
70
|
+
echo "Scanning PR commits only" >> $GITHUB_STEP_SUMMARY
|
|
71
|
+
else
|
|
72
|
+
echo "Full repository scan" >> $GITHUB_STEP_SUMMARY
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
if gitleaks detect $ARGS 2>&1; then
|
|
76
|
+
echo "result=clean" >> "$GITHUB_OUTPUT"
|
|
77
|
+
echo "**No secrets detected.**" >> $GITHUB_STEP_SUMMARY
|
|
78
|
+
else
|
|
79
|
+
echo "result=found" >> "$GITHUB_OUTPUT"
|
|
80
|
+
FINDINGS=$(jq length /tmp/gitleaks-report.json 2>/dev/null || echo "unknown")
|
|
81
|
+
echo "**${FINDINGS} potential secret(s) detected.**" >> $GITHUB_STEP_SUMMARY
|
|
82
|
+
echo "" >> $GITHUB_STEP_SUMMARY
|
|
83
|
+
echo "Review the findings and rotate any exposed credentials immediately." >> $GITHUB_STEP_SUMMARY
|
|
84
|
+
exit 1
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
- name: Notify on findings
|
|
88
|
+
if: failure() && steps.scan.outputs.result == 'found'
|
|
89
|
+
run: |
|
|
90
|
+
REPO="${{ github.event.repository.name }}"
|
|
91
|
+
curl -sS \
|
|
92
|
+
-H "Title: ${REPO} — secrets detected in code" \
|
|
93
|
+
-H "Tags: rotating_light,key" \
|
|
94
|
+
-H "Priority: urgent" \
|
|
95
|
+
-d "Gitleaks found potential secrets. Review and rotate credentials immediately." \
|
|
96
|
+
"${NTFY_URL}/${NTFY_TOPIC}" || true
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
|
+
#
|
|
5
|
+
# FILE INFORMATION
|
|
6
|
+
# DEFGROUP: Gitea.Workflow
|
|
7
|
+
# INGROUP: moko-platform.Automation
|
|
8
|
+
# VERSION: 01.00.00
|
|
9
|
+
# BRIEF: Auto-create feature branch when an issue is opened
|
|
10
|
+
|
|
11
|
+
name: "Universal: Issue Branch"
|
|
12
|
+
|
|
13
|
+
on:
|
|
14
|
+
issues:
|
|
15
|
+
types: [opened]
|
|
16
|
+
|
|
17
|
+
permissions:
|
|
18
|
+
contents: write
|
|
19
|
+
issues: write
|
|
20
|
+
|
|
21
|
+
env:
|
|
22
|
+
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
|
|
23
|
+
|
|
24
|
+
jobs:
|
|
25
|
+
create-branch:
|
|
26
|
+
name: Create feature branch
|
|
27
|
+
runs-on: ubuntu-latest
|
|
28
|
+
steps:
|
|
29
|
+
- name: Create branch and comment
|
|
30
|
+
run: |
|
|
31
|
+
TOKEN="${{ secrets.GA_TOKEN }}"
|
|
32
|
+
API="${GITEA_URL}/api/v1/repos/${{ github.repository }}"
|
|
33
|
+
ISSUE_NUM="${{ github.event.issue.number }}"
|
|
34
|
+
ISSUE_TITLE="${{ github.event.issue.title }}"
|
|
35
|
+
|
|
36
|
+
# Build slug from title: lowercase, replace non-alnum with dash, trim
|
|
37
|
+
SLUG=$(echo "${ISSUE_TITLE}" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-//;s/-$//' | cut -c1-40)
|
|
38
|
+
BRANCH="feature/${ISSUE_NUM}-${SLUG}"
|
|
39
|
+
|
|
40
|
+
# Check dev branch exists
|
|
41
|
+
DEV_EXISTS=$(curl -sf -o /dev/null -w '%{http_code}' \
|
|
42
|
+
-H "Authorization: token ${TOKEN}" \
|
|
43
|
+
"${API}/branches/dev" 2>/dev/null || echo "000")
|
|
44
|
+
|
|
45
|
+
if [ "${DEV_EXISTS}" != "200" ]; then
|
|
46
|
+
echo "No dev branch -- skipping"
|
|
47
|
+
exit 0
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
# Create branch from dev
|
|
51
|
+
HTTP=$(curl -sf -o /dev/null -w '%{http_code}' -X POST \
|
|
52
|
+
-H "Authorization: token ${TOKEN}" \
|
|
53
|
+
-H "Content-Type: application/json" \
|
|
54
|
+
"${API}/branches" \
|
|
55
|
+
-d "{\"new_branch_name\":\"${BRANCH}\",\"old_branch_name\":\"dev\"}" 2>/dev/null || echo "000")
|
|
56
|
+
|
|
57
|
+
if [ "${HTTP}" = "201" ]; then
|
|
58
|
+
echo "Created branch: ${BRANCH}"
|
|
59
|
+
|
|
60
|
+
# Comment on issue with branch link
|
|
61
|
+
REPO_URL="${GITEA_URL}/${{ github.repository }}"
|
|
62
|
+
BODY="Branch created: [\`${BRANCH}\`](${REPO_URL}/src/branch/${BRANCH})\n\n\`\`\`bash\ngit fetch origin\ngit checkout ${BRANCH}\n\`\`\`"
|
|
63
|
+
|
|
64
|
+
curl -sf -X POST \
|
|
65
|
+
-H "Authorization: token ${TOKEN}" \
|
|
66
|
+
-H "Content-Type: application/json" \
|
|
67
|
+
"${API}/issues/${ISSUE_NUM}/comments" \
|
|
68
|
+
-d "{\"body\":\"${BODY}\"}" > /dev/null 2>&1
|
|
69
|
+
|
|
70
|
+
echo "Commented on issue #${ISSUE_NUM}"
|
|
71
|
+
else
|
|
72
|
+
echo "Failed to create branch (HTTP ${HTTP}) -- may already exist"
|
|
73
|
+
fi
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
# MCP Server Auto-Release
|
|
2
|
+
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
|
3
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
|
+
#
|
|
5
|
+
# MCP-specific release pipeline that builds TypeScript, runs validation,
|
|
6
|
+
# attaches the compiled dist/ as a release artifact, and creates a GitHub
|
|
7
|
+
# Release with tool inventory in the release notes.
|
|
8
|
+
#
|
|
9
|
+
# This replaces the generic auto-release.yml for MCP server repos.
|
|
10
|
+
|
|
11
|
+
name: "MCP: Build & Release"
|
|
12
|
+
|
|
13
|
+
on:
|
|
14
|
+
push:
|
|
15
|
+
branches:
|
|
16
|
+
- main
|
|
17
|
+
paths:
|
|
18
|
+
- 'src/**'
|
|
19
|
+
- 'package.json'
|
|
20
|
+
- 'tsconfig.json'
|
|
21
|
+
|
|
22
|
+
env:
|
|
23
|
+
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
|
24
|
+
|
|
25
|
+
permissions:
|
|
26
|
+
contents: write
|
|
27
|
+
issues: write
|
|
28
|
+
|
|
29
|
+
jobs:
|
|
30
|
+
build-and-release:
|
|
31
|
+
name: Build, Validate & Release
|
|
32
|
+
runs-on: ubuntu-latest
|
|
33
|
+
if: >-
|
|
34
|
+
!contains(github.event.head_commit.message, '[skip ci]') &&
|
|
35
|
+
github.actor != 'github-actions[bot]'
|
|
36
|
+
|
|
37
|
+
steps:
|
|
38
|
+
- name: Checkout repository
|
|
39
|
+
uses: actions/checkout@v4
|
|
40
|
+
with:
|
|
41
|
+
token: ${{ secrets.GH_TOKEN || github.token }}
|
|
42
|
+
fetch-depth: 0
|
|
43
|
+
|
|
44
|
+
# ── Build ────────────────────────────────────────────────────────
|
|
45
|
+
- name: Setup Node.js
|
|
46
|
+
uses: actions/setup-node@v4
|
|
47
|
+
with:
|
|
48
|
+
node-version: 20
|
|
49
|
+
|
|
50
|
+
- name: Install dependencies
|
|
51
|
+
run: npm ci
|
|
52
|
+
|
|
53
|
+
- name: TypeScript compile check
|
|
54
|
+
run: npx tsc --noEmit
|
|
55
|
+
|
|
56
|
+
- name: Build
|
|
57
|
+
run: npm run build
|
|
58
|
+
|
|
59
|
+
- name: Verify dist output
|
|
60
|
+
run: |
|
|
61
|
+
for f in index.js client.js config.js types.js; do
|
|
62
|
+
test -f "dist/${f}" || (echo "ERROR: dist/${f} not found" && exit 1)
|
|
63
|
+
done
|
|
64
|
+
echo "✓ All dist files present"
|
|
65
|
+
|
|
66
|
+
# ── Tool Inventory ───────────────────────────────────────────────
|
|
67
|
+
- name: Generate tool inventory
|
|
68
|
+
id: tools
|
|
69
|
+
run: |
|
|
70
|
+
TOOL_COUNT=$(grep -c "server\.tool(" src/index.ts || echo "0")
|
|
71
|
+
echo "count=${TOOL_COUNT}" >> "$GITHUB_OUTPUT"
|
|
72
|
+
|
|
73
|
+
# Extract tool names
|
|
74
|
+
TOOL_LIST=$(grep -oE "'[a-z_]+'" src/index.ts | head -100 | tr -d "'" | sort -u)
|
|
75
|
+
echo "Tools registered: ${TOOL_COUNT}"
|
|
76
|
+
|
|
77
|
+
# Generate inventory for release notes
|
|
78
|
+
echo "## Tool Inventory (${TOOL_COUNT} tools)" > /tmp/tool-inventory.md
|
|
79
|
+
echo "" >> /tmp/tool-inventory.md
|
|
80
|
+
grep -B0 -A1 "server\.tool(" src/index.ts | grep -oE "'[^']+'" | while IFS= read -r name; do
|
|
81
|
+
read -r desc 2>/dev/null || true
|
|
82
|
+
CLEAN_NAME=$(echo "$name" | tr -d "'")
|
|
83
|
+
CLEAN_DESC=$(echo "$desc" | tr -d "'" | sed 's/,$//')
|
|
84
|
+
if [ -n "$CLEAN_NAME" ] && [ -n "$CLEAN_DESC" ]; then
|
|
85
|
+
echo "- \`${CLEAN_NAME}\` — ${CLEAN_DESC}" >> /tmp/tool-inventory.md
|
|
86
|
+
fi
|
|
87
|
+
done
|
|
88
|
+
|
|
89
|
+
# ── Version ──────────────────────────────────────────────────────
|
|
90
|
+
- name: Setup MokoStandards tools
|
|
91
|
+
run: |
|
|
92
|
+
if [ -d /opt/mokoplatform/api/cli ] && [ -f /opt/mokoplatform/vendor/autoload.php ]; then
|
|
93
|
+
ln -sf /opt/mokoplatform /tmp/mokostandards
|
|
94
|
+
echo "Using pre-installed /opt/mokoplatform"
|
|
95
|
+
elif [ -d /opt/moko-platform/api/cli ]; then
|
|
96
|
+
ln -sf /opt/moko-platform /tmp/mokostandards
|
|
97
|
+
echo "Using pre-installed /opt/moko-platform"
|
|
98
|
+
else
|
|
99
|
+
echo "::warning::MokoStandards tools not found on runner"
|
|
100
|
+
echo "MOKO_SKIP=true" >> "$GITHUB_ENV"
|
|
101
|
+
fi
|
|
102
|
+
|
|
103
|
+
- name: Read version from README.md
|
|
104
|
+
id: version
|
|
105
|
+
run: |
|
|
106
|
+
VERSION=$(php /tmp/mokostandards/api/cli/version_read.php --path . 2>/dev/null)
|
|
107
|
+
if [ -z "$VERSION" ]; then
|
|
108
|
+
echo "No VERSION in README.md — skipping release"
|
|
109
|
+
echo "skip=true" >> "$GITHUB_OUTPUT"
|
|
110
|
+
exit 0
|
|
111
|
+
fi
|
|
112
|
+
|
|
113
|
+
MAJOR=$(echo "$VERSION" | awk -F. '{print $1}')
|
|
114
|
+
MINOR=$(echo "$VERSION" | awk -F. '{printf "%s.%s", $1, $2}')
|
|
115
|
+
PATCH=$(echo "$VERSION" | awk -F. '{print $3}')
|
|
116
|
+
|
|
117
|
+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
|
118
|
+
echo "branch=version/${MAJOR}" >> "$GITHUB_OUTPUT"
|
|
119
|
+
echo "major=$MAJOR" >> "$GITHUB_OUTPUT"
|
|
120
|
+
echo "minor=$MINOR" >> "$GITHUB_OUTPUT"
|
|
121
|
+
echo "release_tag=v${MAJOR}" >> "$GITHUB_OUTPUT"
|
|
122
|
+
|
|
123
|
+
if [ "$PATCH" = "00" ]; then
|
|
124
|
+
echo "skip=true" >> "$GITHUB_OUTPUT"
|
|
125
|
+
else
|
|
126
|
+
echo "skip=false" >> "$GITHUB_OUTPUT"
|
|
127
|
+
if [ "$PATCH" = "01" ]; then
|
|
128
|
+
echo "is_first=true" >> "$GITHUB_OUTPUT"
|
|
129
|
+
else
|
|
130
|
+
echo "is_first=false" >> "$GITHUB_OUTPUT"
|
|
131
|
+
fi
|
|
132
|
+
fi
|
|
133
|
+
|
|
134
|
+
- name: Check if already released
|
|
135
|
+
if: steps.version.outputs.skip != 'true'
|
|
136
|
+
id: check
|
|
137
|
+
run: |
|
|
138
|
+
TAG="${{ steps.version.outputs.release_tag }}"
|
|
139
|
+
TAG_EXISTS=false
|
|
140
|
+
git rev-parse "$TAG" >/dev/null 2>&1 && TAG_EXISTS=true
|
|
141
|
+
echo "tag_exists=$TAG_EXISTS" >> "$GITHUB_OUTPUT"
|
|
142
|
+
|
|
143
|
+
# ── Release Artifact ─────────────────────────────────────────────
|
|
144
|
+
- name: Package dist
|
|
145
|
+
if: steps.version.outputs.skip != 'true'
|
|
146
|
+
run: |
|
|
147
|
+
VERSION="${{ steps.version.outputs.version }}"
|
|
148
|
+
REPO_NAME="${{ github.event.repository.name }}"
|
|
149
|
+
tar -czf "/tmp/${REPO_NAME}-${VERSION}.tar.gz" -C dist .
|
|
150
|
+
echo "artifact=/tmp/${REPO_NAME}-${VERSION}.tar.gz" >> "$GITHUB_OUTPUT"
|
|
151
|
+
|
|
152
|
+
# ── Version Updates ──────────────────────────────────────────────
|
|
153
|
+
- name: Set platform version
|
|
154
|
+
if: >-
|
|
155
|
+
steps.version.outputs.skip != 'true' &&
|
|
156
|
+
steps.check.outputs.tag_exists != 'true'
|
|
157
|
+
run: |
|
|
158
|
+
VERSION="${{ steps.version.outputs.version }}"
|
|
159
|
+
php /tmp/mokostandards/api/cli/version_set_platform.php \
|
|
160
|
+
--path . --version "$VERSION" --branch main
|
|
161
|
+
|
|
162
|
+
- name: Update version badges
|
|
163
|
+
if: >-
|
|
164
|
+
steps.version.outputs.skip != 'true' &&
|
|
165
|
+
steps.check.outputs.tag_exists != 'true'
|
|
166
|
+
run: |
|
|
167
|
+
VERSION="${{ steps.version.outputs.version }}"
|
|
168
|
+
find . -name "*.md" ! -path "./.git/*" ! -path "./vendor/*" | while read -r f; do
|
|
169
|
+
if grep -q '\[VERSION:' "$f" 2>/dev/null; then
|
|
170
|
+
sed -i "s/\[VERSION:[[:space:]]*[0-9]\{2\}\.[0-9]\{2\}\.[0-9]\{2\}\]/[VERSION: ${VERSION}]/" "$f"
|
|
171
|
+
fi
|
|
172
|
+
done
|
|
173
|
+
|
|
174
|
+
- name: Commit release changes
|
|
175
|
+
if: >-
|
|
176
|
+
steps.version.outputs.skip != 'true' &&
|
|
177
|
+
steps.check.outputs.tag_exists != 'true'
|
|
178
|
+
run: |
|
|
179
|
+
if git diff --quiet && git diff --cached --quiet; then
|
|
180
|
+
echo "No changes to commit"
|
|
181
|
+
exit 0
|
|
182
|
+
fi
|
|
183
|
+
VERSION="${{ steps.version.outputs.version }}"
|
|
184
|
+
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
|
185
|
+
git config --local user.name "github-actions[bot]"
|
|
186
|
+
git add -A
|
|
187
|
+
git commit -m "chore(release): build ${VERSION} [skip ci]" \
|
|
188
|
+
--author="github-actions[bot] <github-actions[bot]@users.noreply.github.com>"
|
|
189
|
+
git push
|
|
190
|
+
|
|
191
|
+
# ── Version Branch ───────────────────────────────────────────────
|
|
192
|
+
- name: Archive version branch
|
|
193
|
+
if: steps.check.outputs.tag_exists != 'true'
|
|
194
|
+
run: |
|
|
195
|
+
BRANCH="${{ steps.version.outputs.branch }}"
|
|
196
|
+
git push origin HEAD:"$BRANCH" --force
|
|
197
|
+
echo "Updated archive branch: ${BRANCH}" >> $GITHUB_STEP_SUMMARY
|
|
198
|
+
|
|
199
|
+
# ── Tag & Release ────────────────────────────────────────────────
|
|
200
|
+
- name: Create git tag
|
|
201
|
+
if: >-
|
|
202
|
+
steps.version.outputs.skip != 'true' &&
|
|
203
|
+
steps.check.outputs.tag_exists != 'true' &&
|
|
204
|
+
steps.version.outputs.is_first == 'true'
|
|
205
|
+
run: |
|
|
206
|
+
TAG="${{ steps.version.outputs.release_tag }}"
|
|
207
|
+
if ! git rev-parse "$TAG" >/dev/null 2>&1; then
|
|
208
|
+
git tag "$TAG"
|
|
209
|
+
git push origin "$TAG"
|
|
210
|
+
fi
|
|
211
|
+
|
|
212
|
+
- name: GitHub Release
|
|
213
|
+
if: >-
|
|
214
|
+
steps.version.outputs.skip != 'true' &&
|
|
215
|
+
steps.check.outputs.tag_exists != 'true'
|
|
216
|
+
env:
|
|
217
|
+
GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
|
|
218
|
+
run: |
|
|
219
|
+
VERSION="${{ steps.version.outputs.version }}"
|
|
220
|
+
RELEASE_TAG="${{ steps.version.outputs.release_tag }}"
|
|
221
|
+
MAJOR="${{ steps.version.outputs.major }}"
|
|
222
|
+
BRANCH="${{ steps.version.outputs.branch }}"
|
|
223
|
+
TOOL_COUNT="${{ steps.tools.outputs.count }}"
|
|
224
|
+
REPO_NAME="${{ github.event.repository.name }}"
|
|
225
|
+
|
|
226
|
+
# Build release notes
|
|
227
|
+
NOTES=$(php /tmp/mokostandards/api/cli/release_notes.php --path . --version "$VERSION" 2>/dev/null)
|
|
228
|
+
[ -z "$NOTES" ] && NOTES="Release ${VERSION}"
|
|
229
|
+
|
|
230
|
+
{
|
|
231
|
+
echo "$NOTES"
|
|
232
|
+
echo ""
|
|
233
|
+
echo "---"
|
|
234
|
+
echo ""
|
|
235
|
+
echo "### MCP Server Info"
|
|
236
|
+
echo "- **Tools registered**: ${TOOL_COUNT}"
|
|
237
|
+
echo "- **Node.js**: 20+"
|
|
238
|
+
echo "- **MCP SDK**: $(node -p \"require('./package.json').dependencies['@modelcontextprotocol/sdk']\" 2>/dev/null || echo 'unknown')"
|
|
239
|
+
echo ""
|
|
240
|
+
cat /tmp/tool-inventory.md 2>/dev/null || true
|
|
241
|
+
} > /tmp/release_notes.md
|
|
242
|
+
|
|
243
|
+
EXISTING=$(gh release view "$RELEASE_TAG" --json tagName -q .tagName 2>/dev/null || true)
|
|
244
|
+
|
|
245
|
+
ARTIFACT="/tmp/${REPO_NAME}-${VERSION}.tar.gz"
|
|
246
|
+
|
|
247
|
+
if [ -z "$EXISTING" ]; then
|
|
248
|
+
gh release create "$RELEASE_TAG" \
|
|
249
|
+
--title "v${MAJOR} (latest: ${VERSION})" \
|
|
250
|
+
--notes-file /tmp/release_notes.md \
|
|
251
|
+
--target "$BRANCH" \
|
|
252
|
+
"$ARTIFACT"
|
|
253
|
+
echo "Release created: ${RELEASE_TAG} (${VERSION})" >> $GITHUB_STEP_SUMMARY
|
|
254
|
+
else
|
|
255
|
+
gh release edit "$RELEASE_TAG" \
|
|
256
|
+
--title "v${MAJOR} (latest: ${VERSION})" \
|
|
257
|
+
--notes-file /tmp/release_notes.md
|
|
258
|
+
gh release upload "$RELEASE_TAG" "$ARTIFACT" --clobber 2>/dev/null || true
|
|
259
|
+
echo "Release updated: ${RELEASE_TAG} -> ${VERSION}" >> $GITHUB_STEP_SUMMARY
|
|
260
|
+
fi
|
|
261
|
+
|
|
262
|
+
# ── Summary ──────────────────────────────────────────────────────
|
|
263
|
+
- name: Pipeline Summary
|
|
264
|
+
if: always()
|
|
265
|
+
run: |
|
|
266
|
+
VERSION="${{ steps.version.outputs.version }}"
|
|
267
|
+
TOOL_COUNT="${{ steps.tools.outputs.count }}"
|
|
268
|
+
if [ "${{ steps.version.outputs.skip }}" = "true" ]; then
|
|
269
|
+
echo "## Release Skipped" >> $GITHUB_STEP_SUMMARY
|
|
270
|
+
else
|
|
271
|
+
echo "" >> $GITHUB_STEP_SUMMARY
|
|
272
|
+
echo "## MCP Release Complete" >> $GITHUB_STEP_SUMMARY
|
|
273
|
+
echo "" >> $GITHUB_STEP_SUMMARY
|
|
274
|
+
echo "| Detail | Value |" >> $GITHUB_STEP_SUMMARY
|
|
275
|
+
echo "|--------|-------|" >> $GITHUB_STEP_SUMMARY
|
|
276
|
+
echo "| Version | \`${VERSION}\` |" >> $GITHUB_STEP_SUMMARY
|
|
277
|
+
echo "| Tools | ${TOOL_COUNT} |" >> $GITHUB_STEP_SUMMARY
|
|
278
|
+
echo "| Branch | \`${{ steps.version.outputs.branch }}\` |" >> $GITHUB_STEP_SUMMARY
|
|
279
|
+
echo "| Tag | \`${{ steps.version.outputs.release_tag }}\` |" >> $GITHUB_STEP_SUMMARY
|
|
280
|
+
fi
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# MCP Server Build & Validation
|
|
2
|
+
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
|
3
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
|
+
#
|
|
5
|
+
# Builds the MCP server, validates TypeScript compilation, and checks
|
|
6
|
+
# that tools are properly registered with valid Zod schemas.
|
|
7
|
+
|
|
8
|
+
name: "MCP: Build & Validate"
|
|
9
|
+
|
|
10
|
+
on:
|
|
11
|
+
push:
|
|
12
|
+
branches: [main, dev/**]
|
|
13
|
+
paths: ['src/**', 'package.json', 'tsconfig.json']
|
|
14
|
+
pull_request:
|
|
15
|
+
branches: [main]
|
|
16
|
+
paths: ['src/**', 'package.json', 'tsconfig.json']
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
permissions:
|
|
20
|
+
contents: read
|
|
21
|
+
|
|
22
|
+
jobs:
|
|
23
|
+
build:
|
|
24
|
+
runs-on: ubuntu-latest
|
|
25
|
+
strategy:
|
|
26
|
+
matrix:
|
|
27
|
+
node-version: [20, 22]
|
|
28
|
+
|
|
29
|
+
steps:
|
|
30
|
+
- uses: actions/checkout@v4
|
|
31
|
+
|
|
32
|
+
- name: Setup Node.js ${{ matrix.node-version }}
|
|
33
|
+
uses: actions/setup-node@v4
|
|
34
|
+
with:
|
|
35
|
+
node-version: ${{ matrix.node-version }}
|
|
36
|
+
|
|
37
|
+
- name: Install dependencies
|
|
38
|
+
run: npm ci
|
|
39
|
+
|
|
40
|
+
- name: TypeScript compile
|
|
41
|
+
run: npx tsc --noEmit
|
|
42
|
+
|
|
43
|
+
- name: Build
|
|
44
|
+
run: npm run build
|
|
45
|
+
|
|
46
|
+
- name: Verify dist output exists
|
|
47
|
+
run: |
|
|
48
|
+
test -f dist/index.js || (echo "ERROR: dist/index.js not found" && exit 1)
|
|
49
|
+
test -f dist/client.js || (echo "ERROR: dist/client.js not found" && exit 1)
|
|
50
|
+
test -f dist/config.js || (echo "ERROR: dist/config.js not found" && exit 1)
|
|
51
|
+
test -f dist/types.js || (echo "ERROR: dist/types.js not found" && exit 1)
|
|
52
|
+
echo "✓ All required dist files present"
|
|
53
|
+
|
|
54
|
+
- name: Verify shebang in index.js
|
|
55
|
+
run: |
|
|
56
|
+
head -1 dist/index.js | grep -q "#!/usr/bin/env node" || echo "WARNING: Missing shebang in dist/index.js"
|
|
57
|
+
|
|
58
|
+
- name: Count registered tools
|
|
59
|
+
run: |
|
|
60
|
+
TOOL_COUNT=$(grep -c "server\.tool(" src/index.ts || true)
|
|
61
|
+
echo "Registered tools: ${TOOL_COUNT}"
|
|
62
|
+
if [ "${TOOL_COUNT}" -eq 0 ]; then
|
|
63
|
+
echo "ERROR: No tools registered in src/index.ts"
|
|
64
|
+
exit 1
|
|
65
|
+
fi
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# MCP SDK Version Check
|
|
2
|
+
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
|
3
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
|
+
#
|
|
5
|
+
# Weekly check for MCP SDK updates. Creates an issue when a new version
|
|
6
|
+
# of @modelcontextprotocol/sdk is available.
|
|
7
|
+
|
|
8
|
+
name: "MCP: SDK Version Check"
|
|
9
|
+
|
|
10
|
+
on:
|
|
11
|
+
schedule:
|
|
12
|
+
- cron: '0 9 * * 1' # Every Monday at 9am UTC
|
|
13
|
+
workflow_dispatch:
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
permissions:
|
|
17
|
+
contents: read
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
check-sdk:
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@v4
|
|
25
|
+
|
|
26
|
+
- name: Setup Node.js
|
|
27
|
+
uses: actions/setup-node@v4
|
|
28
|
+
with:
|
|
29
|
+
node-version: 20
|
|
30
|
+
|
|
31
|
+
- name: Check for SDK updates
|
|
32
|
+
id: sdk-check
|
|
33
|
+
run: |
|
|
34
|
+
CURRENT=$(node -p "require('./package.json').dependencies['@modelcontextprotocol/sdk']" | sed 's/[\^~]//')
|
|
35
|
+
LATEST=$(npm view @modelcontextprotocol/sdk version 2>/dev/null || echo "unknown")
|
|
36
|
+
|
|
37
|
+
echo "current=${CURRENT}" >> $GITHUB_OUTPUT
|
|
38
|
+
echo "latest=${LATEST}" >> $GITHUB_OUTPUT
|
|
39
|
+
|
|
40
|
+
if [ "${CURRENT}" != "${LATEST}" ] && [ "${LATEST}" != "unknown" ]; then
|
|
41
|
+
echo "update_available=true" >> $GITHUB_OUTPUT
|
|
42
|
+
echo "MCP SDK update available: ${CURRENT} → ${LATEST}"
|
|
43
|
+
else
|
|
44
|
+
echo "update_available=false" >> $GITHUB_OUTPUT
|
|
45
|
+
echo "MCP SDK is up to date: ${CURRENT}"
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
- name: Check for Zod updates
|
|
49
|
+
id: zod-check
|
|
50
|
+
run: |
|
|
51
|
+
CURRENT=$(node -p "require('./package.json').dependencies['zod']" | sed 's/[\^~]//')
|
|
52
|
+
LATEST=$(npm view zod version 2>/dev/null || echo "unknown")
|
|
53
|
+
|
|
54
|
+
echo "current=${CURRENT}" >> $GITHUB_OUTPUT
|
|
55
|
+
echo "latest=${LATEST}" >> $GITHUB_OUTPUT
|
|
56
|
+
|
|
57
|
+
if [ "${CURRENT}" != "${LATEST}" ] && [ "${LATEST}" != "unknown" ]; then
|
|
58
|
+
echo "update_available=true" >> $GITHUB_OUTPUT
|
|
59
|
+
else
|
|
60
|
+
echo "update_available=false" >> $GITHUB_OUTPUT
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
- name: Create update issue
|
|
64
|
+
if: steps.sdk-check.outputs.update_available == 'true'
|
|
65
|
+
uses: actions/github-script@v7
|
|
66
|
+
with:
|
|
67
|
+
script: |
|
|
68
|
+
const title = `chore(deps): update @modelcontextprotocol/sdk ${process.env.CURRENT} → ${process.env.LATEST}`;
|
|
69
|
+
const body = [
|
|
70
|
+
'## MCP SDK Update Available',
|
|
71
|
+
'',
|
|
72
|
+
`| Package | Current | Latest |`,
|
|
73
|
+
`|---------|---------|--------|`,
|
|
74
|
+
`| @modelcontextprotocol/sdk | ${process.env.CURRENT} | ${process.env.LATEST} |`,
|
|
75
|
+
`| zod | ${process.env.ZOD_CURRENT} | ${process.env.ZOD_LATEST} |`,
|
|
76
|
+
'',
|
|
77
|
+
'### Steps',
|
|
78
|
+
'1. Update package.json',
|
|
79
|
+
'2. Run `npm install`',
|
|
80
|
+
'3. Run `npm run build` to verify compilation',
|
|
81
|
+
'4. Test all tools against target API',
|
|
82
|
+
'',
|
|
83
|
+
'### Changelog',
|
|
84
|
+
`https://github.com/modelcontextprotocol/typescript-sdk/releases`,
|
|
85
|
+
].join('\n');
|
|
86
|
+
|
|
87
|
+
// Check for existing open issue
|
|
88
|
+
const existing = await github.rest.issues.listForRepo({
|
|
89
|
+
owner: context.repo.owner,
|
|
90
|
+
repo: context.repo.repo,
|
|
91
|
+
state: 'open',
|
|
92
|
+
labels: 'api-change',
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const alreadyExists = existing.data.some(i => i.title.includes('@modelcontextprotocol/sdk'));
|
|
96
|
+
if (!alreadyExists) {
|
|
97
|
+
await github.rest.issues.create({
|
|
98
|
+
owner: context.repo.owner,
|
|
99
|
+
repo: context.repo.repo,
|
|
100
|
+
title,
|
|
101
|
+
body,
|
|
102
|
+
labels: ['api-change', 'chore'],
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
env:
|
|
106
|
+
CURRENT: ${{ steps.sdk-check.outputs.current }}
|
|
107
|
+
LATEST: ${{ steps.sdk-check.outputs.latest }}
|
|
108
|
+
ZOD_CURRENT: ${{ steps.zod-check.outputs.current }}
|
|
109
|
+
ZOD_LATEST: ${{ steps.zod-check.outputs.latest }}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# MCP Tool Inventory
|
|
2
|
+
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
|
3
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
|
+
#
|
|
5
|
+
# Generates a tool inventory report on each push to main.
|
|
6
|
+
# Extracts tool names, descriptions, and parameter counts from src/index.ts.
|
|
7
|
+
|
|
8
|
+
name: "MCP: Tool Inventory"
|
|
9
|
+
|
|
10
|
+
on:
|
|
11
|
+
push:
|
|
12
|
+
branches: [main]
|
|
13
|
+
paths: ['src/index.ts']
|
|
14
|
+
workflow_dispatch:
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
permissions:
|
|
18
|
+
contents: read
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
inventory:
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@v4
|
|
26
|
+
|
|
27
|
+
- name: Generate tool inventory
|
|
28
|
+
run: |
|
|
29
|
+
echo "# MCP Tool Inventory" > TOOLS.md
|
|
30
|
+
echo "" >> TOOLS.md
|
|
31
|
+
echo "Auto-generated from \`src/index.ts\` on $(date -u +%Y-%m-%dT%H:%M:%SZ)" >> TOOLS.md
|
|
32
|
+
echo "" >> TOOLS.md
|
|
33
|
+
|
|
34
|
+
# Count tools
|
|
35
|
+
TOOL_COUNT=$(grep -c "server\.tool(" src/index.ts || true)
|
|
36
|
+
echo "**Total tools: ${TOOL_COUNT}**" >> TOOLS.md
|
|
37
|
+
echo "" >> TOOLS.md
|
|
38
|
+
|
|
39
|
+
# Extract tool names and descriptions
|
|
40
|
+
echo "| Tool | Description |" >> TOOLS.md
|
|
41
|
+
echo "|------|-------------|" >> TOOLS.md
|
|
42
|
+
|
|
43
|
+
grep -A1 "server\.tool(" src/index.ts | grep -E "^\s*'" | while read -r line; do
|
|
44
|
+
TOOL_NAME=$(echo "$line" | sed "s/.*'\([^']*\)'.*/\1/")
|
|
45
|
+
# Get next line for description
|
|
46
|
+
DESC=$(grep -A2 "'${TOOL_NAME}'" src/index.ts | grep -E "^\s*'" | tail -1 | sed "s/.*'\([^']*\)'.*/\1/" || echo "")
|
|
47
|
+
echo "| \`${TOOL_NAME}\` | ${DESC} |" >> TOOLS.md
|
|
48
|
+
done
|
|
49
|
+
|
|
50
|
+
echo "" >> TOOLS.md
|
|
51
|
+
echo "---" >> TOOLS.md
|
|
52
|
+
echo "*Generated by MCP Tool Inventory workflow*" >> TOOLS.md
|
|
53
|
+
|
|
54
|
+
cat TOOLS.md
|
|
55
|
+
|
|
56
|
+
- name: Upload inventory artifact
|
|
57
|
+
uses: actions/upload-artifact@v4
|
|
58
|
+
with:
|
|
59
|
+
name: tool-inventory
|
|
60
|
+
path: TOOLS.md
|
|
61
|
+
retention-days: 90
|