cache-overflow-mcp 0.3.4 → 0.3.6

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 (43) hide show
  1. package/.env.example +3 -3
  2. package/AGENTS.md +24 -3
  3. package/README.md +59 -0
  4. package/TROUBLESHOOTING.md +219 -0
  5. package/dist/cli.js +13 -1
  6. package/dist/cli.js.map +1 -1
  7. package/dist/client.d.ts.map +1 -1
  8. package/dist/client.js +65 -10
  9. package/dist/client.js.map +1 -1
  10. package/dist/config.d.ts +3 -0
  11. package/dist/config.d.ts.map +1 -1
  12. package/dist/config.js +5 -0
  13. package/dist/config.js.map +1 -1
  14. package/dist/logger.d.ts +16 -0
  15. package/dist/logger.d.ts.map +1 -0
  16. package/dist/logger.js +127 -0
  17. package/dist/logger.js.map +1 -0
  18. package/dist/server.d.ts.map +1 -1
  19. package/dist/server.js +50 -7
  20. package/dist/server.js.map +1 -1
  21. package/dist/testing/mock-data.js +40 -40
  22. package/dist/ui/verification-dialog.d.ts.map +1 -1
  23. package/dist/ui/verification-dialog.js +307 -268
  24. package/dist/ui/verification-dialog.js.map +1 -1
  25. package/package.json +3 -2
  26. package/scripts/view-logs.js +125 -0
  27. package/src/cli.ts +23 -10
  28. package/src/client.test.ts +116 -116
  29. package/src/client.ts +138 -76
  30. package/src/config.ts +14 -9
  31. package/src/index.ts +3 -3
  32. package/src/logger.ts +150 -0
  33. package/src/server.ts +49 -7
  34. package/src/testing/mock-data.ts +142 -142
  35. package/src/testing/mock-server.ts +176 -176
  36. package/src/tools/index.ts +23 -23
  37. package/src/types.ts +39 -39
  38. package/src/ui/verification-dialog.ts +382 -342
  39. package/tsconfig.json +20 -20
  40. package/dist/tools/get-balance.d.ts +0 -3
  41. package/dist/tools/get-balance.d.ts.map +0 -1
  42. package/dist/tools/get-balance.js +0 -34
  43. package/dist/tools/get-balance.js.map +0 -1
package/.env.example CHANGED
@@ -1,3 +1,3 @@
1
- CACHE_OVERFLOW_API_URL=https://api.cache-overflow.dev
2
- CACHE_OVERFLOW_TOKEN=
3
- CACHE_OVERFLOW_TIMEOUT=30000
1
+ CACHE_OVERFLOW_API_URL=https://api.cache-overflow.dev
2
+ CACHE_OVERFLOW_TOKEN=
3
+ CACHE_OVERFLOW_TIMEOUT=30000
package/AGENTS.md CHANGED
@@ -47,7 +47,8 @@ cache-overflow-mcp/
47
47
  │ ├── index.ts # Public exports for library usage
48
48
  │ ├── server.ts # MCP server setup, tool/prompt registration
49
49
  │ ├── client.ts # HTTP client for backend API
50
- │ ├── config.ts # Environment config (API URL, auth token)
50
+ │ ├── config.ts # Environment config (API URL, auth token, log dir)
51
+ │ ├── logger.ts # Error logging system with automatic sanitization
51
52
  │ ├── types.ts # TypeScript type definitions
52
53
  │ ├── tools/
53
54
  │ │ ├── index.ts # Tool registry and ToolDefinition interface
@@ -88,9 +89,17 @@ cache-overflow-mcp/
88
89
  - `submitFeedback(solutionId, isUseful)` - POST /solutions/:id/feedback
89
90
 
90
91
  - **`src/config.ts`**: Reads environment variables:
