@segosolutions/mcp-server 1.0.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.
@@ -0,0 +1,176 @@
1
+ /**
2
+ * CLAUDE.md File Resolver Service
3
+ *
4
+ * Handles secure file path resolution and CLAUDE.md file discovery
5
+ * with path traversal prevention and validation.
6
+ */
7
+ import fs from 'fs/promises';
8
+ import path from 'path';
9
+ // Constants
10
+ const MAX_FILE_SIZE_BYTES = 10 * 1024 * 1024; // 10MB hard limit
11
+ /**
12
+ * Resolve and read CLAUDE.md file
13
+ *
14
+ * @param options - Resolution options
15
+ * @returns Resolved file with content and metadata
16
+ * @throws Error if file not found or validation fails
17
+ *
18
+ * @example
19
+ * // Auto-detect
20
+ * const file = await resolveClaudeFile()
21
+ *
22
+ * @example
23
+ * // Explicit path
24
+ * const file = await resolveClaudeFile({ explicitPath: 'docs/CLAUDE.md' })
25
+ */
26
+ export async function resolveClaudeFile(options = {}) {
27
+ const baseDir = options.baseDir || process.cwd();
28
+ // Strategy 1: Explicit path provided
29
+ if (options.explicitPath) {
30
+ const resolvedPath = await resolveExplicitPath(options.explicitPath, baseDir);
31
+ const stats = await fs.stat(resolvedPath);
32
+ const content = await fs.readFile(resolvedPath, 'utf-8');
33
+ return {
34
+ path: resolvedPath,
35
+ content,
36
+ foundMethod: 'explicit',
37
+ sizeBytes: stats.size,
38
+ };
39
+ }
40
+ // Strategy 2: Auto-detect
41
+ const autoDetectedPath = await autoDetectClaudeFile(baseDir, options.searchDirs);
42
+ if (!autoDetectedPath) {
43
+ const searchPaths = getSearchPaths(baseDir, options.searchDirs);
44
+ throw new ClaudeFileNotFoundError(searchPaths);
45
+ }
46
+ const stats = await fs.stat(autoDetectedPath);
47
+ const content = await fs.readFile(autoDetectedPath, 'utf-8');
48
+ return {
49
+ path: autoDetectedPath,
50
+ content,
51
+ foundMethod: 'auto-detect',
52
+ sizeBytes: stats.size,
53
+ };
54
+ }
55
+ /**
56
+ * Resolve explicit path with security checks
57
+ *
58
+ * Prevents path traversal attacks by ensuring the resolved path
59
+ * stays within the allowed baseDir.
60
+ *
61
+ * @param explicitPath - User-provided file path
62
+ * @param baseDir - Base directory to restrict access to
63
+ * @returns Absolute path to file
64
+ * @throws Error if path is invalid or escapes baseDir
65
+ */
66
+ export async function resolveExplicitPath(explicitPath, baseDir) {
67
+ // Resolve to absolute path
68
+ const absolutePath = path.resolve(baseDir, explicitPath);
69
+ // Security: ensure path doesn't escape baseDir
70
+ const normalizedBase = path.normalize(baseDir);
71
+ const normalizedPath = path.normalize(absolutePath);
72
+ if (!normalizedPath.startsWith(normalizedBase)) {
73
+ throw new SecurityError(`Path "${explicitPath}" attempts to access files outside allowed directory`);
74
+ }
75
+ // Check file exists and is readable
76
+ try {
77
+ await fs.access(absolutePath, fs.constants.R_OK);
78
+ }
79
+ catch (error) {
80
+ throw new Error(`File not found or not readable: ${explicitPath}`);
81
+ }
82
+ // Check it's a file (not directory)
83
+ const stats = await fs.stat(absolutePath);
84
+ if (!stats.isFile()) {
85
+ throw new Error(`Path is not a file: ${explicitPath}`);
86
+ }
87
+ // Check file size
88
+ if (stats.size > MAX_FILE_SIZE_BYTES) {
89
+ const sizeMB = (stats.size / (1024 * 1024)).toFixed(2);
90
+ const maxMB = (MAX_FILE_SIZE_BYTES / (1024 * 1024)).toFixed(0);
91
+ throw new Error(`File size (${sizeMB}MB) exceeds maximum allowed size (${maxMB}MB)`);
92
+ }
93
+ return absolutePath;
94
+ }
95
+ /**
96
+ * Auto-detect CLAUDE.md in common locations
97
+ *
98
+ * Searches for CLAUDE.md in standard locations:
99
+ * 1. ./CLAUDE.md
100
+ * 2. ./.claude/CLAUDE.md
101
+ * 3. ./claude.md (lowercase variant)
102
+ * 4. ./.claude/claude.md
103
+ *
104
+ * @param baseDir - Base directory to search from
105
+ * @param additionalDirs - Additional directories to search
106
+ * @returns Absolute path to CLAUDE.md or null if not found
107
+ */
108
+ export async function autoDetectClaudeFile(baseDir, additionalDirs = []) {
109
+ const searchPaths = getSearchPaths(baseDir, additionalDirs);
110
+ for (const searchPath of searchPaths) {
111
+ try {
112
+ await fs.access(searchPath, fs.constants.R_OK);
113
+ const stats = await fs.stat(searchPath);
114
+ if (stats.isFile()) {
115
+ // Check file size
116
+ if (stats.size > MAX_FILE_SIZE_BYTES) {
117
+ console.warn(`Found ${searchPath} but file is too large (${(stats.size / (1024 * 1024)).toFixed(2)}MB)`);
118
+ continue;
119
+ }
120
+ return searchPath;
121
+ }
122
+ }
123
+ catch {
124
+ // File doesn't exist, continue searching
125
+ continue;
126
+ }
127
+ }
128
+ return null;
129
+ }
130
+ /**
131
+ * Get list of paths to search for CLAUDE.md
132
+ *
133
+ * @param baseDir - Base directory
134
+ * @param additionalDirs - Additional directories to search
135
+ * @returns Array of paths to search
136
+ */
137
+ function getSearchPaths(baseDir, additionalDirs = []) {
138
+ return [
139
+ path.join(baseDir, 'CLAUDE.md'),
140
+ path.join(baseDir, '.claude', 'CLAUDE.md'),
141
+ path.join(baseDir, 'claude.md'), // lowercase variant
142
+ path.join(baseDir, '.claude', 'claude.md'),
143
+ ...additionalDirs.map(dir => path.join(baseDir, dir, 'CLAUDE.md')),
144
+ ];
145
+ }
146
+ /**
147
+ * Get relative path for display purposes
148
+ *
149
+ * @param absolutePath - Absolute path to file
150
+ * @param baseDir - Base directory (defaults to CWD)
151
+ * @returns Relative path from baseDir
152
+ */
153
+ export function getDisplayPath(absolutePath, baseDir) {
154
+ const base = baseDir || process.cwd();
155
+ const relativePath = path.relative(base, absolutePath);
156
+ return relativePath || absolutePath;
157
+ }
158
+ // Custom Error Classes
159
+ export class SecurityError extends Error {
160
+ constructor(message) {
161
+ super(message);
162
+ this.name = 'SecurityError';
163
+ }
164
+ }
165
+ export class ClaudeFileNotFoundError extends Error {
166
+ constructor(searchedPaths) {
167
+ const pathList = searchedPaths.map(p => ` - ${p}`).join('\n');
168
+ super(`Could not find CLAUDE.md in the following locations:\n${pathList}\n\n` +
169
+ `Please either:\n` +
170
+ ` 1. Create a CLAUDE.md file in your project root, or\n` +
171
+ ` 2. Create one in a .claude/ subdirectory, or\n` +
172
+ ` 3. Provide explicit path using 'claudePath' parameter`);
173
+ this.name = 'ClaudeFileNotFoundError';
174
+ }
175
+ }
176
+ //# sourceMappingURL=claude-file-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-file-resolver.js","sourceRoot":"","sources":["../../src/lib/claude-file-resolver.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@segosolutions/mcp-server",
3
+ "version": "1.0.0",
4
+ "description": "MCP server for Sego PM - enables Claude to manage tasks via API",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "type": "module",
8
+ "bin": {
9
+ "sego-mcp": "dist/index.js"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "README.md"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsc",
17
+ "dev": "tsx watch src/index.ts",
18
+ "start": "node dist/index.js",
19
+ "typecheck": "tsc --noEmit",
20
+ "prepublishOnly": "npm run build"
21
+ },
22
+ "keywords": [
23
+ "mcp",
24
+ "model-context-protocol",
25
+ "claude",
26
+ "task-management",
27
+ "project-management",
28
+ "sego"
29
+ ],
30
+ "author": "Sego Solutions",
31
+ "license": "MIT",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "https://github.com/sego-solutions/sego-pm"
35
+ },
36
+ "bugs": {
37
+ "url": "https://github.com/sego-solutions/sego-pm/issues"
38
+ },
39
+ "homepage": "https://sego.pm",
40
+ "engines": {
41
+ "node": ">=18.0.0"
42
+ },
43
+ "dependencies": {
44
+ "@modelcontextprotocol/sdk": "^1.0.0",
45
+ "dotenv": "^16.4.5"
46
+ },
47
+ "devDependencies": {
48
+ "@types/node": "^20.12.0",
49
+ "tsx": "^4.10.0",
50
+ "typescript": "^5.4.0"
51
+ }
52
+ }