@simplysf/simply-gitlab-mcp 0.6.2 → 0.7.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.
Files changed (40) hide show
  1. package/README.md +4 -0
  2. package/docs/guides/mcp-server.md +34 -0
  3. package/lib/commands/gitlab/mcp/install.d.ts +33 -0
  4. package/lib/commands/gitlab/mcp/install.js +123 -0
  5. package/lib/commands/gitlab/mcp/install.js.map +1 -0
  6. package/lib/mcpClients/apply.d.ts +10 -0
  7. package/lib/mcpClients/apply.js +209 -0
  8. package/lib/mcpClients/apply.js.map +1 -0
  9. package/lib/mcpClients/clients.d.ts +36 -0
  10. package/lib/mcpClients/clients.js +111 -0
  11. package/lib/mcpClients/clients.js.map +1 -0
  12. package/lib/mcpClients/existingEntry.d.ts +16 -0
  13. package/lib/mcpClients/existingEntry.js +140 -0
  14. package/lib/mcpClients/existingEntry.js.map +1 -0
  15. package/lib/mcpClients/index.d.ts +8 -0
  16. package/lib/mcpClients/index.js +29 -0
  17. package/lib/mcpClients/index.js.map +1 -0
  18. package/lib/mcpClients/install.d.ts +14 -0
  19. package/lib/mcpClients/install.js +55 -0
  20. package/lib/mcpClients/install.js.map +1 -0
  21. package/lib/mcpClients/jsonEdit.d.ts +12 -0
  22. package/lib/mcpClients/jsonEdit.js +123 -0
  23. package/lib/mcpClients/jsonEdit.js.map +1 -0
  24. package/lib/mcpClients/launch.d.ts +36 -0
  25. package/lib/mcpClients/launch.js +75 -0
  26. package/lib/mcpClients/launch.js.map +1 -0
  27. package/lib/mcpClients/plan.d.ts +14 -0
  28. package/lib/mcpClients/plan.js +95 -0
  29. package/lib/mcpClients/plan.js.map +1 -0
  30. package/lib/mcpClients/report.d.ts +12 -0
  31. package/lib/mcpClients/report.js +63 -0
  32. package/lib/mcpClients/report.js.map +1 -0
  33. package/lib/mcpClients/runner.d.ts +9 -0
  34. package/lib/mcpClients/runner.js +38 -0
  35. package/lib/mcpClients/runner.js.map +1 -0
  36. package/lib/mcpClients/types.d.ts +98 -0
  37. package/lib/mcpClients/types.js +18 -0
  38. package/lib/mcpClients/types.js.map +1 -0
  39. package/oclif.manifest.json +124 -1
  40. package/package.json +6 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.js","sourceRoot":"","sources":["../../src/mcpClients/plan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { type ClientId, type InstallResult, type Launcher } from './types.js';
