mcp-web-inspector 0.1.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 (85) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1017 -0
  3. package/dist/evals/evals.d.ts +5 -0
  4. package/dist/evals/evals.js +41 -0
  5. package/dist/index.d.ts +2 -0
  6. package/dist/index.js +62 -0
  7. package/dist/requestHandler.d.ts +3 -0
  8. package/dist/requestHandler.js +53 -0
  9. package/dist/toolHandler.d.ts +91 -0
  10. package/dist/toolHandler.js +725 -0
  11. package/dist/tools/api/base.d.ts +33 -0
  12. package/dist/tools/api/base.js +49 -0
  13. package/dist/tools/api/index.d.ts +2 -0
  14. package/dist/tools/api/index.js +3 -0
  15. package/dist/tools/api/requests.d.ts +47 -0
  16. package/dist/tools/api/requests.js +168 -0
  17. package/dist/tools/browser/base.d.ts +51 -0
  18. package/dist/tools/browser/base.js +111 -0
  19. package/dist/tools/browser/cleanSession.d.ts +10 -0
  20. package/dist/tools/browser/cleanSession.js +42 -0
  21. package/dist/tools/browser/comparePositions.d.ts +11 -0
  22. package/dist/tools/browser/comparePositions.js +149 -0
  23. package/dist/tools/browser/computedStyles.d.ts +11 -0
  24. package/dist/tools/browser/computedStyles.js +128 -0
  25. package/dist/tools/browser/console.d.ts +37 -0
  26. package/dist/tools/browser/console.js +106 -0
  27. package/dist/tools/browser/elementExists.d.ts +9 -0
  28. package/dist/tools/browser/elementExists.js +57 -0
  29. package/dist/tools/browser/elementInspection.d.ts +21 -0
  30. package/dist/tools/browser/elementInspection.js +151 -0
  31. package/dist/tools/browser/elementPosition.d.ts +11 -0
  32. package/dist/tools/browser/elementPosition.js +107 -0
  33. package/dist/tools/browser/elementVisibility.d.ts +12 -0
  34. package/dist/tools/browser/elementVisibility.js +224 -0
  35. package/dist/tools/browser/findByText.d.ts +13 -0
  36. package/dist/tools/browser/findByText.js +207 -0
  37. package/dist/tools/browser/getRequestDetails.d.ts +9 -0
  38. package/dist/tools/browser/getRequestDetails.js +137 -0
  39. package/dist/tools/browser/getTestIds.d.ts +12 -0
  40. package/dist/tools/browser/getTestIds.js +148 -0
  41. package/dist/tools/browser/index.d.ts +7 -0
  42. package/dist/tools/browser/index.js +7 -0
  43. package/dist/tools/browser/inspectDom.d.ts +12 -0
  44. package/dist/tools/browser/inspectDom.js +447 -0
  45. package/dist/tools/browser/interaction.d.ts +104 -0
  46. package/dist/tools/browser/interaction.js +259 -0
  47. package/dist/tools/browser/listNetworkRequests.d.ts +10 -0
  48. package/dist/tools/browser/listNetworkRequests.js +74 -0
  49. package/dist/tools/browser/measureElement.d.ts +9 -0
  50. package/dist/tools/browser/measureElement.js +139 -0
  51. package/dist/tools/browser/navigation.d.ts +38 -0
  52. package/dist/tools/browser/navigation.js +109 -0
  53. package/dist/tools/browser/output.d.ts +11 -0
  54. package/dist/tools/browser/output.js +29 -0
  55. package/dist/tools/browser/querySelectorAll.d.ts +12 -0
  56. package/dist/tools/browser/querySelectorAll.js +201 -0
  57. package/dist/tools/browser/response.d.ts +29 -0
  58. package/dist/tools/browser/response.js +67 -0
  59. package/dist/tools/browser/screenshot.d.ts +16 -0
  60. package/dist/tools/browser/screenshot.js +70 -0
  61. package/dist/tools/browser/useragent.d.ts +15 -0
  62. package/dist/tools/browser/useragent.js +32 -0
  63. package/dist/tools/browser/visiblePage.d.ts +20 -0
  64. package/dist/tools/browser/visiblePage.js +170 -0
  65. package/dist/tools/browser/waitForElement.d.ts +10 -0
  66. package/dist/tools/browser/waitForElement.js +38 -0
  67. package/dist/tools/browser/waitForNetworkIdle.d.ts +8 -0
  68. package/dist/tools/browser/waitForNetworkIdle.js +32 -0
  69. package/dist/tools/codegen/generator.d.ts +21 -0
  70. package/dist/tools/codegen/generator.js +158 -0
  71. package/dist/tools/codegen/index.d.ts +11 -0
  72. package/dist/tools/codegen/index.js +187 -0
  73. package/dist/tools/codegen/recorder.d.ts +14 -0
  74. package/dist/tools/codegen/recorder.js +62 -0
  75. package/dist/tools/codegen/types.d.ts +28 -0
  76. package/dist/tools/codegen/types.js +1 -0
  77. package/dist/tools/common/types.d.ts +17 -0
  78. package/dist/tools/common/types.js +20 -0
  79. package/dist/tools/index.d.ts +2 -0
  80. package/dist/tools/index.js +2 -0
  81. package/dist/tools.d.ts +557 -0
  82. package/dist/tools.js +554 -0
  83. package/dist/types.d.ts +16 -0
  84. package/dist/types.js +1 -0
  85. package/package.json +60 -0
