@mokoconsulting/mcp-mokosuite 1.0.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/.editorconfig +19 -0
- package/.gitattributes +94 -0
- package/.gitmessage +9 -0
- package/.mokogit/ISSUE_TEMPLATE/adr.md +110 -0
- package/.mokogit/ISSUE_TEMPLATE/bug_report.md +48 -0
- package/.mokogit/ISSUE_TEMPLATE/config.yml +18 -0
- package/.mokogit/ISSUE_TEMPLATE/documentation.md +52 -0
- package/.mokogit/ISSUE_TEMPLATE/feature_request.md +51 -0
- package/.mokogit/ISSUE_TEMPLATE/mcp_api_integration.md +48 -0
- package/.mokogit/ISSUE_TEMPLATE/mcp_connection_issue.md +69 -0
- package/.mokogit/ISSUE_TEMPLATE/mcp_tool_request.md +50 -0
- package/.mokogit/ISSUE_TEMPLATE/question.md +82 -0
- package/.mokogit/ISSUE_TEMPLATE/rfc.md +126 -0
- package/.mokogit/ISSUE_TEMPLATE/security.md +51 -0
- package/.mokogit/ISSUE_TEMPLATE/version.md +24 -0
- package/.mokogit/actions/resolve-source-dir/action.yml +108 -0
- package/.mokogit/workflows/auto-assign.yml +76 -0
- package/.mokogit/workflows/auto-bump.yml +78 -0
- package/.mokogit/workflows/auto-dev-issue.yml +207 -0
- package/.mokogit/workflows/auto-release.yml +596 -0
- package/.mokogit/workflows/branch-cleanup.yml +60 -0
- package/.mokogit/workflows/cascade-dev.yml +198 -0
- package/.mokogit/workflows/changelog-validation.yml +101 -0
- package/.mokogit/workflows/ci-generic.yml +203 -0
- package/.mokogit/workflows/ci-issue-reporter.yml +75 -0
- package/.mokogit/workflows/cleanup.yml +87 -0
- package/.mokogit/workflows/gitleaks.yml +94 -0
- package/.mokogit/workflows/issue-branch.yml +81 -0
- package/.mokogit/workflows/notify.yml +73 -0
- package/.mokogit/workflows/npm-build-test.yml +83 -0
- package/.mokogit/workflows/npm-publish.yml +126 -0
- package/.mokogit/workflows/npm-sdk-check.yml +110 -0
- package/.mokogit/workflows/npm-tool-inventory.yml +80 -0
- package/.mokogit/workflows/pr-branch-check.yml +90 -0
- package/.mokogit/workflows/pr-check.yml +565 -0
- package/.mokogit/workflows/pre-release.yml +413 -0
- package/.mokogit/workflows/push-notify.yml +43 -0
- package/.mokogit/workflows/rc-revert.yml +72 -0
- package/.mokogit/workflows/repo-health.yml +700 -0
- package/.mokogit/workflows/repository-cleanup.yml +525 -0
- package/.mokogit/workflows/standards-compliance.yml +2507 -0
- package/.mokogit/workflows/sync-version-on-merge.yml +130 -0
- package/.mokogit/workflows/version-set.yml +131 -0
- package/CHANGELOG.md +18 -0
- package/CLAUDE.md +52 -0
- package/CODE_OF_CONDUCT.md +70 -0
- package/CONTRIBUTING.md +161 -0
- package/LICENSE +696 -0
- package/Makefile +70 -0
- package/README.md +83 -0
- package/SECURITY.md +34 -0
- package/config.example.json +21 -0
- package/dist/client.d.ts +22 -0
- package/dist/client.js +124 -0
- package/dist/config.d.ts +4 -0
- package/dist/config.js +53 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +181 -0
- package/dist/signing.d.ts +14 -0
- package/dist/signing.js +62 -0
- package/dist/types.d.ts +44 -0
- package/dist/types.js +16 -0
- package/docs/API.md +63 -0
- package/docs/ARCHITECTURE.md +73 -0
- package/docs/INSTALLATION.md +102 -0
- package/docs/index.md +12 -0
- package/package.json +35 -0
- package/src/client.ts +142 -0
- package/src/config.ts +63 -0
- package/src/index.ts +336 -0
- package/src/signing.ts +67 -0
- package/src/types.ts +63 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,94 @@
|
|
|
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: MokoGIT.Workflow
|
|
7
|
+
# INGROUP: MokoCLI.Security
|
|
8
|
+
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli
|
|
9
|
+
# PATH: /.mokogit/workflows/gitleaks.yml
|
|
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
|
+
schedule:
|
|
29
|
+
- cron: '0 5 * * 1' # Weekly Monday 05:00 UTC
|
|
30
|
+
workflow_dispatch:
|
|
31
|
+
|
|
32
|
+
permissions:
|
|
33
|
+
contents: read
|
|
34
|
+
|
|
35
|
+
env:
|
|
36
|
+
NTFY_URL: ${{ vars.NTFY_URL || 'https://ntfy.mokoconsulting.tech' }}
|
|
37
|
+
NTFY_TOPIC: ${{ vars.NTFY_TOPIC || 'mokogit-security' }}
|
|
38
|
+
NTFY_TOKEN: ${{ secrets.NTFY_TOKEN }}
|
|
39
|
+
|
|
40
|
+
jobs:
|
|
41
|
+
gitleaks:
|
|
42
|
+
name: Gitleaks Secret Scan
|
|
43
|
+
runs-on: ubuntu-latest
|
|
44
|
+
|
|
45
|
+
steps:
|
|
46
|
+
- name: Checkout
|
|
47
|
+
uses: actions/checkout@v4
|
|
48
|
+
with:
|
|
49
|
+
fetch-depth: 0
|
|
50
|
+
|
|
51
|
+
- name: Install Gitleaks
|
|
52
|
+
run: |
|
|
53
|
+
GITLEAKS_VERSION="8.21.2"
|
|
54
|
+
curl -sSL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" \
|
|
55
|
+
| tar -xz -C /usr/local/bin gitleaks
|
|
56
|
+
gitleaks version
|
|
57
|
+
|
|
58
|
+
- name: Scan for secrets
|
|
59
|
+
id: scan
|
|
60
|
+
run: |
|
|
61
|
+
echo "### Secret Scanning" >> $GITHUB_STEP_SUMMARY
|
|
62
|
+
ARGS="--source . --verbose --report-format json --report-path /tmp/gitleaks-report.json"
|
|
63
|
+
|
|
64
|
+
if [ "${{ github.event_name }}" = "pull_request" ]; then
|
|
65
|
+
# Scan only PR commits
|
|
66
|
+
ARGS="$ARGS --log-opts=${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }}"
|
|
67
|
+
echo "Scanning PR commits only" >> $GITHUB_STEP_SUMMARY
|
|
68
|
+
else
|
|
69
|
+
echo "Full repository scan" >> $GITHUB_STEP_SUMMARY
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
if gitleaks detect $ARGS 2>&1; then
|
|
73
|
+
echo "result=clean" >> "$GITHUB_OUTPUT"
|
|
74
|
+
echo "**No secrets detected.**" >> $GITHUB_STEP_SUMMARY
|
|
75
|
+
else
|
|
76
|
+
echo "result=found" >> "$GITHUB_OUTPUT"
|
|
77
|
+
FINDINGS=$(jq length /tmp/gitleaks-report.json 2>/dev/null || echo "unknown")
|
|
78
|
+
echo "**${FINDINGS} potential secret(s) detected.**" >> $GITHUB_STEP_SUMMARY
|
|
79
|
+
echo "" >> $GITHUB_STEP_SUMMARY
|
|
80
|
+
echo "Review the findings and rotate any exposed credentials immediately." >> $GITHUB_STEP_SUMMARY
|
|
81
|
+
exit 1
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
- name: Notify on findings
|
|
85
|
+
if: failure() && steps.scan.outputs.result == 'found'
|
|
86
|
+
run: |
|
|
87
|
+
REPO="${{ github.event.repository.name }}"
|
|
88
|
+
curl -sS \
|
|
89
|
+
-H "Title: ${REPO} — secrets detected in code" \
|
|
90
|
+
-H "Tags: rotating_light,key" \
|
|
91
|
+
-H "Priority: urgent" \
|
|
92
|
+
-d "Gitleaks found potential secrets. Review and rotate credentials immediately." \
|
|
93
|
+
-H "Authorization: Bearer ${NTFY_TOKEN}" \
|
|
94
|
+
"${NTFY_URL}/${NTFY_TOPIC}" || true
|
|
@@ -0,0 +1,81 @@
|
|
|
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: MokoGIT.Workflow
|
|
7
|
+
# INGROUP: MokoCLI.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
|
+
MOKOGIT_URL: ${{ vars.MOKOGIT_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
|
+
# SECURITY: never interpolate github.event.* into a run: script — the
|
|
31
|
+
# Actions engine splices the raw value into the shell source (command
|
|
32
|
+
# injection via a crafted issue title). Pass everything through env so
|
|
33
|
+
# the values arrive as ordinary shell variables that are not re-parsed.
|
|
34
|
+
env:
|
|
35
|
+
MOKOGIT_TOKEN: ${{ secrets.MOKOGIT_TOKEN }}
|
|
36
|
+
REPO: ${{ github.repository }}
|
|
37
|
+
ISSUE_NUM: ${{ github.event.issue.number }}
|
|
38
|
+
ISSUE_TITLE: ${{ github.event.issue.title }}
|
|
39
|
+
run: |
|
|
40
|
+
TOKEN="${MOKOGIT_TOKEN}"
|
|
41
|
+
API="${MOKOGIT_URL}/api/v1/repos/${REPO}"
|
|
42
|
+
|
|
43
|
+
# Build slug from title: lowercase, replace non-alnum with dash, trim.
|
|
44
|
+
# printf (not echo) so a title beginning with "-" is not read as flags.
|
|
45
|
+
SLUG=$(printf '%s' "${ISSUE_TITLE}" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-//;s/-$//' | cut -c1-40)
|
|
46
|
+
BRANCH="feature/${ISSUE_NUM}-${SLUG}"
|
|
47
|
+
|
|
48
|
+
# Check dev branch exists
|
|
49
|
+
DEV_EXISTS=$(curl -sf -o /dev/null -w '%{http_code}' \
|
|
50
|
+
-H "Authorization: token ${TOKEN}" \
|
|
51
|
+
"${API}/branches/dev" 2>/dev/null || echo "000")
|
|
52
|
+
|
|
53
|
+
if [ "${DEV_EXISTS}" != "200" ]; then
|
|
54
|
+
echo "No dev branch -- skipping"
|
|
55
|
+
exit 0
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
# Create branch from dev
|
|
59
|
+
HTTP=$(curl -sf -o /dev/null -w '%{http_code}' -X POST \
|
|
60
|
+
-H "Authorization: token ${TOKEN}" \
|
|
61
|
+
-H "Content-Type: application/json" \
|
|
62
|
+
"${API}/branches" \
|
|
63
|
+
-d "{\"new_branch_name\":\"${BRANCH}\",\"old_branch_name\":\"dev\"}" 2>/dev/null || echo "000")
|
|
64
|
+
|
|
65
|
+
if [ "${HTTP}" = "201" ]; then
|
|
66
|
+
echo "Created branch: ${BRANCH}"
|
|
67
|
+
|
|
68
|
+
# Comment on issue with branch link
|
|
69
|
+
REPO_URL="${MOKOGIT_URL}/${REPO}"
|
|
70
|
+
BODY="Branch created: [\`${BRANCH}\`](${REPO_URL}/src/branch/${BRANCH})\n\n\`\`\`bash\ngit fetch origin\ngit checkout ${BRANCH}\n\`\`\`"
|
|
71
|
+
|
|
72
|
+
curl -sf -X POST \
|
|
73
|
+
-H "Authorization: token ${TOKEN}" \
|
|
74
|
+
-H "Content-Type: application/json" \
|
|
75
|
+
"${API}/issues/${ISSUE_NUM}/comments" \
|
|
76
|
+
-d "{\"body\":\"${BODY}\"}" > /dev/null 2>&1
|
|
77
|
+
|
|
78
|
+
echo "Commented on issue #${ISSUE_NUM}"
|
|
79
|
+
else
|
|
80
|
+
echo "Failed to create branch (HTTP ${HTTP}) -- may already exist"
|
|
81
|
+
fi
|
|
@@ -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: MokoGIT.Workflow
|
|
7
|
+
# INGROUP: MokoCLI.Notifications
|
|
8
|
+
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli
|
|
9
|
+
# PATH: /.mokogit/workflows/notify.yml
|
|
10
|
+
# VERSION: 01.00.00
|
|
11
|
+
# BRIEF: Push notifications via ntfy on release success or workflow failure
|
|
12
|
+
|
|
13
|
+
name: "Universal: Notifications"
|
|
14
|
+
|
|
15
|
+
on:
|
|
16
|
+
workflow_run:
|
|
17
|
+
workflows:
|
|
18
|
+
- "Universal: Build & Release"
|
|
19
|
+
- "Joomla: Extension CI"
|
|
20
|
+
- "Generic: Project CI"
|
|
21
|
+
types:
|
|
22
|
+
- completed
|
|
23
|
+
|
|
24
|
+
permissions:
|
|
25
|
+
contents: read
|
|
26
|
+
|
|
27
|
+
env:
|
|
28
|
+
NTFY_URL: ${{ vars.NTFY_URL || 'https://ntfy.mokoconsulting.tech' }}
|
|
29
|
+
NTFY_TOPIC: ${{ vars.NTFY_TOPIC || 'mokogit-releases' }}
|
|
30
|
+
NTFY_TOKEN: ${{ secrets.NTFY_TOKEN }}
|
|
31
|
+
|
|
32
|
+
jobs:
|
|
33
|
+
notify:
|
|
34
|
+
name: Send Notification
|
|
35
|
+
runs-on: ubuntu-latest
|
|
36
|
+
if: >-
|
|
37
|
+
github.event.workflow_run.conclusion == 'success' ||
|
|
38
|
+
github.event.workflow_run.conclusion == 'failure'
|
|
39
|
+
|
|
40
|
+
steps:
|
|
41
|
+
- name: Notify on success (releases only)
|
|
42
|
+
if: >-
|
|
43
|
+
github.event.workflow_run.conclusion == 'success' &&
|
|
44
|
+
contains(github.event.workflow_run.name, 'Release')
|
|
45
|
+
run: |
|
|
46
|
+
REPO="${{ github.event.repository.name }}"
|
|
47
|
+
WORKFLOW="${{ github.event.workflow_run.name }}"
|
|
48
|
+
URL="${{ github.event.workflow_run.html_url }}"
|
|
49
|
+
|
|
50
|
+
curl -sS --retry 3 --retry-connrefused --retry-delay 2 --max-time 20 \
|
|
51
|
+
-H "Title: ${REPO} released" \
|
|
52
|
+
-H "Tags: white_check_mark,package" \
|
|
53
|
+
-H "Priority: default" \
|
|
54
|
+
-H "Click: ${URL}" \
|
|
55
|
+
-d "${WORKFLOW} completed successfully." \
|
|
56
|
+
-H "Authorization: Bearer ${NTFY_TOKEN}" \
|
|
57
|
+
"${NTFY_URL}/${NTFY_TOPIC}" || echo "::warning::ntfy notification could not be delivered (non-fatal)"
|
|
58
|
+
|
|
59
|
+
- name: Notify on failure
|
|
60
|
+
if: github.event.workflow_run.conclusion == 'failure'
|
|
61
|
+
run: |
|
|
62
|
+
REPO="${{ github.event.repository.name }}"
|
|
63
|
+
WORKFLOW="${{ github.event.workflow_run.name }}"
|
|
64
|
+
URL="${{ github.event.workflow_run.html_url }}"
|
|
65
|
+
|
|
66
|
+
curl -sS --retry 3 --retry-connrefused --retry-delay 2 --max-time 20 \
|
|
67
|
+
-H "Title: ${REPO} workflow failed" \
|
|
68
|
+
-H "Tags: x,warning" \
|
|
69
|
+
-H "Priority: high" \
|
|
70
|
+
-H "Click: ${URL}" \
|
|
71
|
+
-d "${WORKFLOW} failed. Check the run for details." \
|
|
72
|
+
-H "Authorization: Bearer ${NTFY_TOKEN}" \
|
|
73
|
+
"${NTFY_URL}/${NTFY_TOPIC}" || echo "::warning::ntfy notification could not be delivered (non-fatal)"
|
|
@@ -0,0 +1,83 @@
|
|
|
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: ['source/**', 'src/**', 'package.json', 'tsconfig.json']
|
|
14
|
+
pull_request:
|
|
15
|
+
branches: [main]
|
|
16
|
+
paths: ['source/**', 'src/**', 'package.json', 'tsconfig.json']
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
permissions:
|
|
20
|
+
contents: read
|
|
21
|
+
|
|
22
|
+
env:
|
|
23
|
+
MOKOGIT_URL: ${{ vars.MOKOGIT_URL || 'https://git.mokoconsulting.tech' }}
|
|
24
|
+
GIT_ORG: ${{ vars.MOKOGIT_ORG || github.repository_owner }}
|
|
25
|
+
GIT_REPO: ${{ vars.MOKOGIT_REPO || github.event.repository.name }}
|
|
26
|
+
|
|
27
|
+
jobs:
|
|
28
|
+
build:
|
|
29
|
+
runs-on: ubuntu-latest
|
|
30
|
+
if: ${{ !startsWith(github.event.repository.name, 'Template-') }}
|
|
31
|
+
strategy:
|
|
32
|
+
matrix:
|
|
33
|
+
node-version: [20, 22]
|
|
34
|
+
|
|
35
|
+
steps:
|
|
36
|
+
- uses: actions/checkout@v4
|
|
37
|
+
|
|
38
|
+
- name: Resolve source dir
|
|
39
|
+
id: srcdir
|
|
40
|
+
uses: ./.mokogit/actions/resolve-source-dir
|
|
41
|
+
with:
|
|
42
|
+
mokogit_token: ${{ secrets.MOKOGIT_TOKEN }}
|
|
43
|
+
strict: 'false'
|
|
44
|
+
|
|
45
|
+
- name: Setup Node.js ${{ matrix.node-version }}
|
|
46
|
+
uses: actions/setup-node@v4
|
|
47
|
+
with:
|
|
48
|
+
node-version: ${{ matrix.node-version }}
|
|
49
|
+
|
|
50
|
+
- name: Install dependencies
|
|
51
|
+
run: npm ci
|
|
52
|
+
|
|
53
|
+
- name: TypeScript compile
|
|
54
|
+
run: npx tsc --noEmit
|
|
55
|
+
|
|
56
|
+
- name: Build
|
|
57
|
+
run: npm run build
|
|
58
|
+
|
|
59
|
+
- name: Verify dist output exists
|
|
60
|
+
run: |
|
|
61
|
+
test -f dist/index.js || (echo "ERROR: dist/index.js not found" && exit 1)
|
|
62
|
+
test -f dist/client.js || (echo "ERROR: dist/client.js not found" && exit 1)
|
|
63
|
+
test -f dist/config.js || (echo "ERROR: dist/config.js not found" && exit 1)
|
|
64
|
+
test -f dist/types.js || (echo "ERROR: dist/types.js not found" && exit 1)
|
|
65
|
+
echo "✓ All required dist files present"
|
|
66
|
+
|
|
67
|
+
- name: Verify shebang in index.js
|
|
68
|
+
run: |
|
|
69
|
+
head -1 dist/index.js | grep -q "#!/usr/bin/env node" || echo "WARNING: Missing shebang in dist/index.js"
|
|
70
|
+
|
|
71
|
+
- name: Count registered tools
|
|
72
|
+
run: |
|
|
73
|
+
INDEX_FILE="${{ steps.srcdir.outputs.source_dir }}index.ts"
|
|
74
|
+
if [ ! -f "${INDEX_FILE}" ]; then
|
|
75
|
+
echo "::warning::resolved entrypoint ${INDEX_FILE} missing; falling back to src/index.ts"
|
|
76
|
+
INDEX_FILE="src/index.ts"
|
|
77
|
+
fi
|
|
78
|
+
TOOL_COUNT=$(grep -c "server\.tool(" "${INDEX_FILE}" || true)
|
|
79
|
+
echo "Registered tools in ${INDEX_FILE}: ${TOOL_COUNT}"
|
|
80
|
+
if [ "${TOOL_COUNT}" -eq 0 ]; then
|
|
81
|
+
echo "ERROR: No tools registered in ${INDEX_FILE}"
|
|
82
|
+
exit 1
|
|
83
|
+
fi
|
|
@@ -0,0 +1,126 @@
|
|
|
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: MokoGIT.Workflow
|
|
7
|
+
# INGROUP: MokoCLI.Release
|
|
8
|
+
# REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-NPM
|
|
9
|
+
# PATH: /.mokogit/workflows/npm-publish.yml
|
|
10
|
+
# VERSION: 02.00.00
|
|
11
|
+
# BRIEF: Build + publish shim. The shared release engine (pre-release.yml /
|
|
12
|
+
# auto-release.yml) owns version bump, tag, changelog and release
|
|
13
|
+
# object; this workflow only builds and publishes the version the
|
|
14
|
+
# engine has already written to package.json. It never bumps or
|
|
15
|
+
# writes the version.
|
|
16
|
+
|
|
17
|
+
name: "Publish to npm"
|
|
18
|
+
|
|
19
|
+
on:
|
|
20
|
+
push:
|
|
21
|
+
branches:
|
|
22
|
+
- main
|
|
23
|
+
workflow_dispatch:
|
|
24
|
+
|
|
25
|
+
jobs:
|
|
26
|
+
publish:
|
|
27
|
+
runs-on: release
|
|
28
|
+
if: >-
|
|
29
|
+
!contains(github.event.head_commit.message, '[skip ci]') &&
|
|
30
|
+
!contains(github.event.head_commit.message, '[skip publish]') &&
|
|
31
|
+
!startsWith(github.event.repository.name, 'Template-')
|
|
32
|
+
steps:
|
|
33
|
+
- name: Checkout
|
|
34
|
+
uses: actions/checkout@v4
|
|
35
|
+
with:
|
|
36
|
+
fetch-depth: 2
|
|
37
|
+
|
|
38
|
+
- name: Resolve source dir
|
|
39
|
+
id: srcdir
|
|
40
|
+
uses: ./.mokogit/actions/resolve-source-dir
|
|
41
|
+
with:
|
|
42
|
+
mokogit_token: ${{ secrets.MOKOGIT_TOKEN }}
|
|
43
|
+
strict: 'true'
|
|
44
|
+
|
|
45
|
+
- name: Detect publishable changes
|
|
46
|
+
id: detect
|
|
47
|
+
run: |
|
|
48
|
+
set -euo pipefail
|
|
49
|
+
|
|
50
|
+
# workflow_dispatch has no diff base — always treat as changed.
|
|
51
|
+
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
|
52
|
+
echo "::notice::workflow_dispatch — forcing changed=true"
|
|
53
|
+
echo "changed=true" >> "$GITHUB_OUTPUT"
|
|
54
|
+
exit 0
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
# Build the source-dir alternative from the resolved dir (escape ERE metachars).
|
|
58
|
+
# Class lists ] first and [ last to avoid a [. collating-symbol parse; the
|
|
59
|
+
# \\\\& replacement reaches sed as \\& = literal backslash + matched char.
|
|
60
|
+
SRC_DIR='${{ steps.srcdir.outputs.source_dir }}'
|
|
61
|
+
SRC_RE=$(printf '%s' "$SRC_DIR" | sed 's/[].^$*+?(){}|[]/\\\\&/g')
|
|
62
|
+
PATTERN="^(${SRC_RE}|package\.json$|package-lock\.json$|tsconfig\.json$|README\.md$)"
|
|
63
|
+
echo "Detect pattern: ${PATTERN}"
|
|
64
|
+
|
|
65
|
+
BEFORE="${{ github.event.before }}"
|
|
66
|
+
if [ -z "${BEFORE}" ] || ! git cat-file -e "${BEFORE}^{commit}" 2>/dev/null; then
|
|
67
|
+
BEFORE=$(git rev-parse HEAD^ 2>/dev/null || echo "")
|
|
68
|
+
fi
|
|
69
|
+
if [ -n "${BEFORE}" ]; then
|
|
70
|
+
FILES=$(git diff --name-only "${BEFORE}" HEAD)
|
|
71
|
+
else
|
|
72
|
+
FILES=$(git show --name-only --pretty=format: HEAD)
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
if printf '%s\n' "${FILES}" | grep -Eq "${PATTERN}"; then
|
|
76
|
+
echo "changed=true" >> "$GITHUB_OUTPUT"
|
|
77
|
+
else
|
|
78
|
+
echo "::notice::No publishable changes under '${SRC_DIR}'. Files: ${FILES}"
|
|
79
|
+
echo "changed=false" >> "$GITHUB_OUTPUT"
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
- name: Setup Node.js
|
|
83
|
+
if: steps.detect.outputs.changed == 'true'
|
|
84
|
+
uses: actions/setup-node@v4
|
|
85
|
+
with:
|
|
86
|
+
node-version: '20'
|
|
87
|
+
|
|
88
|
+
- name: Install dependencies
|
|
89
|
+
if: steps.detect.outputs.changed == 'true'
|
|
90
|
+
run: npm install --no-audit --no-fund
|
|
91
|
+
|
|
92
|
+
- name: Build
|
|
93
|
+
if: steps.detect.outputs.changed == 'true'
|
|
94
|
+
run: npm run build
|
|
95
|
+
|
|
96
|
+
- name: Read version to publish
|
|
97
|
+
id: version
|
|
98
|
+
if: steps.detect.outputs.changed == 'true'
|
|
99
|
+
run: |
|
|
100
|
+
set -euo pipefail
|
|
101
|
+
# READ-ONLY. The shared release engine (pre-release.yml / auto-release.yml)
|
|
102
|
+
# has already bumped and written this version into package.json and created
|
|
103
|
+
# the tag + release object. This shim only publishes it — it never bumps or
|
|
104
|
+
# writes the version.
|
|
105
|
+
VERSION=$(node -p "require('./package.json').version")
|
|
106
|
+
echo "Publishing version ${VERSION} (set by the shared release engine)."
|
|
107
|
+
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
|
|
108
|
+
|
|
109
|
+
- name: Publish to npmjs.org + git.mokoconsulting.tech
|
|
110
|
+
if: steps.detect.outputs.changed == 'true'
|
|
111
|
+
run: |
|
|
112
|
+
set -uo pipefail
|
|
113
|
+
{
|
|
114
|
+
echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}"
|
|
115
|
+
echo "//git.mokoconsulting.tech/api/packages/MokoConsulting/npm/:_authToken=${MOKOGIT_TOKEN}"
|
|
116
|
+
} >> .npmrc
|
|
117
|
+
VER=$(node -p "require('./package.json').version")
|
|
118
|
+
rc=0
|
|
119
|
+
echo "Publishing ${VER} -> npmjs.org"
|
|
120
|
+
npm publish --access public --registry https://registry.npmjs.org/ || { echo "::warning::npmjs.org publish failed (version ${VER} may already exist)"; rc=$((rc+1)); }
|
|
121
|
+
echo "Publishing ${VER} -> git.mokoconsulting.tech"
|
|
122
|
+
npm publish --access public --registry https://git.mokoconsulting.tech/api/packages/MokoConsulting/npm/ || { echo "::warning::git.mokoconsulting.tech publish failed (version ${VER} may already exist)"; rc=$((rc+1)); }
|
|
123
|
+
[ "$rc" -lt 2 ]
|
|
124
|
+
env:
|
|
125
|
+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
126
|
+
MOKOGIT_TOKEN: ${{ secrets.MOKOGIT_TOKEN }}
|
|
@@ -0,0 +1,110 @@
|
|
|
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
|
+
if: ${{ !startsWith(github.event.repository.name, 'Template-') }}
|
|
23
|
+
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@v4
|
|
26
|
+
|
|
27
|
+
- name: Setup Node.js
|
|
28
|
+
uses: actions/setup-node@v4
|
|
29
|
+
with:
|
|
30
|
+
node-version: 20
|
|
31
|
+
|
|
32
|
+
- name: Check for SDK updates
|
|
33
|
+
id: sdk-check
|
|
34
|
+
run: |
|
|
35
|
+
CURRENT=$(node -p "require('./package.json').dependencies['@modelcontextprotocol/sdk']" | sed 's/[\^~]//')
|
|
36
|
+
LATEST=$(npm view @modelcontextprotocol/sdk version 2>/dev/null || echo "unknown")
|
|
37
|
+
|
|
38
|
+
echo "current=${CURRENT}" >> $GITHUB_OUTPUT
|
|
39
|
+
echo "latest=${LATEST}" >> $GITHUB_OUTPUT
|
|
40
|
+
|
|
41
|
+
if [ "${CURRENT}" != "${LATEST}" ] && [ "${LATEST}" != "unknown" ]; then
|
|
42
|
+
echo "update_available=true" >> $GITHUB_OUTPUT
|
|
43
|
+
echo "MCP SDK update available: ${CURRENT} → ${LATEST}"
|
|
44
|
+
else
|
|
45
|
+
echo "update_available=false" >> $GITHUB_OUTPUT
|
|
46
|
+
echo "MCP SDK is up to date: ${CURRENT}"
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
- name: Check for Zod updates
|
|
50
|
+
id: zod-check
|
|
51
|
+
run: |
|
|
52
|
+
CURRENT=$(node -p "require('./package.json').dependencies['zod']" | sed 's/[\^~]//')
|
|
53
|
+
LATEST=$(npm view zod version 2>/dev/null || echo "unknown")
|
|
54
|
+
|
|
55
|
+
echo "current=${CURRENT}" >> $GITHUB_OUTPUT
|
|
56
|
+
echo "latest=${LATEST}" >> $GITHUB_OUTPUT
|
|
57
|
+
|
|
58
|
+
if [ "${CURRENT}" != "${LATEST}" ] && [ "${LATEST}" != "unknown" ]; then
|
|
59
|
+
echo "update_available=true" >> $GITHUB_OUTPUT
|
|
60
|
+
else
|
|
61
|
+
echo "update_available=false" >> $GITHUB_OUTPUT
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
- name: Create update issue
|
|
65
|
+
if: steps.sdk-check.outputs.update_available == 'true'
|
|
66
|
+
uses: actions/github-script@v7
|
|
67
|
+
with:
|
|
68
|
+
script: |
|
|
69
|
+
const title = `chore(deps): update @modelcontextprotocol/sdk ${process.env.CURRENT} → ${process.env.LATEST}`;
|
|
70
|
+
const body = [
|
|
71
|
+
'## MCP SDK Update Available',
|
|
72
|
+
'',
|
|
73
|
+
`| Package | Current | Latest |`,
|
|
74
|
+
`|---------|---------|--------|`,
|
|
75
|
+
`| @modelcontextprotocol/sdk | ${process.env.CURRENT} | ${process.env.LATEST} |`,
|
|
76
|
+
`| zod | ${process.env.ZOD_CURRENT} | ${process.env.ZOD_LATEST} |`,
|
|
77
|
+
'',
|
|
78
|
+
'### Steps',
|
|
79
|
+
'1. Update package.json',
|
|
80
|
+
'2. Run `npm install`',
|
|
81
|
+
'3. Run `npm run build` to verify compilation',
|
|
82
|
+
'4. Test all tools against target API',
|
|
83
|
+
'',
|
|
84
|
+
'### Changelog',
|
|
85
|
+
`https://github.com/modelcontextprotocol/typescript-sdk/releases`,
|
|
86
|
+
].join('\n');
|
|
87
|
+
|
|
88
|
+
// Check for existing open issue
|
|
89
|
+
const existing = await github.rest.issues.listForRepo({
|
|
90
|
+
owner: context.repo.owner,
|
|
91
|
+
repo: context.repo.repo,
|
|
92
|
+
state: 'open',
|
|
93
|
+
labels: 'api-change',
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const alreadyExists = existing.data.some(i => i.title.includes('@modelcontextprotocol/sdk'));
|
|
97
|
+
if (!alreadyExists) {
|
|
98
|
+
await github.rest.issues.create({
|
|
99
|
+
owner: context.repo.owner,
|
|
100
|
+
repo: context.repo.repo,
|
|
101
|
+
title,
|
|
102
|
+
body,
|
|
103
|
+
labels: ['api-change', 'chore'],
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
env:
|
|
107
|
+
CURRENT: ${{ steps.sdk-check.outputs.current }}
|
|
108
|
+
LATEST: ${{ steps.sdk-check.outputs.latest }}
|
|
109
|
+
ZOD_CURRENT: ${{ steps.zod-check.outputs.current }}
|
|
110
|
+
ZOD_LATEST: ${{ steps.zod-check.outputs.latest }}
|
|
@@ -0,0 +1,80 @@
|
|
|
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: ['source/index.ts', 'src/index.ts']
|
|
14
|
+
workflow_dispatch:
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
permissions:
|
|
18
|
+
contents: read
|
|
19
|
+
|
|
20
|
+
env:
|
|
21
|
+
MOKOGIT_URL: ${{ vars.MOKOGIT_URL || 'https://git.mokoconsulting.tech' }}
|
|
22
|
+
GIT_ORG: ${{ vars.MOKOGIT_ORG || github.repository_owner }}
|
|
23
|
+
GIT_REPO: ${{ vars.MOKOGIT_REPO || github.event.repository.name }}
|
|
24
|
+
|
|
25
|
+
jobs:
|
|
26
|
+
inventory:
|
|
27
|
+
runs-on: ubuntu-latest
|
|
28
|
+
|
|
29
|
+
steps:
|
|
30
|
+
- uses: actions/checkout@v4
|
|
31
|
+
|
|
32
|
+
- name: Resolve source dir
|
|
33
|
+
id: srcdir
|
|
34
|
+
uses: ./.mokogit/actions/resolve-source-dir
|
|
35
|
+
with:
|
|
36
|
+
mokogit_token: ${{ secrets.MOKOGIT_TOKEN }}
|
|
37
|
+
strict: 'false'
|
|
38
|
+
|
|
39
|
+
- name: Generate tool inventory
|
|
40
|
+
run: |
|
|
41
|
+
INDEX_FILE="${{ steps.srcdir.outputs.source_dir }}index.ts"
|
|
42
|
+
if [ ! -f "${INDEX_FILE}" ]; then
|
|
43
|
+
echo "::warning::resolved entrypoint ${INDEX_FILE} missing; falling back to src/index.ts"
|
|
44
|
+
INDEX_FILE="src/index.ts"
|
|
45
|
+
fi
|
|
46
|
+
[ -r "${INDEX_FILE}" ] || { echo "::error::entry file ${INDEX_FILE} unreadable"; exit 1; }
|
|
47
|
+
|
|
48
|
+
echo "# MCP Tool Inventory" > TOOLS.md
|
|
49
|
+
echo "" >> TOOLS.md
|
|
50
|
+
echo "Auto-generated from \`${INDEX_FILE}\` on $(date -u +%Y-%m-%dT%H:%M:%SZ)" >> TOOLS.md
|
|
51
|
+
echo "" >> TOOLS.md
|
|
52
|
+
|
|
53
|
+
# Count tools
|
|
54
|
+
TOOL_COUNT=$(grep -c "server\.tool(" "${INDEX_FILE}" || true)
|
|
55
|
+
echo "**Total tools: ${TOOL_COUNT}**" >> TOOLS.md
|
|
56
|
+
echo "" >> TOOLS.md
|
|
57
|
+
|
|
58
|
+
# Extract tool names and descriptions
|
|
59
|
+
echo "| Tool | Description |" >> TOOLS.md
|
|
60
|
+
echo "|------|-------------|" >> TOOLS.md
|
|
61
|
+
|
|
62
|
+
grep -A1 "server\.tool(" "${INDEX_FILE}" | grep -E "^\s*'" | while read -r line; do
|
|
63
|
+
TOOL_NAME=$(echo "$line" | sed "s/.*'\([^']*\)'.*/\1/")
|
|
64
|
+
# Get next line for description
|
|
65
|
+
DESC=$(grep -A2 "'${TOOL_NAME}'" "${INDEX_FILE}" | grep -E "^\s*'" | tail -1 | sed "s/.*'\([^']*\)'.*/\1/" || echo "")
|
|
66
|
+
echo "| \`${TOOL_NAME}\` | ${DESC} |" >> TOOLS.md
|
|
67
|
+
done
|
|
68
|
+
|
|
69
|
+
echo "" >> TOOLS.md
|
|
70
|
+
echo "---" >> TOOLS.md
|
|
71
|
+
echo "*Generated by MCP Tool Inventory workflow*" >> TOOLS.md
|
|
72
|
+
|
|
73
|
+
cat TOOLS.md
|
|
74
|
+
|
|
75
|
+
- name: Upload inventory artifact
|
|
76
|
+
uses: actions/upload-artifact@v4
|
|
77
|
+
with:
|
|
78
|
+
name: tool-inventory
|
|
79
|
+
path: TOOLS.md
|
|
80
|
+
retention-days: 90
|