2
+ /**
3
+ * Renders results as the text a command prints. Returned rather than printed, so this module never
4
+ * touches a stream.
5
+ *
6
+ * @param results - From `installServer`.
7
+ * @param launcher - Adds the note about a pinned Node binary when it is `absolute`.
8
+ * @returns The report, ending with what to do next in each client that changed.
9
+ */
10
+ export declare function formatInstallReport(results: readonly InstallResult[], launcher?: Launcher): string;
11
+ /** @returns The message for a missing `--client`: every id, marking the ones installed here. */
12
+ export declare function formatClientChoices(installed: readonly ClientId[]): string;
@@ -0,0 +1,63 @@
1
+ /*
2
+ * Copyright (c) 2026, SimplySF.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import { CLIENTS } from './clients.js';
17
+ import { CLIENT_IDS } from './types.js';
18
+ const OUTCOME_TEXT = {
19
+ added: { done: 'added', planned: 'would add' },
20
+ replaced: { done: 'replaced', planned: 'would replace' },
21
+ unchanged: { done: 'already installed', planned: 'already installed' },
22
+ conflict: { done: 'not changed (conflict)', planned: 'would not change (conflict)' },
23
+ failed: { done: 'failed', planned: 'would fail' },
24
+ };
25
+ /**
26
+ * Renders results as the text a command prints. Returned rather than printed, so this module never
27
+ * touches a stream.
28
+ *
29
+ * @param results - From `installServer`.
30
+ * @param launcher - Adds the note about a pinned Node binary when it is `absolute`.
31
+ * @returns The report, ending with what to do next in each client that changed.
32
+ */
33
+ export function formatInstallReport(results, launcher) {
34
+ const lines = [];
35
+ for (const result of results) {
36
+ const outcome = OUTCOME_TEXT[result.outcome][result.dryRun ? 'planned' : 'done'];
37
+ lines.push(`${CLIENTS[result.client].displayName}: ${outcome} "${result.name}"`, ` ${result.target}`);
38
+ if (result.message)
39
+ lines.push(...result.message.split('\n').map((line) => ` ${line}`));
40
+ if (result.dryRun && result.outcome !== 'failed' && result.outcome !== 'unchanged') {
41
+ lines.push(...result.preview.split('\n').map((line) => ` ${line}`));
42
+ }
43
+ }
44
+ const changed = results.filter((result) => !result.dryRun && ['added', 'replaced'].includes(result.outcome));
45
+ if (changed.length > 0) {
46
+ lines.push('', 'Next:');
47
+ for (const result of changed)
48
+ lines.push(` ${CLIENTS[result.client].displayName}: ${CLIENTS[result.client].nextStep}`);
49
+ if (launcher === 'absolute') {
50
+ lines.push('', 'These entries start this exact Node binary. If a Node upgrade (nvm, fnm, Volta) moves it, ' +
51
+ 'run this command again with --force.');
52
+ }
53
+ }
54
+ return lines.join('\n');
55
+ }
56
+ /** @returns The message for a missing `--client`: every id, marking the ones installed here. */
57
+ export function formatClientChoices(installed) {
58
+ return [
59
+ 'Name at least one client with --client. Clients:',
60
+ ...CLIENT_IDS.map((client) => ` ${client.padEnd(15)} ${CLIENTS[client].displayName}${installed.includes(client) ? ' (found on this machine)' : ''}`),
61
+ ].join('\n');
62
+ }
63
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/mcpClients/report.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { ProcessRunner } from './types.js';
2
+ /**
3
+ * Runs a client CLI with its output captured. `cross-spawn` rather than `child_process.spawn`
4
+ * because npm installs `claude` and `codex` as `.cmd` shims on Windows, which plain `spawn` refuses
5
+ * to start without a shell, and a shell would need the JSON argument quoted for `cmd.exe`.
6
+ */
7
+ export declare const runProcess: ProcessRunner;
8
+ /** @returns A command line a person can paste: POSIX quoting, or double quotes on Windows. */
9
+ export declare function formatCommandLine(executable: string, args: readonly string[], platform?: NodeJS.Platform): string;
@@ -0,0 +1,38 @@
1
+ /*
2
+ * Copyright (c) 2026, SimplySF.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import spawn from 'cross-spawn';
17
+ /**
18
+ * Runs a client CLI with its output captured. `cross-spawn` rather than `child_process.spawn`
19
+ * because npm installs `claude` and `codex` as `.cmd` shims on Windows, which plain `spawn` refuses
20
+ * to start without a shell, and a shell would need the JSON argument quoted for `cmd.exe`.
21
+ */
22
+ export const runProcess = (executable, args) => new Promise((resolve, reject) => {
23
+ const child = spawn(executable, [...args], { stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true });
24
+ let stdout = '';
25
+ let stderr = '';
26
+ child.stdout?.on('data', (chunk) => (stdout += chunk.toString()));
27
+ child.stderr?.on('data', (chunk) => (stderr += chunk.toString()));
28
+ child.on('error', reject);
29
+ child.on('close', (code) => resolve({ exitCode: code ?? 1, stdout, stderr }));
30
+ });
31
+ /** @returns A command line a person can paste: POSIX quoting, or double quotes on Windows. */
32
+ export function formatCommandLine(executable, args, platform = process.platform) {
33
+ const quote = platform === 'win32'
34
+ ? (arg) => (/^[\w@%+=:,./\\-]+$/.test(arg) ? arg : `"${arg.replaceAll('"', '\\"')}"`)
35
+ : (arg) => (/^[\w@%+=:,./-]+$/.test(arg) ? arg : `'${arg.replaceAll("'", "'\\''")}'`);
36
+ return [executable, ...args].map(quote).join(' ');
37
+ }
38
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/mcpClients/runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,MAAM,aAAa,CAAC;AAGhC;;;;GAIG;AACH,MAAM,CAAC,MAAM,UAAU,GAAkB,CAAC,UAAU,EAAE,IAAI,EAAE,EAAE,CAC5D,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;IAC9B,MAAM,KAAK,GAAG,KAAK,CAAC,UAAU,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC;IACrG,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;IAC1E,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;IAC1E,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC1B,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,IAAI,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;AAChF,CAAC,CAAC,CAAC;AAEL,8FAA8F;AAC9F,MAAM,UAAU,iBAAiB,CAC/B,UAAkB,EAClB,IAAuB,EACvB,WAA4B,OAAO,CAAC,QAAQ;IAE5C,MAAM,KAAK,GACT,QAAQ,KAAK,OAAO;QAClB,CAAC,CAAC,CAAC,GAAW,EAAU,EAAE,CAAC,CAAC,oBAAoB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC;QACrG,CAAC,CAAC,CAAC,GAAW,EAAU,EAAE,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IAC1G,OAAO,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACpD,CAAC"}
@@ -0,0 +1,98 @@
1
+ /** Every client this module can install into, by the id `--client` takes. */
2
+ export declare const CLIENT_IDS: readonly ["claude-code", "claude-desktop", "cursor", "vscode", "windsurf", "gemini", "codex"];
3
+ export type ClientId = (typeof CLIENT_IDS)[number];
4
+ /** `user` writes the client's personal configuration; `project` its repo-level file under `cwd`. */
5
+ export type InstallScope = 'user' | 'project';
6
+ /**
7
+ * How the entry starts the server. `absolute` runs this Node on the host's `bin/run.js`, which
8
+ * survives a GUI client's missing `PATH` and Windows' `.cmd` shims; `simply` relies on `PATH`, which
9
+ * is what a committed project file needs; `npx` needs no global install at all.
10
+ */
11
+ export type Launcher = 'absolute' | 'simply' | 'npx';
12
+ /** The server to install: the entry's name and the process a client should launch. */
13
+ export type ServerSpec = {
14
+ name: string;
15
+ command: string;
16
+ args: string[];
17
+ };
18
+ /**
19
+ * Everything about the machine the plan depends on, passed in rather than read from `process` so
20
+ * planning stays pure and every platform's paths can be tested from any one of them.
21
+ */
22
+ export type InstallEnvironment = {
23
+ platform: NodeJS.Platform;
24
+ homedir: string;
25
+ cwd: string;
26
+ env: Readonly<Record<string, string | undefined>>;
27
+ };
28
+ /** The top-level key a client keeps its servers under. */
29
+ export type ServersKey = 'mcpServers' | 'servers';
30
+ /** A JSON (or JSONC) configuration file to edit in place. */
31
+ export type FileInstallPlan = {
32
+ kind: 'file';
33
+ client: ClientId;
34
+ scope: InstallScope;
35
+ name: string;
36
+ file: string;
37
+ key: ServersKey;
38
+ entry: Record<string, unknown>;
39
+ /** A directory whose absence means the client isn't installed, so the file must not be created. */
40
+ clientDir?: string;
41
+ };
42
+ /** A client whose configuration is changed through its own CLI. */
43
+ export type CliInstallPlan = {
44
+ kind: 'cli';
45
+ client: ClientId;
46
+ scope: InstallScope;
47
+ name: string;
48
+ executable: string;
49
+ addArgs: string[];
50
+ removeArgs: string[];
51
+ /** What the entry launches, compared with what is already configured. */
52
+ launch: {
53
+ command: string;
54
+ args: string[];
55
+ };
56
+ /** The file the client keeps its servers in, read (never written) to find an existing entry. */
57
+ configFile: string;
58
+ configFormat: 'claude-json' | 'codex-toml';
59
+ };
60
+ /** A client/scope pair that has no configuration to write, e.g. Claude Desktop at project scope. */
61
+ export type UnsupportedInstallPlan = {
62
+ kind: 'unsupported';
63
+ client: ClientId;
64
+ scope: InstallScope;
65
+ name: string;
66
+ reason: string;
67
+ };
68
+ export type InstallPlan = FileInstallPlan | CliInstallPlan | UnsupportedInstallPlan;
69
+ export type InstallOutcome = 'added' | 'replaced' | 'unchanged' | 'conflict' | 'failed';
70
+ export type InstallResult = {
71
+ client: ClientId;
72
+ name: string;
73
+ outcome: InstallOutcome;
74
+ /** The file written, or the command run (or to run). */
75
+ target: string;
76
+ /** True when nothing was changed because the caller asked only for the plan. */
77
+ dryRun: boolean;
78
+ /** 0 for added/replaced/unchanged, 2 for a conflict or a refused install, 1 for an I/O failure. */
79
+ exitCode: 0 | 1 | 2;
80
+ /** Why a `conflict` or `failed` happened, and what to do about it. */
81
+ message?: string;
82
+ /** The entry as written (or as it would be written), for display. */
83
+ preview: string;
84
+ };
85
+ /** Runs a client's CLI. Rejects with `code: 'ENOENT'` when the executable isn't on `PATH`. */
86
+ export type ProcessRunner = (executable: string, args: readonly string[]) => Promise<{
87
+ exitCode: number;
88
+ stdout: string;
89
+ stderr: string;
90
+ }>;
91
+ export type ApplyOptions = {
92
+ /** Replace an existing entry of the same name that differs. */
93
+ force?: boolean;
94
+ /** Work out the outcome and change nothing. */
95
+ dryRun?: boolean;
96
+ /** Replaces the real process runner, for tests. */
97
+ runner?: ProcessRunner;
98
+ };
@@ -0,0 +1,18 @@
1
+ /*
2
+ * Copyright (c) 2026, SimplySF.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ /** Every client this module can install into, by the id `--client` takes. */
17
+ export const CLIENT_IDS = ['claude-code', 'claude-desktop', 'cursor', 'vscode', 'windsurf', 'gemini', 'codex'];
18
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/mcpClients/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,6EAA6E;AAC7E,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,aAAa,EAAE,gBAAgB,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,CAAU,CAAC"}
@@ -59,7 +59,130 @@
59
59
  "gitlab",
