@graphty/remote-logger 1.1.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/README.md +318 -10
  2. package/dist/client/RemoteLogClient.d.ts +2 -0
  3. package/dist/client/RemoteLogClient.d.ts.map +1 -1
  4. package/dist/client/RemoteLogClient.js +35 -4
  5. package/dist/client/RemoteLogClient.js.map +1 -1
  6. package/dist/client/types.d.ts +13 -0
  7. package/dist/client/types.d.ts.map +1 -1
  8. package/dist/mcp/index.d.ts +9 -0
  9. package/dist/mcp/index.d.ts.map +1 -0
  10. package/dist/mcp/index.js +9 -0
  11. package/dist/mcp/index.js.map +1 -0
  12. package/dist/mcp/mcp-server.d.ts +32 -0
  13. package/dist/mcp/mcp-server.d.ts.map +1 -0
  14. package/dist/mcp/mcp-server.js +270 -0
  15. package/dist/mcp/mcp-server.js.map +1 -0
  16. package/dist/mcp/tools/index.d.ts +14 -0
  17. package/dist/mcp/tools/index.d.ts.map +1 -0
  18. package/dist/mcp/tools/index.js +14 -0
  19. package/dist/mcp/tools/index.js.map +1 -0
  20. package/dist/mcp/tools/logs-clear.d.ts +76 -0
  21. package/dist/mcp/tools/logs-clear.d.ts.map +1 -0
  22. package/dist/mcp/tools/logs-clear.js +58 -0
  23. package/dist/mcp/tools/logs-clear.js.map +1 -0
  24. package/dist/mcp/tools/logs-get-all.d.ts +60 -0
  25. package/dist/mcp/tools/logs-get-all.d.ts.map +1 -0
  26. package/dist/mcp/tools/logs-get-all.js +50 -0
  27. package/dist/mcp/tools/logs-get-all.js.map +1 -0
  28. package/dist/mcp/tools/logs-get-errors.d.ts +65 -0
  29. package/dist/mcp/tools/logs-get-errors.d.ts.map +1 -0
  30. package/dist/mcp/tools/logs-get-errors.js +46 -0
  31. package/dist/mcp/tools/logs-get-errors.js.map +1 -0
  32. package/dist/mcp/tools/logs-get-file-path.d.ts +75 -0
  33. package/dist/mcp/tools/logs-get-file-path.d.ts.map +1 -0
  34. package/dist/mcp/tools/logs-get-file-path.js +90 -0
  35. package/dist/mcp/tools/logs-get-file-path.js.map +1 -0
  36. package/dist/mcp/tools/logs-get-recent.d.ts +89 -0
  37. package/dist/mcp/tools/logs-get-recent.d.ts.map +1 -0
  38. package/dist/mcp/tools/logs-get-recent.js +74 -0
  39. package/dist/mcp/tools/logs-get-recent.js.map +1 -0
  40. package/dist/mcp/tools/logs-list-sessions.d.ts +64 -0
  41. package/dist/mcp/tools/logs-list-sessions.d.ts.map +1 -0
  42. package/dist/mcp/tools/logs-list-sessions.js +48 -0
  43. package/dist/mcp/tools/logs-list-sessions.js.map +1 -0
  44. package/dist/mcp/tools/logs-receive.d.ts +150 -0
  45. package/dist/mcp/tools/logs-receive.d.ts.map +1 -0
  46. package/dist/mcp/tools/logs-receive.js +68 -0
  47. package/dist/mcp/tools/logs-receive.js.map +1 -0
  48. package/dist/mcp/tools/logs-search.d.ts +91 -0
  49. package/dist/mcp/tools/logs-search.d.ts.map +1 -0
  50. package/dist/mcp/tools/logs-search.js +68 -0
  51. package/dist/mcp/tools/logs-search.js.map +1 -0
  52. package/dist/mcp/tools/logs-status.d.ts +45 -0
  53. package/dist/mcp/tools/logs-status.d.ts.map +1 -0
  54. package/dist/mcp/tools/logs-status.js +45 -0
  55. package/dist/mcp/tools/logs-status.js.map +1 -0
  56. package/dist/server/dual-server.d.ts +76 -0
  57. package/dist/server/dual-server.d.ts.map +1 -0
  58. package/dist/server/dual-server.js +214 -0
  59. package/dist/server/dual-server.js.map +1 -0
  60. package/dist/server/index.d.ts +5 -1
  61. package/dist/server/index.d.ts.map +1 -1
  62. package/dist/server/index.js +5 -1
  63. package/dist/server/index.js.map +1 -1
  64. package/dist/server/jsonl-writer.d.ts +93 -0
  65. package/dist/server/jsonl-writer.d.ts.map +1 -0
  66. package/dist/server/jsonl-writer.js +205 -0
  67. package/dist/server/jsonl-writer.js.map +1 -0
  68. package/dist/server/log-server.d.ts +62 -11
  69. package/dist/server/log-server.d.ts.map +1 -1
  70. package/dist/server/log-server.js +237 -101
  71. package/dist/server/log-server.js.map +1 -1
  72. package/dist/server/log-storage.d.ts +301 -0
  73. package/dist/server/log-storage.d.ts.map +1 -0
  74. package/dist/server/log-storage.js +408 -0
  75. package/dist/server/log-storage.js.map +1 -0
  76. package/dist/server/marker-utils.d.ts +69 -0
  77. package/dist/server/marker-utils.d.ts.map +1 -0
  78. package/dist/server/marker-utils.js +118 -0
  79. package/dist/server/marker-utils.js.map +1 -0
  80. package/dist/vite/index.d.ts +8 -0
  81. package/dist/vite/index.d.ts.map +1 -0
  82. package/dist/vite/index.js +8 -0
  83. package/dist/vite/index.js.map +1 -0
  84. package/dist/vite/plugin.d.ts +42 -0
  85. package/dist/vite/plugin.d.ts.map +1 -0
  86. package/dist/vite/plugin.js +46 -0
  87. package/dist/vite/plugin.js.map +1 -0
  88. package/package.json +12 -2
  89. package/src/client/RemoteLogClient.ts +52 -4
  90. package/src/client/types.ts +13 -0
  91. package/src/mcp/index.ts +25 -0
  92. package/src/mcp/mcp-server.ts +364 -0
  93. package/src/mcp/tools/index.ts +69 -0
  94. package/src/mcp/tools/logs-clear.ts +86 -0
  95. package/src/mcp/tools/logs-get-all.ts +78 -0
  96. package/src/mcp/tools/logs-get-errors.ts +71 -0
  97. package/src/mcp/tools/logs-get-file-path.ts +121 -0
  98. package/src/mcp/tools/logs-get-recent.ts +104 -0
  99. package/src/mcp/tools/logs-list-sessions.ts +71 -0
  100. package/src/mcp/tools/logs-receive.ts +96 -0
  101. package/src/mcp/tools/logs-search.ts +95 -0
  102. package/src/mcp/tools/logs-status.ts +69 -0
  103. package/src/server/dual-server.ts +308 -0
  104. package/src/server/index.ts +37 -0
  105. package/src/server/jsonl-writer.ts +277 -0
  106. package/src/server/log-server.ts +311 -119
  107. package/src/server/log-storage.ts +651 -0
  108. package/src/server/marker-utils.ts +144 -0
  109. package/src/vite/index.ts +8 -0
  110. package/src/vite/plugin.ts +59 -0
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Vite plugin for automatic project marker injection.
3
+ *
4
+ * This plugin injects global variables that the RemoteLogClient
5
+ * can use to automatically identify which project/worktree logs
6
+ * are coming from.
7
+ * @module vite/plugin
8
+ */
9
+ /**
10
+ * Vite plugin configuration object.
11
+ * Matches Vite's Plugin type but without requiring the full vite dependency.
12
+ */
13
+ interface VitePlugin {
14
+ name: string;
15
+ config: () => {
16
+ define: Record<string, string>;
17
+ };
18
+ }
19
+ /**
20
+ * Creates a Vite plugin that injects project marker globals.
21
+ *
22
+ * The plugin detects the current working directory and:
23
+ * 1. Extracts a project marker (worktree name or directory basename)
24
+ * 2. Injects `__REMOTE_LOG_PROJECT_MARKER__` with the marker
25
+ * 3. Injects `__REMOTE_LOG_WORKTREE_PATH__` with the full path
26
+ *
27
+ * These globals are automatically read by RemoteLogClient when no
28
+ * explicit projectMarker/worktreePath options are provided.
29
+ * @returns A Vite plugin configuration object
30
+ * @example
31
+ * ```typescript
32
+ * // vite.config.ts
33
+ * import { remoteLoggerPlugin } from "@graphty/remote-logger/vite";
34
+ *
35
+ * export default defineConfig({
36
+ * plugins: [remoteLoggerPlugin()]
37
+ * });
38
+ * ```
39
+ */
40
+ export declare function remoteLoggerPlugin(): VitePlugin;
41
+ export {};
42
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/vite/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH;;;GAGG;AACH,UAAU,UAAU;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM;QACV,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KAClC,CAAC;CACL;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,kBAAkB,IAAI,UAAU,CAe/C"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Vite plugin for automatic project marker injection.
3
+ *
4
+ * This plugin injects global variables that the RemoteLogClient
5
+ * can use to automatically identify which project/worktree logs
6
+ * are coming from.
7
+ * @module vite/plugin
8
+ */
9
+ import { extractMarkerFromPath } from "../server/marker-utils.js";
10
+ /**
11
+ * Creates a Vite plugin that injects project marker globals.
12
+ *
13
+ * The plugin detects the current working directory and:
14
+ * 1. Extracts a project marker (worktree name or directory basename)
15
+ * 2. Injects `__REMOTE_LOG_PROJECT_MARKER__` with the marker
16
+ * 3. Injects `__REMOTE_LOG_WORKTREE_PATH__` with the full path
17
+ *
18
+ * These globals are automatically read by RemoteLogClient when no
19
+ * explicit projectMarker/worktreePath options are provided.
20
+ * @returns A Vite plugin configuration object
21
+ * @example
22
+ * ```typescript
23
+ * // vite.config.ts
24
+ * import { remoteLoggerPlugin } from "@graphty/remote-logger/vite";
25
+ *
26
+ * export default defineConfig({
27
+ * plugins: [remoteLoggerPlugin()]
28
+ * });
29
+ * ```
30
+ */
31
+ export function remoteLoggerPlugin() {
32
+ return {
33
+ name: "remote-logger",
34
+ config() {
35
+ const cwd = process.cwd();
36
+ const marker = extractMarkerFromPath(cwd);
37
+ return {
38
+ define: {
39
+ __REMOTE_LOG_PROJECT_MARKER__: JSON.stringify(marker),
40
+ __REMOTE_LOG_WORKTREE_PATH__: JSON.stringify(cwd),
41
+ },
42
+ };
43
+ },
44
+ };
45
+ }
46
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/vite/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAalE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,kBAAkB;IAC9B,OAAO;QACH,IAAI,EAAE,eAAe;QACrB,MAAM;YACF,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;YAC1B,MAAM,MAAM,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC;YAE1C,OAAO;gBACH,MAAM,EAAE;oBACJ,6BAA6B,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;oBACrD,4BAA4B,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC;iBACpD;aACJ,CAAC;QACN,CAAC;KACJ,CAAC;AACN,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphty/remote-logger",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "Remote logging client and server for browser debugging",
5
5
  "author": "Adam Powers <apowers@ato.ms>",
