@mokoconsulting/mcp-mokosuite 1.0.0 → 1.1.0-dev.372

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.
@@ -2,8 +2,16 @@
2
2
  # Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
3
3
  # SPDX-License-Identifier: GPL-3.0-or-later
4
4
  #
5
- # Builds the MCP server, validates TypeScript compilation, and checks
6
- # that tools are properly registered with valid Zod schemas.
5
+ # Builds the MCP server via the centralized MokoCLI build agent
6
+ # (moko lint|build|test), then validates that compiled output exists and that
7
+ # tools are properly registered. The build agent is platform-aware via the
8
+ # repo's NATIVE manifest (package.json) — no metadata API call — so inline
9
+ # npm install / npx tsc / npm run build / npm test are no longer needed here.
10
+ #
11
+ # GATE: `moko` is provided by mokocli on the runner PATH (/opt/mokocli/cli).
12
+ # It becomes available only after the mokocli build agent lands on `main` and
13
+ # the runner image is rebuilt. Until then this workflow is authored/reviewed
14
+ # but should not be expected to run green.
7
15
 
8
16
  name: "MCP: Build & Validate"
9
17
 
@@ -18,6 +26,7 @@ on:
18
26
 
19
27
  permissions:
20
28
  contents: read
29
+ pull-requests: write
21
30
 
22
31
  env:
23
32
  MOKOGIT_URL: ${{ vars.MOKOGIT_URL || 'https://git.mokoconsulting.tech' }}
@@ -47,22 +56,57 @@ jobs:
47
56
  with:
48
57
  node-version: ${{ matrix.node-version }}
49
58
 
50
- - name: Install dependencies
51
- run: npm ci
59
+ - name: Setup MokoCLI build agent (moko on PATH)
60
+ env:
61
+ MOKO_CLONE_TOKEN: ${{ secrets.MOKOGIT_TOKEN }}
62
+ MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
63
+ run: |
64
+ # Reach mokocli the SAME way the release workflows' "Setup MokoCLI tools"
65
+ # step does: prefer the pre-installed /opt/mokocli, else fall back to a
66
+ # fresh clone. The only difference is we expose the `moko` binary on PATH
67
+ # (mokocli's cli/ dir) so `moko build|test|lint` resolve — we do NOT invent
68
+ # a new install mechanism.
69
+ if [ -x /opt/mokocli/cli/moko ] || [ -f /opt/mokocli/cli/moko ]; then
70
+ echo Using pre-installed /opt/mokocli
71
+ echo "/opt/mokocli/cli" >> "$GITHUB_PATH"
72
+ else
73
+ echo Falling back to fresh clone
74
+ MOKO_CLONE_TOKEN="$(printf '%s' "${MOKO_CLONE_TOKEN}" | tr -d '[:space:]')"
75
+ echo "::add-mask::${MOKO_CLONE_TOKEN}"
76
+ if [ -z "${MOKO_CLONE_TOKEN}" ]; then
77
+ echo "::error::MOKOGIT_TOKEN secret is empty — cannot clone mokocli fallback." >&2
78
+ exit 1
79
+ fi
80
+ if ! command -v composer > /dev/null 2>&1; then
81
+ sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer > /dev/null 2>&1
82
+ fi
83
+ rm -rf /tmp/mokocli
84
+ CLONE_URL="https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/mokocli.git"
85
+ git clone --depth 1 --branch main --quiet "${CLONE_URL}" /tmp/mokocli
86
+ ( cd /tmp/mokocli && composer install --no-dev --no-interaction --no-progress --optimize-autoloader --quiet )
87
+ echo "/tmp/mokocli/cli" >> "$GITHUB_PATH"
88
+ fi
52
89
 
53
- - name: TypeScript compile
54
- run: npx tsc --noEmit
90
+ - name: Lint
91
+ run: moko lint
55
92
 
56
93
  - name: Build
57
- run: npm run build
94
+ run: moko build
95
+
96
+ - name: Test
97
+ run: moko test
58
98
 
59
99
  - name: Verify dist output exists
60
100
  run: |
101
+ # dist/index.js is the bin/main entry for every MCP server (shared
102
+ # package.json convention). Assert that + that the build emitted
103
+ # compiled output. Do NOT hard-code other filenames: source layouts
104
+ # differ per server (many have no client.ts/types.ts/root config.ts),
105
+ # which false-failed this check on every build fleet-wide.
61
106
  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"
