@mokoconsulting/mcp-mokogitea-api 1.4.0 → 1.4.2
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/.mokogitea/workflows/auto-bump.yml +9 -9
- package/.mokogitea/workflows/auto-release.yml +90 -28
- package/.mokogitea/workflows/branch-cleanup.yml +1 -1
- package/.mokogitea/workflows/ci-generic.yml +0 -13
- package/.mokogitea/workflows/gitleaks.yml +0 -4
- package/.mokogitea/workflows/npm-publish.yml +69 -10
- package/.mokogitea/workflows/pr-check.yml +26 -0
- package/.mokogitea/workflows/pre-release.yml +244 -3
- package/.mokogitea/workflows/rc-revert.yml +66 -0
- package/.mokogitea/workflows/repo-health.yml +4 -3
- package/.mokogitea/workflows/workflow-sync-trigger.yml +73 -0
- package/dist/client.js +20 -1
- package/dist/index.js +10 -2
- package/package.json +1 -1
- package/src/client.ts +15 -1
- package/src/index.ts +10 -2
- package/.mokogitea/manifest.xml +0 -25
- package/Dockerfile +0 -18
- package/dist/server.d.ts +0 -4
- package/dist/server.js +0 -12
- package/dist/sse.d.ts +0 -2
- package/dist/sse.js +0 -87
- package/src/server.ts +0 -16
- package/src/sse.ts +0 -100
- package/wiki/ARCHITECTURE.md +0 -144
- package/wiki/Home.md +0 -35
- package/wiki/INSTALLATION.md +0 -170
|
@@ -0,0 +1,66 @@
|
|
|
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: MokoPlatform.Universal
|
|
8
|
+
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
|
|
9
|
+
# PATH: /.mokogitea/workflows/rc-revert.yml
|
|
10
|
+
# VERSION: 09.23.00
|
|
11
|
+
# BRIEF: Rename rc/ branch back to dev/ when PR is closed without merge
|
|
12
|
+
|
|
13
|
+
name: "RC Revert"
|
|
14
|
+
|
|
15
|
+
on:
|
|
16
|
+
pull_request:
|
|
17
|
+
types: [closed]
|
|
18
|
+
|
|
19
|
+
env:
|
|
20
|
+
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
|
21
|
+
|
|
22
|
+
jobs:
|
|
23
|
+
revert:
|
|
24
|
+
name: Rename rc/ back to dev/
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
if: >-
|
|
27
|
+
github.event.pull_request.merged == false &&
|
|
28
|
+
startsWith(github.event.pull_request.head.ref, 'rc/')
|
|
29
|
+
|
|
30
|
+
steps:
|
|
31
|
+
- name: Rename branch
|
|
32
|
+
run: |
|
|
33
|
+
BRANCH="${{ github.event.pull_request.head.ref }}"
|
|
34
|
+
SUFFIX="${BRANCH#rc/}"
|
|
35
|
+
DEV_BRANCH="dev/${SUFFIX}"
|
|
36
|
+
API="${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}/api/v1/repos/${{ github.repository }}/branches"
|
|
37
|
+
TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
|
|
38
|
+
|
|
39
|
+
# Create dev/ branch from rc/ branch
|
|
40
|
+
STATUS=$(curl -sf -o /dev/null -w "%{http_code}" -X POST \
|
|
41
|
+
-H "Authorization: token ${TOKEN}" \
|
|
42
|
+
-H "Content-Type: application/json" \
|
|
43
|
+
-d "{\"new_branch_name\": \"${DEV_BRANCH}\", \"old_branch_name\": \"${BRANCH}\"}" \
|
|
44
|
+
"${API}" 2>/dev/null || true)
|
|
45
|
+
|
|
46
|
+
if [ "$STATUS" = "201" ]; then
|
|
47
|
+
echo "Created branch: ${DEV_BRANCH}" >> $GITHUB_STEP_SUMMARY
|
|
48
|
+
else
|
|
49
|
+
echo "::error::Failed to create ${DEV_BRANCH} from ${BRANCH} (HTTP ${STATUS})"
|
|
50
|
+
exit 1
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
# Delete rc/ branch
|
|
54
|
+
ENCODED=$(php -r "echo rawurlencode('${BRANCH}');")
|
|
55
|
+
STATUS=$(curl -sf -o /dev/null -w "%{http_code}" -X DELETE \
|
|
56
|
+
-H "Authorization: token ${TOKEN}" \
|
|
57
|
+
"${API}/${ENCODED}" 2>/dev/null || true)
|
|
58
|
+
|
|
59
|
+
if [ "$STATUS" = "204" ]; then
|
|
60
|
+
echo "Deleted branch: ${BRANCH}" >> $GITHUB_STEP_SUMMARY
|
|
61
|
+
else
|
|
62
|
+
echo "::warning::Failed to delete ${BRANCH} (HTTP ${STATUS})"
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
echo "### RC Reverted" >> $GITHUB_STEP_SUMMARY
|
|
66
|
+
echo "${BRANCH} → ${DEV_BRANCH}" >> $GITHUB_STEP_SUMMARY
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
#
|
|
8
8
|
# FILE INFORMATION
|
|
9
9
|
# DEFGROUP: Gitea.Workflow
|
|
10
|
-
# INGROUP:
|
|
11
|
-
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/
|
|
10
|
+
# INGROUP: mokocli.Validation
|
|
11
|
+
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/mokocli
|
|
12
12
|
# PATH: /templates/workflows/joomla/repo_health.yml.template
|
|
13
13
|
# VERSION: 09.23.00
|
|
14
14
|
# BRIEF: Enforces repository guardrails by validating scripts governance, tooling availability, and core repository health artifacts.
|
|
@@ -33,7 +33,8 @@ on:
|
|
|
33
33
|
- scripts
|
|
34
34
|
- repo
|
|
35
35
|
pull_request:
|
|
36
|
-
|
|
36
|
+
branches:
|
|
37
|
+
- main
|
|
37
38
|
|
|
38
39
|
permissions:
|
|
39
40
|
contents: read
|
|
@@ -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: MokoPlatform.Universal
|
|
8
|
+
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform
|
|
9
|
+
# PATH: /.mokogitea/workflows/workflow-sync-trigger.yml
|
|
10
|
+
# VERSION: 01.01.00
|
|
11
|
+
# BRIEF: Trigger workflow sync to live repos when a PR is merged to main
|
|
12
|
+
|
|
13
|
+
name: "Universal: Workflow Sync Trigger"
|
|
14
|
+
|
|
15
|
+
on:
|
|
16
|
+
pull_request:
|
|
17
|
+
types: [closed]
|
|
18
|
+
branches:
|
|
19
|
+
- main
|
|
20
|
+
|
|
21
|
+
env:
|
|
22
|
+
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
|
23
|
+
|
|
24
|
+
jobs:
|
|
25
|
+
sync:
|
|
26
|
+
name: Sync workflows to live repos
|
|
27
|
+
runs-on: ubuntu-latest
|
|
28
|
+
if: >-
|
|
29
|
+
github.event.pull_request.merged == true &&
|
|
30
|
+
!contains(github.event.pull_request.title, '[skip sync]')
|
|
31
|
+
|
|
32
|
+
steps:
|
|
33
|
+
- name: Determine platform from repo name
|
|
34
|
+
id: platform
|
|
35
|
+
run: |
|
|
36
|
+
REPO="${{ github.event.repository.name }}"
|
|
37
|
+
case "$REPO" in
|
|
38
|
+
Template-Joomla) PLATFORM="joomla" ;;
|
|
39
|
+
Template-Dolibarr) PLATFORM="dolibarr" ;;
|
|
40
|
+
Template-Go) PLATFORM="go" ;;
|
|
41
|
+
Template-MCP) PLATFORM="mcp" ;;
|
|
42
|
+
Template-Generic) PLATFORM="" ;;
|
|
43
|
+
*) PLATFORM="" ;;
|
|
44
|
+
esac
|
|
45
|
+
echo "platform=$PLATFORM" >> "$GITHUB_OUTPUT"
|
|
46
|
+
echo "Platform: ${PLATFORM:-all}"
|
|
47
|
+
|
|
48
|
+
- name: Clone mokoplatform
|
|
49
|
+
env:
|
|
50
|
+
MOKOGITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
|
|
51
|
+
run: |
|
|
52
|
+
GITEA_URL="${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}"
|
|
53
|
+
git clone --depth 1 "${GITEA_URL}/MokoConsulting/mokoplatform.git" /tmp/mokoplatform
|
|
54
|
+
|
|
55
|
+
- name: Install dependencies
|
|
56
|
+
run: |
|
|
57
|
+
cd /tmp/mokoplatform
|
|
58
|
+
composer install --no-dev --no-interaction --quiet 2>/dev/null || true
|
|
59
|
+
|
|
60
|
+
- name: Run workflow sync
|
|
61
|
+
env:
|
|
62
|
+
MOKOGITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
|
|
63
|
+
run: |
|
|
64
|
+
ARGS="--token ${MOKOGITEA_TOKEN}"
|
|
65
|
+
ARGS="${ARGS} --org ${{ vars.GITEA_ORG || github.repository_owner }}"
|
|
66
|
+
ARGS="${ARGS} --phase repos"
|
|
67
|
+
|
|
68
|
+
PLATFORM="${{ steps.platform.outputs.platform }}"
|
|
69
|
+
if [ -n "$PLATFORM" ]; then
|
|
70
|
+
ARGS="${ARGS} --platform-filter ${PLATFORM}"
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
php /tmp/mokoplatform/cli/workflow_sync.php ${ARGS}
|
package/dist/client.js
CHANGED
|
@@ -42,7 +42,26 @@ export class GiteaClient {
|
|
|
42
42
|
return this.request(this.buildUrl(endpoint), 'PUT', body);
|
|
43
43
|
}
|
|
44
44
|
async delete(endpoint, body) {
|
|
45
|
-
|
|
45
|
+
if (body === undefined) {
|
|
46
|
+
return this.request(this.buildUrl(endpoint), 'DELETE');
|
|
47
|
+
}
|
|
48
|
+
// Use fetch for DELETE+body — node:https drops the body on some
|
|
49
|
+
// proxy/TLS configurations, causing the server to see an empty request.
|
|
50
|
+
const url = this.buildUrl(endpoint);
|
|
51
|
+
const resp = await fetch(url, {
|
|
52
|
+
method: 'DELETE',
|
|
53
|
+
headers: { ...this.headers },
|
|
54
|
+
body: JSON.stringify(body),
|
|
55
|
+
});
|
|
56
|
+
const raw = await resp.text();
|
|
57
|
+
let data;
|
|
58
|
+
try {
|
|
59
|
+
data = JSON.parse(raw);
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
data = raw;
|
|
63
|
+
}
|
|
64
|
+
return { status: resp.status, data };
|
|
46
65
|
}
|
|
47
66
|
buildUrl(endpoint, params) {
|
|
48
67
|
const path = endpoint.startsWith('/') ? endpoint : `/${endpoint}`;
|
package/dist/index.js
CHANGED
|
@@ -1114,14 +1114,22 @@ server.tool('gitea_metadata_update', 'Update repo metadata settings (merges with
|
|
|
1114
1114
|
repo: z.string().describe('Repository name'),
|
|
1115
1115
|
name: z.string().optional().describe('Project name'),
|
|
1116
1116
|
org: z.string().optional().describe('Organization'),
|
|
1117
|
+
description: z.string().optional().describe('Project description'),
|
|
1117
1118
|
version: z.string().optional().describe('Version string (e.g. 06.00.00)'),
|
|
1118
1119
|
version_prefix: z.string().optional().describe('Tag prefix for version display (e.g. v1.26.1-moko.)'),
|
|
1119
1120
|
license_spdx: z.string().optional().describe('SPDX license identifier'),
|
|
1121
|
+
license_name: z.string().optional().describe('Human-readable license name (e.g. GNU General Public License v3)'),
|
|
1122
|
+
element_name: z.string().optional().describe('Extension element name (e.g. pkg_mokosuitecrm, mod_mokojoomhero)'),
|
|
1120
1123
|
platform: z.string().optional().describe('Platform (joomla, wordpress, dolibarr, go, mcp, platform, generic)'),
|
|
1124
|
+
standards_version: z.string().optional().describe('mokoplatform standards version (e.g. 05.01.00)'),
|
|
1125
|
+
standards_source: z.string().optional().describe('URL to standards repo'),
|
|
1126
|
+
maintainer: z.string().optional().describe('Maintainer name (e.g. Moko Consulting)'),
|
|
1127
|
+
maintainer_url: z.string().optional().describe('Maintainer website URL'),
|
|
1121
1128
|
info_url: z.string().optional().describe('Extension info/product page URL'),
|
|
1122
|
-
target_version: z.string().optional().describe('Target platform version regex (e.g.
|
|
1129
|
+
target_version: z.string().optional().describe('Target platform version regex (e.g. 6..*)'),
|
|
1123
1130
|
php_minimum: z.string().optional().describe('Minimum PHP version (e.g. 8.1)'),
|
|
1124
|
-
|
|
1131
|
+
language: z.string().optional().describe('Primary language (e.g. PHP, Go, TypeScript)'),
|
|
1132
|
+
extension_type: z.string().optional().describe('Extension type (component, module, plugin, package, template, library, file)'),
|
|
1125
1133
|
entry_point: z.string().optional().describe('Build entry point path'),
|
|
1126
1134
|
...ConnectionParam,
|
|
1127
1135
|
}, async ({ owner, repo, connection, ...fields }) => {
|
package/package.json
CHANGED
package/src/client.ts
CHANGED
|
@@ -52,7 +52,21 @@ export class GiteaClient {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
async delete(endpoint: string, body?: unknown): Promise<ApiResponse> {
|
|
55
|
-
|
|
55
|
+
if (body === undefined) {
|
|
56
|
+
return this.request(this.buildUrl(endpoint), 'DELETE');
|
|
57
|
+
}
|
|
58
|
+
// Use fetch for DELETE+body — node:https drops the body on some
|
|
59
|
+
// proxy/TLS configurations, causing the server to see an empty request.
|
|
60
|
+
const url = this.buildUrl(endpoint);
|
|
61
|
+
const resp = await fetch(url, {
|
|
62
|
+
method: 'DELETE',
|
|
63
|
+
headers: { ...this.headers },
|
|
64
|
+
body: JSON.stringify(body),
|
|
65
|
+
});
|
|
66
|
+
const raw = await resp.text();
|
|
67
|
+
let data: unknown;
|
|
68
|
+
try { data = JSON.parse(raw); } catch { data = raw; }
|
|
69
|
+
return { status: resp.status, data };
|
|
56
70
|
}
|
|
57
71
|
|
|
58
72
|
private buildUrl(endpoint: string, params?: Record<string, string>): string {
|
package/src/index.ts
CHANGED
|
@@ -1720,14 +1720,22 @@ server.tool(
|
|
|
1720
1720
|
repo: z.string().describe('Repository name'),
|
|
1721
1721
|
name: z.string().optional().describe('Project name'),
|
|
1722
1722
|
org: z.string().optional().describe('Organization'),
|
|
1723
|
+
description: z.string().optional().describe('Project description'),
|
|
1723
1724
|
version: z.string().optional().describe('Version string (e.g. 06.00.00)'),
|
|
1724
1725
|
version_prefix: z.string().optional().describe('Tag prefix for version display (e.g. v1.26.1-moko.)'),
|
|
1725
1726
|
license_spdx: z.string().optional().describe('SPDX license identifier'),
|
|
1727
|
+
license_name: z.string().optional().describe('Human-readable license name (e.g. GNU General Public License v3)'),
|
|
1728
|
+
element_name: z.string().optional().describe('Extension element name (e.g. pkg_mokosuitecrm, mod_mokojoomhero)'),
|
|
1726
1729
|
platform: z.string().optional().describe('Platform (joomla, wordpress, dolibarr, go, mcp, platform, generic)'),
|
|
1730
|
+
standards_version: z.string().optional().describe('mokoplatform standards version (e.g. 05.01.00)'),
|
|
1731
|
+
standards_source: z.string().optional().describe('URL to standards repo'),
|
|
1732
|
+
maintainer: z.string().optional().describe('Maintainer name (e.g. Moko Consulting)'),
|
|
1733
|
+
maintainer_url: z.string().optional().describe('Maintainer website URL'),
|
|
1727
1734
|
info_url: z.string().optional().describe('Extension info/product page URL'),
|
|
1728
|
-
target_version: z.string().optional().describe('Target platform version regex (e.g.
|
|
1735
|
+
target_version: z.string().optional().describe('Target platform version regex (e.g. 6..*)'),
|
|
1729
1736
|
php_minimum: z.string().optional().describe('Minimum PHP version (e.g. 8.1)'),
|
|
1730
|
-
|
|
1737
|
+
language: z.string().optional().describe('Primary language (e.g. PHP, Go, TypeScript)'),
|
|
1738
|
+
extension_type: z.string().optional().describe('Extension type (component, module, plugin, package, template, library, file)'),
|
|
1731
1739
|
entry_point: z.string().optional().describe('Build entry point path'),
|
|
1732
1740
|
...ConnectionParam,
|
|
1733
1741
|
},
|
package/.mokogitea/manifest.xml
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<!--
|
|
3
|
-
MokoStandards Repository Manifest
|
|
4
|
-
Auto-generated by cleanup script.
|
|
5
|
-
See: https://git.mokoconsulting.tech/MokoConsulting/moko-platform/wiki/Home
|
|
6
|
-
-->
|
|
7
|
-
<moko-platform xmlns="https://standards.mokoconsulting.tech/moko-platform/1.0" schema-version="1.0">
|
|
8
|
-
<identity>
|
|
9
|
-
<name>gitea-api-mcp</name>
|
|
10
|
-
<org>MokoConsulting</org>
|
|
11
|
-
<description>MCP server for Gitea REST API v1 operations — 61 tools for repos, issues, PRs, releases, branches, actions, orgs, wiki, webhooks, and more</description>
|
|
12
|
-
<license spdx="GPL-3.0-or-later">GNU General Public License v3</license>
|
|
13
|
-
</identity>
|
|
14
|
-
<governance>
|
|
15
|
-
<platform>nodejs</platform>
|
|
16
|
-
<standards-version>04.07.00</standards-version>
|
|
17
|
-
<standards-source>https://git.mokoconsulting.tech/MokoConsulting/moko-platform</standards-source>
|
|
18
|
-
<last-synced>2026-05-10T19:51:11+00:00</last-synced>
|
|
19
|
-
</governance>
|
|
20
|
-
<build>
|
|
21
|
-
<language>TypeScript</language>
|
|
22
|
-
<package-type>mcp-server</package-type>
|
|
23
|
-
<entry-point>src/</entry-point>
|
|
24
|
-
</build>
|
|
25
|
-
</moko-platform>
|
package/Dockerfile
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
FROM node:20-alpine
|
|
2
|
-
|
|
3
|
-
WORKDIR /app
|
|
4
|
-
|
|
5
|
-
COPY package.json package-lock.json ./
|
|
6
|
-
RUN npm ci --production=false
|
|
7
|
-
|
|
8
|
-
COPY tsconfig.json ./
|
|
9
|
-
COPY src/ ./src/
|
|
10
|
-
RUN npx tsc && npm prune --production
|
|
11
|
-
|
|
12
|
-
EXPOSE 3100
|
|
13
|
-
|
|
14
|
-
ENV PORT=3100
|
|
15
|
-
ENV NODE_ENV=production
|
|
16
|
-
|
|
17
|
-
# SSE mode by default for Docker deployments
|
|
18
|
-
CMD ["node", "dist/sse.js"]
|
package/dist/server.d.ts
DELETED
package/dist/server.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
// Copyright 2026 Moko Consulting <hello@mokoconsulting.tech>
|
|
2
|
-
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
3
|
-
//
|
|
4
|
-
// Creates a configured MCP server instance for use by both stdio and SSE transports.
|
|
5
|
-
// Import index.ts to register all tools on its exported `server` singleton,
|
|
6
|
-
// then re-export a factory that initializes config and returns the server.
|
|
7
|
-
import { server, initConfig } from './index.js';
|
|
8
|
-
export function createMcpServer(cfg) {
|
|
9
|
-
initConfig(cfg);
|
|
10
|
-
return server;
|
|
11
|
-
}
|
|
12
|
-
//# sourceMappingURL=server.js.map
|
package/dist/sse.d.ts
DELETED
package/dist/sse.js
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
// Copyright 2026 Moko Consulting <hello@mokoconsulting.tech>
|
|
2
|
-
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
3
|
-
//
|
|
4
|
-
// SSE transport entry point for MokoGitea MCP server.
|
|
5
|
-
// Run with: node dist/sse.js
|
|
6
|
-
// Or: GITEA_URL=https://gitea.example.com GITEA_TOKEN=xxx node dist/sse.js
|
|
7
|
-
//
|
|
8
|
-
// Listens on PORT (default 3100) and serves SSE at /sse with POST at /message.
|
|
9
|
-
import { createServer } from 'node:http';
|
|
10
|
-
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
|
|
11
|
-
import { createMcpServer } from './server.js';
|
|
12
|
-
import { loadConfig } from './config.js';
|
|
13
|
-
const PORT = parseInt(process.env.PORT ?? '3100', 10);
|
|
14
|
-
async function main() {
|
|
15
|
-
const config = await loadConfig();
|
|
16
|
-
const transports = new Map();
|
|
17
|
-
const httpServer = createServer(async (req, res) => {
|
|
18
|
-
// CORS headers for browser clients
|
|
19
|
-
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
20
|
-
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
21
|
-
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
|
|
22
|
-
if (req.method === 'OPTIONS') {
|
|
23
|
-
res.writeHead(204);
|
|
24
|
-
res.end();
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
// Health check
|
|
28
|
-
if (req.url === '/health') {
|
|
29
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
30
|
-
res.end(JSON.stringify({ status: 'ok', tools: 120 }));
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
// SSE endpoint - client connects here
|
|
34
|
-
if (req.url === '/sse' && req.method === 'GET') {
|
|
35
|
-
const transport = new SSEServerTransport('/message', res);
|
|
36
|
-
const sessionId = transport.sessionId;
|
|
37
|
-
transports.set(sessionId, transport);
|
|
38
|
-
const server = createMcpServer(config);
|
|
39
|
-
await server.connect(transport);
|
|
40
|
-
req.on('close', () => {
|
|
41
|
-
transports.delete(sessionId);
|
|
42
|
-
});
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
// Message endpoint - client sends tool calls here
|
|
46
|
-
if (req.url?.startsWith('/message') && req.method === 'POST') {
|
|
47
|
-
const url = new URL(req.url, `http://${req.headers.host}`);
|
|
48
|
-
const sessionId = url.searchParams.get('sessionId');
|
|
49
|
-
if (!sessionId || !transports.has(sessionId)) {
|
|
50
|
-
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
51
|
-
res.end(JSON.stringify({ error: 'Invalid or missing sessionId' }));
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
const transport = transports.get(sessionId);
|
|
55
|
-
await transport.handlePostMessage(req, res);
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
// Root - info page
|
|
59
|
-
if (req.url === '/' || req.url === '') {
|
|
60
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
61
|
-
res.end(JSON.stringify({
|
|
62
|
-
name: '@mokoconsulting/mokogitea-mcp',
|
|
63
|
-
version: '1.1.0',
|
|
64
|
-
description: 'MCP server for Gitea and MokoGitea - 120+ tools',
|
|
65
|
-
endpoints: {
|
|
66
|
-
sse: '/sse',
|
|
67
|
-
message: '/message',
|
|
68
|
-
health: '/health',
|
|
69
|
-
},
|
|
70
|
-
docs: 'https://git.mokoconsulting.tech/MokoConsulting/mcp_mokogitea_api',
|
|
71
|
-
}));
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
res.writeHead(404);
|
|
75
|
-
res.end('Not found');
|
|
76
|
-
});
|
|
77
|
-
httpServer.listen(PORT, () => {
|
|
78
|
-
process.stderr.write(`MokoGitea MCP SSE server listening on port ${PORT}\n`);
|
|
79
|
-
process.stderr.write(` SSE: http://localhost:${PORT}/sse\n`);
|
|
80
|
-
process.stderr.write(` Health: http://localhost:${PORT}/health\n`);
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
main().catch((err) => {
|
|
84
|
-
process.stderr.write(`Fatal: ${err}\n`);
|
|
85
|
-
process.exit(1);
|
|
86
|
-
});
|
|
87
|
-
//# sourceMappingURL=sse.js.map
|
package/src/server.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
// Copyright 2026 Moko Consulting <hello@mokoconsulting.tech>
|
|
2
|
-
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
3
|
-
//
|
|
4
|
-
// Creates a configured MCP server instance for use by both stdio and SSE transports.
|
|
5
|
-
|
|
6
|
-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
7
|
-
import type { GiteaConfig } from './types.js';
|
|
8
|
-
|
|
9
|
-
// Import index.ts to register all tools on its exported `server` singleton,
|
|
10
|
-
// then re-export a factory that initializes config and returns the server.
|
|
11
|
-
import { server, initConfig } from './index.js';
|
|
12
|
-
|
|
13
|
-
export function createMcpServer(cfg: GiteaConfig): McpServer {
|
|
14
|
-
initConfig(cfg);
|
|
15
|
-
return server;
|
|
16
|
-
}
|
package/src/sse.ts
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
// Copyright 2026 Moko Consulting <hello@mokoconsulting.tech>
|
|
2
|
-
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
3
|
-
//
|
|
4
|
-
// SSE transport entry point for MokoGitea MCP server.
|
|
5
|
-
// Run with: node dist/sse.js
|
|
6
|
-
// Or: GITEA_URL=https://gitea.example.com GITEA_TOKEN=xxx node dist/sse.js
|
|
7
|
-
//
|
|
8
|
-
// Listens on PORT (default 3100) and serves SSE at /sse with POST at /message.
|
|
9
|
-
|
|
10
|
-
import { createServer } from 'node:http';
|
|
11
|
-
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
|
|
12
|
-
import { createMcpServer } from './server.js';
|
|
13
|
-
import { loadConfig } from './config.js';
|
|
14
|
-
|
|
15
|
-
const PORT = parseInt(process.env.PORT ?? '3100', 10);
|
|
16
|
-
|
|
17
|
-
async function main(): Promise<void> {
|
|
18
|
-
const config = await loadConfig();
|
|
19
|
-
const transports = new Map<string, SSEServerTransport>();
|
|
20
|
-
|
|
21
|
-
const httpServer = createServer(async (req, res) => {
|
|
22
|
-
// CORS headers for browser clients
|
|
23
|
-
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
24
|
-
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
25
|
-
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
|
|
26
|
-
|
|
27
|
-
if (req.method === 'OPTIONS') {
|
|
28
|
-
res.writeHead(204);
|
|
29
|
-
res.end();
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Health check
|
|
34
|
-
if (req.url === '/health') {
|
|
35
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
36
|
-
res.end(JSON.stringify({ status: 'ok', tools: 120 }));
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// SSE endpoint - client connects here
|
|
41
|
-
if (req.url === '/sse' && req.method === 'GET') {
|
|
42
|
-
const transport = new SSEServerTransport('/message', res);
|
|
43
|
-
const sessionId = transport.sessionId;
|
|
44
|
-
transports.set(sessionId, transport);
|
|
45
|
-
|
|
46
|
-
const server = createMcpServer(config);
|
|
47
|
-
await server.connect(transport);
|
|
48
|
-
|
|
49
|
-
req.on('close', () => {
|
|
50
|
-
transports.delete(sessionId);
|
|
51
|
-
});
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Message endpoint - client sends tool calls here
|
|
56
|
-
if (req.url?.startsWith('/message') && req.method === 'POST') {
|
|
57
|
-
const url = new URL(req.url, `http://${req.headers.host}`);
|
|
58
|
-
const sessionId = url.searchParams.get('sessionId');
|
|
59
|
-
if (!sessionId || !transports.has(sessionId)) {
|
|
60
|
-
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
61
|
-
res.end(JSON.stringify({ error: 'Invalid or missing sessionId' }));
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
const transport = transports.get(sessionId)!;
|
|
65
|
-
await transport.handlePostMessage(req, res);
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Root - info page
|
|
70
|
-
if (req.url === '/' || req.url === '') {
|
|
71
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
72
|
-
res.end(JSON.stringify({
|
|
73
|
-
name: '@mokoconsulting/mokogitea-mcp',
|
|
74
|
-
version: '1.1.0',
|
|
75
|
-
description: 'MCP server for Gitea and MokoGitea - 120+ tools',
|
|
76
|
-
endpoints: {
|
|
77
|
-
sse: '/sse',
|
|
78
|
-
message: '/message',
|
|
79
|
-
health: '/health',
|
|
80
|
-
},
|
|
81
|
-
docs: 'https://git.mokoconsulting.tech/MokoConsulting/mcp_mokogitea_api',
|
|
82
|
-
}));
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
res.writeHead(404);
|
|
87
|
-
res.end('Not found');
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
httpServer.listen(PORT, () => {
|
|
91
|
-
process.stderr.write(`MokoGitea MCP SSE server listening on port ${PORT}\n`);
|
|
92
|
-
process.stderr.write(` SSE: http://localhost:${PORT}/sse\n`);
|
|
93
|
-
process.stderr.write(` Health: http://localhost:${PORT}/health\n`);
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
main().catch((err) => {
|
|
98
|
-
process.stderr.write(`Fatal: ${err}\n`);
|
|
99
|
-
process.exit(1);
|
|
100
|
-
});
|