mcp-docs-service 0.2.13 → 0.2.15

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/CHANGELOG.md CHANGED
@@ -2,7 +2,21 @@
2
2
 
3
3
  All notable changes to the MCP Docs Service will be documented in this file.
4
4
 
5
- ## [0.2.13] - 2024-05-16
5
+ ## [0.2.15] - 2024-05-16
6
+
7
+ ### Added
8
+
9
+ - Added `mcp-docs-npx` standalone wrapper for more reliable npx execution
10
+ - Enhanced debugging capabilities with detailed logging in all wrapper scripts
11
+ - Improved error handling and recovery in wrapper scripts
12
+
13
+ ### Fixed
14
+
15
+ - Fixed issue with file access when running via npx
16
+ - Improved robustness of path resolution in wrapper scripts
17
+ - Enhanced error handling for edge cases
18
+
19
+ ## [0.2.14] - 2024-05-16
6
20
 
7
21
  ### Added
8
22
 
@@ -16,6 +30,12 @@ All notable changes to the MCP Docs Service will be documented in this file.
16
30
  - Improved robustness of docs directory resolution
17
31
  - Enhanced error handling for Cursor integration
18
32
 
33
+ ## [0.2.13] - 2024-05-16
34
+
35
+ ### Fixed
36
+
37
+ - Fixed packaging issue with wrapper scripts
38
+
19
39
  ## [0.2.12] - 2024-05-15
20
40
 
21
41
  ### Fixed