6
6
  "main": "dist/index.js",
@@ -21,6 +21,14 @@
21
21
  "./ui": {
22
22
  "import": "./dist/ui/index.js",
23
23
  "types": "./dist/ui/index.d.ts"
24
+ },
25
+ "./mcp": {
26
+ "import": "./dist/mcp/index.js",
27
+ "types": "./dist/mcp/index.d.ts"
28
+ },
29
+ "./vite": {
30
+ "import": "./dist/vite/index.js",
31
+ "types": "./dist/vite/index.d.ts"
24
32
  }
25
33
  },
26
34
  "types": "dist/index.d.ts",
@@ -60,7 +68,9 @@
60
68
  "node": ">=18.19.0"
61
69
  },
62
70
  "dependencies": {
63
- "selfsigned": "^2.4.1"
71
+ "@modelcontextprotocol/sdk": "^1.0.0",
72
+ "selfsigned": "^2.4.1",
73
+ "zod": "^3.25.0"
64
74
  },
65
75
  "devDependencies": {
66
76
  "@types/node": "^20.0.0",
@@ -6,6 +6,33 @@
6
6
 
7
7
  import type { LogEntry, RemoteLogClientOptions, ThrottlePattern } from "./types.js";
8
8
 
9
+ /**
10
+ * Global variables that may be injected by the Vite plugin.
11
+ * These provide automatic project marker detection.
12
+ */
13
+ declare const __REMOTE_LOG_PROJECT_MARKER__: string | undefined;
14
+ declare const __REMOTE_LOG_WORKTREE_PATH__: string | undefined;
15
+
16
+ /**
17
+ * Safely read a global variable that may or may not be defined.
18
+ * @param name - Name of the global variable
19
+ * @returns The value of the global variable, or undefined if not defined
20
+ */
21
+ function getGlobalValue(name: "__REMOTE_LOG_PROJECT_MARKER__" | "__REMOTE_LOG_WORKTREE_PATH__"): string | undefined {
22
+ try {
23
+ if (name === "__REMOTE_LOG_PROJECT_MARKER__") {
24
+ return typeof __REMOTE_LOG_PROJECT_MARKER__ !== "undefined" ? __REMOTE_LOG_PROJECT_MARKER__ : undefined;
25
+ }
26
+ if (name === "__REMOTE_LOG_WORKTREE_PATH__") {
27
+ return typeof __REMOTE_LOG_WORKTREE_PATH__ !== "undefined" ? __REMOTE_LOG_WORKTREE_PATH__ : undefined;
28
+ }
29
+ } catch {
30
+ // ReferenceError if the global is not defined at all
31
+ return undefined;
32
+ }
33
+ return undefined;
34
+ }
35
+
9
36
  /** Default configuration values */
10
37
  const DEFAULT_BATCH_INTERVAL_MS = 1000;
11
38
  const DEFAULT_MAX_RETRIES = 3;
@@ -57,6 +84,8 @@ export class RemoteLogClient {
57
84
  private readonly maxRetries: number;
58
85
  private readonly retryDelayMs: number;
59
86
  private readonly throttlePatterns: ThrottlePattern[];
87
+ private readonly projectMarker: string | undefined;
88
+ private readonly worktreePath: string | undefined;
60
89
 
61
90
  private pendingLogs: LogEntry[] = [];
62
91
  private batchTimer: ReturnType<typeof setTimeout> | null = null;
@@ -77,6 +106,10 @@ export class RemoteLogClient {
77
106
  this.maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
78
107
  this.retryDelayMs = options.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS;
79
108
  this.throttlePatterns = options.throttlePatterns ?? [];
109
+
110
+ // Priority: explicit option > global variable
111
+ this.projectMarker = options.projectMarker ?? getGlobalValue("__REMOTE_LOG_PROJECT_MARKER__");
112
+ this.worktreePath = options.worktreePath ?? getGlobalValue("__REMOTE_LOG_WORKTREE_PATH__");
80
113
  }
81
114
 
82
115
  /**
@@ -199,15 +232,30 @@ export class RemoteLogClient {
199
232
  * @throws Error if the request fails
200
233
  */
201
234
  private async sendRequest(logs: LogEntry[]): Promise<void> {
235
+ const requestBody: {
236
+ sessionId: string;
237
+ logs: LogEntry[];
238
+ projectMarker?: string;
239
+ worktreePath?: string;
240
+ } = {
241
+ sessionId: this.sessionId,
242
+ logs,
243
+ };
244
+
245
+ // Only include these fields if they have values
246
+ if (this.projectMarker !== undefined) {
247
+ requestBody.projectMarker = this.projectMarker;
248
+ }
249
+ if (this.worktreePath !== undefined) {
250
+ requestBody.worktreePath = this.worktreePath;
251
+ }
252
+
202
253
  const response = await fetch(`${this.serverUrl}/log`, {
203
254
  method: "POST",
204
255
  headers: {
205
256
  "Content-Type": "application/json",
206
257
  },
207
- body: JSON.stringify({
208
- sessionId: this.sessionId,
209
- logs,
210
- }),
258
+ body: JSON.stringify(requestBody),
211
259
  });
212
260
 
213
261
  if (!response.ok) {
@@ -46,4 +46,17 @@ export interface RemoteLogClientOptions {
46
46
  * Messages matching a pattern will only be sent once per the configured interval.
47
47
  */
48
48
  throttlePatterns?: ThrottlePattern[];
49
+ /**
50
+ * Project marker to identify logs from this project.
51
+ * If not provided, the client will attempt to read from the
52
+ * __REMOTE_LOG_PROJECT_MARKER__ global variable (injected by Vite plugin).
53
+ */
54
+ projectMarker?: string;
55
+ /**
56
+ * Full path to the worktree or project directory.
57
+ * Used for debugging and log organization.
58
+ * If not provided, the client will attempt to read from the
59
+ * __REMOTE_LOG_WORKTREE_PATH__ global variable (injected by Vite plugin).
60
+ */
61
+ worktreePath?: string;
49
62
  }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * MCP server module exports.
3
+ *
4
+ * Provides Model Context Protocol interface for log queries.
5
+ * @module mcp
6
+ */
7
+
8
+ export { createMcpServer, getToolNames, startMcpServer } from "./mcp-server.js";
9
+ export {
10
+ logsGetRecentHandler,
11
+ type LogsGetRecentInput,
12
+ logsGetRecentInputSchema,
13
+ type LogsGetRecentOutput,
14
+ logsGetRecentTool,
15
+ logsListSessionsHandler,
16
+ type LogsListSessionsInput,
17
+ logsListSessionsInputSchema,
18
+ type LogsListSessionsOutput,
19
+ logsListSessionsTool,
20
+ logsStatusHandler,
21
+ type LogsStatusInput,
22
+ logsStatusInputSchema,
23
+ type LogsStatusOutput,
24
+ logsStatusTool,
25
+ } from "./tools/index.js";
@@ -0,0 +1,364 @@
1
+ /**
2
+ * MCP Server for remote logging.
3
+ *
4
+ * Provides an MCP interface for Claude Code to query logs from browser
5
+ * applications. Uses STDIO transport for communication.
6
+ * @module mcp/mcp-server
7
+ */
8
+
9
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
10
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
11
+
12
+ import type { LogStorage } from "../server/log-storage.js";
13
+ import {
14
+ logsClearHandler,
15
+ type LogsClearInput,
16
+ logsClearInputSchema,
17
+ logsClearTool,
18
+ logsGetAllHandler,
19
+ type LogsGetAllInput,
20
+ logsGetAllInputSchema,
21
+ logsGetAllTool,
22
+ logsGetErrorsHandler,
23
+ type LogsGetErrorsInput,
24
+ logsGetErrorsInputSchema,
25
+ logsGetErrorsTool,
26
+ logsGetFilePathHandler,
27
+ type LogsGetFilePathInput,
28
+ logsGetFilePathInputSchema,
29
+ logsGetFilePathTool,
30
+ logsGetRecentHandler,
31
+ type LogsGetRecentInput,
32
+ logsGetRecentInputSchema,
33
+ logsGetRecentTool,
34
+ logsListSessionsHandler,
35
+ type LogsListSessionsInput,
36
+ logsListSessionsInputSchema,
37
+ logsListSessionsTool,
38
+ logsReceiveHandler,
39
+ type LogsReceiveInput,
40
+ logsReceiveInputSchema,
41
+ logsReceiveTool,
42
+ logsSearchHandler,
43
+ type LogsSearchInput,
44
+ logsSearchInputSchema,
45
+ logsSearchTool,
46
+ logsStatusHandler,
47
+ logsStatusTool,
48
+ } from "./tools/index.js";
49
+
50
+ // Track registered tool names for testing
51
+ let registeredTools: string[] = [];
52
+
53
+ /**
54
+ * Get the names of all registered tools.
55
+ * Useful for testing.
56
+ * @returns Array of registered tool names
57
+ */
58
+ export function getToolNames(): string[] {
59
+ return [...registeredTools];
60
+ }
61
+
62
+ /**
63
+ * Server instructions for LLMs describing the overall purpose and usage.
64
+ */
65
+ const SERVER_INSTRUCTIONS = `Remote Logger MCP Server - View console.log output from browser applications.
66
+
67
+ ## What is Remote Logging?
68
+
69
+ Browser applications run in a sandbox - their console.log() output appears in browser DevTools but is NOT visible to CLI tools or this assistant. Remote logging bridges this gap by sending browser logs to a server where they can be queried.
70
+
71
+ ## When to Use Remote Logging
72
+
73
+ Use this when debugging applications where developer tools aren't easily accessible:
74
+ - Storybook components (stories running in browser)
75
+ - Web applications during development
76
+ - Mobile web apps (phones, tablets) where DevTools requires USB debugging
77
+ - VR/AR applications where you can't see a console while wearing a headset
78
+ - Embedded devices, kiosks, or smart displays without keyboard access
79
+ - Any JavaScript running in a browser context
80
+
81
+ Remote logging is especially valuable for LLM assistants like this one - it enables reading, interpreting, and acting on application logs without requiring user interaction with browser DevTools.
82
+
83
+ ## Architecture
84
+
85
+ Browser App → HTTP POST to /logs → Log Server (stores in memory + JSONL files) → MCP Tools (query logs)
86
+
87
+ ## Setting Up a Browser App to Send Logs
88
+
89
+ First, get the server endpoint URL by calling logs_status - look for server.httpEndpoint in the response.
90
+
91
+ ### Option 1: Using the RemoteLogClient SDK (Recommended)
92
+
93
+ Install: npm install @graphty/remote-logger
94
+
95
+ \`\`\`typescript
96
+ import { RemoteLogClient } from "@graphty/remote-logger";
97
+
98
+ const logger = new RemoteLogClient({
99
+ serverUrl: "http://localhost:9080/logs", // Get this from logs_status
100
+ projectMarker: "my-project", // Optional: for filtering
101
+ });
102
+
103
+ // Intercept all console.log/warn/error calls
104
+ logger.interceptConsole();
105
+
106
+ // Or log manually
107
+ logger.log("INFO", "Hello from browser!");
108
+ \`\`\`
109
+
110
+ ### Option 2: Raw fetch() calls
111
+
112
+ \`\`\`typescript
113
+ fetch("http://localhost:9080/logs", {
114
+ method: "POST",
115
+ headers: { "Content-Type": "application/json" },
116
+ body: JSON.stringify({
117
+ sessionId: "unique-session-id",
118
+ logs: [
119
+ { time: new Date().toISOString(), level: "INFO", message: "Hello!" }
120
+ ]
121
+ })
122
+ });
123
+ \`\`\`
124
+
125
+ ## Querying Logs (MCP Tools)
126
+
127
+ Once browser logs are flowing to the server:
128
+
129
+ 1. logs_status - Check server health, get endpoint URL, see retention settings
130
+ 2. logs_get_recent - View recent logs (primary tool, sorted chronologically)
131
+ 3. logs_get_errors - Quick filter for ERROR level only
132
+ 4. logs_search - Find specific text (supports regex)
133
+ 5. logs_list_sessions - See all browser sessions
134
+ 6. logs_get_all - Get all logs grouped by session
135
+ 7. logs_get_file_path - Get JSONL file path for Grep/Read tools
136
+ 8. logs_clear - Delete logs (requires confirmation)
137
+
138
+ ## Typical Debugging Workflow
139
+
140
+ 1. Call logs_status to verify server is running and get the endpoint URL
141
+ 2. Ensure the browser app is configured to send logs to that endpoint
142
+ 3. Trigger the action in the browser you want to debug
143
+ 4. Call logs_get_recent to see what happened
144
+ 5. Use logs_search if looking for specific errors or messages`;
145
+
146
+ /**
147
+ * Create an MCP server with logging tools.
148
+ *
149
+ * Registers all logging tools and returns the configured server.
150
+ * The server is not started; use `startMcpServer` to run it.
151
+ * @param storage - The LogStorage instance to use for log operations
152
+ * @returns Configured McpServer instance
153
+ */
154
+ export function createMcpServer(storage: LogStorage): McpServer {
155
+ const server = new McpServer(
156
+ {
157
+ name: "remote-logger",
158
+ version: "1.0.0",
159
+ },
160
+ {
161
+ instructions: SERVER_INSTRUCTIONS,
162
+ },
163
+ );
164
+
165
+ // Reset registered tools
166
+ registeredTools = [];
167
+
168
+ // Register logs_get_recent tool
169
+ server.registerTool(
170
+ logsGetRecentTool.name,
171
+ {
172
+ description: logsGetRecentTool.description,
173
+ inputSchema: logsGetRecentInputSchema,
174
+ },
175
+ (args: LogsGetRecentInput) => {
176
+ return logsGetRecentHandler(storage, args).then((r) => ({
177
+ content: [
178
+ {
179
+ type: "text" as const,
180
+ text: JSON.stringify(r, null, 2),
181
+ },
182
+ ],
183
+ }));
184
+ },
185
+ );
186
+ registeredTools.push(logsGetRecentTool.name);
187
+
188
+ // Register logs_status tool
189
+ server.registerTool(
190
+ logsStatusTool.name,
191
+ {
192
+ description: logsStatusTool.description,
193
+ },
194
+ () => {
195
+ return logsStatusHandler(storage).then((r) => ({
196
+ content: [
197
+ {
198
+ type: "text" as const,
199
+ text: JSON.stringify(r, null, 2),
200
+ },
201
+ ],
202
+ }));
203
+ },
204
+ );
205
+ registeredTools.push(logsStatusTool.name);
206
+
207
+ // Register logs_list_sessions tool
208
+ server.registerTool(
209
+ logsListSessionsTool.name,
210
+ {
211
+ description: logsListSessionsTool.description,
212
+ inputSchema: logsListSessionsInputSchema,
213
+ },
214
+ (args: LogsListSessionsInput) => {
215
+ return logsListSessionsHandler(storage, args).then((r) => ({
216
+ content: [
217
+ {
218
+ type: "text" as const,
219
+ text: JSON.stringify(r, null, 2),
220
+ },
221
+ ],
222
+ }));
223
+ },
224
+ );
225
+ registeredTools.push(logsListSessionsTool.name);
226
+
227
+ // Register logs_receive tool
228
+ server.registerTool(
229
+ logsReceiveTool.name,
230
+ {
231
+ description: logsReceiveTool.description,
232
+ inputSchema: logsReceiveInputSchema,
233
+ },
234
+ (args: LogsReceiveInput) => {
235
+ return logsReceiveHandler(storage, args).then((r) => ({
236
+ content: [
237
+ {
238
+ type: "text" as const,
239
+ text: JSON.stringify(r, null, 2),
240
+ },
241
+ ],
242
+ }));
243
+ },
244
+ );
245
+ registeredTools.push(logsReceiveTool.name);
246
+
247
+ // Register logs_get_all tool
248
+ server.registerTool(
249
+ logsGetAllTool.name,
250
+ {
251
+ description: logsGetAllTool.description,
252
+ inputSchema: logsGetAllInputSchema,
253
+ },
254
+ (args: LogsGetAllInput) => {
255
+ return logsGetAllHandler(storage, args).then((r) => ({
256
+ content: [
257
+ {
258
+ type: "text" as const,
259
+ text: JSON.stringify(r, null, 2),
260
+ },
261
+ ],
262
+ }));
263
+ },
264
+ );
265
+ registeredTools.push(logsGetAllTool.name);
266
+
267
+ // Register logs_get_errors tool
268
+ server.registerTool(
269
+ logsGetErrorsTool.name,
270
+ {
271
+ description: logsGetErrorsTool.description,
272
+ inputSchema: logsGetErrorsInputSchema,
273
+ },
274
+ (args: LogsGetErrorsInput) => {
275
+ return logsGetErrorsHandler(storage, args).then((r) => ({
276
+ content: [
277
+ {
278
+ type: "text" as const,
279
+ text: JSON.stringify(r, null, 2),
280
+ },
281
+ ],
282
+ }));
283
+ },
284
+ );
285
+ registeredTools.push(logsGetErrorsTool.name);
286
+
287
+ // Register logs_clear tool
288
+ server.registerTool(
289
+ logsClearTool.name,
290
+ {
291
+ description: logsClearTool.description,
292
+ inputSchema: logsClearInputSchema,
293
+ },
294
+ (args: LogsClearInput) => {
295
+ return logsClearHandler(storage, args).then((r) => ({
296
+ content: [
297
+ {
298
+ type: "text" as const,
299
+ text: JSON.stringify(r, null, 2),
300
+ },
301
+ ],
302
+ }));
303
+ },
304
+ );
305
+ registeredTools.push(logsClearTool.name);
306
+
307
+ // Register logs_search tool
308
+ server.registerTool(
309
+ logsSearchTool.name,
310
+ {
311
+ description: logsSearchTool.description,
312
+ inputSchema: logsSearchInputSchema,
313
+ },
314
+ (args: LogsSearchInput) => {
315
+ return logsSearchHandler(storage, args).then((r) => ({
316
+ content: [
317
+ {
318
+ type: "text" as const,
319
+ text: JSON.stringify(r, null, 2),
320
+ },
321
+ ],
322
+ }));
323
+ },
324
+ );
325
+ registeredTools.push(logsSearchTool.name);
326
+
327
+ // Register logs_get_file_path tool
328
+ server.registerTool(
329
+ logsGetFilePathTool.name,
330
+ {
331
+ description: logsGetFilePathTool.description,
332
+ inputSchema: logsGetFilePathInputSchema,
333
+ },
334
+ (args: LogsGetFilePathInput) => {
335
+ return logsGetFilePathHandler(storage, args).then((r) => ({
336
+ content: [
337
+ {
338
+ type: "text" as const,
339
+ text: JSON.stringify(r, null, 2),
340
+ },
341
+ ],
342
+ }));
343
+ },
344
+ );
345
+ registeredTools.push(logsGetFilePathTool.name);
346
+
347
+ return server;
348
+ }
349
+
350
+ /**
351
+ * Start the MCP server with STDIO transport.
352
+ *
353
+ * This function runs the MCP server and blocks until the connection is closed.
354
+ * @param storage - The LogStorage instance to use for log operations
355
+ */
356
+ export async function startMcpServer(storage: LogStorage): Promise<void> {
357
+ const server = createMcpServer(storage);
358
+ const transport = new StdioServerTransport();
359
+
360
+ await server.connect(transport);
361
+
362
+ // Keep the process alive
363
+ // The connection will handle cleanup when stdin closes
364
+ }
@@ -0,0 +1,69 @@
1
+ /**
2
+ * MCP tool exports and registration.
3
+ * @module mcp/tools
4
+ */
5
+
6
+ export {
7
+ logsClearHandler,
8
+ type LogsClearInput,
9
+ logsClearInputSchema,
10
+ type LogsClearOutput,
11
+ logsClearTool,
12
+ } from "./logs-clear.js";
13
+ export {
14
+ logsGetAllHandler,
15
+ type LogsGetAllInput,
16
+ logsGetAllInputSchema,
17
+ type LogsGetAllOutput,
18
+ logsGetAllTool,
19
+ } from "./logs-get-all.js";
20
+ export {
21
+ logsGetErrorsHandler,
22
+ type LogsGetErrorsInput,
23
+ logsGetErrorsInputSchema,
24
+ type LogsGetErrorsOutput,
25
+ logsGetErrorsTool,
26
+ } from "./logs-get-errors.js";
27
+ export {
28
+ getLogFilePath,
29
+ logsGetFilePathHandler,
30
+ type LogsGetFilePathInput,
31
+ logsGetFilePathInputSchema,
32
+ type LogsGetFilePathOutput,
33
+ logsGetFilePathTool,
34
+ } from "./logs-get-file-path.js";
35
+ export {
36
+ logsGetRecentHandler,
37
+ type LogsGetRecentInput,
38
+ logsGetRecentInputSchema,
39
+ type LogsGetRecentOutput,
40
+ logsGetRecentTool,
41
+ } from "./logs-get-recent.js";
42
+ export {
43
+ logsListSessionsHandler,
44
+ type LogsListSessionsInput,
45
+ logsListSessionsInputSchema,
46
+ type LogsListSessionsOutput,
47
+ logsListSessionsTool,
48
+ } from "./logs-list-sessions.js";
49
+ export {
50
+ logsReceiveHandler,
51
+ type LogsReceiveInput,
52
+ logsReceiveInputSchema,
53
+ type LogsReceiveOutput,
54
+ logsReceiveTool,
55
+ } from "./logs-receive.js";
56
+ export {
57
+ logsSearchHandler,
58
+ type LogsSearchInput,
59
+ logsSearchInputSchema,
60
+ type LogsSearchOutput,
61
+ logsSearchTool,
62
+ } from "./logs-search.js";
63
+ export {
64
+ logsStatusHandler,
65
+ type LogsStatusInput,
66
+ logsStatusInputSchema,
67
+ type LogsStatusOutput,
68
+ logsStatusTool,
69
+ } from "./logs-status.js";