Skip to main content
Glama

Backlog MCP Server

backlogApi.ts5.69 kB
import fetch from "node-fetch"; import type { RequestInit } from "node-fetch"; // エラー型の定義 interface BacklogError { errors: Array<{ message: string; code: number; moreInfo: string; }>; } // レスポンスがBacklogErrorかどうかを判定 function isBacklogError(obj: any): obj is BacklogError { return obj && Array.isArray(obj.errors) && obj.errors.length > 0; } /** * Backlog APIにリクエストを送信する関数 * * @param endpoint APIエンドポイントのパス * @param params リクエストパラメータ * @returns APIレスポンス * @throws エラー発生時 */ export async function fetchFromBacklog( endpoint: string, params: Record<string, any> = {} ): Promise<any> { try { // 環境変数のバリデーション const domain = process.env.BACKLOG_DOMAIN?.trim(); const apiKey = process.env.BACKLOG_API_KEY?.trim(); if (!domain || !apiKey) { throw new Error( "環境変数BACKLOG_DOMAINまたはBACKLOG_API_KEYが設定されていません" ); } // パラメータのサニタイズ const sanitizedParams = Object.fromEntries( Object.entries(params).map(([key, value]) => [ key, typeof value === "string" ? value.trim() : value ]) ); // エンドポイントのパスパラメータを置換 let processedEndpoint = endpoint; if (endpoint.includes("{")) { // {issueId}のようなパスパラメータを実際の値で置換 const matches = endpoint.match(/\{([^}]+)\}/g) || []; for (const match of matches) { const paramName = match.slice(1, -1); // {issueId} -> issueId if (sanitizedParams[paramName]) { processedEndpoint = processedEndpoint.replace( match, sanitizedParams[paramName] ); delete sanitizedParams[paramName]; // URLに埋め込んだパラメータは削除 } else { throw new Error(`パスパラメータ ${paramName} が指定されていません`); } } } // URLの構築 const url = new URL(`https://${domain}/api/v2/${processedEndpoint}`); url.searchParams.append("apiKey", apiKey); // メソッドの判定 const method = sanitizedParams.method || (endpoint.toLowerCase().includes("post") ? "POST" : "GET"); delete sanitizedParams.method; // methodパラメータは削除 // リクエストオプションの準備 const options: RequestInit = { method, headers: { "User-Agent": "Backlog-MCP-Server/1.0.0", "Accept": "application/json" } }; // POSTリクエストの場合はボディにパラメータを設定 if (method === "POST") { // POSTリクエストの場合はFormDataを使用(Backlog APIの仕様に合わせる) const formData = new URLSearchParams(); for (const [key, value] of Object.entries(sanitizedParams)) { if (value !== undefined && value !== null) { // 配列の場合は複数のパラメータとして追加 if (Array.isArray(value)) { value.forEach(item => { formData.append(`${key}[]`, String(item)); }); } else { formData.append(key, String(value)); } } } options.body = formData.toString(); options.headers = { ...options.headers, "Content-Type": "application/x-www-form-urlencoded" }; } else { // GETリクエストの場合はURLにパラメータを追加 for (const [key, value] of Object.entries(sanitizedParams)) { if (value !== undefined && value !== null) { // 配列の場合は複数のパラメータとして追加 if (Array.isArray(value)) { value.forEach(item => { url.searchParams.append(`${key}[]`, String(item)); }); } else { url.searchParams.append(key, String(value)); } } } } // デバッグ情報(開発時のみ使用) if (process.env.NODE_ENV === 'development') { console.log(`[DEBUG] リクエスト: ${method} ${url.toString()}`); if (method === 'POST') { console.log(`[DEBUG] リクエストボディ: ${options.body}`); } } // リクエストの実行 const response = await fetch(url.toString(), options); const data = await response.json(); // Backlogエラーレスポンスのチェックとハンドリング if (isBacklogError(data)) { const error = data.errors[0]; const errorDetails = error.moreInfo ? ` (詳細: ${error.moreInfo})` : ''; throw new Error(`Backlogエラー [${error.code}]: ${error.message}${errorDetails}`); } if (!response.ok) { throw new Error(`HTTPエラー ${response.status}: ${response.statusText}`); } return data; } catch (error) { if (error instanceof Error) { // エラーの種類に応じて詳細なメッセージを提供 if (error.message.includes('ENOTFOUND')) { throw new Error(`Backlog API接続エラー: ドメイン ${process.env.BACKLOG_DOMAIN} に接続できません`); } else if (error.message.includes('ETIMEDOUT')) { throw new Error(`Backlog API接続タイムアウト: リクエストがタイムアウトしました`); } else if (error.message.includes('SyntaxError')) { throw new Error(`Backlog APIレスポースエラー: 不正なJSONレスポンスを受信しました`); } else { throw new Error(`Backlog API呼び出しエラー: ${error.message}`); } } throw error; } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/tmhr1850/backlog-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server