60
60
  "mcp.js"
61
61
  ]
62
+ },
63
+ "gitlab:mcp:install": {
64
+ "aliases": [],
65
+ "args": {},
66
+ "description": "Writes an entry that launches \"simply gitlab mcp\" into each client named with --client, keeping the rest of that client’s configuration as it was. Claude Code and Codex are changed through their own CLIs; every other client’s JSON file is edited in place, with a .bak copy kept.\n\nCredentials are never written. Give the server its connection settings with --env-file, which is written as an absolute path and must exist now. A GUI client will not pass on your shell’s environment, so without --env-file the entry starts with no settings.\n\nRunning it again is safe: an identical entry is left alone, and a different one is only replaced with --force.",
67
+ "examples": [
68
+ {
69
+ "description": "Add the read-only server to Claude Code and Cursor",
70
+ "command": "<%= config.bin %> <%= command.id %> --client claude-code --client cursor --env-file ~/gitlab.env"
71
+ },
72
+ {
73
+ "description": "Add a second, write-enabled entry (named simply-gitlab-write) to Claude Desktop",
74
+ "command": "<%= config.bin %> <%= command.id %> --client claude-desktop --allow-writes --env-file ~/gitlab-write.env"
75
+ },
76
+ {
77
+ "description": "Commit an entry for this repository’s VS Code users",
78
+ "command": "<%= config.bin %> <%= command.id %> --client vscode --scope project"
79
+ },
80
+ {
81
+ "description": "See what would be written, and change nothing",
82
+ "command": "<%= config.bin %> <%= command.id %> --client gemini --dry-run"
83
+ }
84
+ ],
85
+ "flags": {
86
+ "json": {
87
+ "description": "Format output as json.",
88
+ "helpGroup": "GLOBAL",
89
+ "name": "json",
90
+ "allowNo": false,
91
+ "type": "boolean"
92
+ },
93
+ "client": {
94
+ "name": "client",
95
+ "summary": "Client to add the server to. Repeat for several.",
96
+ "hasDynamicHelp": false,
97
+ "multiple": true,
98
+ "options": [
99
+ "claude-code",
100
+ "claude-desktop",
101
+ "cursor",
102
+ "vscode",
103
+ "windsurf",
104
+ "gemini",
105
+ "codex"
106
+ ],
107
+ "type": "option"
108
+ },
109
+ "scope": {
110
+ "name": "scope",
111
+ "summary": "Your own configuration, or the repository-level file in the current directory.",
112
+ "default": "user",
113
+ "hasDynamicHelp": false,
114
+ "multiple": false,
115
+ "options": [
116
+ "user",
117
+ "project"
118
+ ],
119
+ "type": "option"
120
+ },
121
+ "env-file": {
122
+ "char": "e",
123
+ "name": "env-file",
124
+ "summary": "Connection settings file for the server. Written as an absolute path.",
125
+ "hasDynamicHelp": false,
126
+ "multiple": false,
127
+ "type": "option"
128
+ },
129
+ "allow-writes": {
130
+ "name": "allow-writes",
131
+ "summary": "Register the tools that change data. Also makes the default name simply-gitlab-write.",
132
+ "allowNo": false,
133
+ "type": "boolean"
134
+ },
135
+ "name": {
136
+ "name": "name",
137
+ "summary": "Entry name. Default simply-gitlab, or simply-gitlab-write with --allow-writes.",
138
+ "hasDynamicHelp": false,
139
+ "multiple": false,
140
+ "type": "option"
141
+ },
142
+ "launcher": {
143
+ "description": "absolute: this Node binary and the simply CLI’s own script, which works for GUI clients that do not see your PATH (re-run with --force after a Node upgrade moves it). simply: \"simply\" on PATH, right for a committed file. npx: \"npx -y @simplysf/simply-cli\", for machines without a global install.",
144
+ "name": "launcher",
145
+ "summary": "How the entry starts simply. Default absolute for --scope user, simply for --scope project.",
146
+ "hasDynamicHelp": false,
147
+ "multiple": false,
148
+ "options": [
149
+ "absolute",
150
+ "simply",
151
+ "npx"
152
+ ],
153
+ "type": "option"
154
+ },
155
+ "force": {
156
+ "name": "force",
157
+ "summary": "Replace an existing entry of the same name that differs.",
158
+ "allowNo": false,
159
+ "type": "boolean"
160
+ },
161
+ "dry-run": {
162
+ "name": "dry-run",
163
+ "summary": "Show what would be written, and change nothing.",
164
+ "allowNo": false,
165
+ "type": "boolean"
166
+ }
167
+ },
168
+ "hasDynamicHelp": false,
169
+ "hiddenAliases": [],
170
+ "id": "gitlab:mcp:install",
171
+ "pluginAlias": "@simplysf/simply-gitlab-mcp",
172
+ "pluginName": "@simplysf/simply-gitlab-mcp",
173
+ "pluginType": "core",
174
+ "strict": true,
175
+ "summary": "Add the GitLab MCP server to MCP clients.",
176
+ "enableJsonFlag": true,
177
+ "isESM": true,
178
+ "relativePath": [
179
+ "lib",
180
+ "commands",
181
+ "gitlab",
182
+ "mcp",
183
+ "install.js"
184
+ ]
62
185
  }
