check_browser_support
Check browser compatibility for Web APIs using Can I Use database to identify supported versions and polyfill recommendations.
Instructions
使用 Can I Use 資料庫檢查 Web API 的瀏覽器相容性,取得支援版本和 polyfill 建議
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| feature | Yes | Web API 功能名稱,如 "fetch", "flexbox", "css-grid", "webgl" | |
| targetBrowsers | No | 目標瀏覽器版本 (預設: { chrome: "90", firefox: "88", safari: "14", edge: "90" }) |
Implementation Reference
- src/server.ts:219-237 (registration)Registration of the 'check_browser_support' tool including its input schema and description in the ListToolsRequestSchema handler{ name: 'check_browser_support', description: '使用 Can I Use 資料庫檢查 Web API 的瀏覽器相容性,取得支援版本和 polyfill 建議', inputSchema: { type: 'object', properties: { feature: { type: 'string', description: 'Web API 功能名稱,如 "fetch", "flexbox", "css-grid", "webgl"', }, targetBrowsers: { type: 'object', description: '目標瀏覽器版本 (預設: { chrome: "90", firefox: "88", safari: "14", edge: "90" })', default: { chrome: '90', firefox: '88', safari: '14', edge: '90' } } }, required: ['feature'], }, },
- src/services/caniuse-service.ts:284-361 (handler)Core implementation of browser support checking using Can I Use database. Matches the tool's input parameters (feature, targetBrowsers) and returns compatibility report with support status, polyfills etc.async checkCompatibility( featureId: string, targetBrowsers: Record<string, string> = { chrome: '90', firefox: '88', safari: '14', edge: '90' } ): Promise<CompatibilityReport> { const support = await this.getFeatureSupport(featureId); if (!support) { return { feature: featureId, globalSupport: 0, supported: [], notSupported: Object.keys(targetBrowsers), partialSupport: [], recommendation: `找不到 ${featureId} 的相容性資料,建議查詢 MDN 文件`, polyfillAvailable: false }; } const supported: string[] = []; const notSupported: string[] = []; const partialSupport: string[] = []; for (const [browser, targetVersion] of Object.entries(targetBrowsers)) { const browserSupport = (support.browsers as any)[browser]; if (!browserSupport) { notSupported.push(browser); continue; } if (browserSupport.supported) { if (browserSupport.sinceVersion) { const sinceNum = parseFloat(browserSupport.sinceVersion); const targetNum = parseFloat(targetVersion); if (sinceNum <= targetNum) { if (browserSupport.partialSupport) { partialSupport.push(`${browser} >= ${browserSupport.sinceVersion}`); } else { supported.push(`${browser} >= ${browserSupport.sinceVersion}`); } } else { notSupported.push(`${browser} < ${browserSupport.sinceVersion}`); } } else { supported.push(browser); } } else { notSupported.push(browser); } } // 生成建議 let recommendation = ''; if (notSupported.length === 0) { recommendation = '✅ 所有目標瀏覽器都支援此功能'; } else if (supported.length === 0) { recommendation = '❌ 此功能在目標瀏覽器中不受支援,需要 polyfill 或替代方案'; } else { recommendation = `⚠️ 部分瀏覽器不支援:${notSupported.join(', ')}。建議提供 fallback 或使用 polyfill`; } return { feature: support.title, globalSupport: support.usage, supported, notSupported, partialSupport, recommendation, polyfillAvailable: this.checkPolyfillAvailable(featureId), polyfillUrl: this.getPolyfillUrl(featureId) }; }
- Helper method to search for Can I Use feature IDs by name, used prior to checking supportasync searchFeature(query: string): Promise<string[]> { const data = await this.loadData(); const features = data.data || {}; const lowerQuery = query.toLowerCase(); const matches: { id: string; score: number }[] = []; for (const [id, feature] of Object.entries(features) as [string, any][]) { let score = 0; // 完全匹配 ID if (id.toLowerCase() === lowerQuery) { score = 100; } // ID 包含查詢 else if (id.toLowerCase().includes(lowerQuery)) { score = 80; } // 標題匹配 else if (feature.title?.toLowerCase().includes(lowerQuery)) { score = 60; } // 描述匹配 else if (feature.description?.toLowerCase().includes(lowerQuery)) { score = 40; } // 關鍵字匹配 else if (feature.keywords?.toLowerCase().includes(lowerQuery)) { score = 30; } if (score > 0) { matches.push({ id, score }); } } // 按分數排序並返回 ID return matches .sort((a, b) => b.score - a.score) .slice(0, 10) .map(m => m.id); }
- src/server.ts:95-96 (helper)Instantiation of CanIUseService used for browser support checksthis.canIUseService = new CanIUseService(); this.baselineService = new BaselineService();
- src/server.ts:1112-1311 (handler)Comprehensive handler for compatibility checks (case 'check_compatibility') that performs feature search and browser support analysis using CanIUseService, closely matching the tool's purpose despite name differenceprivate async handleCompatibilityCheck(args: unknown) { try { if (!args || typeof args !== 'object') { throw new ValidationError('參數格式錯誤'); } const { feature, targetBrowsers = { chrome: '90', firefox: '88', safari: '14', edge: '90' } } = args as Record<string, unknown>; if (typeof feature !== 'string' || !feature.trim()) { throw new ValidationError('feature 為必填欄位,請提供要檢查的 Web API 功能名稱'); } // 同時查詢 Can I Use 和 Baseline const [caniuseMatches, baselineMatches] = await Promise.all([ this.canIUseService.searchFeature(feature), this.baselineService.searchFeature(feature) ]); // 如果兩個來源都找不到 if (caniuseMatches.length === 0 && baselineMatches.length === 0) { return { content: [{ type: 'text', text: `🔍 相容性查詢結果\n\n找不到與 "${feature}" 相關的功能。\n\n建議:\n- 嘗試使用不同的關鍵字\n- 常見功能名稱:fetch, flexbox, css-grid, webgl, es6-module, async-functions` }] }; } let report = `# 🌐 Web API 相容性報告: ${feature}\n\n`; // ========== Can I Use 資料 ========== if (caniuseMatches.length > 0) { const featureSupport = await this.canIUseService.getFeatureSupport(caniuseMatches[0]); if (featureSupport) { const compatReport = await this.canIUseService.checkCompatibility( caniuseMatches[0], targetBrowsers as Record<string, string> ); report += `## 📊 概覽\n\n`; report += `- **功能**: ${featureSupport.title}\n`; report += `- **全球支援率**: ${compatReport.globalSupport.toFixed(1)}%\n`; report += `- **標準狀態**: ${this.getStatusText(featureSupport.status)}\n`; if (featureSupport.description) { report += `\n### 說明\n${featureSupport.description}\n`; } report += `\n## 🎯 目標瀏覽器相容性\n\n`; report += `${compatReport.recommendation}\n\n`; if (compatReport.supported.length > 0) { report += `### ✅ 支援的瀏覽器\n`; for (const browser of compatReport.supported) { report += `- ${browser}\n`; } report += '\n'; } if (compatReport.partialSupport.length > 0) { report += `### ⚠️ 部分支援\n`; for (const browser of compatReport.partialSupport) { report += `- ${browser}\n`; } report += '\n'; } if (compatReport.notSupported.length > 0) { report += `### ❌ 不支援\n`; for (const browser of compatReport.notSupported) { report += `- ${browser}\n`; } report += '\n'; } // Polyfill 資訊 if (compatReport.polyfillAvailable) { report += `## 🔧 Polyfill\n\n`; report += `此功能有 polyfill 可用。\n`; if (compatReport.polyfillUrl) { report += `\n\`\`\`html\n<script src="${compatReport.polyfillUrl}"></script>\n\`\`\`\n`; } report += '\n'; } // 各瀏覽器詳細支援版本 report += `## 📱 各瀏覽器支援版本\n\n`; const browsers = featureSupport.browsers; const browserNames: Record<string, string> = { chrome: 'Chrome', firefox: 'Firefox', safari: 'Safari', edge: 'Edge', ie: 'Internet Explorer', opera: 'Opera', ios_saf: 'iOS Safari', android: 'Android Browser', samsung: 'Samsung Internet' }; for (const [key, name] of Object.entries(browserNames)) { const support = (browsers as any)[key]; if (support) { const icon = support.supported ? '✅' : (support.partialSupport ? '⚠️' : '❌'); const version = support.sinceVersion ? `v${support.sinceVersion}+` : (support.supported ? '支援' : '不支援'); report += `| ${icon} ${name} | ${version} |\n`; } } report += '\n'; } } // ========== Baseline 狀態 ========== report += `## 📊 Baseline 狀態\n\n`; if (baselineMatches.length > 0) { const baselineInfo = await this.baselineService.getFeature(baselineMatches[0].id) || baselineMatches[0]; if (baselineInfo.baseline) { report += this.baselineService.formatBaselineInfo(baselineInfo); report += `\n${this.baselineService.getRecommendation(baselineInfo)}\n\n`; // Baseline 的瀏覽器支援資訊 if (baselineInfo.compat) { report += `### Baseline 瀏覽器支援\n\n`; const compat = baselineInfo.compat; if (compat.chrome) { const since = compat.chrome.since || '未知'; const flags = compat.chrome.flags ? ' (需要啟用實驗性功能)' : ''; report += `- **Chrome**: ${since}${flags}\n`; } if (compat.firefox) { const since = compat.firefox.since || '未知'; const flags = compat.firefox.flags ? ' (需要啟用實驗性功能)' : ''; report += `- **Firefox**: ${since}${flags}\n`; } if (compat.safari) { const since = compat.safari.since || '未知'; const flags = compat.safari.flags ? ' (需要啟用實驗性功能)' : ''; report += `- **Safari**: ${since}${flags}\n`; } if (compat.edge) { const since = compat.edge.since || '未知'; const flags = compat.edge.flags ? ' (需要啟用實驗性功能)' : ''; report += `- **Edge**: ${since}${flags}\n`; } report += '\n'; } } else { report += `❓ 此功能尚未有 Baseline 狀態資訊\n\n`; } } else { report += `❓ 在 Baseline 資料庫中找不到此功能\n\n`; report += `建議查閱 [web.dev/baseline](https://web.dev/baseline) 確認。\n\n`; } // ========== 相關連結 ========== report += `## 🔗 相關連結\n\n`; if (caniuseMatches.length > 0) { report += `- [Can I Use](https://caniuse.com/${caniuseMatches[0]})\n`; } if (baselineMatches.length > 0 && baselineMatches[0].mdn?.url) { report += `- [MDN 文件](${baselineMatches[0].mdn.url})\n`; } report += `- [Baseline 狀態](https://web.dev/baseline)\n`; // 其他相關功能 const allMatches = [...new Set([...caniuseMatches.slice(1, 4), ...baselineMatches.slice(1, 4).map(m => m.name)])]; if (allMatches.length > 0) { report += `\n## 🔍 其他相關功能\n\n`; report += `您可能也在尋找:\n`; for (const match of allMatches.slice(0, 5)) { report += `- \`${typeof match === 'string' ? match : match}\`\n`; } } return { content: [{ type: 'text', text: report }] }; } catch (error) { const errorMessage = error instanceof ValidationError ? `參數驗證失敗: ${error.message}` : `相容性檢查失敗: ${error instanceof Error ? error.message : String(error)}`; return { content: [{ type: 'text', text: errorMessage }], isError: true, }; } }