Skip to content

Instantly share code, notes, and snippets.

@yamanoku
Last active April 12, 2025 08:03
Show Gist options
  • Save yamanoku/4f31453747b1517798fb50bf965193d0 to your computer and use it in GitHub Desktop.
Save yamanoku/4f31453747b1517798fb50bf965193d0 to your computer and use it in GitHub Desktop.
Baselineの情報を教えてくれるMCPサーバー
// mcp-baseline-server.ts
import { McpServer } from "npm:@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "npm:@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "npm:zod@^3.24.2";
import process from "node:process";
import type { WebFeature, WebFeatureResponse } from "./types.ts";
const APIURL = "https://api.webstatus.dev/v1/features";
// Baselineのカテゴリを判定する関数
const determineBaselineCategory = (status: string): string | undefined => {
if (!status) return undefined;
if (status.includes("baseline")) {
if (status.includes("widely")) {
return "Widely";
} else if (status.includes("newly")) {
return "Newly";
} else if (status.includes("limited")) {
return "Limited";
}
}
return undefined;
};
// Web Platform APIからフィーチャー情報を取得する関数
const getFeatureStatus = async (
query: string
): Promise<WebFeature[] | undefined> => {
try {
const encodedQuery = encodeURIComponent(query);
const url = `${APIURL}?q=${encodedQuery}`;
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000);
const response = await fetch(url, {
signal: controller.signal,
});
clearTimeout(timeoutId);
if (!response.ok) {
throw new Error(`API request failed with status ${response.status}`);
}
const responseData: WebFeatureResponse = await response.json();
const features = responseData.data;
// Baselineカテゴリを追加
return features.map((feature) => ({
...feature,
baselineCategory: determineBaselineCategory(feature.baseline.status),
}));
} catch (error) {
console.error(error);
}
};
// MCPサーバーの初期化
const server = new McpServer({
name: "Baseline MCP Server",
version: "0.1.0",
capabilities: {
resource: {},
tools: {},
},
});
server.tool(
"getWebFeaturesApi",
"クエリを指定し、Web Platform Dashboardからfeatureの結果を取得します",
{
query: z.string().describe("調べたいWeb APIの名前"),
},
async ({ query }: { query: string }) => {
try {
// フィーチャー情報を取得
const features = await getFeatureStatus(query);
if (features === undefined || features.length === 0) {
return {
content: [
{
type: "text",
text: `「${query}」に関する情報は見つかりませんでした。別の機能名で試してみてください。`,
},
],
};
}
// Baselineカテゴリのリストを作成
const categories = features
.map((f) => f.baseline || "Baseline外")
.filter((value, index, self) => self.indexOf(value) === index); // 重複を削除
// レスポンスを構築
const categoryInfo = {
widely:
"広くサポートされているWeb標準機能です。ほとんどのブラウザで安全に使用できます。",
newly:
"新しく標準化されたWeb機能です。主要なブラウザでサポートされ始めていますが、まだ普及途上です。",
limited:
"限定的にサポートされているWeb機能です。一部のブラウザでは使用できないか、フラグが必要な場合があります。",
Baseline外:
"現時点ではBaselineに含まれていないWeb機能です。ブラウザのサポート状況を個別に確認する必要があります。",
};
// 結果を整形して応答を構築
const baselineInfo = features
.map(
(feature) =>
`${feature.name}: ${feature.baseline?.status || "Baseline外"}`
)
.join("\n- ");
const categoryDescriptions = categories
.filter((category) => categoryInfo[category.status])
.map((category) => `- ${query}: ${categoryInfo[category.status]}`)
.join("\n");
const response = [
categoryDescriptions,
features.length > 1 ? `\n具体的な機能:\n- ${baselineInfo}` : "",
]
.join("\n")
.trim();
return {
content: [
{
type: "text",
text: response,
},
],
};
} catch (error) {
console.error("Error processing event:", error);
return {
content: [
{
type: "text",
text: "Web機能の情報取得中にエラーが発生しました。しばらく経ってから再試行してください。",
},
],
};
}
}
);
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Weather MCP Server running on stdio");
}
main().catch((error) => {
console.error("Fatal error in main():", error);
process.exit(1);
});
type Status = "widely" | "limited" | "newly" | "Baseline外";
type BrowserName = "chrome" | "edge" | "firefox" | "safari";
type Baseline = {
high_date?: string;
low_date?: string;
status: Status;
};
type BrowserImplementation = {
date: string;
status: Status;
version: string;
};
type BrowserImplementations = {
[key in BrowserName]: BrowserImplementation;
};
type Spec = {
links: {
link: string;
};
};
type BrowserUsage = {
daily: number;
};
type Usage = {
[key in BrowserName]?: BrowserUsage;
};
type BrowserWptScore = {
score: number;
metadata?: {
status: Status;
};
};
type WptEnvironment = {
[key in BrowserName]: BrowserWptScore;
};
type Wpt = {
experimental: WptEnvironment;
stable: WptEnvironment;
};
export type WebFeature = {
baseline: Baseline;
browser_implementations: BrowserImplementations;
feature_id: string;
name: string;
spec: Spec;
usage: Usage;
wpt: Wpt;
};
export type WebFeatureResponse = {
data: WebFeature[]
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
OSZAR »