diff --git a/src/tools/console.ts b/src/tools/console.ts index 13630ff..59b2c9d 100644 --- a/src/tools/console.ts +++ b/src/tools/console.ts @@ -12,7 +12,7 @@ import { truncationFooter, } from '../utils/response-helpers.js'; import { saveOutput } from '../utils/save-output.js'; -import { defineModule } from './module.js'; +import { defineModule, type ToolDefinition } from './module.js'; import type { McpToolResponse } from '../types/common.js'; export const listConsoleMessagesTool = { @@ -63,7 +63,7 @@ export const listConsoleMessagesTool = { }, }, }, -}; +} satisfies ToolDefinition; export const clearConsoleMessagesTool = { name: 'clear_console_messages', @@ -75,7 +75,7 @@ export const clearConsoleMessagesTool = { type: 'object', properties: {}, }, -}; +} satisfies ToolDefinition; const DEFAULT_LIMIT = 50; diff --git a/src/tools/debugging.ts b/src/tools/debugging.ts index 8cba07c..62e03e3 100644 --- a/src/tools/debugging.ts +++ b/src/tools/debugging.ts @@ -1,7 +1,7 @@ import { successResponse, errorResponse } from '../utils/response-helpers.js'; import { compareVersions } from '../utils/version.js'; import { remoteValueToNative } from '../utils/remote-value.js'; -import { defineModule } from './module.js'; +import { defineModule, type ToolDefinition } from './module.js'; import type { McpToolResponse } from '../types/common.js'; const MIN_VERSION = '153'; @@ -34,7 +34,7 @@ export const enableDebuggerTool = { readOnlyHint: false, }, inputSchema: { type: 'object', properties: {} }, -}; +} satisfies ToolDefinition; export const listScriptsTool = { name: 'list_scripts', @@ -44,7 +44,7 @@ export const listScriptsTool = { readOnlyHint: true, }, inputSchema: { type: 'object', properties: {} }, -}; +} satisfies ToolDefinition; export const getScriptSourceTool = { name: 'get_script_source', @@ -60,7 +60,7 @@ export const getScriptSourceTool = { }, required: ['scriptUrl'], }, -}; +} satisfies ToolDefinition; export const setLogpointTool = { name: 'set_logpoint', @@ -81,7 +81,7 @@ export const setLogpointTool = { }, required: ['url', 'line', 'expression'], }, -}; +} satisfies ToolDefinition; export const removeLogpointTool = { name: 'remove_logpoint', @@ -96,7 +96,7 @@ export const removeLogpointTool = { }, required: ['logpoint'], }, -}; +} satisfies ToolDefinition; export const getLogpointResultsTool = { name: 'get_logpoint_results', @@ -111,7 +111,7 @@ export const getLogpointResultsTool = { }, required: ['logpoint'], }, -}; +} satisfies ToolDefinition; // ============================================================================ // Handlers diff --git a/src/tools/downloads.ts b/src/tools/downloads.ts index f3203ed..e8ab702 100644 --- a/src/tools/downloads.ts +++ b/src/tools/downloads.ts @@ -4,7 +4,7 @@ */ import { successResponse, errorResponse, jsonResponse } from '../utils/response-helpers.js'; -import { defineModule } from './module.js'; +import { defineModule, type ToolDefinition } from './module.js'; import type { McpToolResponse } from '../types/common.js'; // Tool definitions @@ -15,7 +15,7 @@ export const listDownloadsTool = { readOnlyHint: true, }, inputSchema: { - type: 'object' as const, + type: 'object', properties: { status: { type: 'string', @@ -37,23 +37,23 @@ export const listDownloadsTool = { }, }, }, -}; +} satisfies ToolDefinition; export const clearDownloadsTool = { name: 'clear_downloads', description: 'Clear the tracked downloads buffer.', inputSchema: { - type: 'object' as const, + type: 'object', properties: {}, }, -}; +} satisfies ToolDefinition; export const setDownloadBehaviorTool = { name: 'set_download_behavior', description: 'Control how downloads are handled: allow (save silently to the default download directory), deny (cancel), or reset to default. Avoids the native save-file dialog. Requires a recent Firefox.', inputSchema: { - type: 'object' as const, + type: 'object', properties: { behavior: { type: 'string', @@ -64,7 +64,7 @@ export const setDownloadBehaviorTool = { }, required: ['behavior'], }, -}; +} satisfies ToolDefinition; // Tool handlers export async function handleListDownloads(args: unknown): Promise { diff --git a/src/tools/firefox-management.ts b/src/tools/firefox-management.ts index 5950fec..e8310db 100644 --- a/src/tools/firefox-management.ts +++ b/src/tools/firefox-management.ts @@ -5,7 +5,7 @@ import { readFileSync, existsSync, statSync } from 'node:fs'; import { errorResponse, successResponse } from '../utils/response-helpers.js'; -import { defineModule } from './module.js'; +import { defineModule, type ToolDefinition } from './module.js'; // ============================================================================ // Tool: get_firefox_logs @@ -35,7 +35,7 @@ export const getFirefoxLogsTool = { }, }, }, -}; +} satisfies ToolDefinition; export async function handleGetFirefoxLogs(input: unknown) { try { @@ -121,7 +121,7 @@ export const getFirefoxInfoTool = { type: 'object', properties: {}, }, -}; +} satisfies ToolDefinition; export async function handleGetFirefoxInfo(_input: unknown) { try { @@ -239,7 +239,7 @@ export const restartFirefoxTool = { }, }, }, -}; +} satisfies ToolDefinition; export async function handleRestartFirefox(input: unknown) { try { diff --git a/src/tools/firefox-prefs.ts b/src/tools/firefox-prefs.ts index 2787e64..e541290 100644 --- a/src/tools/firefox-prefs.ts +++ b/src/tools/firefox-prefs.ts @@ -6,7 +6,7 @@ import { successResponse, errorResponse } from '../utils/response-helpers.js'; import { generatePrefScript } from '../firefox/pref-utils.js'; -import { defineModule } from './module.js'; +import { defineModule, type ToolDefinition } from './module.js'; import type { McpToolResponse } from '../types/common.js'; // ============================================================================ @@ -34,7 +34,7 @@ export const setFirefoxPrefsTool = { }, required: ['prefs'], }, -}; +} satisfies ToolDefinition; export async function handleSetFirefoxPrefs(args: unknown): Promise { try { @@ -145,7 +145,7 @@ export const getFirefoxPrefsTool = { }, required: ['names'], }, -}; +} satisfies ToolDefinition; export async function handleGetFirefoxPrefs(args: unknown): Promise { try { diff --git a/src/tools/input.ts b/src/tools/input.ts index 37ff43e..1e235c5 100644 --- a/src/tools/input.ts +++ b/src/tools/input.ts @@ -5,7 +5,7 @@ import { successResponse, errorResponse } from '../utils/response-helpers.js'; import { handleUidError } from '../utils/uid-helpers.js'; -import { defineModule } from './module.js'; +import { defineModule, type ToolDefinition } from './module.js'; import type { McpToolResponse } from '../types/common.js'; // Tool definitions @@ -29,7 +29,7 @@ export const clickByUidTool = { }, required: ['uid'], }, -}; +} satisfies ToolDefinition; export const hoverByUidTool = { name: 'hover_by_uid', @@ -47,7 +47,7 @@ export const hoverByUidTool = { }, required: ['uid'], }, -}; +} satisfies ToolDefinition; export const fillByUidTool = { name: 'fill_by_uid', @@ -69,7 +69,7 @@ export const fillByUidTool = { }, required: ['uid', 'value'], }, -}; +} satisfies ToolDefinition; export const dragByUidToUidTool = { name: 'drag_by_uid_to_uid', @@ -91,7 +91,7 @@ export const dragByUidToUidTool = { }, required: ['fromUid', 'toUid'], }, -}; +} satisfies ToolDefinition; export const fillFormByUidTool = { name: 'fill_form_by_uid', @@ -123,7 +123,7 @@ export const fillFormByUidTool = { }, required: ['elements'], }, -}; +} satisfies ToolDefinition; export const uploadFileByUidTool = { name: 'upload_file_by_uid', @@ -145,7 +145,7 @@ export const uploadFileByUidTool = { }, required: ['uid', 'filePath'], }, -}; +} satisfies ToolDefinition; // Handlers export async function handleClickByUid(args: unknown): Promise { diff --git a/src/tools/module.ts b/src/tools/module.ts index 910b8cc..4811af3 100644 --- a/src/tools/module.ts +++ b/src/tools/module.ts @@ -8,11 +8,31 @@ import type { McpToolResponse } from '../types/common.js'; +export type JsonSchemaType = 'array' | 'boolean' | 'integer' | 'number' | 'object' | 'string'; + +export interface JsonSchemaProperty { + type: JsonSchemaType | readonly JsonSchemaType[]; + description?: string; + enum?: readonly string[]; + /** Schema of array elements (when type is 'array'). */ + items?: JsonSchemaProperty; + /** Schema for values of an open-key object (prefs-style maps). */ + additionalProperties?: { oneOf: Array<{ type: JsonSchemaType }> }; + properties?: Record; + required?: readonly string[]; +} + +export interface InputSchema { + type: 'object'; + properties: Record; + required?: readonly string[]; +} + export interface ToolDefinition { name: string; description: string; annotations?: { readOnlyHint?: boolean; [key: string]: unknown }; - inputSchema: Record; + inputSchema: InputSchema; } export type ToolHandler = (input: unknown) => Promise; diff --git a/src/tools/network.ts b/src/tools/network.ts index 12841fc..aed6318 100644 --- a/src/tools/network.ts +++ b/src/tools/network.ts @@ -14,7 +14,7 @@ import { TOKEN_LIMITS, } from '../utils/response-helpers.js'; import { saveOutput } from '../utils/save-output.js'; -import { defineModule } from './module.js'; +import { defineModule, type ToolDefinition } from './module.js'; import type { McpToolResponse } from '../types/common.js'; import type { NetworkBodyResult } from '../firefox/events/network.js'; @@ -27,7 +27,7 @@ export const listNetworkRequestsTool = { readOnlyHint: true, }, inputSchema: { - type: 'object' as const, + type: 'object', properties: { limit: { type: 'number', @@ -92,7 +92,7 @@ export const listNetworkRequestsTool = { }, }, }, -}; +} satisfies ToolDefinition; export const getNetworkRequestTool = { name: 'get_network_request', @@ -102,7 +102,7 @@ export const getNetworkRequestTool = { readOnlyHint: true, }, inputSchema: { - type: 'object' as const, + type: 'object', properties: { id: { type: 'string', @@ -129,7 +129,7 @@ export const getNetworkRequestTool = { }, }, }, -}; +} satisfies ToolDefinition; /** * Fetch a body without letting a missing facade method or transport error fail diff --git a/src/tools/pages.ts b/src/tools/pages.ts index ebc4b4d..2ece6e1 100644 --- a/src/tools/pages.ts +++ b/src/tools/pages.ts @@ -9,8 +9,8 @@ import { truncationFooter, } from '../utils/response-helpers.js'; import { saveOutput } from '../utils/save-output.js'; -import { defineModule } from './module.js'; import { READINESS_STATES, isReadinessState, type ReadinessState } from '../firefox/pages.js'; +import { defineModule, type JsonSchemaProperty, type ToolDefinition } from './module.js'; import type { McpToolResponse } from '../types/common.js'; const DEFAULT_MAX_CONTENT_CHARS = 20_000; @@ -25,7 +25,7 @@ const waitSchema = { type: 'string', enum: [...READINESS_STATES], description: WAIT_DESCRIPTION, -}; +} satisfies JsonSchemaProperty; /** * Validate the optional `wait` argument. @@ -61,7 +61,7 @@ export const listPagesTool = { type: 'object', properties: {}, }, -}; +} satisfies ToolDefinition; export const newPageTool = { name: 'new_page', @@ -80,7 +80,7 @@ export const newPageTool = { }, required: ['url'], }, -}; +} satisfies ToolDefinition; export const navigatePageTool = { name: 'navigate_page', @@ -99,7 +99,7 @@ export const navigatePageTool = { }, required: ['url'], }, -}; +} satisfies ToolDefinition; export const selectPageTool = { name: 'select_page', @@ -125,7 +125,7 @@ export const selectPageTool = { }, required: [], }, -}; +} satisfies ToolDefinition; export const closePageTool = { name: 'close_page', @@ -143,7 +143,7 @@ export const closePageTool = { }, required: ['pageIdx'], }, -}; +} satisfies ToolDefinition; export const getPageTextTool = { name: 'get_page_text', @@ -153,7 +153,7 @@ export const getPageTextTool = { readOnlyHint: true, }, inputSchema: { - type: 'object' as const, + type: 'object', properties: { maxLength: { type: 'number', @@ -172,7 +172,7 @@ export const getPageTextTool = { }, }, }, -}; +} satisfies ToolDefinition; /** * Format page list compactly diff --git a/src/tools/privileged-context.ts b/src/tools/privileged-context.ts index 5ad1c02..325f8e0 100644 --- a/src/tools/privileged-context.ts +++ b/src/tools/privileged-context.ts @@ -7,7 +7,7 @@ import { successResponse, errorResponse, previewExcerpt } from '../utils/respons import { validateFunction } from '../utils/js-validation.js'; import { remoteValueToNative } from '../utils/remote-value.js'; import { saveOutput } from '../utils/save-output.js'; -import { defineModule } from './module.js'; +import { defineModule, type ToolDefinition } from './module.js'; // list_extensions lives with the other extension tools in webextension.ts, but // it needs parent access (AddonManager), so it is registered here under the // privileged module rather than the unprivileged webextension module. @@ -25,7 +25,7 @@ export const listPrivilegedContextsTool = { type: 'object', properties: {}, }, -}; +} satisfies ToolDefinition; export const selectPrivilegedContextTool = { name: 'select_privileged_context', @@ -44,7 +44,7 @@ export const selectPrivilegedContextTool = { }, required: ['contextId'], }, -}; +} satisfies ToolDefinition; export const evaluatePrivilegedScriptTool = { name: 'evaluate_privileged_script', @@ -77,7 +77,7 @@ export const evaluatePrivilegedScriptTool = { }, required: ['function', 'context'], }, -}; +} satisfies ToolDefinition; function formatContextList(contexts: any[]): string { if (contexts.length === 0) { diff --git a/src/tools/profiler.ts b/src/tools/profiler.ts index 5992edd..986efcf 100644 --- a/src/tools/profiler.ts +++ b/src/tools/profiler.ts @@ -1,7 +1,7 @@ import { successResponse, errorResponse } from '../utils/response-helpers.js'; import { compareVersions } from '../utils/version.js'; import type { FirefoxDevTools } from '../firefox/index.js'; -import { defineModule } from './module.js'; +import { defineModule, type ToolDefinition } from './module.js'; import type { McpToolResponse } from '../types/common.js'; const MIN_FIREFOX_VERSION = '154.0'; @@ -40,7 +40,7 @@ export const profilerIsActiveTool = { type: 'object', properties: {}, }, -}; +} satisfies ToolDefinition; export async function handleProfilerIsActive(_args: unknown): Promise { try { @@ -101,7 +101,7 @@ export const profilerStartTool = { }, }, }, -}; +} satisfies ToolDefinition; export async function handleProfilerStart(args: unknown): Promise { try { @@ -172,7 +172,7 @@ export const profilerStopTool = { }, }, }, -}; +} satisfies ToolDefinition; export async function handleProfilerStop(args: unknown): Promise { try { diff --git a/src/tools/screencast.ts b/src/tools/screencast.ts index cc28921..dd83eac 100644 --- a/src/tools/screencast.ts +++ b/src/tools/screencast.ts @@ -1,7 +1,7 @@ import { successResponse, errorResponse } from '../utils/response-helpers.js'; import { compareVersions } from '../utils/version.js'; import type { FirefoxDevTools } from '../firefox/index.js'; -import { defineModule } from './module.js'; +import { defineModule, type ToolDefinition } from './module.js'; import type { McpToolResponse } from '../types/common.js'; const MIN_FIREFOX_VERSION = '154.0'; @@ -60,7 +60,7 @@ export const screencastStartTool = { }, }, }, -}; +} satisfies ToolDefinition; export async function handleScreencastStart(args: unknown): Promise { try { @@ -134,7 +134,7 @@ export const screencastStopTool = { }, }, }, -}; +} satisfies ToolDefinition; export async function handleScreencastStop(args: unknown): Promise { try { diff --git a/src/tools/screenshot.ts b/src/tools/screenshot.ts index 1e1bac9..1705ad8 100644 --- a/src/tools/screenshot.ts +++ b/src/tools/screenshot.ts @@ -5,7 +5,7 @@ import { successResponse, errorResponse } from '../utils/response-helpers.js'; import { handleUidError } from '../utils/uid-helpers.js'; import { saveOutput } from '../utils/save-output.js'; -import { defineModule } from './module.js'; +import { defineModule, type ToolDefinition } from './module.js'; import type { McpToolResponse } from '../types/common.js'; const SAVE_TO_SCHEMA = { @@ -27,7 +27,7 @@ export const screenshotPageTool = { saveTo: SAVE_TO_SCHEMA, }, }, -}; +} satisfies ToolDefinition; export const screenshotByUidTool = { name: 'screenshot_by_uid', @@ -46,7 +46,7 @@ export const screenshotByUidTool = { }, required: ['uid'], }, -}; +} satisfies ToolDefinition; /** * Save screenshot to file and return text response with path. diff --git a/src/tools/script.ts b/src/tools/script.ts index 0c4bac3..686eb1c 100644 --- a/src/tools/script.ts +++ b/src/tools/script.ts @@ -6,7 +6,7 @@ import { successResponse, errorResponse, previewExcerpt } from '../utils/respons import { remoteValueToNative } from '../utils/remote-value.js'; import { validateFunction } from '../utils/js-validation.js'; import { saveOutput } from '../utils/save-output.js'; -import { defineModule } from './module.js'; +import { defineModule, type ToolDefinition } from './module.js'; import type { McpToolResponse } from '../types/common.js'; export const evaluateScriptTool = { @@ -59,7 +59,7 @@ export const evaluateScriptTool = { }, required: ['function'], }, -}; +} satisfies ToolDefinition; // Constants const DEFAULT_TIMEOUT = 5000; // 5 seconds diff --git a/src/tools/snapshot.ts b/src/tools/snapshot.ts index 00f2b47..8903e1c7 100644 --- a/src/tools/snapshot.ts +++ b/src/tools/snapshot.ts @@ -11,7 +11,7 @@ import { } from '../utils/response-helpers.js'; import { handleUidError } from '../utils/uid-helpers.js'; import { saveOutput } from '../utils/save-output.js'; -import { defineModule } from './module.js'; +import { defineModule, type ToolDefinition } from './module.js'; import type { McpToolResponse } from '../types/common.js'; const DEFAULT_SNAPSHOT_LINES = 100; @@ -64,7 +64,7 @@ export const takeSnapshotTool = { }, }, }, -}; +} satisfies ToolDefinition; export const resolveUidToSelectorTool = { name: 'resolve_uid_to_selector', @@ -82,7 +82,7 @@ export const resolveUidToSelectorTool = { }, required: ['uid'], }, -}; +} satisfies ToolDefinition; export const clearSnapshotTool = { name: 'clear_snapshot', @@ -94,7 +94,7 @@ export const clearSnapshotTool = { type: 'object', properties: {}, }, -}; +} satisfies ToolDefinition; // Handlers export async function handleTakeSnapshot(args: unknown): Promise { diff --git a/src/tools/utilities.ts b/src/tools/utilities.ts index c592259..bb34439 100644 --- a/src/tools/utilities.ts +++ b/src/tools/utilities.ts @@ -3,7 +3,7 @@ */ import { successResponse, errorResponse } from '../utils/response-helpers.js'; -import { defineModule } from './module.js'; +import { defineModule, type ToolDefinition } from './module.js'; import type { McpToolResponse } from '../types/common.js'; // Tool definitions - Dialogs @@ -22,7 +22,7 @@ export const acceptDialogTool = { }, }, }, -}; +} satisfies ToolDefinition; export const dismissDialogTool = { name: 'dismiss_dialog', @@ -34,7 +34,7 @@ export const dismissDialogTool = { type: 'object', properties: {}, }, -}; +} satisfies ToolDefinition; // Tool definitions - History export const navigateHistoryTool = { @@ -54,7 +54,7 @@ export const navigateHistoryTool = { }, required: ['direction'], }, -}; +} satisfies ToolDefinition; // Tool definitions - Viewport export const setViewportSizeTool = { @@ -77,7 +77,7 @@ export const setViewportSizeTool = { }, required: ['width', 'height'], }, -}; +} satisfies ToolDefinition; // Handlers - Dialogs export async function handleAcceptDialog(args: unknown): Promise { diff --git a/src/tools/webextension.ts b/src/tools/webextension.ts index d22f961..f68c3a8 100644 --- a/src/tools/webextension.ts +++ b/src/tools/webextension.ts @@ -10,7 +10,7 @@ */ import { successResponse, errorResponse } from '../utils/response-helpers.js'; -import { defineModule } from './module.js'; +import { defineModule, type ToolDefinition } from './module.js'; import type { McpToolResponse } from '../types/common.js'; // ============================================================================ @@ -49,7 +49,7 @@ export const installExtensionTool = { }, required: ['type'], }, -}; +} satisfies ToolDefinition; export async function handleInstallExtension(args: unknown): Promise { try { @@ -124,7 +124,7 @@ export const uninstallExtensionTool = { }, required: ['id'], }, -}; +} satisfies ToolDefinition; export async function handleUninstallExtension(args: unknown): Promise { try { @@ -182,7 +182,7 @@ export const listExtensionsTool = { }, }, }, -}; +} satisfies ToolDefinition; interface ExtensionInfo { id: string;