@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.
@@ -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: moko-platform.Validation
11
- # REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/moko-platform
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
- push:
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
- return this.request(this.buildUrl(endpoint), 'DELETE', body);
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. (5|6)\\.*)'),
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
- package_type: z.string().optional().describe('Extension type (component, module, plugin, package, template, library, file)'),
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mokoconsulting/mcp-mokogitea-api",
3
- "version": "1.4.0",
3
+ "version": "1.4.2",
4
4
  "description": "MCP server for Gitea REST API v1 operations",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
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
- return this.request(this.buildUrl(endpoint), 'DELETE', body);
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. (5|6)\\.*)'),
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
- package_type: z.string().optional().describe('Extension type (component, module, plugin, package, template, library, file)'),
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
  },
@@ -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
@@ -1,4 +0,0 @@
1
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
- import type { GiteaConfig } from './types.js';
3
- export declare function createMcpServer(cfg: GiteaConfig): McpServer;
4
- //# sourceMappingURL=server.d.ts.map
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
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=sse.d.ts.map
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
- });