107
+ JS_COUNT=$(find dist -name '*.js' | wc -l)
108
+ [ "${JS_COUNT}" -gt 0 ] || (echo "ERROR: no compiled .js files in dist/" && exit 1)
109
+ echo "✓ dist/index.js present; ${JS_COUNT} compiled .js file(s) in dist/"
66
110
 
67
111
  - name: Verify shebang in index.js
68
112
  run: |
@@ -70,14 +114,54 @@ jobs:
70
114
 
71
115
  - name: Count registered tools
72
116
  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}"
117
+ # Tools may be registered in the entry file OR in modules it imports
118
+ # (modular servers call server.tool( / .registerTool( inside
119
+ # source/tools/*.ts). Count registrations across the whole source
120
+ # tree, not just index.ts, else modular servers false-report zero.
121
+ SRC_DIR="${{ steps.srcdir.outputs.source_dir }}"
122
+ [ -n "${SRC_DIR}" ] && [ -d "${SRC_DIR}" ] || SRC_DIR="source"
123
+ [ -d "${SRC_DIR}" ] || SRC_DIR="src"
124
+ TOOL_COUNT=$(grep -rE "server\.tool\(|\.registerTool\(" "${SRC_DIR}" 2>/dev/null | wc -l | tr -d ' ')
125
+ echo "Registered tool calls under ${SRC_DIR}: ${TOOL_COUNT}"
80
126
  if [ "${TOOL_COUNT}" -eq 0 ]; then
81
- echo "ERROR: No tools registered in ${INDEX_FILE}"
127
+ echo "ERROR: No tools registered under ${SRC_DIR}"
82
128
  exit 1
83
129
  fi
