UNPKG

growi-mcp-server

Version:

MCP Server for GROWI - a modern Wiki system

139 lines 6.45 kB
import { z } from 'zod'; import https from 'https'; import http from 'http'; import { URL } from 'url'; const logToStderr = (...args) => { console.error(...args); }; export const pageExistsSchema = z.object({ path: z.string().describe('Path of the page to check'), }); function makeNativeHttpRequest(url, apiToken) { return new Promise((resolve, reject) => { const parsedUrl = new URL(url); logToStderr(`Making native HTTP request to: ${url}`); // トークンデータをx-www-form-urlencodedデータとして準備 const postData = `access_token=${encodeURIComponent(apiToken)}`; // curlと同じリクエストオプションを使用 const options = { hostname: parsedUrl.hostname, port: parsedUrl.port || (parsedUrl.protocol === 'https:' ? 443 : 80), path: `${parsedUrl.pathname}${parsedUrl.search}`, method: 'GET', headers: { 'User-Agent': 'curl/8.7.1', 'Accept': '*/*', 'Content-Type': 'application/x-www-form-urlencoded', 'Content-Length': Buffer.byteLength(postData) } }; const safeToken = apiToken.substring(0, 5) + '...'; logToStderr(`Making native curl-like request to URL: ${parsedUrl.protocol}//${parsedUrl.hostname}${options.path}`); logToStderr(`Sending access_token in request body: ${safeToken}`); logToStderr(`Full request options: ${JSON.stringify(options)}`); const protocol = parsedUrl.protocol === 'https:' ? https : http; const req = protocol.request(options, (res) => { logToStderr(`Response status: ${res.statusCode}`); logToStderr(`Response headers: ${JSON.stringify(res.headers)}`); let data = ''; res.on('data', (chunk) => { data += chunk.toString(); logToStderr(`Received chunk data: ${chunk.toString()}`); }); res.on('end', () => { logToStderr(`Response completed. Data length: ${data.length}`); if (data.length < 1000) { logToStderr(`Response data: ${data}`); } else { logToStderr(`Response data (truncated): ${data.substring(0, 500)}...`); } if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) { try { const jsonData = JSON.parse(data); logToStderr(`Parsed JSON data: ${JSON.stringify(jsonData)}`); // 利用可能なすべての属性をログに出力 Object.keys(jsonData).forEach(key => { logToStderr(`Response JSON key "${key}": ${JSON.stringify(jsonData[key])}`); }); resolve(jsonData); } catch (error) { reject(new Error(`Failed to parse JSON: ${error instanceof Error ? error.message : String(error)}`)); } } else { reject(new Error(`HTTP Error: ${res.statusCode} ${res.statusMessage || ''} - ${data}`)); } }); }); req.on('error', (error) => { logToStderr(`Request failed: ${error.message}`); reject(error); }); // Send the request with the access token in the body req.write(postData); req.end(); }); } export async function pageExists(client, params) { try { const parsed = pageExistsSchema.parse(params); let path = parsed.path; if (!path.startsWith('/')) path = '/' + path; logToStderr(`Checking if page exists at path: ${path}`); try { const apiUrl = client.baseURL; const apiToken = client.apiToken; if (!apiUrl || !apiToken) { throw new Error('Missing API URL or token'); } const url = new URL(`${apiUrl}/_api/v3/page/exist`); url.searchParams.append('path', path); logToStderr(`Base API URL: ${url.toString()}`); const data = await makeNativeHttpRequest(url.toString(), apiToken); // レスポンスのプロパティを詳細にチェック logToStderr(`Response data properties: ${Object.keys(data).join(', ')}`); logToStderr(`Response data.ok value: ${data.ok}, type: ${typeof data.ok}`); if (data.hasOwnProperty('isExist')) { logToStderr(`Response data.isExist value: ${data.isExist}, type: ${typeof data.isExist}`); } // 柔軟にok または isExist プロパティを確認 const exists = Boolean(data.ok || data.isExist); if (data && (typeof data.ok === 'boolean' || typeof data.isExist === 'boolean')) { const text = exists ? `Page exists: ${path}` : `Page not found: ${path}`; logToStderr(`Page existence result: ${text}`); return { content: [{ type: 'text', text }] }; } else { logToStderr(`Unexpected API response format: ${JSON.stringify(data)}`); } } catch (directError) { logToStderr(`Direct request failed: ${directError instanceof Error ? directError.message : String(directError)}`); } logToStderr(`Falling back to client.pageExists method`); const response = await client.pageExists(path); if (!response.ok) { logToStderr(`Client method failed: ${response.error}`); return { content: [ { type: 'text', text: `Error checking page: ${response.error || 'Unknown error'}` }, ], }; } const text = response.exists ? `Page exists: ${path}` : `Page not found: ${path}`; logToStderr(`Client method result: ${text}`); return { content: [{ type: 'text', text }] }; } catch (error) { console.error('Exception in pageExists tool:', error); return { content: [ { type: 'text', text: `Error checking page: ${error instanceof Error ? error.message : String(error)}` }, ], }; } } //# sourceMappingURL=page-exists.js.map