Skip to main content
Glama
RecordTools.js9.95 kB
// src/server/tools/RecordTools.js import { KintoneRecord } from '../../models/KintoneRecord.js'; import { ValidationUtils } from '../../utils/ValidationUtils.js'; import { LoggingUtils } from '../../utils/LoggingUtils.js'; import { ResponseBuilder } from '../../utils/ResponseBuilder.js'; // レコード関連のツールを処理する関数 export async function handleRecordTools(name, args, repository) { // 共通のツール実行ログ LoggingUtils.logToolExecution('record', name, args); switch (name) { case 'get_record': { ValidationUtils.validateRequired(args, ['app_id', 'record_id']); const record = await repository.getRecord(args.app_id, args.record_id); return record.fields; // KintoneRecord ではなく fields を返す } case 'search_records': { ValidationUtils.validateRequired(args, ['app_id']); // クエリーが提供されている場合、kintoneクエリー構文を検証 if (args.query) { ValidationUtils.validateKintoneQuery(args.query); } const records = await repository.searchRecords( args.app_id, args.query, args.fields ); return records.map(r => r.fields); } case 'create_record': { ValidationUtils.validateRequired(args, ['app_id', 'fields']); ValidationUtils.validateObject(args.fields, 'fields'); const recordId = await repository.createRecord( args.app_id, args.fields ); return ResponseBuilder.recordCreated(recordId); } case 'update_record': { ValidationUtils.validateRequired(args, ['app_id', 'fields']); // レコードIDまたはupdateKeyのいずれかが必要 if (!args.record_id && !args.updateKey) { throw new Error('record_id または updateKey は必須パラメータです。'); } ValidationUtils.validateObject(args.fields, 'fields'); let response; if (args.record_id) { // レコードIDを使用した更新 response = await repository.updateRecord( new KintoneRecord( args.app_id, args.record_id, args.fields ) ); } else { // updateKeyを使用した更新 response = await repository.updateRecordByKey( args.app_id, args.updateKey.field, args.updateKey.value, args.fields ); } return ResponseBuilder.recordUpdated(response.revision); } case 'add_record_comment': { ValidationUtils.validateRequired(args, ['app_id', 'record_id', 'text']); ValidationUtils.validateString(args.text, 'text'); const commentId = await repository.addRecordComment( args.app_id, args.record_id, args.text, args.mentions || [] ); return ResponseBuilder.withId('comment_id', commentId); } case 'update_record_status': { ValidationUtils.validateRequired(args, ['app_id', 'record_id', 'action']); ValidationUtils.validateString(args.action, 'action'); const response = await repository.updateRecordStatus( args.app_id, args.record_id, args.action, args.assignee ); return ResponseBuilder.withRevision(response.revision); } case 'update_record_assignees': { ValidationUtils.validateRequired(args, ['app_id', 'record_id', 'assignees']); ValidationUtils.validateArray(args.assignees, 'assignees', { maxLength: 100 }); const response = await repository.updateRecordAssignees( args.app_id, args.record_id, args.assignees ); return ResponseBuilder.withRevision(response.revision); } case 'get_record_comments': { ValidationUtils.validateRequired(args, ['app_id', 'record_id']); const PAGE_SIZE = 10; const order = (args.order ?? 'desc').toString(); ValidationUtils.validateString(order, 'order', { allowedValues: ['asc', 'desc'] }); const offset = args.offset ?? 0; ValidationUtils.validateNumber(offset, 'offset', { min: 0, allowString: true }); const limitProvided = args.limit !== undefined && args.limit !== null && args.limit !== ''; let targetLimit = null; if (limitProvided) { targetLimit = args.limit; ValidationUtils.validateNumber(targetLimit, 'limit', { min: 1, allowString: true }); targetLimit = Number(targetLimit); } const apiOrder = targetLimit === null ? 'asc' : order; const outputOrder = order; let currentOffset = Number(offset); const collected = []; let totalCount = null; while (true) { const response = await repository.getRecordComments( args.app_id, args.record_id, apiOrder, currentOffset, PAGE_SIZE ); const fetched = response.comments || []; totalCount = response.totalCount ?? totalCount; collected.push(...fetched); const hasMore = apiOrder === 'asc' ? Boolean(response?.newer) : Boolean(response?.older); const reachedLimit = targetLimit !== null && collected.length >= targetLimit; if (fetched.length === 0 || reachedLimit || !hasMore) { break; } currentOffset += PAGE_SIZE; } const sorted = [...collected].sort((a, b) => { const aId = Number(a.id); const bId = Number(b.id); return outputOrder === 'asc' ? aId - bId : bId - aId; }); const finalComments = targetLimit !== null ? sorted.slice(0, targetLimit) : sorted; const finalTotalCount = totalCount ?? (targetLimit !== null ? finalComments.length : sorted.length); return { comments: finalComments, totalCount: finalTotalCount, order: outputOrder }; } case 'create_records': { ValidationUtils.validateRequired(args, ['app_id', 'records']); ValidationUtils.validateArray(args.records, 'records', { minLength: 1, maxLength: 100 }); const result = await repository.createRecords(args.app_id, args.records); return ResponseBuilder.recordsCreated(result.ids, result.revisions); } case 'upsert_record': { ValidationUtils.validateRequired(args, ['app_id', 'updateKey', 'fields']); ValidationUtils.validateObject(args.updateKey, 'updateKey'); ValidationUtils.validateString(args.updateKey.field, 'updateKey.field'); ValidationUtils.validateObject(args.fields, 'fields'); const result = await repository.upsertRecord( args.app_id, args.updateKey, args.fields ); return { record_id: result.id, revision: result.revision, message: `レコードをupsertしました (ID: ${result.id})`, operation: result.operation }; } case 'upsert_records': { ValidationUtils.validateRequired(args, ['app_id', 'records']); ValidationUtils.validateArray(args.records, 'records', { minLength: 1, maxLength: 100 }); const normalizedRecords = args.records.map((entry, index) => { ValidationUtils.validateObject(entry, `records[${index}]`); ValidationUtils.validateObject(entry.updateKey, `records[${index}].updateKey`); ValidationUtils.validateString(entry.updateKey.field, `records[${index}].updateKey.field`); if (entry.updateKey.value === undefined || entry.updateKey.value === null) { throw new Error(`records[${index}].updateKey.value は必須です。`); } ValidationUtils.validateObject(entry.fields, `records[${index}].fields`); return { updateKey: { field: entry.updateKey.field, value: entry.updateKey.value }, fields: entry.fields }; }); const result = await repository.upsertRecords(args.app_id, normalizedRecords); return { records: result.map((r) => ({ record_id: r.id, revision: r.revision, operation: r.operation })), message: `${result.length}件のレコードをupsertしました` }; } default: throw new Error(`Unknown record tool: ${name}`); } }

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/r3-yamauchi/kintone-mcp-server'

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