130
+
131
+ ci-summary:
132
+ name: CI Summary (sticky comment)
133
+ runs-on: ubuntu-latest
134
+ needs: [build]
135
+ if: always()
136
+ steps:
137
+ - name: Upsert sticky CI summary comment
138
+ env:
139
+ TOKEN: ${{ secrets.MOKOGIT_TOKEN || github.token }}
140
+ SERVER: ${{ vars.MOKOGIT_URL || 'https://git.mokoconsulting.tech' }}
141
+ REPO: ${{ github.repository }}
142
+ PR: ${{ github.event.pull_request.number }}
143
+ BUILD: ${{ needs.build.result }}
144
+ RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
145
+ HEAD_REF: ${{ github.head_ref }}
146
+ BASE_REF: ${{ github.base_ref }}
147
+ run: |
148
+ set -uo pipefail
149
+ { [ -n "${TOKEN:-}" ] && [ -n "${PR:-}" ]; } || { echo "no token/PR; skip"; exit 0; }
150
+ icon() { case "$1" in success) printf '✅';; failure) printf '❌';; skipped) printf '⏭️';; *) printf '⚪';; esac; }
151
+ MARKER="<!-- ci-summary -->"
152
+ BODY="$(printf '%s\n## MCP Build & Validate\n\n- %s Build & validate (`%s` → `%s`)\n\n_Updated %s · [run](%s)_' \
153
+ "${MARKER}" \
154
+ "$(icon "${BUILD}")" "${HEAD_REF}" "${BASE_REF}" \
155
+ "$(date -u +%FT%TZ)" "${RUN_URL}")"
156
+ LIST="${SERVER}/api/v1/repos/${REPO}/issues/${PR}/comments"
157
+ EDIT="${SERVER}/api/v1/repos/${REPO}/issues/comments"
158
+ CID="$(curl -sf -H "Authorization: token ${TOKEN}" "${LIST}?limit=100" 2>/dev/null \
159
+ | python3 -c "import sys,json; c=[x for x in json.load(sys.stdin) if '${MARKER}' in (x.get('body') or '')]; print(c[-1]['id'] if c else '')" 2>/dev/null || true)"
160
+ PAYLOAD="$(python3 -c "import json,sys; print(json.dumps({'body': sys.stdin.read()}))" <<<"${BODY}")"
161
+ if [ -n "${CID}" ]; then
162
+ curl -sf -X PATCH -H "Authorization: token ${TOKEN}" -H "Content-Type: application/json" -d "${PAYLOAD}" "${EDIT}/${CID}" >/dev/null 2>&1 || true
163
+ echo "updated sticky CI summary #${CID} on PR #${PR}"
164
+ else
165
+ curl -sf -X POST -H "Authorization: token ${TOKEN}" -H "Content-Type: application/json" -d "${PAYLOAD}" "${LIST}" >/dev/null 2>&1 || true
166
+ echo "created sticky CI summary on PR #${PR}"
167
+ fi
@@ -0,0 +1,174 @@
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-prerelease.yml
10
+ # VERSION: 02.00.00
11
+ # BRIEF: Pre-release (dev/alpha/beta/rc) npm publishing for npm-family repos. Split
12
+ # out of the universal pre-release.yml (Template-Generic 06.01.00) so npm
13
+ # dist-tag publishing lives ONLY in the npm template. Build + publish now
14
+ # delegate to the centralized MokoCLI build agent (moko build / moko
15
+ # publish); `moko publish` preserves the same dev-channel dist-tag publish
16
+ # to npmjs.org + the MokoGIT npm registry that the former inline block did.
17
+ # npm-publish.yml handles STABLE (latest) on main; this handles the dev
18
+ # channel on dev.
19
+ #
20
+ # GATE: `moko` is provided by mokocli on the runner PATH (/opt/mokocli/cli),
21
+ # available only after the mokocli build agent lands on `main` and the runner
22
+ # image is rebuilt — authored/reviewed now, runs green later.
23
+
24
+ name: "Publish to npm (pre-release channel)"
25
+
26
+ on:
27
+ # Dev-channel publish on every merge to dev. paths-ignore is a non-code denylist:
28
+ # a push touching only docs / CI config / repo metadata does not publish. The
29
+ # concurrency guard below collapses a burst of merges into one.
30
+ push:
31
+ branches:
32
+ - dev
33
+ paths-ignore:
34
+ - '.mokogit/**'
35
+ - '.gitea/**'
36
+ - '.github/**'
37
+ - '.vscode/**'
38
+ - '.idea/**'
39
+ - 'docs/**'
40
+ - 'wiki/**'
41
+ - '**/*.md'
42
+ - '.editorconfig'
43
+ - '.gitignore'
44
+ - '.gitattributes'
45
+ - '.gitmodules'
46
+ - '.gitmessage'
47
+ - 'LICENSE'
48
+ schedule:
49
+ # Nightly at 07:00 UTC — safety-net batch for any dev merge a push publish missed.
50
+ - cron: '0 7 * * *'
51
+ workflow_dispatch:
52
+ inputs:
53
+ stability:
54
+ description: 'Pre-release channel'
55
+ required: true
56
+ default: development
57
+ type: choice
58
+ options:
59
+ - development
60
+ - alpha
61
+ - beta
62
+ - release-candidate
63
+ ref:
64
+ description: 'Branch to build (default: dev)'
65
+ required: false
66
+ default: dev
67
+ type: string
68
+
69
+ concurrency:
70
+ group: npm-prerelease-${{ github.ref }}-${{ inputs.stability || 'development' }}
71
+ cancel-in-progress: true
72
+
73
+ permissions:
74
+ contents: read
75
+
76
+ jobs:
77
+ publish:
78
+ name: "npm pre-release (${{ inputs.stability || 'development' }})"
79
+ runs-on: release
80
+ # Skip on template repos (Template-*) — they scaffold other repos and do not
81
+ # release. Triggers: push to dev, the nightly schedule, and manual dispatch.
82
+ # As defence-in-depth we also refuse a manual dispatch aimed at a bot/sync ref
83
+ # (mirrors pre-release.yml).
84
+ if: >-
85
+ !startsWith(github.event.repository.name, 'Template-') &&
86
+ (
87
+ github.event_name == 'push' ||
88
+ github.event_name == 'schedule' ||
89
+ (
90
+ github.event_name == 'workflow_dispatch' &&
91
+ !startsWith(inputs.ref, 'chore/') &&
92
+ !startsWith(inputs.ref, 'sync/') &&
93
+ !startsWith(inputs.ref, 'bot/') &&
94
+ !startsWith(inputs.ref, 'mokoonyx-template-sync') &&
95
+ !startsWith(inputs.ref, 'template-sync')
96
+ )
97
+ )
98
+ steps:
99
+ # Build ref: the dispatch input if given, else `dev` — correct for both a push
100
+ # (only `dev` triggers it) and the nightly schedule (where github.ref_name
101
+ # would otherwise be the default branch, main).
102
+ - name: Resolve build ref
103
+ id: ref
104
+ run: echo "ref=${{ inputs.ref || 'dev' }}" >> "$GITHUB_OUTPUT"
105
+
106
+ - name: Checkout
107
+ uses: actions/checkout@v4
108
+ with:
109
+ ref: ${{ steps.ref.outputs.ref }}
110
+
111
+ - name: Setup Node.js
112
+ uses: actions/setup-node@v4
113
+ with:
114
+ node-version: '20'
115
+ registry-url: 'https://registry.npmjs.org'
116
+
117
+ - name: Setup MokoCLI build agent (moko on PATH)
118
+ env:
119
+ MOKO_CLONE_TOKEN: ${{ secrets.MOKOGIT_TOKEN }}
120
+ MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
121
+ run: |
122
+ # Reach mokocli the SAME way the release workflows' "Setup MokoCLI tools"
123
+ # step does: prefer the pre-installed /opt/mokocli, else a fresh clone. We
124
+ # expose the `moko` binary on PATH so `moko build|publish` resolve — no new
125
+ # install mechanism is introduced.
126
+ if [ -x /opt/mokocli/cli/moko ] || [ -f /opt/mokocli/cli/moko ]; then
127
+ echo Using pre-installed /opt/mokocli
128
+ echo "/opt/mokocli/cli" >> "$GITHUB_PATH"
129
+ else
130
+ echo Falling back to fresh clone
131
+ MOKO_CLONE_TOKEN="$(printf '%s' "${MOKO_CLONE_TOKEN}" | tr -d '[:space:]')"
132
+ echo "::add-mask::${MOKO_CLONE_TOKEN}"
133
+ if [ -z "${MOKO_CLONE_TOKEN}" ]; then
134
+ echo "::error::MOKOGIT_TOKEN secret is empty — cannot clone mokocli fallback." >&2
135
+ exit 1
136
+ fi
137
+ if ! command -v composer > /dev/null 2>&1; then
138
+ sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer > /dev/null 2>&1
139
+ fi
140
+ rm -rf /tmp/mokocli
141
+ CLONE_URL="https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/mokocli.git"
142
+ git clone --depth 1 --branch main --quiet "${CLONE_URL}" /tmp/mokocli
143
+ ( cd /tmp/mokocli && composer install --no-dev --no-interaction --no-progress --optimize-autoloader --quiet )
144
+ echo "/tmp/mokocli/cli" >> "$GITHUB_PATH"
145
+ fi
146
+
147
+ - name: Build
148
+ run: moko build
149
+
150
+ # dev/rc/beta/alpha channel maps to the matching npm dist-tag; the version is
151
+ # <base>-<tag>.<run_number> so it is unique per run and npm won't reject it.
152
+ # The nightly schedule always publishes the development channel. Repos without
153
+ # an NPM_TOKEN secret warn-and-skip rather than fail the run. Published to
154
+ # npmjs.org AND the MokoGIT npm registry (matching npm-publish.yml). A
155
+ # per-registry publish that fails because the version already exists is a
156
+ # warning, not a failure — the run only fails if BOTH registries reject it.
157
+ # moko publish preserves that dist-tag / dual-registry behavior; it derives
158
+ # the channel from --stability (schedule → development).
159
+ - name: Publish npm package (pre-release channel)
160
+ env:
161
+ NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
162
+ MOKOGIT_TOKEN: ${{ secrets.MOKOGIT_TOKEN }}
163
+ run: |
164
+ set -uo pipefail
165
+ if [ -z "${NPM_TOKEN}" ]; then
166
+ echo "::warning::NPM_TOKEN not set — skipping npm pre-release publish"
167
+ exit 0
168
+ fi
169
+ if [ "${{ github.event_name }}" = "schedule" ]; then
170
+ STABILITY=development
171
+ else
172
+ STABILITY="${{ inputs.stability || 'development' }}"
173
+ fi
174
+ moko publish --stability "$STABILITY"
@@ -7,12 +7,19 @@
7
7
  # INGROUP: MokoCLI.Release
