http-options
Check available HTTP methods and headers for a specified URL using an OPTIONS request. Supports secret substitution for secure API interactions.
Instructions
Make an HTTP OPTIONS request to a specified URL to check available methods and headers. Supports secret substitution using {secrets.key} syntax in URL and headers where 'key' corresponds to HAL_SECRET_KEY environment variables.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| headers | No | ||
| url | Yes |
Implementation Reference
- src/index.ts:679-692 (registration)Registration of the 'http-options' tool, including input schema validation using Zod and a handler function that delegates to the shared makeHttpRequest helper with 'OPTIONS' method.server.registerTool( "http-options", { title: "HTTP OPTIONS Request", description: "Make an HTTP OPTIONS request to a specified URL to check available methods and headers. Supports secret substitution using {secrets.key} syntax in URL and headers where 'key' corresponds to HAL_SECRET_KEY environment variables.", inputSchema: { url: z.string().url(), headers: z.record(z.string()).optional() } }, async ({ url, headers = {} }: { url: string; headers?: Record<string, string> }) => { return makeHttpRequest('OPTIONS', url, { headers }); } );
- src/index.ts:343-447 (helper)Core helper function that implements the HTTP request logic for all HTTP tools, including OPTIONS. Handles secret substitution with URL restrictions, global URL filters, fetch execution, response formatting, and automatic secret redaction from outputs.async function makeHttpRequest( method: string, url: string, options: { headers?: Record<string, string>; body?: string; queryParams?: Record<string, any>; } = {} ) { try { const { headers = {}, body, queryParams = {} } = options; // First, substitute secrets in URL to get the final URL for validation // We need to do this in two passes to handle URL restrictions properly const processedUrl = substituteSecrets(url, url); // Now substitute secrets in headers, body, and query parameters using the processed URL const processedHeaders = substituteSecretsInObject(headers, processedUrl); const processedBody = body ? substituteSecrets(body, processedUrl) : body; const processedQueryParams = substituteSecretsInObject(queryParams, processedUrl); // Build URL with query parameters const urlObj = new URL(processedUrl); Object.entries(processedQueryParams).forEach(([key, value]) => { if (value !== undefined && value !== null) { urlObj.searchParams.set(key, String(value)); } }); const finalUrl = urlObj.toString(); // Check global URL whitelist/blacklist const urlCheck = isUrlAllowedGlobal(finalUrl); if (!urlCheck.allowed) { throw new Error(urlCheck.reason || 'URL is not allowed'); } const defaultHeaders = { 'User-Agent': 'HAL-MCP/1.0.0', ...processedHeaders }; // Add Content-Type for methods that typically send data if (['POST', 'PUT', 'PATCH'].includes(method.toUpperCase()) && processedBody && !('Content-Type' in processedHeaders)) { (defaultHeaders as any)['Content-Type'] = 'application/json'; } const response = await fetch(finalUrl, { method: method.toUpperCase(), headers: defaultHeaders, body: processedBody }); const contentType = response.headers.get('content-type') || 'text/plain'; let content: string; // HEAD requests don't have a body by design if (method.toUpperCase() === 'HEAD') { content = '(No body - HEAD request)'; } else { try { if (contentType.includes('application/json')) { const text = await response.text(); if (text.trim()) { content = JSON.stringify(JSON.parse(text), null, 2); } else { content = '(Empty response)'; } } else { content = await response.text(); } } catch (parseError) { // If JSON parsing fails, try to get text try { content = await response.text(); } catch (textError) { content = '(Unable to parse response)'; } } } // Redact secrets from response headers and content before returning const redactedHeaders = Array.from(response.headers.entries()) .map(([key, value]) => `${key}: ${redactSecretsFromText(value)}`) .join('\n'); const redactedContent = redactSecretsFromText(content); return { content: [{ type: "text" as const, text: `Status: ${response.status} ${response.statusText}\n\nHeaders:\n${redactedHeaders}\n\nBody:\n${redactedContent}` }] }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; const redactedErrorMessage = redactSecretsFromText(errorMessage); return { content: [{ type: "text" as const, text: `Error making ${method.toUpperCase()} request: ${redactedErrorMessage}` }], isError: true }; } }
- src/index.ts:684-687 (schema)Zod input schema for the 'http-options' tool: requires a URL (validated as URL format) and optional headers object.inputSchema: { url: z.string().url(), headers: z.record(z.string()).optional() }