@@ -0,0 +1,33 @@
1
+ import type { APIRequestContext } from 'playwright';
2
+ import { ToolHandler, ToolContext, ToolResponse } from '../common/types.js';
3
+ /**
4
+ * Base class for all API-based tools
5
+ * Provides common functionality and error handling
6
+ */
7
+ export declare abstract class ApiToolBase implements ToolHandler {
8
+ protected server: any;
9
+ constructor(server: any);
10
+ /**
11
+ * Main execution method that all tools must implement
12
+ */
13
+ abstract execute(args: any, context: ToolContext): Promise<ToolResponse>;
14
+ /**
15
+ * Ensures an API context is available and returns it
16
+ * @param context The tool context containing apiContext
17
+ * @returns The apiContext or null if not available
18
+ */
19
+ protected ensureApiContext(context: ToolContext): APIRequestContext | null;
20
+ /**
21
+ * Validates that an API context is available and returns an error response if not
22
+ * @param context The tool context
23
+ * @returns Either null if apiContext is available, or an error response
24
+ */
25
+ protected validateApiContextAvailable(context: ToolContext): ToolResponse | null;
26
+ /**
27
+ * Safely executes an API operation with proper error handling
28
+ * @param context The tool context
29
+ * @param operation The async operation to perform
30
+ * @returns The tool response
31
+ */
32
+ protected safeExecute(context: ToolContext, operation: (apiContext: APIRequestContext) => Promise<ToolResponse>): Promise<ToolResponse>;
33
+ }
@@ -0,0 +1,49 @@
1
+ import { createErrorResponse } from '../common/types.js';
2
+ /**
3
+ * Base class for all API-based tools
4
+ * Provides common functionality and error handling
5
+ */
6
+ export class ApiToolBase {
7
+ constructor(server) {
8
+ this.server = server;
9
+ }
10
+ /**
11
+ * Ensures an API context is available and returns it
12
+ * @param context The tool context containing apiContext
13
+ * @returns The apiContext or null if not available
14
+ */
15
+ ensureApiContext(context) {
16
+ if (!context.apiContext) {
17
+ return null;
18
+ }
19
+ return context.apiContext;
20
+ }
21
+ /**
22
+ * Validates that an API context is available and returns an error response if not
23
+ * @param context The tool context
24
+ * @returns Either null if apiContext is available, or an error response
25
+ */
26
+ validateApiContextAvailable(context) {
27
+ if (!this.ensureApiContext(context)) {
28
+ return createErrorResponse("API context not initialized");
29
+ }
30
+ return null;
31
+ }
32
+ /**
33
+ * Safely executes an API operation with proper error handling
34
+ * @param context The tool context
35
+ * @param operation The async operation to perform
36
+ * @returns The tool response
37
+ */
38
+ async safeExecute(context, operation) {
39
+ const apiError = this.validateApiContextAvailable(context);
40
+ if (apiError)
41
+ return apiError;
42
+ try {
43
+ return await operation(context.apiContext);
44
+ }
45
+ catch (error) {
46
+ return createErrorResponse(`API operation failed: ${error.message}`);
47
+ }
48
+ }
49
+ }
@@ -0,0 +1,2 @@
1
+ export * from './base.js';
2
+ export * from './requests.js';
@@ -0,0 +1,3 @@
1
+ export * from './base.js';
2
+ export * from './requests.js';
3
+ // TODO: Add exports for other API tools as they are implemented
@@ -0,0 +1,47 @@
1
+ import { ApiToolBase } from './base.js';
2
+ import { ToolContext, ToolResponse } from '../common/types.js';
3
+ /**
4
+ * Tool for making GET requests
5
+ */
6
+ export declare class GetRequestTool extends ApiToolBase {
7
+ /**
8
+ * Execute the GET request tool
9
+ */
10
+ execute(args: any, context: ToolContext): Promise<ToolResponse>;
11
+ }
12
+ /**
13
+ * Tool for making POST requests
14
+ */
15
+ export declare class PostRequestTool extends ApiToolBase {
16
+ /**
17
+ * Execute the POST request tool
18
+ */
19
+ execute(args: any, context: ToolContext): Promise<ToolResponse>;
20
+ }
21
+ /**
22
+ * Tool for making PUT requests
23
+ */
24
+ export declare class PutRequestTool extends ApiToolBase {
25
+ /**
26
+ * Execute the PUT request tool
27
+ */
28
+ execute(args: any, context: ToolContext): Promise<ToolResponse>;
29
+ }
30
+ /**
31
+ * Tool for making PATCH requests
32
+ */
33
+ export declare class PatchRequestTool extends ApiToolBase {
34
+ /**
35
+ * Execute the PATCH request tool
36
+ */
37
+ execute(args: any, context: ToolContext): Promise<ToolResponse>;
38
+ }
39
+ /**
40
+ * Tool for making DELETE requests
41
+ */
42
+ export declare class DeleteRequestTool extends ApiToolBase {
43
+ /**
44
+ * Execute the DELETE request tool
45
+ */
46
+ execute(args: any, context: ToolContext): Promise<ToolResponse>;
47
+ }
@@ -0,0 +1,168 @@
1
+ import { ApiToolBase } from './base.js';
2
+ import { createSuccessResponse, createErrorResponse } from '../common/types.js';
3
+ /**
4
+ * Tool for making GET requests
5
+ */
6
+ export class GetRequestTool extends ApiToolBase {
7
+ /**
8
+ * Execute the GET request tool
9
+ */
10
+ async execute(args, context) {
11
+ return this.safeExecute(context, async (apiContext) => {
12
+ const response = await apiContext.get(args.url);
13
+ let responseText;
14
+ try {
15
+ responseText = await response.text();
16
+ }
17
+ catch (error) {
18
+ responseText = "Unable to get response text";
19
+ }
20
+ return createSuccessResponse([
21
+ `GET request to ${args.url}`,
22
+ `Status: ${response.status()} ${response.statusText()}`,
23
+ `Response: ${responseText.substring(0, 1000)}${responseText.length > 1000 ? '...' : ''}`
24
+ ]);
25
+ });
26
+ }
27
+ }
28
+ /**
29
+ * Tool for making POST requests
30
+ */
31
+ export class PostRequestTool extends ApiToolBase {
32
+ /**
33
+ * Execute the POST request tool
34
+ */
35
+ async execute(args, context) {
36
+ return this.safeExecute(context, async (apiContext) => {
37
+ // Check if the value is valid JSON if it starts with { or [
38
+ if (args.value && typeof args.value === 'string' &&
39
+ (args.value.startsWith('{') || args.value.startsWith('['))) {
40
+ try {
41
+ JSON.parse(args.value);
42
+ }
43
+ catch (error) {
44
+ return createErrorResponse(`Failed to parse request body: ${error.message}`);
45
+ }
46
+ }
47
+ const response = await apiContext.post(args.url, {
48
+ data: typeof args.value === 'string' ? JSON.parse(args.value) : args.value,
49
+ headers: {
50
+ 'Content-Type': 'application/json',
51
+ ...(args.token ? { 'Authorization': `Bearer ${args.token}` } : {}),
52
+ ...(args.headers || {})
53
+ }
54
+ });
55
+ let responseText;
56
+ try {
57
+ responseText = await response.text();
58
+ }
59
+ catch (error) {
60
+ responseText = "Unable to get response text";
61
+ }
62
+ return createSuccessResponse([
63
+ `POST request to ${args.url}`,
64
+ `Status: ${response.status()} ${response.statusText()}`,
65
+ `Response: ${responseText.substring(0, 1000)}${responseText.length > 1000 ? '...' : ''}`
66
+ ]);
67
+ });
68
+ }
69
+ }
70
+ /**
71
+ * Tool for making PUT requests
72
+ */
73
+ export class PutRequestTool extends ApiToolBase {
74
+ /**
75
+ * Execute the PUT request tool
76
+ */
77
+ async execute(args, context) {
78
+ return this.safeExecute(context, async (apiContext) => {
79
+ // Check if the value is valid JSON if it starts with { or [
80
+ if (args.value && typeof args.value === 'string' &&
81
+ (args.value.startsWith('{') || args.value.startsWith('['))) {
82
+ try {
83
+ JSON.parse(args.value);
84
+ }
85
+ catch (error) {
86
+ return createErrorResponse(`Failed to parse request body: ${error.message}`);
87
+ }
88
+ }
89
+ const response = await apiContext.put(args.url, {
90
+ data: args.value
91
+ });
92
+ let responseText;
93
+ try {
94
+ responseText = await response.text();
95
+ }
96
+ catch (error) {
97
+ responseText = "Unable to get response text";
98
+ }
99
+ return createSuccessResponse([
100
+ `PUT request to ${args.url}`,
101
+ `Status: ${response.status()} ${response.statusText()}`,
102
+ `Response: ${responseText.substring(0, 1000)}${responseText.length > 1000 ? '...' : ''}`
103
+ ]);
104
+ });
105
+ }
106
+ }
107
+ /**
108
+ * Tool for making PATCH requests
109
+ */
110
+ export class PatchRequestTool extends ApiToolBase {
111
+ /**
112
+ * Execute the PATCH request tool
113
+ */
114
+ async execute(args, context) {
115
+ return this.safeExecute(context, async (apiContext) => {
116
+ // Check if the value is valid JSON if it starts with { or [
117
+ if (args.value && typeof args.value === 'string' &&
118
+ (args.value.startsWith('{') || args.value.startsWith('['))) {
119
+ try {
120
+ JSON.parse(args.value);
121
+ }
122
+ catch (error) {
123
+ return createErrorResponse(`Failed to parse request body: ${error.message}`);
124
+ }
125
+ }
126
+ const response = await apiContext.patch(args.url, {
127
+ data: args.value
128
+ });
129
+ let responseText;
130
+ try {
131
+ responseText = await response.text();
132
+ }
133
+ catch (error) {
134
+ responseText = "Unable to get response text";
135
+ }
136
+ return createSuccessResponse([
137
+ `PATCH request to ${args.url}`,
138
+ `Status: ${response.status()} ${response.statusText()}`,
139
+ `Response: ${responseText.substring(0, 1000)}${responseText.length > 1000 ? '...' : ''}`
140
+ ]);
141
+ });
142
+ }
143
+ }
144
+ /**
145
+ * Tool for making DELETE requests
146
+ */
147
+ export class DeleteRequestTool extends ApiToolBase {
148
+ /**
149
+ * Execute the DELETE request tool
150
+ */
151
+ async execute(args, context) {
152
+ return this.safeExecute(context, async (apiContext) => {
153
+ const response = await apiContext.delete(args.url);
154
+ let responseText;
155
+ try {
156
+ responseText = await response.text();
157
+ }
158
+ catch (error) {
159
+ responseText = "Unable to get response text";
160
+ }
161
+ return createSuccessResponse([
162
+ `DELETE request to ${args.url}`,
163
+ `Status: ${response.status()} ${response.statusText()}`,
164
+ `Response: ${responseText.substring(0, 1000)}${responseText.length > 1000 ? '...' : ''}`
165
+ ]);
166
+ });
167
+ }
168
+ }
@@ -0,0 +1,51 @@
1
+ import type { Page } from 'playwright';
2
+ import { ToolHandler, ToolContext, ToolResponse } from '../common/types.js';
3
+ /**
4
+ * Base class for all browser-based tools
5
+ * Provides common functionality and error handling
6
+ */
7
+ export declare abstract class BrowserToolBase implements ToolHandler {
8
+ protected server: any;
9
+ constructor(server: any);
10
+ /**
11
+ * Main execution method that all tools must implement
12
+ */
13
+ abstract execute(args: any, context: ToolContext): Promise<ToolResponse>;
14
+ /**
15
+ * Normalize selector shortcuts to full Playwright selectors
16
+ * - "testid:foo" → "[data-testid='foo']"
17
+ * - "data-test:bar" → "[data-test='bar']"
18
+ * - "data-cy:baz" → "[data-cy='baz']"
19
+ * - Everything else → pass through
20
+ * @param selector The selector string
21
+ * @returns Normalized selector
22
+ */
23
+ protected normalizeSelector(selector: string): string;
24
+ /**
25
+ * Ensures a page is available and returns it
26
+ * @param context The tool context containing browser and page
27
+ * @returns The page or null if not available
28
+ */
29
+ protected ensurePage(context: ToolContext): Page | null;
30
+ /**
31
+ * Validates that a page is available and returns an error response if not
32
+ * @param context The tool context
33
+ * @returns Either null if page is available, or an error response
34
+ */
35
+ protected validatePageAvailable(context: ToolContext): ToolResponse | null;
36
+ /**
37
+ * Safely executes a browser operation with proper error handling
38
+ * @param context The tool context
39
+ * @param operation The async operation to perform
40
+ * @returns The tool response
41
+ */
42
+ protected safeExecute(context: ToolContext, operation: (page: Page) => Promise<ToolResponse>): Promise<ToolResponse>;
43
+ /**
44
+ * Record that a user interaction occurred (for console log filtering)
45
+ */
46
+ protected recordInteraction(): void;
47
+ /**
48
+ * Record that a navigation occurred (for console log filtering)
49
+ */
50
+ protected recordNavigation(): void;
51
+ }
@@ -0,0 +1,111 @@
1
+ import { createErrorResponse } from '../common/types.js';
2
+ /**
3
+ * Base class for all browser-based tools
4
+ * Provides common functionality and error handling
5
+ */
6
+ export class BrowserToolBase {
7
+ constructor(server) {
8
+ this.server = server;
9
+ }
10
+ /**
11
+ * Normalize selector shortcuts to full Playwright selectors
12
+ * - "testid:foo" → "[data-testid='foo']"
13
+ * - "data-test:bar" → "[data-test='bar']"
14
+ * - "data-cy:baz" → "[data-cy='baz']"
15
+ * - Everything else → pass through
16
+ * @param selector The selector string
17
+ * @returns Normalized selector
18
+ */
19
+ normalizeSelector(selector) {
20
+ const prefixMap = {
21
+ 'testid:': 'data-testid',
22
+ 'data-test:': 'data-test',
23
+ 'data-cy:': 'data-cy',
24
+ };
25
+ for (const [prefix, attr] of Object.entries(prefixMap)) {
26
+ if (selector.startsWith(prefix)) {
27
+ const value = selector.slice(prefix.length);
28
+ return `[${attr}="${value}"]`;
29
+ }
30
+ }
31
+ return selector; // CSS, text=, etc. pass through
32
+ }
33
+ /**
34
+ * Ensures a page is available and returns it
35
+ * @param context The tool context containing browser and page
36
+ * @returns The page or null if not available
37
+ */
38
+ ensurePage(context) {
39
+ if (!context.page) {
40
+ return null;
41
+ }
42
+ return context.page;
43
+ }
44
+ /**
45
+ * Validates that a page is available and returns an error response if not
46
+ * @param context The tool context
47
+ * @returns Either null if page is available, or an error response
48
+ */
49
+ validatePageAvailable(context) {
50
+ if (!this.ensurePage(context)) {
51
+ return createErrorResponse("Browser page not initialized!");
52
+ }
53
+ return null;
54
+ }
55
+ /**
56
+ * Safely executes a browser operation with proper error handling
57
+ * @param context The tool context
58
+ * @param operation The async operation to perform
59
+ * @returns The tool response
60
+ */
61
+ async safeExecute(context, operation) {
62
+ const pageError = this.validatePageAvailable(context);
63
+ if (pageError)
64
+ return pageError;
65
+ try {
66
+ // Verify browser is connected before proceeding
67
+ if (context.browser && !context.browser.isConnected()) {
68
+ // If browser exists but is disconnected, reset state
69
+ const { resetBrowserState } = await import('../../toolHandler.js');
70
+ resetBrowserState();
71
+ return createErrorResponse("Browser is disconnected. Please retry the operation.");
72
+ }
73
+ // Check if page is closed
74
+ if (context.page.isClosed()) {
75
+ return createErrorResponse("Page is closed. Please retry the operation.");
76
+ }
77
+ return await operation(context.page);
78
+ }
79
+ catch (error) {
80
+ const errorMessage = error.message;
81
+ // Check for common browser disconnection errors
82
+ if (errorMessage.includes("Target page, context or browser has been closed") ||
83
+ errorMessage.includes("Target closed") ||
84
+ errorMessage.includes("Browser has been disconnected") ||
85
+ errorMessage.includes("Protocol error") ||
86
+ errorMessage.includes("Connection closed")) {
87
+ // Reset browser state on connection issues
88
+ const { resetBrowserState } = await import('../../toolHandler.js');
89
+ resetBrowserState();
90
+ return createErrorResponse(`Browser connection error: ${errorMessage}. Connection has been reset - please retry the operation.`);
91
+ }
92
+ return createErrorResponse(`Operation failed: ${errorMessage}`);
93
+ }
94
+ }
95
+ /**
96
+ * Record that a user interaction occurred (for console log filtering)
97
+ */
98
+ recordInteraction() {
99
+ import('../../toolHandler.js').then(({ updateLastInteractionTimestamp }) => {
100
+ updateLastInteractionTimestamp();
101
+ });
102
+ }
103
+ /**
104
+ * Record that a navigation occurred (for console log filtering)
105
+ */
106
+ recordNavigation() {
107
+ import('../../toolHandler.js').then(({ updateLastNavigationTimestamp }) => {
108
+ updateLastNavigationTimestamp();
109
+ });
110
+ }
111
+ }
@@ -0,0 +1,10 @@
1
+ import { BrowserToolBase } from './base.js';
2
+ import type { ToolContext, ToolResponse } from '../common/types.js';
3
+ /**
4
+ * Tool to clean/remove session data
5
+ */
6
+ export declare class CleanSessionTool extends BrowserToolBase {
7
+ execute(args: {
8
+ userDataDir?: string;
9
+ }, context: ToolContext): Promise<ToolResponse>;
10
+ }
@@ -0,0 +1,42 @@
1
+ import { BrowserToolBase } from './base.js';
2
+ import { rmSync, existsSync } from 'fs';
3
+ /**
4
+ * Tool to clean/remove session data
5
+ */
6
+ export class CleanSessionTool extends BrowserToolBase {
7
+ async execute(args, context) {
8
+ const { server } = context;
9
+ // Get the session directory from args or use the default
10
+ const sessionDir = args.userDataDir || './.mcp-web-inspector';
11
+ try {
12
+ // Check if the directory exists
13
+ if (!existsSync(sessionDir)) {
14
+ return {
15
+ content: [{
16
+ type: "text",
17
+ text: `Session directory does not exist: ${sessionDir}`,
18
+ }],
19
+ isError: false,
20
+ };
21
+ }
22
+ // Remove the directory recursively
23
+ rmSync(sessionDir, { recursive: true, force: true });
24
+ return {
25
+ content: [{
26
+ type: "text",
27
+ text: `Session data cleaned successfully from: ${sessionDir}`,
28
+ }],
29
+ isError: false,
30
+ };
31
+ }
32
+ catch (error) {
33
+ return {
34
+ content: [{
35
+ type: "text",
36
+ text: `Failed to clean session data: ${error.message}`,
37
+ }],
38
+ isError: true,
39
+ };
40
+ }
41
+ }
42
+ }
@@ -0,0 +1,11 @@
1
+ import { BrowserToolBase } from './base.js';
2
+ import { ToolContext, ToolResponse } from '../common/types.js';
3
+ /**
4
+ * Tool for comparing positions and sizes of two elements
5
+ */
6
+ export declare class ComparePositionsTool extends BrowserToolBase {
7
+ /**
8
+ * Execute the compare positions tool
9
+ */
10
+ execute(args: any, context: ToolContext): Promise<ToolResponse>;
11
+ }