8
8
  # REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-NPM
9
9
  # PATH: /.mokogit/workflows/npm-publish.yml
10
- # VERSION: 02.00.00
10
+ # VERSION: 03.00.00
11
11
  # BRIEF: Build + publish shim. The shared release engine (pre-release.yml /
12
12
  # auto-release.yml) owns version bump, tag, changelog and release
13
13
  # object; this workflow only builds and publishes the version the
14
14
  # engine has already written to package.json. It never bumps or
15
- # writes the version.
15
+ # writes the version. Build + publish now delegate to the centralized
16
+ # MokoCLI build agent (moko build / moko publish); `moko publish`
17
+ # preserves the same dual-registry npm publish (npmjs.org + the MokoGIT
18
+ # npm registry) that the former inline block performed.
19
+ #
20
+ # GATE: `moko` is provided by mokocli on the runner PATH (/opt/mokocli/cli),
21
+ # available only after the mokocli build agent lands on `main` and the runner
22
+ # image is rebuilt — authored/reviewed now, runs green later.
16
23
 
17
24
  name: "Publish to npm"
18
25
 
@@ -85,13 +92,40 @@ jobs:
85
92
  with:
86
93
  node-version: '20'
87
94
 
88
- - name: Install dependencies
95
+ - name: Setup MokoCLI build agent (moko on PATH)
89
96
  if: steps.detect.outputs.changed == 'true'