@@ -0,0 +1,199 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Cursor Wrapper for MCP Docs Service
5
+ *
6
+ * This script is designed to be used as the entry point for Cursor's MCP integration.
7
+ * It handles the arguments properly and forwards them to the actual MCP Docs Service.
8
+ */
9
+
10
+ import fs from "fs";
11
+ import path from "path";
12
+ import { spawn } from "child_process";
13
+ import { fileURLToPath } from "url";
14
+
15
+ // Wrap everything in a try/catch to catch any initialization errors
16
+ try {
17
+ // Get the current directory
18
+ const __filename = fileURLToPath(import.meta.url);
19
+ const __dirname = path.dirname(__filename);
20
+
21
+ // Create a log file for debugging
22
+ const logFile = path.join(process.cwd(), "cursor-debug.log");
23
+ fs.writeFileSync(
24
+ logFile,
25
+ `Cursor wrapper called at ${new Date().toISOString()}\n`
26
+ );
27
+ fs.appendFileSync(logFile, `Arguments: ${JSON.stringify(process.argv)}\n`);
28
+ fs.appendFileSync(logFile, `Working directory: ${process.cwd()}\n`);
29
+ fs.appendFileSync(logFile, `Script directory: ${__dirname}\n`);
30
+ fs.appendFileSync(logFile, `Package structure:\n`);
31
+
32
+ // List files in the package directory to debug
33
+ try {
34
+ const files = fs.readdirSync(__dirname);
35
+ fs.appendFileSync(
36
+ logFile,
37
+ `Files in package dir: ${JSON.stringify(files)}\n`
38
+ );
39
+
40
+ // Check if dist directory exists
41
+ const distDir = path.join(__dirname, "dist");
42
+ if (fs.existsSync(distDir)) {
43
+ const distFiles = fs.readdirSync(distDir);
44
+ fs.appendFileSync(
45
+ logFile,
46
+ `Files in dist dir: ${JSON.stringify(distFiles)}\n`
47
+ );
48
+
49
+ // Check if cli directory exists
50
+ const cliDir = path.join(distDir, "cli");
51
+ if (fs.existsSync(cliDir)) {
52
+ const cliFiles = fs.readdirSync(cliDir);
53
+ fs.appendFileSync(
54
+ logFile,
55
+ `Files in cli dir: ${JSON.stringify(cliFiles)}\n`
56
+ );
57
+ } else {
58
+ fs.appendFileSync(logFile, `CLI directory not found: ${cliDir}\n`);
59
+ }
60
+ } else {
61
+ fs.appendFileSync(logFile, `Dist directory not found: ${distDir}\n`);
62
+ }
63
+ } catch (err) {
64
+ fs.appendFileSync(logFile, `Error listing files: ${err.message}\n`);
65
+ }
66
+
67
+ // Extract the docs directory from the arguments
68
+ // The docs directory is expected to be the last argument
69
+ let docsDir = path.join(process.cwd(), "docs");
70
+ const args = process.argv.slice(2);
71
+
72
+ fs.appendFileSync(logFile, `Processing args: ${JSON.stringify(args)}\n`);
73
+
74
+ if (args.length > 0) {
75
+ // Check if --docs-dir flag is used
76
+ const docsDirIndex = args.indexOf("--docs-dir");
77
+ if (docsDirIndex !== -1 && docsDirIndex + 1 < args.length) {
78
+ docsDir = args[docsDirIndex + 1];
79
+ fs.appendFileSync(logFile, `Found --docs-dir flag, using: ${docsDir}\n`);
80
+ } else {
81
+ // Otherwise, use the last argument if it looks like a path
82
+ const lastArg = args[args.length - 1];
83
+ if (!lastArg.startsWith("-")) {
84
+ docsDir = lastArg;
85
+ fs.appendFileSync(logFile, `Using last arg as docs dir: ${docsDir}\n`);
86
+ }
87
+ }
88
+ } else {
89
+ fs.appendFileSync(
90
+ logFile,
91
+ `No args provided, using default docs dir: ${docsDir}\n`
92
+ );
93
+ }
94
+
95
+ // Resolve the docs directory to an absolute path
96
+ docsDir = path.resolve(docsDir);
97
+ fs.appendFileSync(logFile, `Using docs directory: ${docsDir}\n`);
98
+
99
+ // Ensure the docs directory exists
100
+ if (!fs.existsSync(docsDir)) {
101
+ fs.appendFileSync(logFile, `Creating docs directory: ${docsDir}\n`);
102
+ try {
103
+ fs.mkdirSync(docsDir, { recursive: true });
104
+ fs.appendFileSync(logFile, `Successfully created docs directory\n`);
105
+ } catch (error) {
106
+ fs.appendFileSync(logFile, `Error creating docs directory: ${error}\n`);
107
+ console.error(`Error creating docs directory: ${error}`);
108
+ process.exit(1);
109
+ }
110
+ }
111
+
112
+ // Set up the arguments for the actual service
113
+ const serviceArgs = ["--docs-dir", docsDir];
114
+ fs.appendFileSync(
115
+ logFile,
116
+ `Service arguments: ${JSON.stringify(serviceArgs)}\n`
117
+ );
118
+
119
+ // Find the bin.js file
120
+ let binPath = path.join(__dirname, "dist", "cli", "bin.js");
121
+
122
+ // Check if the bin.js file exists
123
+ if (!fs.existsSync(binPath)) {
124
+ fs.appendFileSync(
125
+ logFile,
126
+ `bin.js not found at ${binPath}, searching...\n`
127
+ );
128
+
129
+ // Try to find bin.js in node_modules
130
+ const nodeModulesPath = path.join(
131
+ process.cwd(),
132
+ "node_modules",
133
+ "mcp-docs-service"
134
+ );
135
+ if (fs.existsSync(nodeModulesPath)) {
136
+ const potentialBinPath = path.join(
137
+ nodeModulesPath,
138
+ "dist",
139
+ "cli",
140
+ "bin.js"
141
+ );
142
+ if (fs.existsSync(potentialBinPath)) {
143
+ binPath = potentialBinPath;
144
+ fs.appendFileSync(
145
+ logFile,
146
+ `Found bin.js in node_modules: ${binPath}\n`
147
+ );
148
+ }
149
+ }
150
+ }
151
+
152
+ fs.appendFileSync(
153
+ logFile,
154
+ `Running service: ${binPath} ${serviceArgs.join(" ")}\n`
155
+ );
156
+
157
+ // Check if the bin file exists before trying to run it
158
+ if (!fs.existsSync(binPath)) {
159
+ fs.appendFileSync(logFile, `ERROR: bin.js not found at ${binPath}\n`);
160
+ console.error(
161
+ `ERROR: Could not find the MCP Docs Service binary at ${binPath}`
162
+ );
163
+ process.exit(1);
164
+ }
165
+
166
+ // Run the actual service
167
+ const child = spawn("node", [binPath, ...serviceArgs], {
168
+ stdio: "inherit",
169
+ env: { ...process.env, MCP_CURSOR_INTEGRATION: "true" },
170
+ });
171
+
172
+ child.on("exit", (code) => {
173
+ fs.appendFileSync(logFile, `Child process exited with code ${code}\n`);
174
+ process.exit(code);
175
+ });
176
+
177
+ // Handle errors
178
+ child.on("error", (err) => {
179
+ fs.appendFileSync(
180
+ logFile,
181
+ `Error spawning child process: ${err.message}\n`
182
+ );
183
+ console.error(`Error spawning MCP Docs Service: ${err.message}`);
184
+ process.exit(1);
185
+ });
186
+ } catch (error) {
187
+ // Write to a fallback log file in case the main one couldn't be created
188
+ try {
189
+ fs.writeFileSync(
190
+ path.join(process.cwd(), "cursor-error.log"),
191
+ `Fatal error in cursor-wrapper.js: ${error.message}\n${error.stack}\n`
192
+ );
193
+ } catch (e) {
194
+ // Last resort, just log to console
195
+ console.error(`Fatal error in cursor-wrapper.js: ${error.message}`);
196
+ console.error(error.stack);
197
+ }
198
+ process.exit(1);
199
+ }
@@ -0,0 +1,208 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * MCP Inspector Wrapper
5
+ *
6
+ * This script is a wrapper for the MCP Docs Service that handles the MCP Inspector's argument format.
7
+ * It extracts the docs directory from the arguments and passes it to the MCP Docs Service.
8
+ */
9
+
10
+ import path from "path";
11
+ import { spawn } from "child_process";
12
+ import fs from "fs";
13
+ import { fileURLToPath } from "url";
14
+
15
+ // Wrap everything in a try/catch to catch any initialization errors
16
+ try {
17
+ // Get the current directory
18
+ const __filename = fileURLToPath(import.meta.url);
19
+ const __dirname = path.dirname(__filename);
20
+
21
+ // Redirect logs to stderr instead of stdout to avoid interfering with JSON communication
22
+ const log = (...args) => {
23
+ console.error(...args);
24
+ };
25
+
26
+ // Create a log file for debugging
27
+ const logFile = path.join(process.cwd(), "inspector-debug.log");
28
+ fs.writeFileSync(
29
+ logFile,
30
+ `MCP Inspector Wrapper called at ${new Date().toISOString()}\n`
31
+ );
32
+
33
+ // Get all arguments
34
+ const args = process.argv.slice(2);
35
+ fs.appendFileSync(
36
+ logFile,
37
+ `MCP Inspector Wrapper - Arguments: ${JSON.stringify(args)}\n`
38
+ );
39
+ fs.appendFileSync(logFile, `Working directory: ${process.cwd()}\n`);
40
+ fs.appendFileSync(logFile, `Script directory: ${__dirname}\n`);
41
+ log("MCP Inspector Wrapper - Arguments:", args);
42
+
43
+ // List files in the package directory to debug
44
+ try {
45
+ const files = fs.readdirSync(__dirname);
46
+ fs.appendFileSync(
47
+ logFile,
48
+ `Files in package dir: ${JSON.stringify(files)}\n`
49
+ );
50
+
51
+ // Check if dist directory exists
52
+ const distDir = path.join(__dirname, "dist");
53
+ if (fs.existsSync(distDir)) {
54
+ const distFiles = fs.readdirSync(distDir);
55
+ fs.appendFileSync(
56
+ logFile,
57
+ `Files in dist dir: ${JSON.stringify(distFiles)}\n`
58
+ );
59
+
60
+ // Check if cli directory exists
61
+ const cliDir = path.join(distDir, "cli");
62
+ if (fs.existsSync(cliDir)) {
63
+ const cliFiles = fs.readdirSync(cliDir);
64
+ fs.appendFileSync(
65
+ logFile,
66
+ `Files in cli dir: ${JSON.stringify(cliFiles)}\n`
67
+ );
68
+ } else {
69
+ fs.appendFileSync(logFile, `CLI directory not found: ${cliDir}\n`);
70
+ }
71
+ } else {
72
+ fs.appendFileSync(logFile, `Dist directory not found: ${distDir}\n`);
73
+ }
74
+ } catch (err) {
75
+ fs.appendFileSync(logFile, `Error listing files: ${err.message}\n`);
76
+ }
77
+
78
+ // Find the docs directory in the arguments
79
+ let docsDir = path.join(process.cwd(), "docs");
80
+ let foundDocsDir = false;
81
+
82
+ // Look for a path ending with /docs
83
+ for (const arg of args) {
84
+ if (arg.endsWith("/docs") || arg.includes("/docs ")) {
85
+ const potentialPath = arg.split(" ")[0];
86
+ log("Found potential docs path:", potentialPath);
87
+ fs.appendFileSync(
88
+ logFile,
89
+ `Found potential docs path: ${potentialPath}\n`
90
+ );
91
+
92
+ if (fs.existsSync(potentialPath)) {
93
+ docsDir = potentialPath;
94
+ foundDocsDir = true;
95
+ log("Using docs directory:", docsDir);
96
+ fs.appendFileSync(logFile, `Using docs directory: ${docsDir}\n`);
97
+ break;
98
+ }
99
+ }
100
+ }
101
+
102
+ if (!foundDocsDir) {
103
+ log("No docs directory found in arguments, using default:", docsDir);
104
+ fs.appendFileSync(
105
+ logFile,
106
+ `No docs directory found in arguments, using default: ${docsDir}\n`
107
+ );
108
+
109
+ // Ensure the docs directory exists
110
+ if (!fs.existsSync(docsDir)) {
111
+ fs.appendFileSync(logFile, `Creating docs directory: ${docsDir}\n`);
112
+ try {
113
+ fs.mkdirSync(docsDir, { recursive: true });
114
+ fs.appendFileSync(logFile, `Successfully created docs directory\n`);
115
+ } catch (error) {
116
+ fs.appendFileSync(logFile, `Error creating docs directory: ${error}\n`);
117
+ log(`Error creating docs directory: ${error}`);
118
+ process.exit(1);
119
+ }
120
+ }
121
+ }
122
+
123
+ // Find the bin.js file
124
+ let binPath = path.join(__dirname, "dist", "cli", "bin.js");
125
+
126
+ // Check if the bin.js file exists
127
+ if (!fs.existsSync(binPath)) {
128
+ fs.appendFileSync(
129
+ logFile,
130
+ `bin.js not found at ${binPath}, searching...\n`
131
+ );
132
+
133
+ // Try to find bin.js in node_modules
134
+ const nodeModulesPath = path.join(
135
+ process.cwd(),
136
+ "node_modules",
137
+ "mcp-docs-service"
138
+ );
139
+ if (fs.existsSync(nodeModulesPath)) {
140
+ const potentialBinPath = path.join(
141
+ nodeModulesPath,
142
+ "dist",
143
+ "cli",
144
+ "bin.js"
145
+ );
146
+ if (fs.existsSync(potentialBinPath)) {
147
+ binPath = potentialBinPath;
148
+ fs.appendFileSync(
149
+ logFile,
150
+ `Found bin.js in node_modules: ${binPath}\n`
151
+ );
152
+ }
153
+ }
154
+ }
155
+
156
+ log("Spawning MCP Docs Service:", binPath, "--docs-dir", docsDir);
157
+ fs.appendFileSync(
158
+ logFile,
159
+ `Spawning MCP Docs Service: ${binPath} --docs-dir ${docsDir}\n`
160
+ );
161
+
162
+ // Check if the bin file exists before trying to run it
163
+ if (!fs.existsSync(binPath)) {
164
+ fs.appendFileSync(logFile, `ERROR: bin.js not found at ${binPath}\n`);
165
+ log(`ERROR: Could not find the MCP Docs Service binary at ${binPath}`);
166
+ process.exit(1);
167
+ }
168
+
169
+ // Set environment variable to indicate we're running under MCP Inspector
170
+ const env = { ...process.env, MCP_INSPECTOR: "true" };
171
+
172
+ // Spawn the process with stdio inheritance
173
+ // This ensures that the JSON communication between the MCP Inspector and the service
174
+ // is not interrupted by our logs
175
+ const child = spawn("node", [binPath, "--docs-dir", docsDir], {
176
+ stdio: "inherit",
177
+ env,
178
+ });
179
+
180
+ // Forward exit code
181
+ child.on("exit", (code) => {
182
+ fs.appendFileSync(logFile, `Child process exited with code ${code}\n`);
183
+ process.exit(code);
184
+ });
185
+
186
+ // Handle errors
187
+ child.on("error", (err) => {
188
+ fs.appendFileSync(
189
+ logFile,
190
+ `Error spawning child process: ${err.message}\n`
191
+ );
192
+ log(`Error spawning MCP Docs Service: ${err.message}`);
193
+ process.exit(1);
194
+ });
195
+ } catch (error) {
196
+ // Write to a fallback log file in case the main one couldn't be created
197
+ try {
198
+ fs.writeFileSync(
199
+ path.join(process.cwd(), "inspector-error.log"),
200
+ `Fatal error in mcp-inspector-wrapper.js: ${error.message}\n${error.stack}\n`
201
+ );
202
+ } catch (e) {
203
+ // Last resort, just log to console
204
+ console.error(`Fatal error in mcp-inspector-wrapper.js: ${error.message}`);
205
+ console.error(error.stack);
206
+ }
207
+ process.exit(1);
208
+ }
package/npx-wrapper.js ADDED
@@ -0,0 +1,119 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * NPX Wrapper for MCP Docs Service
5
+ *
6
+ * This script is a standalone wrapper that can be used directly with npx.
7
+ * It doesn't require any additional files from the package and will download
8
+ * and run the MCP Docs Service directly.
9
+ */
10
+
11
+ import fs from "fs";
12
+ import path from "path";
13
+ import { spawn } from "child_process";
14
+ import { fileURLToPath } from "url";
15
+
16
+ // Wrap everything in a try/catch to catch any initialization errors
17
+ try {
18
+ // Create a log file for debugging
19
+ const logFile = path.join(process.cwd(), "npx-debug.log");
20
+ fs.writeFileSync(
21
+ logFile,
22
+ `NPX wrapper called at ${new Date().toISOString()}\n`
23
+ );
24
+ fs.appendFileSync(logFile, `Arguments: ${JSON.stringify(process.argv)}\n`);
25
+ fs.appendFileSync(logFile, `Working directory: ${process.cwd()}\n`);
26
+
27
+ // Get the docs directory from arguments or use default
28
+ let docsDir = path.join(process.cwd(), "docs");
29
+ const args = process.argv.slice(2);
30
+
31
+ fs.appendFileSync(logFile, `Processing args: ${JSON.stringify(args)}\n`);
32
+
33
+ if (args.length > 0) {
34
+ // Check if --docs-dir flag is used
35
+ const docsDirIndex = args.indexOf("--docs-dir");
36
+ if (docsDirIndex !== -1 && docsDirIndex + 1 < args.length) {
37
+ docsDir = args[docsDirIndex + 1];
38
+ fs.appendFileSync(logFile, `Found --docs-dir flag, using: ${docsDir}\n`);
39
+ } else {
40
+ // Otherwise, use the last argument if it looks like a path
41
+ const lastArg = args[args.length - 1];
42
+ if (!lastArg.startsWith("-")) {
43
+ docsDir = lastArg;
44
+ fs.appendFileSync(logFile, `Using last arg as docs dir: ${docsDir}\n`);
45
+ }
46
+ }
47
+ } else {
48
+ fs.appendFileSync(
49
+ logFile,
50
+ `No args provided, using default docs dir: ${docsDir}\n`
51
+ );
52
+ }
53
+
54
+ // Resolve the docs directory to an absolute path
55
+ docsDir = path.resolve(docsDir);
56
+ fs.appendFileSync(logFile, `Using docs directory: ${docsDir}\n`);
57
+
58
+ // Ensure the docs directory exists
59
+ if (!fs.existsSync(docsDir)) {
60
+ fs.appendFileSync(logFile, `Creating docs directory: ${docsDir}\n`);
61
+ try {
62
+ fs.mkdirSync(docsDir, { recursive: true });
63
+ fs.appendFileSync(logFile, `Successfully created docs directory\n`);
64
+ } catch (error) {
65
+ fs.appendFileSync(logFile, `Error creating docs directory: ${error}\n`);
66
+ console.error(`Error creating docs directory: ${error}`);
67
+ process.exit(1);
68
+ }
69
+ }
70
+
71
+ // Install the MCP Docs Service if not already installed
72
+ const packageName = "mcp-docs-service";
73
+ fs.appendFileSync(logFile, `Checking if ${packageName} is installed...\n`);
74
+
75
+ // Run the MCP Docs Service
76
+ fs.appendFileSync(
77
+ logFile,
78
+ `Running MCP Docs Service with docs dir: ${docsDir}\n`
79
+ );
80
+
81
+ // Use npx to run the service directly
82
+ const npxArgs = ["-y", packageName, "--docs-dir", docsDir];
83
+ fs.appendFileSync(
84
+ logFile,
85
+ `Running npx with args: ${JSON.stringify(npxArgs)}\n`
86
+ );
87
+
88
+ const child = spawn("npx", npxArgs, {
89
+ stdio: "inherit",
90
+ env: { ...process.env, MCP_STANDALONE_WRAPPER: "true" },
91
+ });
92
+
93
+ child.on("exit", (code) => {
94
+ fs.appendFileSync(logFile, `Child process exited with code ${code}\n`);
95
+ process.exit(code);
96
+ });
97
+
98
+ child.on("error", (err) => {
99
+ fs.appendFileSync(
100
+ logFile,
101
+ `Error spawning child process: ${err.message}\n`
102
+ );
103
+ console.error(`Error running MCP Docs Service: ${err.message}`);
104
+ process.exit(1);
105
+ });
106
+ } catch (error) {
107
+ // Write to a fallback log file in case the main one couldn't be created
108
+ try {
109
+ fs.writeFileSync(
110
+ path.join(process.cwd(), "npx-error.log"),
111
+ `Fatal error in npx-wrapper.js: ${error.message}\n${error.stack}\n`
112
+ );
113
+ } catch (e) {
114
+ // Last resort, just log to console
115
+ console.error(`Fatal error in npx-wrapper.js: ${error.message}`);
116
+ console.error(error.stack);
117
+ }
118
+ process.exit(1);
119
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-docs-service",
3
- "version": "0.2.13",
3
+ "version": "0.2.15",
4
4
  "description": "MCP Documentation Management Service - A Model Context Protocol implementation for documentation management",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -8,7 +8,8 @@
8
8
  "bin": {
9
9
  "mcp-docs-service": "dist/cli/bin.js",
10
10
  "mcp-docs-inspector": "mcp-inspector-wrapper.js",
11
- "mcp-docs-cursor": "cursor-wrapper.js"
11
+ "mcp-docs-cursor": "cursor-wrapper.js",
12
+ "mcp-docs-npx": "npx-wrapper.js"
12
13
  },
13
14
  "scripts": {
14
15
  "build": "tsc",
@@ -35,6 +36,7 @@
35
36
  "@modelcontextprotocol/sdk": "^0.5.0",
36
37
  "diff": "^7.0.0",
37
38
  "glob": "^11.0.1",
39
+ "gray-matter": "^4.0.3",
38
40
  "js-yaml": "^4.1.0",
39
41
  "minimatch": "^10.0.1",
40
42
  "zod-to-json-schema": "^3.23.5"
@@ -52,7 +54,8 @@
52
54
  "CHANGELOG.md",
53
55
  "LICENSE",
54
56
  "mcp-inspector-wrapper.js",
55
- "cursor-wrapper.js"
57
+ "cursor-wrapper.js",
58
+ "npx-wrapper.js"
56
59
  ],
57
60
  "engines": {
58
61
  "node": ">=18"