@cyanheads/git-mcp-server 2.2.1 → 2.2.3
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/README.md +63 -124
- package/dist/config/index.js +248 -53
- package/dist/mcp-server/server.js +6 -6
- package/dist/mcp-server/tools/gitCherryPick/logic.js +39 -13
- package/dist/mcp-server/tools/gitCommit/logic.js +1 -1
- package/dist/mcp-server/tools/gitMerge/logic.js +38 -13
- package/dist/mcp-server/tools/gitTag/logic.js +38 -19
- package/dist/mcp-server/tools/gitWrapupInstructions/logic.js +4 -0
- package/dist/mcp-server/tools/gitWrapupInstructions/registration.js +1 -1
- package/dist/mcp-server/transports/auth/authFactory.js +41 -0
- package/dist/mcp-server/transports/auth/authMiddleware.js +57 -0
- package/dist/mcp-server/transports/auth/index.js +6 -4
- package/dist/mcp-server/transports/auth/lib/authTypes.js +8 -0
- package/dist/mcp-server/transports/auth/{core → lib}/authUtils.js +21 -14
- package/dist/mcp-server/transports/auth/strategies/authStrategy.js +1 -0
- package/dist/mcp-server/transports/auth/strategies/jwtStrategy.js +113 -0
- package/dist/mcp-server/transports/auth/strategies/oauthStrategy.js +102 -0
- package/dist/mcp-server/transports/core/baseTransportManager.js +19 -0
- package/dist/mcp-server/transports/core/honoNodeBridge.js +51 -0
- package/dist/mcp-server/transports/core/statefulTransportManager.js +234 -0
- package/dist/mcp-server/transports/core/statelessTransportManager.js +92 -0
- package/dist/mcp-server/transports/core/transportTypes.js +5 -0
- package/dist/mcp-server/transports/{httpErrorHandler.js → http/httpErrorHandler.js} +33 -8
- package/dist/mcp-server/transports/http/httpTransport.js +254 -0
- package/dist/mcp-server/transports/http/httpTypes.js +5 -0
- package/dist/mcp-server/transports/http/index.js +6 -0
- package/dist/mcp-server/transports/http/mcpTransportMiddleware.js +63 -0
- package/dist/mcp-server/transports/stdio/index.js +5 -0
- package/dist/mcp-server/transports/{stdioTransport.js → stdio/stdioTransport.js} +10 -5
- package/dist/types-global/errors.js +75 -19
- package/dist/utils/internal/errorHandler.js +11 -13
- package/package.json +19 -8
- package/dist/mcp-server/transports/auth/core/authTypes.js +0 -5
- package/dist/mcp-server/transports/auth/strategies/jwt/jwtMiddleware.js +0 -149
- package/dist/mcp-server/transports/auth/strategies/oauth/oauthMiddleware.js +0 -127
- package/dist/mcp-server/transports/httpTransport.js +0 -207
- /package/dist/mcp-server/transports/auth/{core → lib}/authContext.js +0 -0
package/README.md
CHANGED
|
@@ -1,18 +1,31 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
[](https://modelcontextprotocol.io/)
|
|
5
|
-
[](./CHANGELOG.md)
|
|
6
|
-
[](https://opensource.org/licenses/Apache-2.0)
|
|
7
|
-
[](https://github.com/cyanheads/git-mcp-server/issues)
|
|
8
|
-
[](https://github.com/cyanheads/git-mcp-server)
|
|
3
|
+
# @cyanheads/git-mcp-server
|
|
9
4
|
|
|
10
5
|
**Empower your AI agents with comprehensive, secure, and programmatic control over Git repositories!**
|
|
11
6
|
|
|
7
|
+
[](https://www.typescriptlang.org/)
|
|
8
|
+
[](https://github.com/modelcontextprotocol/typescript-sdk)
|
|
9
|
+
[](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-06-18/changelog.mdx)
|
|
10
|
+
[](./CHANGELOG.md)
|
|
11
|
+
[](./vitest.config.ts)
|
|
12
|
+
[](https://opensource.org/licenses/Apache-2.0)
|
|
13
|
+
[](https://github.com/cyanheads/git-mcp-server/issues)
|
|
14
|
+
[](https://github.com/cyanheads/git-mcp-server)
|
|
15
|
+
|
|
16
|
+
</div>
|
|
17
|
+
|
|
12
18
|
An MCP (Model Context Protocol) server providing a robust, LLM-friendly interface to the standard `git` command-line tool. Enables LLMs and AI agents to perform a wide range of Git operations like clone, commit, push, pull, branch, diff, log, status, and more via the MCP standard.
|
|
13
19
|
|
|
14
20
|
Built on the [`cyanheads/mcp-ts-template`](https://github.com/cyanheads/mcp-ts-template), this server follows a modular architecture with robust error handling, logging, and security features.
|
|
15
21
|
|
|
22
|
+
## 🤔 Why Use This Server?
|
|
23
|
+
|
|
24
|
+
- **Automate Git Workflows**: Enable AI agents to programmatically clone, commit, push, and manage branches.
|
|
25
|
+
- **Gain Repository Insights**: Allow tools to check status, view logs, and diff changes without direct shell access.
|
|
26
|
+
- **Integrate Git into AI-driven Development**: Let LLMs manage version control as part of their coding tasks.
|
|
27
|
+
- **Production-Ready Foundation**: Inherits logging, error handling, and security from the template.
|
|
28
|
+
|
|
16
29
|
## 🚀 Core Capabilities: Git Tools 🛠️
|
|
17
30
|
|
|
18
31
|
This server equips your AI with a comprehensive suite of tools to interact with Git repositories:
|
|
@@ -104,35 +117,41 @@ Add the following to your MCP client's configuration file (e.g., `cline_mcp_sett
|
|
|
104
117
|
#### Install via npm
|
|
105
118
|
|
|
106
119
|
```bash
|
|
107
|
-
npm
|
|
120
|
+
npm run build
|
|
121
|
+
# Or use 'npm run rebuild' for a clean install
|
|
108
122
|
```
|
|
109
123
|
|
|
110
|
-
|
|
124
|
+
### 3. Running the Server
|
|
111
125
|
|
|
112
|
-
|
|
126
|
+
- **Via Stdio (Default):**
|
|
127
|
+
```bash
|
|
128
|
+
npm run start:server
|
|
129
|
+
```
|
|
130
|
+
- **Via Streamable HTTP:**
|
|
131
|
+
```bash
|
|
132
|
+
npm run start:server:http
|
|
133
|
+
```
|
|
113
134
|
|
|
114
|
-
|
|
115
|
-
git clone https://github.com/cyanheads/git-mcp-server.git
|
|
116
|
-
cd git-mcp-server
|
|
117
|
-
```
|
|
135
|
+
### 4. Running Tests
|
|
118
136
|
|
|
119
|
-
|
|
137
|
+
This server uses [Vitest](https://vitest.dev/) for testing.
|
|
120
138
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
139
|
+
- **Run all tests once:**
|
|
140
|
+
```bash
|
|
141
|
+
npm test
|
|
142
|
+
```
|
|
143
|
+
- **Run tests in watch mode:**
|
|
144
|
+
```bash
|
|
145
|
+
npm run test:watch
|
|
146
|
+
```
|
|
147
|
+
- **Run tests and generate a coverage report:**
|
|
148
|
+
```bash
|
|
149
|
+
npm run test:coverage
|
|
150
|
+
```
|
|
124
151
|
|
|
125
|
-
|
|
126
|
-
```bash
|
|
127
|
-
npm run build
|
|
128
|
-
# or npm run rebuild
|
|
129
|
-
```
|
|
152
|
+
## ⚙️ Configuration
|
|
130
153
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
### Environment Variables
|
|
134
|
-
|
|
135
|
-
Configure the server using environment variables. These environmental variables are set within your MCP client config/settings (e.g. `claude_desktop_config.json` for Claude Desktop)
|
|
154
|
+
Configure the server using these environment variables (or a `.env` file):
|
|
136
155
|
|
|
137
156
|
| Variable | Description | Default |
|
|
138
157
|
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
|
|
@@ -147,111 +166,31 @@ Configure the server using environment variables. These environmental variables
|
|
|
147
166
|
| `OAUTH_ISSUER_URL` | OIDC issuer URL for OAuth validation (if `MCP_AUTH_MODE=oauth`). | `''` |
|
|
148
167
|
| `OAUTH_AUDIENCE` | Audience claim for OAuth validation (if `MCP_AUTH_MODE=oauth`). | `''` |
|
|
149
168
|
|
|
150
|
-
## Project Structure
|
|
151
|
-
|
|
152
|
-
The codebase follows a modular structure within the `src/` directory:
|
|
153
|
-
|
|
154
|
-
```
|
|
155
|
-
src/
|
|
156
|
-
├── index.ts # Entry point: Initializes and starts the server
|
|
157
|
-
├── config/ # Configuration loading (env vars, package info)
|
|
158
|
-
│ └── index.ts
|
|
159
|
-
├── mcp-server/ # Core MCP server logic and capability registration
|
|
160
|
-
│ ├── server.ts # Server setup, capability registration
|
|
161
|
-
│ ├── transports/ # Transport handling (stdio, http)
|
|
162
|
-
│ ├── resources/ # MCP Resource implementations (currently none)
|
|
163
|
-
│ └── tools/ # MCP Tool implementations (subdirs per tool)
|
|
164
|
-
├── types-global/ # Shared TypeScript type definitions
|
|
165
|
-
└── utils/ # Common utility functions (logger, error handler, etc.)
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
For a detailed file tree, run `npm run tree` or see [docs/tree.md](docs/tree.md).
|
|
169
|
-
|
|
170
|
-
## Tools
|
|
171
|
-
|
|
172
|
-
The Git MCP Server provides a suite of tools for interacting with Git repositories, callable via the Model Context Protocol.
|
|
169
|
+
## 🏗️ Project Structure
|
|
173
170
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
| `git_cherry_pick` | Applies changes introduced by existing commits. | `path?`, `commitRef`, `mainline?`, `strategy?`, `noCommit?`, `signoff?` |
|
|
180
|
-
| `git_clean` | Removes untracked files. **Requires `force: true`**. | `path?`, `force`, `dryRun?`, `directories?`, `ignored?` |
|
|
181
|
-
| `git_clear_working_dir` | Clears the session-specific working directory. | (none) |
|
|
182
|
-
| `git_clone` | Clones a repository into a specified absolute path. | `repositoryUrl`, `targetPath`, `branch?`, `depth?`, `quiet?` |
|
|
183
|
-
| `git_commit` | Commits staged changes. Supports author override, signing control. | `path?`, `message`, `author?`, `allowEmpty?`, `amend?`, `forceUnsignedOnFailure?` |
|
|
184
|
-
| `git_diff` | Shows changes between commits, working tree, etc. | `path?`, `commit1?`, `commit2?`, `staged?`, `file?`, `includeUntracked?` |
|
|
185
|
-
| `git_fetch` | Downloads objects and refs from other repositories. | `path?`, `remote?`, `prune?`, `tags?`, `all?` |
|
|
186
|
-
| `git_init` | Initializes a new Git repository at the specified absolute path. Defaults to 'main' for initial branch. | `path`, `initialBranch?`, `bare?`, `quiet?` |
|
|
187
|
-
| `git_log` | Shows commit logs. | `path?`, `maxCount?`, `author?`, `since?`, `until?`, `branchOrFile?` |
|
|
188
|
-
| `git_merge` | Merges the specified branch into the current branch. | `path?`, `branch`, `commitMessage?`, `noFf?`, `squash?`, `abort?` |
|
|
189
|
-
| `git_pull` | Fetches from and integrates with another repository or local branch. | `path?`, `remote?`, `branch?`, `rebase?`, `ffOnly?` |
|
|
190
|
-
| `git_push` | Updates remote refs using local refs. | `path?`, `remote?`, `branch?`, `remoteBranch?`, `force?`, `forceWithLease?`, `setUpstream?`, `tags?`, `delete?` |
|
|
191
|
-
| `git_rebase` | Reapplies commits on top of another base tip. | `path?`, `mode?`, `upstream?`, `branch?`, `interactive?`, `strategy?`, `strategyOption?`, `onto?` |
|
|
192
|
-
| `git_remote` | Manages remote repositories (list, add, remove, show). | `path?`, `mode`, `name?`, `url?` |
|
|
193
|
-
| `git_reset` | Resets current HEAD to a specified state. Supports soft, mixed, hard modes. **USE 'hard' WITH CAUTION**. | `path?`, `mode?`, `commit?` |
|
|
194
|
-
| `git_set_working_dir` | Sets the default working directory. Can optionally initialize repo if not present. Requires absolute path. | `path`, `validateGitRepo?`, `initializeIfNotPresent?` |
|
|
195
|
-
| `git_show` | Shows information about Git objects (commits, tags, etc.). | `path?`, `ref`, `filePath?` |
|
|
196
|
-
| `git_stash` | Manages stashed changes (list, apply, pop, drop, save). | `path?`, `mode`, `stashRef?`, `message?` |
|
|
197
|
-
| `git_status` | Gets repository status (branch, staged, modified, untracked files). | `path?` |
|
|
198
|
-
| `git_tag` | Manages tags (list, create annotated/lightweight, delete). | `path?`, `mode`, `tagName?`, `message?`, `commitRef?`, `annotate?` |
|
|
199
|
-
| `git_worktree` | Manages Git worktrees (list, add, remove, move, prune). | `path?`, `mode`, `worktreePath?`, `commitish?`, `newBranch?`, `force?`, `detach?`, `newPath?`, `verbose?`, `dryRun?`, `expire?` |
|
|
200
|
-
| `git_wrapup_instructions` | Provides a standard Git wrap-up workflow. | `acknowledgement`, `updateAgentMetaFiles?` |
|
|
171
|
+
- **`src/mcp-server/`**: Contains the core MCP server, tools, resources, and transport handlers.
|
|
172
|
+
- **`src/config/`**: Handles loading and validation of environment variables.
|
|
173
|
+
- **`src/types-global/`**: Defines shared TypeScript interfaces and type definitions.
|
|
174
|
+
- **`src/utils/`**: Core utilities (logging, error handling, security, etc.).
|
|
175
|
+
- **`src/index.ts`**: The main entry point that initializes and starts the server.
|
|
201
176
|
|
|
202
|
-
|
|
177
|
+
**Explore the full structure yourself:**
|
|
203
178
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
**MCP Resources are not implemented in this version (v2.2.0).**
|
|
207
|
-
|
|
208
|
-
This version focuses on the refactored Git tools implementation based on the latest `mcp-ts-template` and MCP SDK v1.15.1. Resource capabilities, previously available, have been temporarily removed during this major update.
|
|
209
|
-
|
|
210
|
-
If you require MCP Resource access (e.g., for reading file content directly via the server), please use the stable **[v1.2.4 release](https://github.com/cyanheads/git-mcp-server/releases/tag/v1.2.4)**.
|
|
211
|
-
|
|
212
|
-
Future development may reintroduce resource capabilities in a subsequent release.
|
|
213
|
-
|
|
214
|
-
## Development
|
|
215
|
-
|
|
216
|
-
### Build and Test
|
|
179
|
+
See the current file tree in [docs/tree.md](docs/tree.md) or generate it dynamically:
|
|
217
180
|
|
|
218
181
|
```bash
|
|
219
|
-
# Build the project (compile TS to JS in dist/ and make executable)
|
|
220
|
-
npm run build
|
|
221
|
-
|
|
222
|
-
# Test the server locally using the MCP inspector tool (stdio transport)
|
|
223
|
-
npm run inspector
|
|
224
|
-
|
|
225
|
-
# Test the server locally using the MCP inspector tool (http transport)
|
|
226
|
-
npm run inspector:http
|
|
227
|
-
|
|
228
|
-
# Clean build artifacts
|
|
229
|
-
npm run clean
|
|
230
|
-
|
|
231
|
-
# Generate a file tree representation for documentation
|
|
232
182
|
npm run tree
|
|
183
|
+
```
|
|
233
184
|
|
|
234
|
-
|
|
235
|
-
npm run rebuild
|
|
236
|
-
|
|
237
|
-
# Format code with Prettier
|
|
238
|
-
npm run format
|
|
185
|
+
## 🧩 Extending the System
|
|
239
186
|
|
|
240
|
-
|
|
241
|
-
npm start
|
|
242
|
-
# Or explicitly:
|
|
243
|
-
npm run start:stdio
|
|
187
|
+
The canonical pattern for adding new tools is defined in the [.clinerules](.clinerules) file. It mandates a strict separation of concerns:
|
|
244
188
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
```
|
|
189
|
+
1. **`logic.ts`**: Contains the pure business logic, Zod schemas, and type definitions. This file throws structured errors on failure.
|
|
190
|
+
2. **`registration.ts`**: Acts as the "handler." It registers the tool with the server, wraps the logic call in a `try...catch` block, and formats the final success or error response.
|
|
248
191
|
|
|
249
|
-
|
|
192
|
+
This "Logic Throws, Handler Catches" pattern ensures that core logic remains pure and testable, while the registration layer handles all side effects and response formatting.
|
|
250
193
|
|
|
251
|
-
|
|
194
|
+
## 📜 License
|
|
252
195
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
<div align="center">
|
|
256
|
-
Built with the <a href="https://modelcontextprotocol.io/">Model Context Protocol</a>
|
|
257
|
-
</div>
|
|
196
|
+
This project is licensed under the Apache License 2.0. See the [LICENSE](LICENSE) file for details.
|
package/dist/config/index.js
CHANGED
|
@@ -1,76 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Loads, validates, and exports application configuration.
|
|
3
|
+
* This module centralizes configuration management, sourcing values from
|
|
4
|
+
* environment variables and `package.json`. It uses Zod for schema validation
|
|
5
|
+
* to ensure type safety and correctness of configuration parameters.
|
|
6
|
+
*
|
|
7
|
+
* Key responsibilities:
|
|
8
|
+
* - Load environment variables from a `.env` file.
|
|
9
|
+
* - Read `package.json` for default server name and version.
|
|
10
|
+
* - Define a Zod schema for all expected environment variables.
|
|
11
|
+
* - Validate environment variables against the schema.
|
|
12
|
+
* - Construct and export a comprehensive `config` object.
|
|
13
|
+
* - Export individual configuration values like `logLevel` and `environment` for convenience.
|
|
14
|
+
*
|
|
15
|
+
* @module src/config/index
|
|
16
|
+
*/
|
|
1
17
|
import dotenv from "dotenv";
|
|
2
|
-
import { readFileSync } from "fs";
|
|
3
|
-
import { dirname, join } from "path";
|
|
18
|
+
import { existsSync, mkdirSync, readFileSync, statSync } from "fs";
|
|
19
|
+
import path, { dirname, join } from "path";
|
|
4
20
|
import { fileURLToPath } from "url";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
21
|
+
import { z } from "zod";
|
|
22
|
+
dotenv.config();
|
|
23
|
+
// --- Determine Project Root ---
|
|
24
|
+
/**
|
|
25
|
+
* Finds the project root directory by searching upwards for package.json.
|
|
26
|
+
* @param startDir The directory to start searching from.
|
|
27
|
+
* @returns The absolute path to the project root, or throws an error if not found.
|
|
28
|
+
*/
|
|
29
|
+
const findProjectRoot = (startDir) => {
|
|
30
|
+
let currentDir = startDir;
|
|
31
|
+
while (true) {
|
|
32
|
+
const packageJsonPath = join(currentDir, "package.json");
|
|
33
|
+
if (existsSync(packageJsonPath)) {
|
|
34
|
+
return currentDir;
|
|
35
|
+
}
|
|
36
|
+
const parentDir = dirname(currentDir);
|
|
37
|
+
if (parentDir === currentDir) {
|
|
38
|
+
// Reached the root of the filesystem without finding package.json
|
|
39
|
+
throw new Error(`Could not find project root (package.json) starting from ${startDir}`);
|
|
40
|
+
}
|
|
41
|
+
currentDir = parentDir;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
let projectRoot;
|
|
45
|
+
try {
|
|
46
|
+
// For ESM, __dirname is not available directly.
|
|
47
|
+
// import.meta.url gives the URL of the current module.
|
|
48
|
+
const currentModuleDir = dirname(fileURLToPath(import.meta.url));
|
|
49
|
+
projectRoot = findProjectRoot(currentModuleDir);
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
53
|
+
console.error(`FATAL: Error determining project root: ${errorMessage}`);
|
|
54
|
+
// Fallback to process.cwd() if project root cannot be determined.
|
|
55
|
+
// This might happen in unusual execution environments.
|
|
56
|
+
projectRoot = process.cwd();
|
|
57
|
+
console.warn(`Warning: Using process.cwd() (${projectRoot}) as fallback project root.`);
|
|
58
|
+
}
|
|
59
|
+
// --- End Determine Project Root ---
|
|
60
|
+
const pkgPath = join(projectRoot, "package.json"); // Use determined projectRoot
|
|
61
|
+
let pkg = { name: "git-mcp-server", version: "0.0.0" };
|
|
14
62
|
try {
|
|
15
|
-
// Read and parse package.json to get server name and version
|
|
16
63
|
pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
17
64
|
}
|
|
18
65
|
catch (error) {
|
|
19
|
-
|
|
66
|
+
if (process.stdout.isTTY) {
|
|
67
|
+
console.error("Warning: Could not read package.json for default config values. Using hardcoded defaults.", error);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Zod schema for validating environment variables.
|
|
72
|
+
* Provides type safety, validation, defaults, and clear error messages.
|
|
73
|
+
* @private
|
|
74
|
+
*/
|
|
75
|
+
const EnvSchema = z.object({
|
|
76
|
+
/** Optional. The desired name for the MCP server. Defaults to `package.json` name. */
|
|
77
|
+
MCP_SERVER_NAME: z.string().optional(),
|
|
78
|
+
/** Optional. The version of the MCP server. Defaults to `package.json` version. */
|
|
79
|
+
MCP_SERVER_VERSION: z.string().optional(),
|
|
80
|
+
/** Minimum logging level. See `McpLogLevel` in logger utility. Default: "info". */
|
|
81
|
+
MCP_LOG_LEVEL: z.string().default("info"),
|
|
82
|
+
/** Directory for log files. Defaults to "logs" in project root. */
|
|
83
|
+
LOGS_DIR: z.string().default(path.join(projectRoot, "logs")),
|
|
84
|
+
/** Runtime environment (e.g., "development", "production"). Default: "development". */
|
|
85
|
+
NODE_ENV: z.string().default("development"),
|
|
86
|
+
/** MCP communication transport ("stdio" or "http"). Default: "stdio". */
|
|
87
|
+
MCP_TRANSPORT_TYPE: z.enum(["stdio", "http"]).default("stdio"),
|
|
88
|
+
/** MCP session mode ('stateless', 'stateful', 'auto'). Default: 'auto'. */
|
|
89
|
+
MCP_SESSION_MODE: z.enum(["stateless", "stateful", "auto"]).default("auto"),
|
|
90
|
+
/** HTTP server port (if MCP_TRANSPORT_TYPE is "http"). Default: 3010. */
|
|
91
|
+
MCP_HTTP_PORT: z.coerce.number().int().positive().default(3010),
|
|
92
|
+
/** HTTP server host (if MCP_TRANSPORT_TYPE is "http"). Default: "127.0.0.1". */
|
|
93
|
+
MCP_HTTP_HOST: z.string().default("127.0.0.1"),
|
|
94
|
+
/** The endpoint path for the MCP server. Default: "/mcp". */
|
|
95
|
+
MCP_HTTP_ENDPOINT_PATH: z.string().default("/mcp"),
|
|
96
|
+
/** Max retries for binding to a port if the initial one is in use. Default: 15. */
|
|
97
|
+
MCP_HTTP_MAX_PORT_RETRIES: z.coerce.number().int().nonnegative().default(15),
|
|
98
|
+
/** Delay in ms between port binding retries. Default: 50. */
|
|
99
|
+
MCP_HTTP_PORT_RETRY_DELAY_MS: z.coerce
|
|
100
|
+
.number()
|
|
101
|
+
.int()
|
|
102
|
+
.nonnegative()
|
|
103
|
+
.default(50),
|
|
104
|
+
/** Timeout in ms for considering a stateful session stale and eligible for cleanup. Default: 1800000 (30 minutes). */
|
|
105
|
+
MCP_STATEFUL_SESSION_STALE_TIMEOUT_MS: z.coerce
|
|
106
|
+
.number()
|
|
107
|
+
.int()
|
|
108
|
+
.positive()
|
|
109
|
+
.default(1_800_000),
|
|
110
|
+
/** Optional. Comma-separated allowed origins for CORS (HTTP transport). */
|
|
111
|
+
MCP_ALLOWED_ORIGINS: z.string().optional(),
|
|
112
|
+
/** Optional. Secret key (min 32 chars) for auth tokens (HTTP transport). CRITICAL for production. */
|
|
113
|
+
MCP_AUTH_SECRET_KEY: z
|
|
114
|
+
.string()
|
|
115
|
+
.min(32, "MCP_AUTH_SECRET_KEY must be at least 32 characters long for security reasons.")
|
|
116
|
+
.optional(),
|
|
117
|
+
/** The authentication mode to use. 'jwt' for internal simple JWTs, 'oauth' for OAuth 2.1, or 'none'. Default: 'none'. */
|
|
118
|
+
MCP_AUTH_MODE: z.enum(["jwt", "oauth", "none"]).default("none"),
|
|
119
|
+
/** The expected issuer URL for OAuth 2.1 access tokens. CRITICAL for validation. */
|
|
120
|
+
OAUTH_ISSUER_URL: z.string().url().optional(),
|
|
121
|
+
/** The JWKS (JSON Web Key Set) URI for the OAuth 2.1 provider. If not provided, it's often discoverable from the issuer URL. */
|
|
122
|
+
OAUTH_JWKS_URI: z.string().url().optional(),
|
|
123
|
+
/** The audience claim for the OAuth 2.1 access tokens. This server will reject tokens not intended for it. */
|
|
124
|
+
OAUTH_AUDIENCE: z.string().optional(),
|
|
125
|
+
/** Optional. Client ID to use in development mode for JWT strategy. Default: "dev-client-id". */
|
|
126
|
+
DEV_MCP_CLIENT_ID: z.string().optional(),
|
|
127
|
+
/** Optional. Comma-separated scopes for development mode JWT strategy. Default: "dev-scope". */
|
|
128
|
+
DEV_MCP_SCOPES: z.string().optional(),
|
|
129
|
+
/** Flag to enable GPG signing for commits made by the git_commit tool. */
|
|
130
|
+
GIT_SIGN_COMMITS: z.string().transform((val) => val === "true").optional(),
|
|
131
|
+
});
|
|
132
|
+
const parsedEnv = EnvSchema.safeParse(process.env);
|
|
133
|
+
if (!parsedEnv.success) {
|
|
134
|
+
if (process.stdout.isTTY) {
|
|
135
|
+
console.error("❌ Invalid environment variables found:", parsedEnv.error.flatten().fieldErrors);
|
|
136
|
+
}
|
|
137
|
+
// Consider throwing an error in production for critical misconfigurations.
|
|
138
|
+
}
|
|
139
|
+
const env = parsedEnv.success ? parsedEnv.data : EnvSchema.parse({});
|
|
140
|
+
// --- Directory Ensurance Function ---
|
|
141
|
+
const ensureDirectory = (dirPath, rootDir, dirName) => {
|
|
142
|
+
const resolvedDirPath = path.isAbsolute(dirPath)
|
|
143
|
+
? dirPath
|
|
144
|
+
: path.resolve(rootDir, dirPath);
|
|
145
|
+
if (!resolvedDirPath.startsWith(rootDir + path.sep) &&
|
|
146
|
+
resolvedDirPath !== rootDir) {
|
|
147
|
+
if (process.stdout.isTTY) {
|
|
148
|
+
console.error(`Error: ${dirName} path "${dirPath}" resolves to "${resolvedDirPath}", which is outside the project boundary "${rootDir}".`);
|
|
149
|
+
}
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
if (!existsSync(resolvedDirPath)) {
|
|
153
|
+
try {
|
|
154
|
+
mkdirSync(resolvedDirPath, { recursive: true });
|
|
155
|
+
if (process.stdout.isTTY) {
|
|
156
|
+
console.log(`Created ${dirName} directory: ${resolvedDirPath}`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
161
|
+
if (process.stdout.isTTY) {
|
|
162
|
+
console.error(`Error creating ${dirName} directory at ${resolvedDirPath}: ${errorMessage}`);
|
|
163
|
+
}
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
try {
|
|
169
|
+
const stats = statSync(resolvedDirPath);
|
|
170
|
+
if (!stats.isDirectory()) {
|
|
171
|
+
if (process.stdout.isTTY) {
|
|
172
|
+
console.error(`Error: ${dirName} path ${resolvedDirPath} exists but is not a directory.`);
|
|
173
|
+
}
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
catch (statError) {
|
|
178
|
+
if (process.stdout.isTTY) {
|
|
179
|
+
const statErrorMessage = statError instanceof Error ? statError.message : String(statError);
|
|
180
|
+
console.error(`Error accessing ${dirName} path ${resolvedDirPath}: ${statErrorMessage}`);
|
|
181
|
+
}
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return resolvedDirPath;
|
|
186
|
+
};
|
|
187
|
+
// --- End Directory Ensurance Function ---
|
|
188
|
+
// --- Logs Directory Handling ---
|
|
189
|
+
let validatedLogsPath = ensureDirectory(env.LOGS_DIR, projectRoot, "logs");
|
|
190
|
+
if (!validatedLogsPath) {
|
|
191
|
+
if (process.stdout.isTTY) {
|
|
192
|
+
console.warn(`Warning: Custom logs directory ('${env.LOGS_DIR}') is invalid or outside the project boundary. Falling back to default.`);
|
|
193
|
+
}
|
|
194
|
+
const defaultLogsDir = path.join(projectRoot, "logs");
|
|
195
|
+
validatedLogsPath = ensureDirectory(defaultLogsDir, projectRoot, "logs");
|
|
196
|
+
if (!validatedLogsPath) {
|
|
197
|
+
if (process.stdout.isTTY) {
|
|
198
|
+
console.warn("Warning: Default logs directory could not be created. File logging will be disabled.");
|
|
199
|
+
}
|
|
200
|
+
}
|
|
20
201
|
}
|
|
202
|
+
// --- End Logs Directory Handling ---
|
|
21
203
|
/**
|
|
22
204
|
* Main application configuration object.
|
|
23
|
-
* Aggregates settings from environment variables and package.json
|
|
205
|
+
* Aggregates settings from validated environment variables and `package.json`.
|
|
24
206
|
*/
|
|
25
207
|
export const config = {
|
|
26
|
-
/**
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
|
|
208
|
+
/** Information from package.json. */
|
|
209
|
+
pkg,
|
|
210
|
+
/** MCP server name. Env `MCP_SERVER_NAME` > `package.json` name > "git-mcp-server". */
|
|
211
|
+
mcpServerName: env.MCP_SERVER_NAME || pkg.name,
|
|
212
|
+
/** MCP server version. Env `MCP_SERVER_VERSION` > `package.json` version > "0.0.0". */
|
|
213
|
+
mcpServerVersion: env.MCP_SERVER_VERSION || pkg.version,
|
|
214
|
+
/** Logging level. From `MCP_LOG_LEVEL` env var. Default: "info". */
|
|
215
|
+
logLevel: env.MCP_LOG_LEVEL,
|
|
216
|
+
/** Absolute path to the logs directory. From `LOGS_DIR` env var. */
|
|
217
|
+
logsPath: validatedLogsPath,
|
|
218
|
+
/** Runtime environment. From `NODE_ENV` env var. Default: "development". */
|
|
219
|
+
environment: env.NODE_ENV,
|
|
220
|
+
/** MCP transport type ('stdio' or 'http'). From `MCP_TRANSPORT_TYPE` env var. Default: "stdio". */
|
|
221
|
+
mcpTransportType: env.MCP_TRANSPORT_TYPE,
|
|
222
|
+
/** MCP session mode ('stateless', 'stateful', 'auto'). From `MCP_SESSION_MODE` env var. Default: "auto". */
|
|
223
|
+
mcpSessionMode: env.MCP_SESSION_MODE,
|
|
224
|
+
/** HTTP server port (if http transport). From `MCP_HTTP_PORT` env var. Default: 3010. */
|
|
225
|
+
mcpHttpPort: env.MCP_HTTP_PORT,
|
|
226
|
+
/** HTTP server host (if http transport). From `MCP_HTTP_HOST` env var. Default: "127.0.0.1". */
|
|
227
|
+
mcpHttpHost: env.MCP_HTTP_HOST,
|
|
228
|
+
/** MCP endpoint path for HTTP transport. From `MCP_HTTP_ENDPOINT_PATH`. Default: "/mcp". */
|
|
229
|
+
mcpHttpEndpointPath: env.MCP_HTTP_ENDPOINT_PATH,
|
|
230
|
+
/** Max retries for port binding. From `MCP_HTTP_MAX_PORT_RETRIES`. Default: 15. */
|
|
231
|
+
mcpHttpMaxPortRetries: env.MCP_HTTP_MAX_PORT_RETRIES,
|
|
232
|
+
/** Delay between port binding retries. From `MCP_HTTP_PORT_RETRY_DELAY_MS`. Default: 50. */
|
|
233
|
+
mcpHttpPortRetryDelayMs: env.MCP_HTTP_PORT_RETRY_DELAY_MS,
|
|
234
|
+
/** Timeout for stale stateful sessions. From `MCP_STATEFUL_SESSION_STALE_TIMEOUT_MS`. Default: 1800000. */
|
|
235
|
+
mcpStatefulSessionStaleTimeoutMs: env.MCP_STATEFUL_SESSION_STALE_TIMEOUT_MS,
|
|
236
|
+
/** Array of allowed CORS origins (http transport). From `MCP_ALLOWED_ORIGINS` (comma-separated). */
|
|
237
|
+
mcpAllowedOrigins: env.MCP_ALLOWED_ORIGINS?.split(",")
|
|
238
|
+
.map((origin) => origin.trim())
|
|
239
|
+
.filter(Boolean),
|
|
240
|
+
/** Auth secret key (JWTs, http transport). From `MCP_AUTH_SECRET_KEY`. CRITICAL. */
|
|
241
|
+
mcpAuthSecretKey: env.MCP_AUTH_SECRET_KEY,
|
|
242
|
+
/** The authentication mode ('jwt' or 'oauth'). From `MCP_AUTH_MODE`. */
|
|
243
|
+
mcpAuthMode: env.MCP_AUTH_MODE,
|
|
244
|
+
/** OAuth 2.1 Issuer URL. From `OAUTH_ISSUER_URL`. */
|
|
245
|
+
oauthIssuerUrl: env.OAUTH_ISSUER_URL,
|
|
246
|
+
/** OAuth 2.1 JWKS URI. From `OAUTH_JWKS_URI`. */
|
|
247
|
+
oauthJwksUri: env.OAUTH_JWKS_URI,
|
|
248
|
+
/** OAuth 2.1 Audience. From `OAUTH_AUDIENCE`. */
|
|
249
|
+
oauthAudience: env.OAUTH_AUDIENCE,
|
|
250
|
+
/** Development mode client ID. From `DEV_MCP_CLIENT_ID`. */
|
|
251
|
+
devMcpClientId: env.DEV_MCP_CLIENT_ID,
|
|
252
|
+
/** Development mode scopes. From `DEV_MCP_SCOPES`. */
|
|
253
|
+
devMcpScopes: env.DEV_MCP_SCOPES?.split(",").map((s) => s.trim()),
|
|
42
254
|
/** Flag to enable GPG signing for commits made by the git_commit tool. Requires server-side GPG setup. */
|
|
43
|
-
gitSignCommits:
|
|
44
|
-
/** The authentication mode ('jwt', 'oauth', or 'none'). Defaults to 'none'. */
|
|
45
|
-
mcpAuthMode: process.env.MCP_AUTH_MODE || "none",
|
|
46
|
-
/** Secret key for signing/verifying JWTs. Required if mcpAuthMode is 'jwt'. */
|
|
47
|
-
mcpAuthSecretKey: process.env.MCP_AUTH_SECRET_KEY,
|
|
48
|
-
/** The OIDC issuer URL for OAuth token validation. Required if mcpAuthMode is 'oauth'. */
|
|
49
|
-
oauthIssuerUrl: process.env.OAUTH_ISSUER_URL,
|
|
50
|
-
/** The audience claim for OAuth token validation. Required if mcpAuthMode is 'oauth'. */
|
|
51
|
-
oauthAudience: process.env.OAUTH_AUDIENCE,
|
|
52
|
-
/** The JWKS URI for fetching public keys for OAuth. Optional, can be derived from issuer URL. */
|
|
53
|
-
oauthJwksUri: process.env.OAUTH_JWKS_URI,
|
|
255
|
+
gitSignCommits: env.GIT_SIGN_COMMITS,
|
|
54
256
|
/** Security-related configurations. */
|
|
55
257
|
security: {
|
|
56
|
-
// Placeholder for security settings
|
|
57
|
-
// Example: authRequired: process.env.AUTH_REQUIRED === 'true'
|
|
58
258
|
/** Indicates if authentication is required for server operations. */
|
|
59
|
-
authRequired:
|
|
259
|
+
authRequired: env.MCP_AUTH_MODE !== "none",
|
|
60
260
|
},
|
|
61
|
-
// Note: mcpClient configuration is now loaded separately from mcp-config.json
|
|
62
261
|
};
|
|
63
262
|
/**
|
|
64
|
-
*
|
|
65
|
-
* Exported
|
|
66
|
-
* @type {string}
|
|
263
|
+
* Configured logging level for the application.
|
|
264
|
+
* Exported for convenience.
|
|
67
265
|
*/
|
|
68
266
|
export const logLevel = config.logLevel;
|
|
69
267
|
/**
|
|
70
|
-
*
|
|
71
|
-
* Exported
|
|
72
|
-
* @type {string}
|
|
268
|
+
* Configured runtime environment ("development", "production", etc.).
|
|
269
|
+
* Exported for convenience.
|
|
73
270
|
*/
|
|
74
271
|
export const environment = config.environment;
|
|
75
|
-
// Logger initialization is now handled in the main application entry point (e.g., src/index.ts)
|
|
76
|
-
// after the config module has been fully loaded.
|
|
@@ -37,8 +37,8 @@ import { registerGitTagTool } from "./tools/gitTag/index.js";
|
|
|
37
37
|
import { registerGitWorktreeTool } from "./tools/gitWorktree/index.js";
|
|
38
38
|
import { registerGitWrapupInstructionsTool } from "./tools/gitWrapupInstructions/index.js";
|
|
39
39
|
// Import transport setup functions
|
|
40
|
-
import { startHttpTransport } from "./transports/
|
|
41
|
-
import {
|
|
40
|
+
import { startHttpTransport } from "./transports/http/index.js";
|
|
41
|
+
import { startStdioTransport } from "./transports/stdio/index.js";
|
|
42
42
|
async function createMcpServerInstance() {
|
|
43
43
|
const context = requestContextService.createRequestContext({
|
|
44
44
|
operation: "createMcpServerInstance",
|
|
@@ -121,13 +121,13 @@ async function startTransport() {
|
|
|
121
121
|
transport: transportType,
|
|
122
122
|
});
|
|
123
123
|
logger.info(`Starting transport: ${transportType}`, context);
|
|
124
|
-
const server = await createMcpServerInstance();
|
|
125
124
|
if (transportType === "http") {
|
|
126
|
-
await startHttpTransport(
|
|
127
|
-
return;
|
|
125
|
+
const { server } = await startHttpTransport(createMcpServerInstance, context);
|
|
126
|
+
return server;
|
|
128
127
|
}
|
|
129
128
|
if (transportType === "stdio") {
|
|
130
|
-
await
|
|
129
|
+
const server = await createMcpServerInstance();
|
|
130
|
+
await startStdioTransport(server, context);
|
|
131
131
|
return server;
|
|
132
132
|
}
|
|
133
133
|
logger.fatal(`Unsupported transport type configured: ${transportType}`, context);
|