90
- run: npm install --no-audit --no-fund
97
+ env:
98
+ MOKO_CLONE_TOKEN: ${{ secrets.MOKOGIT_TOKEN }}
99
+ MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
100
+ run: |
101
+ # Reach mokocli the SAME way the release workflows' "Setup MokoCLI tools"
102
+ # step does: prefer the pre-installed /opt/mokocli, else a fresh clone. We
103
+ # expose the `moko` binary on PATH so `moko build|publish` resolve — no new
104
+ # install mechanism is introduced.
105
+ if [ -x /opt/mokocli/cli/moko ] || [ -f /opt/mokocli/cli/moko ]; then
106
+ echo Using pre-installed /opt/mokocli
107
+ echo "/opt/mokocli/cli" >> "$GITHUB_PATH"
108
+ else
109
+ echo Falling back to fresh clone
110
+ MOKO_CLONE_TOKEN="$(printf '%s' "${MOKO_CLONE_TOKEN}" | tr -d '[:space:]')"
111
+ echo "::add-mask::${MOKO_CLONE_TOKEN}"
112
+ if [ -z "${MOKO_CLONE_TOKEN}" ]; then
113
+ echo "::error::MOKOGIT_TOKEN secret is empty — cannot clone mokocli fallback." >&2
114
+ exit 1
115
+ fi
116
+ if ! command -v composer > /dev/null 2>&1; then
117
+ sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer > /dev/null 2>&1
118
+ fi
119
+ rm -rf /tmp/mokocli
120
+ CLONE_URL="https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/mokocli.git"
121
+ git clone --depth 1 --branch main --quiet "${CLONE_URL}" /tmp/mokocli
122
+ ( cd /tmp/mokocli && composer install --no-dev --no-interaction --no-progress --optimize-autoloader --quiet )
123
+ echo "/tmp/mokocli/cli" >> "$GITHUB_PATH"
124
+ fi
91
125
 
92
126
  - name: Build
93
127
  if: steps.detect.outputs.changed == 'true'
94
- run: npm run build
128
+ run: moko build
95
129
 
96
130
  - name: Read version to publish
97
131
  id: version
@@ -109,18 +143,11 @@ jobs:
109
143
  - name: Publish to npmjs.org + git.mokoconsulting.tech
110
144
  if: steps.detect.outputs.changed == 'true'
111
145
  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 ]
146
+ # moko publish preserves the former inline behavior: idempotent dual-registry
147
+ # npm publish to npmjs.org AND the MokoGIT npm registry, publishing the version
148
+ # the release engine already wrote to package.json (never bumps). It reads the
149
+ # registry auth tokens from the environment below.
150
+ moko publish
124
151
  env:
125
152
  NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
126
153
  MOKOGIT_TOKEN: ${{ secrets.MOKOGIT_TOKEN }}