63
186
  },
64
- "version": "0.6.2"
187
+ "version": "0.7.0"
65
188
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@simplysf/simply-gitlab-mcp",
3
3
  "description": "Model Context Protocol server exposing GitLab to AI agents, built on @simplysf/simply-gitlab-core",
4
- "version": "0.6.2",
4
+ "version": "0.7.0",
5
5
  "author": "@ClayChipps",
6
6
  "homepage": "https://github.com/SimplySF/simply-gitlab",
7
7
  "bugs": "https://github.com/SimplySF/simply-gitlab/issues",
@@ -34,12 +34,15 @@
34
34
  "simply-gitlab-mcp": "./bin/run.js"
35
35
  },
36
36
  "dependencies": {
37
- "@modelcontextprotocol/sdk": "^1.30.0",
37
+ "@modelcontextprotocol/sdk": "^1.32.1",
38
38
  "@oclif/core": "^4.11.2",
39
39
  "@simplysf/simply-gitlab-core": "^0.5.1",
40
+ "cross-spawn": "^7.0.6",
41
+ "jsonc-parser": "^3.3.1",
40
42
  "zod": "^4.6.5"
41
43
  },
42
44
  "devDependencies": {
45
+ "@types/cross-spawn": "^6.0.6",
43
46
  "@vitest/coverage-v8": "^4.1.10",
44
47
  "oclif": "^4.23.0",
45
48
  "shx": "^0.4.0",
@@ -184,5 +187,5 @@
184
187
  }
185
188
  }
186
189
  },
187
- "gitHead": "dc8cdc8e13b8a4053d503cb5efbdb54f637aa19a"
190
+ "gitHead": "a2b493a11e9a3a2ae363c6728f8dcdc2a39b1f32"
188
191
  }