91
- - `CACHE_OVERFLOW_API_URL` (default: https://api.cache-overflow.dev)
92
+ - `CACHE_OVERFLOW_URL` (default: https://cache-overflow.onrender.com/api)
92
93
  - `CACHE_OVERFLOW_TOKEN` (required for auth)
93
94
  - `CACHE_OVERFLOW_TIMEOUT` (default: 30000ms)
95
+ - `CACHE_OVERFLOW_LOG_DIR` (default: ~/.cache-overflow or temp directory)
96
+
97
+ - **`src/logger.ts`**: Comprehensive logging system that:
98
+ - Writes errors and events to `cache-overflow-mcp.log`
99
+ - Automatically sanitizes sensitive data (tokens, passwords)
100
+ - Rotates log file when it exceeds 5MB
101
+ - Includes timestamps, error stacks, and context
102
+ - Logs startup info, tool execution, API errors, network failures
94
103
 
95
104
  - **`src/types.ts`**: Core types:
96
105
  - `Solution` - Full solution with body, price, verification state, votes
@@ -230,6 +239,18 @@ npm run lint # Run ESLint (needs eslint.config.js - not configured)
230
239
  - ESLint not configured (package.json has eslint but no config file for v9)
231
240
  - No integration tests for the MCP server itself (only client unit tests)
232
241
 
242
+ ## Error Logging
243
+
244
+ All errors and important events are logged to `~/.cache-overflow/cache-overflow-mcp.log` by default. The logger:
245
+
246
+ - Automatically sanitizes sensitive data (tokens, passwords, secrets)
247
+ - Rotates when file exceeds 5MB (keeps last 1000 entries)
248
+ - Logs JSON lines for easy parsing
249
+ - Captures: startup info, tool execution, API errors, network failures, verification dialog events
250
+ - Falls back to temp directory if home directory is not writable
251
+
252
+ Customers can send this log file when reporting issues for debugging.
253
+
233
254
  ## Version
234
255
 
235
- Current version: **0.3.0** (see package.json and server.ts)
256
+ Current version: **0.3.4** (see package.json)
package/README.md CHANGED
@@ -59,6 +59,65 @@ Add to `.cursor/mcp.json` in your project:
59
59
 
60
60
  The API key is only shown once at creation, so save it securely.
61
61
 
62
+ ## Error Logging & Debugging
63
+
64
+ cache.overflow MCP server automatically logs errors and important events to help with debugging. When you encounter issues, the log file contains detailed diagnostic information.
65
+
66
+ ### Log File Location
67
+
68
+ By default, logs are written to:
69
+ - **macOS/Linux**: `~/.cache-overflow/cache-overflow-mcp.log`
70
+ - **Windows**: `%USERPROFILE%\.cache-overflow\cache-overflow-mcp.log`
71
+
72
+ If the home directory is not writable, logs fallback to:
73
+ - **All platforms**: `[temp-directory]/cache-overflow/cache-overflow-mcp.log`
74
+
75
+ ### Custom Log Location
76
+
77
+ You can customize the log directory by setting the `CACHE_OVERFLOW_LOG_DIR` environment variable:
78
+
79
+ ```json
80
+ {
81
+ "mcpServers": {
82
+ "cache-overflow": {
83
+ "command": "cache-overflow-mcp",
84
+ "env": {
85
+ "CACHE_OVERFLOW_TOKEN": "your-api-key-here",
86
+ "CACHE_OVERFLOW_LOG_DIR": "/custom/path/to/logs"
87
+ }
88
+ }
89
+ }
90
+ }
91
+ ```
92
+
93
+ ### What Gets Logged
94
+
95
+ The log file includes:
96
+ - Server startup information (version, Node.js version, platform, API URL)
97
+ - Tool execution events (find_solution, unlock_solution, etc.)
98
+ - API request errors with status codes and error messages
99
+ - Network errors (connection failures, timeouts)
100
+ - Verification dialog events
101
+ - Full error stack traces for debugging
102
+
103
+ ### Log Privacy
104
+
105
+ **Sensitive data is automatically redacted:**
106
+ - Authentication tokens are replaced with `[REDACTED]`
107
+ - Passwords, secrets, and other sensitive fields are sanitized
108
+ - Solution content and user queries are NOT logged to protect privacy
109
+
110
+ ### Reporting Issues
111
+
112
+ When reporting bugs or requesting support:
113
+
114
+ 1. Reproduce the error
115
+ 2. Locate your log file (see locations above)
116
+ 3. Share the relevant portion of the log file with support
117
+ 4. The log file is structured as JSON lines for easy parsing
118
+
119
+ The log file is automatically rotated when it exceeds 5MB, keeping the last 1000 log entries.
120
+
62
121
  ## Links
63
122
 
64
123
  - Dashboard: [app.cache-overflow.dev](https://app.cache-overflow.dev)
@@ -0,0 +1,219 @@
1
+ # Troubleshooting cache.overflow MCP Server
2
+
3
+ This guide helps you troubleshoot issues with the cache.overflow MCP server and explains how to use the error logs for debugging.
4
+
5
+ ## Quick Diagnostics
6
+
7
+ ### 1. Check if the server is running
8
+
9
+ If the MCP server isn't working, check your MCP client's logs:
10
+
11
+ **Claude Desktop:**
12
+ - macOS: `~/Library/Logs/Claude/mcp*.log`
13
+ - Windows: `%APPDATA%\Claude\logs\mcp*.log`
14
+
15
+ **Cursor:**
16
+ - Check the Output panel in Cursor (View → Output → MCP)
17
+
18
+ ### 2. Locate the cache.overflow log file
19
+
20
+ The cache.overflow server maintains its own detailed log file:
21
+
22
+ **Default locations:**
23
+ - macOS/Linux: `~/.cache-overflow/cache-overflow-mcp.log`
24
+ - Windows: `%USERPROFILE%\.cache-overflow\cache-overflow-mcp.log`
25
+
26
+ **Fallback location (if home directory is not writable):**
27
+ - All platforms: `[temp-directory]/cache-overflow/cache-overflow-mcp.log`
28
+ - macOS/Linux: `/tmp/cache-overflow/cache-overflow-mcp.log`
29
+ - Windows: `%TEMP%\cache-overflow\cache-overflow-mcp.log`
30
+
31
+ ### 3. View the log file
32
+
33
+ **macOS/Linux:**
34
+ ```bash
35
+ # View the entire log
36
+ cat ~/.cache-overflow/cache-overflow-mcp.log
37
+
38
+ # View the last 50 lines
39
+ tail -n 50 ~/.cache-overflow/cache-overflow-mcp.log
40
+
41
+ # Follow the log in real-time
42
+ tail -f ~/.cache-overflow/cache-overflow-mcp.log
43
+ ```
44
+
45
+ **Windows (PowerShell):**
46
+ ```powershell
47
+ # View the entire log
48
+ Get-Content $env:USERPROFILE\.cache-overflow\cache-overflow-mcp.log
49
+
50
+ # View the last 50 lines
51
+ Get-Content $env:USERPROFILE\.cache-overflow\cache-overflow-mcp.log -Tail 50
52
+
53
+ # Follow the log in real-time
54
+ Get-Content $env:USERPROFILE\.cache-overflow\cache-overflow-mcp.log -Wait
55
+ ```
56
+
57
+ **Windows (Command Prompt):**
58
+ ```cmd
59
+ # View the entire log
60
+ type %USERPROFILE%\.cache-overflow\cache-overflow-mcp.log
61
+
62
+ # View the last few lines
63
+ more %USERPROFILE%\.cache-overflow\cache-overflow-mcp.log
64
+ ```
65
+
66
+ ## Understanding the Log File
67
+
68
+ The log file is structured as JSON lines (one JSON object per line). Each log entry includes:
69
+
70
+ ```json
71
+ {
72
+ "timestamp": "2026-02-01T10:30:45.123Z",
73
+ "level": "ERROR",
74
+ "message": "API request failed",
75
+ "context": {
76
+ "method": "GET",
77
+ "path": "/solutions/search",
78
+ "statusCode": 401,
79
+ "errorMessage": "Invalid token",
80
+ "errorType": "API_ERROR"
81
+ },
82
+ "error": {
83
+ "name": "Error",
84
+ "message": "Unauthorized",
85
+ "stack": "Error: Unauthorized\n at ..."
86
+ }
87
+ }
88
+ ```
89
+
90
+ ### Log Levels
91
+
92
+ - **ERROR**: Critical errors that prevent operations from completing
93
+ - **WARN**: Warnings about unexpected but non-fatal situations
94
+ - **INFO**: Informational messages about normal operations
95
+
96
+ ### Error Types
97
+
98
+ Common `errorType` values and what they mean:
99
+
100
+ | Error Type | Description | Common Causes |
101
+ |------------|-------------|---------------|
102
+ | `STARTUP_FAILURE` | Server failed to start | Missing dependencies, port conflicts |
103
+ | `CONNECTION_FAILURE` | MCP transport connection failed | Communication issues with MCP client |
104
+ | `API_ERROR` | Backend API returned an error | Invalid token, rate limiting, server issues |
105
+ | `NETWORK_ERROR` | Network request failed | No internet, firewall, DNS issues |
106
+ | `TOOL_EXECUTION_FAILURE` | A tool failed to execute | Invalid parameters, API errors |
107
+ | `VERIFICATION_DIALOG_ERROR` | Verification UI failed | Port conflicts, browser issues |
108
+ | `BROWSER_OPEN_FAILURE` | Could not open browser for verification | No default browser, permissions |
109
+
110
+ ## Common Issues
111
+
112
+ ### Issue: "Invalid token" or 401 errors
113
+
114
+ **Symptoms:**
115
+ - Log shows `API_ERROR` with `statusCode: 401`
116
+ - Error message: "Invalid token" or "Unauthorized"
117
+
118
+ **Solution:**
119
+ 1. Verify your API token is correct in the MCP configuration
120
+ 2. Ensure the token starts with `co_`
121
+ 3. Check if the token has expired (tokens don't expire, but can be revoked)
122
+ 4. Generate a new token at [app.cache-overflow.dev](https://app.cache-overflow.dev)
123
+
124
+ ### Issue: "Network error" or timeout
125
+
126
+ **Symptoms:**
127
+ - Log shows `NETWORK_ERROR`
128
+ - Fetch or connection failures
129
+
130
+ **Solution:**
131
+ 1. Check your internet connection
132
+ 2. Verify you can access https://cache-overflow.onrender.com/api
133
+ 3. Check firewall settings
134
+ 4. Try increasing the timeout:
135
+ ```json
136
+ "env": {
137
+ "CACHE_OVERFLOW_TOKEN": "your-token",
138
+ "CACHE_OVERFLOW_TIMEOUT": "60000"
139
+ }
140
+ ```
141
+
142
+ ### Issue: Verification dialog doesn't open
143
+
144
+ **Symptoms:**
145
+ - Log shows `BROWSER_OPEN_FAILURE`
146
+ - Browser window doesn't appear
147
+
148
+ **Solution:**
149
+ 1. Check if your system has a default browser set
150
+ 2. Ensure no firewall is blocking localhost connections
151
+ 3. Try manually opening the URL from the log (looks like `http://localhost:XXXXX`)
152
+
153
+ ### Issue: Server not starting
154
+
155
+ **Symptoms:**
156
+ - Log shows `STARTUP_FAILURE`
157
+ - MCP client reports server crashed
158
+
159
+ **Solution:**
160
+ 1. Check Node.js version: `node --version` (requires >= 18.0.0)
161
+ 2. Reinstall the package: `npm install -g cache-overflow-mcp`
162
+ 3. Clear npm cache: `npm cache clean --force`
163
+ 4. Check for conflicting global packages
164
+
165
+ ## Reporting Bugs
166
+
167
+ When reporting issues to support, please include:
168
+
169
+ 1. **Your configuration** (with token redacted):
170
+ ```json
171
+ {
172
+ "mcpServers": {
173
+ "cache-overflow": {
174
+ "command": "cache-overflow-mcp",
175
+ "env": {
176
+ "CACHE_OVERFLOW_TOKEN": "[REDACTED]"
177
+ }
178
+ }
179
+ }
180
+ }
181
+ ```
182
+
183
+ 2. **Relevant log entries**: Copy the last 20-50 lines from your log file showing the error
184
+
185
+ 3. **Environment information** (from the startup log entry):
186
+ - cache.overflow version
187
+ - Node.js version
188
+ - Platform and architecture
189
+
190
+ 4. **Steps to reproduce**: What were you doing when the error occurred?
191
+
192
+ ## Privacy & Security
193
+
194
+ The log file automatically sanitizes sensitive information:
195
+
196
+ - ✅ **Logged**: Error types, stack traces, API endpoints, tool names
197
+ - ❌ **Not logged**: API tokens, passwords, secrets, solution content, user queries
198
+
199
+ You can safely share your log file with support without exposing credentials.
200
+
201
+ ## Custom Log Location
202
+
203
+ To store logs in a custom directory, set the `CACHE_OVERFLOW_LOG_DIR` environment variable:
204
+
205
+ ```json
206
+ {
207
+ "mcpServers": {
208
+ "cache-overflow": {
209
+ "command": "cache-overflow-mcp",
210
+ "env": {
211
+ "CACHE_OVERFLOW_TOKEN": "your-token",
212
+ "CACHE_OVERFLOW_LOG_DIR": "/custom/path/to/logs"
213
+ }
214
+ }
215
+ }
216
+ }
217
+ ```
218
+
219
+ The directory will be created automatically if it doesn't exist.
package/dist/cli.js CHANGED
@@ -1,8 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
  import { CacheOverflowServer } from './server.js';
3
+ import { logger } from './logger.js';
3
4
  async function main() {
5
+ // Log startup information
6
+ logger.logStartup();
7
+ logger.info(`Log file location: ${logger.getLogFilePath()}`);
4
8
  const server = new CacheOverflowServer();
5
9
  await server.start();
6
10
  }
7
- main().catch(console.error);
11
+ main().catch((error) => {
12
+ logger.error('Fatal error during server startup', error, {
13
+ errorType: 'STARTUP_FAILURE',
14
+ });
15
+ console.error('Fatal error:', error);
16
+ console.error(`\nError details have been logged to: ${logger.getLogFilePath()}`);
17
+ console.error('Please send this log file when reporting issues.');
18
+ process.exit(1);
19
+ });
8
20
  //# sourceMappingURL=cli.js.map
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAElD,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,IAAI,mBAAmB,EAAE,CAAC;IACzC,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;AACvB,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,KAAK,UAAU,IAAI;IACjB,0BAA0B;IAC1B,MAAM,CAAC,UAAU,EAAE,CAAC;IACpB,MAAM,CAAC,IAAI,CAAC,sBAAsB,MAAM,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;IAE7D,MAAM,MAAM,GAAG,IAAI,mBAAmB,EAAE,CAAC;IACzC,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;AACvB,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,MAAM,CAAC,KAAK,CAAC,mCAAmC,EAAE,KAAK,EAAE;QACvD,SAAS,EAAE,iBAAiB;KAC7B,CAAC,CAAC;IACH,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IACrC,OAAO,CAAC,KAAK,CAAC,wCAAwC,MAAM,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;IACjF,OAAO,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC;IAClE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAGvE,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAqB;gBAE1B,MAAM,CAAC,EAAE,MAAM;YAKb,OAAO;IA4Bf,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,kBAAkB,EAAE,CAAC,CAAC;IAIvE,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IAIlE,eAAe,CACnB,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IAO3B,kBAAkB,CACtB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,OAAO,GACd,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IAMvB,cAAc,CAClB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,OAAO,GAChB,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;CAK9B"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAIvE,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAqB;gBAE1B,MAAM,CAAC,EAAE,MAAM;YAKb,OAAO;IAyEf,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,kBAAkB,EAAE,CAAC,CAAC;IAoBvE,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IAIlE,eAAe,CACnB,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IAO3B,kBAAkB,CACtB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,OAAO,GACd,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IAMvB,cAAc,CAClB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,OAAO,GAChB,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;CAK9B"}
package/dist/client.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { config } from './config.js';
2
+ import { logger } from './logger.js';
2
3
  export class CacheOverflowClient {
3
4
  apiUrl;
4
5
  authToken;
@@ -13,19 +14,73 @@ export class CacheOverflowClient {
13
14
  if (this.authToken) {
14
15
  headers['Authorization'] = `Bearer ${this.authToken}`;
15
16
  }
16
- const response = await fetch(`${this.apiUrl}${path}`, {
17
- method,
18
- headers,
19
- body: body ? JSON.stringify(body) : undefined,
20
- });
21
- const data = (await response.json());
22
- if (!response.ok) {
23
- return { success: false, error: data.error ?? 'Unknown error' };
17
+ const url = `${this.apiUrl}${path}`;
18
+ try {
19
+ const response = await fetch(url, {
20
+ method,
21
+ headers,
22
+ body: body ? JSON.stringify(body) : undefined,
23
+ });
24
+ // Read response as text first, then try to parse as JSON
25
+ const textResponse = await response.text();
26
+ const contentType = response.headers.get('content-type');
27
+ let data;
28
+ try {
29
+ data = JSON.parse(textResponse);
30
+ }
31
+ catch (jsonError) {
32
+ // If JSON parsing fails, log and return the text as error
33
+ logger.error('API returned non-JSON response', jsonError, {
34
+ method,
35
+ path,
36
+ statusCode: response.status,
37
+ contentType,
38
+ responseText: textResponse.substring(0, 200), // Log first 200 chars
39
+ errorType: 'INVALID_JSON_RESPONSE',
40
+ });
41
+ // Return the text as an error message
42
+ return {
43
+ success: false,
44
+ error: textResponse || 'Invalid response from server'
45
+ };
46
+ }
47
+ if (!response.ok) {
48
+ const errorMessage = data.error ?? 'Unknown error';
49
+ logger.error('API request failed', undefined, {
50
+ method,
51
+ path,
52
+ statusCode: response.status,
53
+ errorMessage,
54
+ errorType: 'API_ERROR',
55
+ });
56
+ return { success: false, error: errorMessage };
57
+ }
58
+ return { success: true, data: data };
59
+ }
60
+ catch (error) {
61
+ logger.error('Network or fetch error during API request', error, {
62
+ method,
63
+ path,
64
+ url,
65
+ errorType: 'NETWORK_ERROR',
66
+ });
67
+ // Re-throw network errors so they can be handled by the caller
68
+ throw error;
24
69
  }
25
- return { success: true, data: data };
26
70
  }
27
71
  async findSolution(query) {
28
- return this.request('GET', `/solutions/search?query=${encodeURIComponent(query)}`);
72
+ const result = await this.request('GET', `/solutions/search?query=${encodeURIComponent(query)}`);
73
+ // Map API response (uses 'id') to our interface (expects 'solution_id')
74
+ if (result.success) {
75
+ const mappedData = result.data.map(solution => ({
76
+ solution_id: solution.id,
77
+ query_title: solution.query_title,
78
+ solution_body: solution.solution_body,
79
+ human_verification_required: solution.human_verification_required,
80
+ }));
81
+ return { success: true, data: mappedData };
82
+ }
83
+ return result;
29
84
  }
30
85
  async unlockSolution(solutionId) {
31
86
  return this.request('POST', `/solutions/${solutionId}/unlock`);
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,MAAM,OAAO,mBAAmB;IACtB,MAAM,CAAS;IACf,SAAS,CAAqB;IAEtC,YAAY,MAAe;QACzB,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC;QACvC,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;IACrC,CAAC;IAEO,KAAK,CAAC,OAAO,CACnB,MAAc,EACd,IAAY,EACZ,IAAc;QAEd,MAAM,OAAO,GAA2B;YACtC,cAAc,EAAE,kBAAkB;SACnC,CAAC;QAEF,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,OAAO,CAAC,eAAe,CAAC,GAAG,UAAU,IAAI,CAAC,SAAS,EAAE,CAAC;QACxD,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,EAAE,EAAE;YACpD,MAAM;YACN,OAAO;YACP,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;SAC9C,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA4B,CAAC;QAEhE,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAG,IAAI,CAAC,KAAgB,IAAI,eAAe,EAAE,CAAC;QAC9E,CAAC;QAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAS,EAAE,CAAC;IAC5C,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,KAAa;QAC9B,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,2BAA2B,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACrF,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,UAAkB;QACrC,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,cAAc,UAAU,SAAS,CAAC,CAAC;IACjE,CAAC;IAED,KAAK,CAAC,eAAe,CACnB,UAAkB,EAClB,YAAoB;QAEpB,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,YAAY,EAAE;YACxC,WAAW,EAAE,UAAU;YACvB,aAAa,EAAE,YAAY;SAC5B,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,kBAAkB,CACtB,UAAkB,EAClB,MAAe;QAEf,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,cAAc,UAAU,SAAS,EAAE;YAC7D,OAAO,EAAE,MAAM;SAChB,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,cAAc,CAClB,UAAkB,EAClB,QAAiB;QAEjB,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,cAAc,UAAU,WAAW,EAAE;YAC/D,SAAS,EAAE,QAAQ;SACpB,CAAC,CAAC;IACL,CAAC;CACF"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/config.d.ts CHANGED
@@ -6,5 +6,8 @@ export declare const config: {
6
6
  auth: {
7
7
  token: string | undefined;
8
8
  };
9
+ logging: {
10
+ logDir: string | undefined;
11
+ };
9
12
  };
10
13
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,MAAM;;;;;;;;CAQlB,CAAC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,MAAM;;;;;;;;;;;CAalB,CAAC"}
package/dist/config.js CHANGED
@@ -6,5 +6,10 @@ export const config = {
6
6
  auth: {
7
7
  token: process.env.CACHE_OVERFLOW_TOKEN,
8
8
  },
9
+ logging: {
10
+ // Directory where log files will be written
11
+ // Default: ~/.cache-overflow/ (or temp directory if home is not writable)
12
+ logDir: process.env.CACHE_OVERFLOW_LOG_DIR,
13
+ },
9
14
  };
10
15
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,GAAG,EAAE;QACH,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,yCAAyC;QAChF,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,OAAO,CAAC;KACjE;IACD,IAAI,EAAE;QACJ,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB;KACxC;CACF,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,GAAG,EAAE;QACH,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,yCAAyC;QAChF,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,OAAO,CAAC;KACjE;IACD,IAAI,EAAE;QACJ,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB;KACxC;IACD,OAAO,EAAE;QACP,4CAA4C;QAC5C,0EAA0E;QAC1E,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,sBAAsB;KAC3C;CACF,CAAC"}
@@ -0,0 +1,16 @@
1
+ declare class Logger {
2
+ private logFilePath;
3
+ private maxLogSizeBytes;
4
+ constructor();
5
+ private rotateLogIfNeeded;
6
+ private sanitizeContext;
7
+ private writeLog;
8
+ error(message: string, error?: Error, context?: Record<string, unknown>): void;
9
+ warn(message: string, context?: Record<string, unknown>): void;
10
+ info(message: string, context?: Record<string, unknown>): void;
11
+ getLogFilePath(): string;
12
+ logStartup(): void;
13
+ }
14
+ export declare const logger: Logger;
15
+ export {};
16
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAgBA,cAAM,MAAM;IACV,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,eAAe,CAAmB;;IAwB1C,OAAO,CAAC,iBAAiB;IAiBzB,OAAO,CAAC,eAAe;IAoBvB,OAAO,CAAC,QAAQ;IAYhB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAmB9E,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAW9D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAW9D,cAAc,IAAI,MAAM;IAIxB,UAAU,IAAI,IAAI;CAUnB;AAGD,eAAO,MAAM,MAAM,QAAe,CAAC"}
package/dist/logger.js ADDED
@@ -0,0 +1,127 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import * as os from 'os';
4
+ class Logger {
5
+ logFilePath;
6
+ maxLogSizeBytes = 5 * 1024 * 1024; // 5MB max log file size
7
+ constructor() {
8
+ // Determine log file location
9
+ const logDir = process.env.CACHE_OVERFLOW_LOG_DIR ?? path.join(os.homedir(), '.cache-overflow');
10
+ // Ensure log directory exists
11
+ if (!fs.existsSync(logDir)) {
12
+ try {
13
+ fs.mkdirSync(logDir, { recursive: true });
14
+ }
15
+ catch (err) {
16
+ // Fallback to temp directory if home directory is not writable
17
+ const tempLogDir = path.join(os.tmpdir(), 'cache-overflow');
18
+ if (!fs.existsSync(tempLogDir)) {
19
+ fs.mkdirSync(tempLogDir, { recursive: true });
20
+ }
21
+ this.logFilePath = path.join(tempLogDir, 'cache-overflow-mcp.log');
22
+ return;
23
+ }
24
+ }
25
+ this.logFilePath = path.join(logDir, 'cache-overflow-mcp.log');
26
+ }
27
+ rotateLogIfNeeded() {
28
+ try {
29
+ if (fs.existsSync(this.logFilePath)) {
30
+ const stats = fs.statSync(this.logFilePath);
31
+ if (stats.size >= this.maxLogSizeBytes) {
32
+ // Rotate: keep the last 1MB of the file
33
+ const content = fs.readFileSync(this.logFilePath, 'utf-8');
34
+ const lines = content.split('\n');
35
+ const keptLines = lines.slice(-1000); // Keep last 1000 lines
36
+ fs.writeFileSync(this.logFilePath, keptLines.join('\n') + '\n');
37
+ }
38
+ }
39
+ }
40
+ catch (err) {
41
+ // Ignore rotation errors - don't want logging to break the app
42
+ }
43
+ }
44
+ sanitizeContext(context) {
45
+ if (!context)
46
+ return undefined;
47
+ const sanitized = {};
48
+ for (const [key, value] of Object.entries(context)) {
49
+ // Sanitize sensitive fields
50
+ if (key.toLowerCase().includes('token') ||
51
+ key.toLowerCase().includes('password') ||
52
+ key.toLowerCase().includes('secret') ||
53
+ key.toLowerCase().includes('auth')) {
54
+ sanitized[key] = '[REDACTED]';
55
+ }
56
+ else if (typeof value === 'object' && value !== null) {
57
+ sanitized[key] = this.sanitizeContext(value);
58
+ }
59
+ else {
60
+ sanitized[key] = value;
61
+ }
62
+ }
63
+ return sanitized;
64
+ }
65
+ writeLog(entry) {
66
+ try {
67
+ this.rotateLogIfNeeded();
68
+ const logLine = JSON.stringify(entry) + '\n';
69
+ fs.appendFileSync(this.logFilePath, logLine);
70
+ }
71
+ catch (err) {
72
+ // If we can't write to log file, write to stderr as fallback
73
+ console.error('Failed to write to log file:', err);
74
+ console.error('Original log entry:', entry);
75
+ }
76
+ }
77
+ error(message, error, context) {
78
+ const entry = {
79
+ timestamp: new Date().toISOString(),
80
+ level: 'ERROR',
81
+ message,
82
+ context: this.sanitizeContext(context),
83
+ };
84
+ if (error) {
85
+ entry.error = {
86
+ name: error.name,
87
+ message: error.message,
88
+ stack: error.stack,
89
+ };
90
+ }
91
+ this.writeLog(entry);
92
+ }
93
+ warn(message, context) {
94
+ const entry = {
95
+ timestamp: new Date().toISOString(),
96
+ level: 'WARN',
97
+ message,
98
+ context: this.sanitizeContext(context),
99
+ };
100
+ this.writeLog(entry);
101
+ }
102
+ info(message, context) {
103
+ const entry = {
104
+ timestamp: new Date().toISOString(),
105
+ level: 'INFO',
106
+ message,
107
+ context: this.sanitizeContext(context),
108
+ };
109
+ this.writeLog(entry);
110
+ }
111
+ getLogFilePath() {
112
+ return this.logFilePath;
113
+ }
114
+ logStartup() {
115
+ this.info('MCP Server starting', {
116
+ version: '0.3.5',
117
+ nodeVersion: process.version,
118
+ platform: process.platform,
119
+ arch: process.arch,
120
+ apiUrl: process.env.CACHE_OVERFLOW_URL ?? 'https://cache-overflow.onrender.com/api',
121
+ hasAuthToken: !!process.env.CACHE_OVERFLOW_TOKEN,
122
+ });
123
+ }
124
+ }
125
+ // Singleton instance
126
+ export const logger = new Logger();
127
+ //# sourceMappingURL=logger.js.map