Skip to main content
Glama

getUsers

Retrieve a list of users from the Backlog API to manage project access, permissions, and collaboration efficiently. Simplifies user data extraction for project management and issue tracking.

Instructions

ユーザー一覧の取得

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • The shared handler function executed for the 'getUsers' tool. It parses input params using the Zod schema, substitutes path parameters (for 'users' path, none), invokes fetchFromBacklog('users', validated params like keyword, roleType, offset, count), formats the response as JSON text, and handles errors.
    const handler = async (params: Record<string, unknown>): Promise<McpResponse> => { try { // パラメータのバリデーション const validatedParams = await endpoint.schema.parseAsync(params); // URL中のプレースホルダーを置換 let path = endpoint.path; // URIスキーム(例:space://info)の場合はBacklog APIのパスに変換 if (path.includes('://')) { // URIスキームを取り除いてAPIパスに変換 const uriParts = path.split('://'); const resourceType = uriParts[0]; const resourcePath = uriParts[1]; // リソースタイプに応じてAPIパスを構築 switch (resourceType) { case 'space': path = 'space'; break; case 'projects': if (resourcePath === 'list') { path = 'projects'; } else { path = `projects/${resourcePath}`; } break; case 'issues': if (resourcePath.includes('/list')) { const projectPart = resourcePath.split('/')[0]; path = 'issues'; validatedParams.projectIdOrKey = projectPart; } else if (resourcePath.includes('/details')) { const issuePart = resourcePath.split('/')[0]; path = `issues/${issuePart}`; } break; case 'wikis': if (resourcePath.includes('/list')) { const projectPart = resourcePath.split('/')[0]; path = 'wikis'; validatedParams.projectIdOrKey = projectPart; } break; case 'users': path = 'users'; break; default: path = resourcePath; } } // 通常のパスパラメータの置換処理 for (const [key, value] of Object.entries(validatedParams)) { if (typeof value === "string" || typeof value === "number") { const placeholder = `{${key}}`; if (path.includes(placeholder)) { path = path.replace(placeholder, String(value)); // プレースホルダーとして使用したパラメータは削除 delete validatedParams[key]; } } } // メソッドの追加 if (endpoint.method !== "GET") { validatedParams.method = endpoint.method; } // APIリクエストの実行 const data = await fetchFromBacklog(path, validatedParams); return { content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }], }; } catch (error: any) { // エラーメッセージの整形 const errorMessage = error.errors ? `バリデーションエラー: ${JSON.stringify(error.errors)}` : `エラー: ${error.message}`; return { content: [{ type: "text" as const, text: errorMessage }], isError: true, }; } };
  • The endpoint configuration for 'getUsers' tool, including input schema using Zod for parameters: keyword (optional string), roleType (optional enum), offset and count (optional numbers for pagination).
    { name: "getUsers", description: "ユーザー一覧の取得", path: "users", method: "GET", schema: z.object({ keyword: z.string().max(1000, "検索キーワードは1000文字以内である必要があります").optional(), roleType: z.enum(["admin", "user", "reporter", "viewer", "guest"], { errorMap: () => ({ message: "ロールタイプは 'admin', 'user', 'reporter', 'viewer', 'guest' のいずれかである必要があります" }) }).optional(), offset: offsetSchema, count: countSchema, }), type: "tool", },
  • The registration logic within the loop that calls MCP server.tool() for each tool endpoint, including 'getUsers', passing the name, description, and the handler wrapper.
    if (endpoint.type === "tool") { // ツールの登録 server.tool( endpoint.name, endpoint.description, async (args: Record<string, unknown>) => handler(args) ); } else if (endpoint.type === "resource") {
  • Helper function called by the handler to perform the actual HTTP request to Backlog API endpoint 'users' with query params (e.g., keyword, roleType[offset], count), handles authentication via apiKey, param arrays, errors, and returns the user list data.
    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; } }

Other Tools

Related Tools

Latest Blog Posts

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