growi-mcp-server
Version:
MCP Server for GROWI - a modern Wiki system
139 lines • 6.45 kB
JavaScript
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