Skip to main content
Glama
r3-yamauchi

kintone OAuth MCP Server on Cloudflare Workers

by r3-yamauchi
records.ts14.9 kB
import { z } from "zod"; import { KintoneErrorResponse } from "../types"; // ツールスキーマ export const getRecordsSchema = z.object({ appId: z.union([z.number(), z.string()]).describe("The kintone app ID"), query: z.string().optional().describe("Query to filter records (optional)"), fields: z.array(z.string()).optional().describe("Fields to retrieve (optional)") }); export const getRecordSchema = z.object({ appId: z.union([z.number(), z.string()]).describe("The kintone app ID"), id: z.union([z.number(), z.string()]).describe("The record ID") }); export const addRecordSchema = z.object({ appId: z.union([z.number(), z.string()]).describe("The kintone app ID"), record: z.record(z.string(), z.any()).describe("Record data as key-value pairs") }); export const addRecordsSchema = z.object({ appId: z.union([z.number(), z.string()]).describe("The kintone app ID"), records: z.array(z.record(z.string(), z.any())).describe("Array of record data") }); export const updateRecordSchema = z.object({ appId: z.union([z.number(), z.string()]).describe("The kintone app ID"), id: z.union([z.number(), z.string()]).describe("The record ID to update"), record: z.record(z.string(), z.any()).describe("Fields to update as key-value pairs"), revision: z.number().optional().describe("Expected revision number (optional)") }); export const getRecordCommentsSchema = z.object({ appId: z.union([z.number(), z.string()]).describe("The kintone app ID"), recordId: z.union([z.number(), z.string()]).describe("The record ID"), order: z.enum(["asc", "desc"]).optional().describe("Comment order (asc or desc, default: desc)"), offset: z.number().optional().describe("Offset for pagination"), limit: z.number().optional().describe("Number of comments to retrieve (max 10)") }); export const addRecordCommentSchema = z.object({ appId: z.union([z.number(), z.string()]).describe("The kintone app ID"), recordId: z.union([z.number(), z.string()]).describe("The record ID"), comment: z.object({ text: z.string().describe("Comment text"), mentions: z.array(z.object({ code: z.string().describe("User code or organization/group code"), type: z.enum(["USER", "ORGANIZATION", "GROUP"]).describe("Mention type") })).optional().describe("Users/organizations/groups to mention") }).describe("Comment details") }); export const evaluateRecordsAclSchema = z.object({ appId: z.union([z.number(), z.string()]).describe("The kintone app ID"), ids: z.array(z.union([z.number(), z.string()])).describe("Array of record IDs to evaluate") }); // ツール実装 export const recordTools = { async getRecords(params: z.infer<typeof getRecordsSchema>, props: { subdomain: string; accessToken: string }) { const { appId, query, fields } = params; const url = `https://${props.subdomain}.cybozu.com/k/v1/records.json`; const body: any = { app: String(appId) }; if (query) body.query = query; if (fields && fields.length > 0) body.fields = fields; console.error("=== getRecords Request Debug ==="); console.error("URL:", url); console.error("Method: POST with X-HTTP-Method-Override: GET"); console.error("Body:", JSON.stringify(body, null, 2)); console.error("=============================="); const response = await fetch(url, { method: "POST", headers: { "Authorization": `Bearer ${props.accessToken}`, "Content-Type": "application/json", "X-HTTP-Method-Override": "GET" }, body: JSON.stringify(body) }); const data = await response.json() as KintoneErrorResponse | any; if (!response.ok) { console.error("=== API Error Response ==="); console.error("Status:", response.status); console.error("Response:", JSON.stringify(data, null, 2)); console.error("========================"); const errorData = data as KintoneErrorResponse; let errorMessage = `Error ${response.status}: ${errorData.message || 'Unknown error'}`; return { content: [{ type: "text" as const, text: errorMessage }], }; } return { content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }], }; }, async getRecord(params: z.infer<typeof getRecordSchema>, props: { subdomain: string; accessToken: string }) { const { appId, id } = params; const url = `https://${props.subdomain}.cybozu.com/k/v1/record.json`; const body = { app: String(appId), id: String(id) }; console.error("=== getRecord Request Debug ==="); console.error("URL:", url); console.error("Method: POST with X-HTTP-Method-Override: GET"); console.error("Body:", JSON.stringify(body, null, 2)); console.error("=============================="); const response = await fetch(url, { method: "POST", headers: { "Authorization": `Bearer ${props.accessToken}`, "Content-Type": "application/json", "X-HTTP-Method-Override": "GET" }, body: JSON.stringify(body) }); const data = await response.json() as KintoneErrorResponse | any; if (!response.ok) { console.error("=== API Error Response ==="); console.error("Status:", response.status); console.error("Response:", JSON.stringify(data, null, 2)); console.error("========================"); const errorData = data as KintoneErrorResponse; let errorMessage = `Error ${response.status}: ${errorData.message || 'Unknown error'}`; return { content: [{ type: "text" as const, text: errorMessage }], }; } return { content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }], }; }, async addRecord(params: z.infer<typeof addRecordSchema>, props: { subdomain: string; accessToken: string }) { const { appId, record } = params; const url = `https://${props.subdomain}.cybozu.com/k/v1/record.json`; const response = await fetch(url, { method: "POST", headers: { "Authorization": `Bearer ${props.accessToken}`, "Content-Type": "application/json" }, body: JSON.stringify({ app: String(appId), record: record }) }); const data = await response.json() as KintoneErrorResponse | any; if (!response.ok) { console.error("=== API Error Response ==="); console.error("Status:", response.status); console.error("Response:", JSON.stringify(data, null, 2)); console.error("========================"); const errorData = data as KintoneErrorResponse; let errorMessage = `Error ${response.status}: ${errorData.message || 'Unknown error'}`; return { content: [{ type: "text" as const, text: errorMessage }], }; } return { content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }], }; }, async addRecords(params: z.infer<typeof addRecordsSchema>, props: { subdomain: string; accessToken: string }) { const { appId, records } = params; const url = `https://${props.subdomain}.cybozu.com/k/v1/records.json`; console.error("=== addRecords Request Debug ==="); console.error("URL:", url); console.error("Method: POST"); console.error("Records count:", records.length); console.error("==============================="); const response = await fetch(url, { method: "POST", headers: { "Authorization": `Bearer ${props.accessToken}`, "Content-Type": "application/json" }, body: JSON.stringify({ app: String(appId), records: records }) }); const data = await response.json() as KintoneErrorResponse | any; if (!response.ok) { console.error("=== API Error Response ==="); console.error("Status:", response.status); console.error("Response:", JSON.stringify(data, null, 2)); console.error("========================"); const errorData = data as KintoneErrorResponse; let errorMessage = `Error ${response.status}: ${errorData.message || 'Unknown error'}`; return { content: [{ type: "text" as const, text: errorMessage }], }; } return { content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }], }; }, async updateRecord(params: z.infer<typeof updateRecordSchema>, props: { subdomain: string; accessToken: string }) { const { appId, id, record, revision } = params; const url = `https://${props.subdomain}.cybozu.com/k/v1/record.json`; const body: any = { app: String(appId), id: String(id), record: record }; if (revision !== undefined) { body.revision = revision; } console.error("=== updateRecord Request Debug ==="); console.error("URL:", url); console.error("Method: PUT"); console.error("Body:", JSON.stringify(body, null, 2)); console.error("================================"); const response = await fetch(url, { method: "PUT", headers: { "Authorization": `Bearer ${props.accessToken}`, "Content-Type": "application/json" }, body: JSON.stringify(body) }); const data = await response.json() as KintoneErrorResponse | any; if (!response.ok) { console.error("=== API Error Response ==="); console.error("Status:", response.status); console.error("Response:", JSON.stringify(data, null, 2)); console.error("========================"); const errorData = data as KintoneErrorResponse; let errorMessage = `Error ${response.status}: ${errorData.message || 'Unknown error'}`; return { content: [{ type: "text" as const, text: errorMessage }], }; } return { content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }], }; }, async getRecordComments(params: z.infer<typeof getRecordCommentsSchema>, props: { subdomain: string; accessToken: string }) { const { appId, recordId, order = "desc", offset, limit } = params; const url = `https://${props.subdomain}.cybozu.com/k/v1/record/comments.json`; const body: any = { app: String(appId), record: String(recordId), order: order }; if (offset !== undefined) body.offset = offset; if (limit !== undefined) body.limit = Math.min(limit, 10); console.error("=== getRecordComments Request Debug ==="); console.error("URL:", url); console.error("Method: POST with X-HTTP-Method-Override: GET"); console.error("Body:", JSON.stringify(body, null, 2)); console.error("======================================"); const response = await fetch(url, { method: "POST", headers: { "Authorization": `Bearer ${props.accessToken}`, "Content-Type": "application/json", "X-HTTP-Method-Override": "GET" }, body: JSON.stringify(body) }); const data = await response.json() as KintoneErrorResponse | any; if (!response.ok) { console.error("=== API Error Response ==="); console.error("Status:", response.status); console.error("Response:", JSON.stringify(data, null, 2)); console.error("========================"); const errorData = data as KintoneErrorResponse; let errorMessage = `Error ${response.status}: ${errorData.message || 'Unknown error'}`; return { content: [{ type: "text" as const, text: errorMessage }], }; } return { content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }], }; }, async addRecordComment(params: z.infer<typeof addRecordCommentSchema>, props: { subdomain: string; accessToken: string }) { const { appId, recordId, comment } = params; const url = `https://${props.subdomain}.cybozu.com/k/v1/record/comment.json`; const body: any = { app: String(appId), record: String(recordId), comment: comment }; console.error("=== addRecordComment Request Debug ==="); console.error("URL:", url); console.error("Method: POST"); console.error("Body:", JSON.stringify(body, null, 2)); console.error("====================================="); const response = await fetch(url, { method: "POST", headers: { "Authorization": `Bearer ${props.accessToken}`, "Content-Type": "application/json" }, body: JSON.stringify(body) }); const data = await response.json() as KintoneErrorResponse | any; if (!response.ok) { console.error("=== API Error Response ==="); console.error("Status:", response.status); console.error("Response:", JSON.stringify(data, null, 2)); console.error("========================"); const errorData = data as KintoneErrorResponse; let errorMessage = `Error ${response.status}: ${errorData.message || 'Unknown error'}`; return { content: [{ type: "text" as const, text: errorMessage }], }; } return { content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }], }; }, async evaluateRecordsAcl(params: z.infer<typeof evaluateRecordsAclSchema>, props: { subdomain: string; accessToken: string }) { const { appId, ids } = params; const url = `https://${props.subdomain}.cybozu.com/k/v1/records/acl/evaluate.json`; const body = { app: String(appId), ids: ids.map(id => String(id)) }; console.error("=== evaluateRecordsAcl Request Debug ==="); console.error("URL:", url); console.error("Method: POST with X-HTTP-Method-Override: GET"); console.error("Body:", JSON.stringify(body, null, 2)); console.error("======================================="); const response = await fetch(url, { method: "POST", headers: { "Authorization": `Bearer ${props.accessToken}`, "Content-Type": "application/json", "X-HTTP-Method-Override": "GET" }, body: JSON.stringify(body) }); const data = await response.json() as KintoneErrorResponse | any; if (!response.ok) { console.error("=== API Error Response ==="); console.error("Status:", response.status); console.error("Response:", JSON.stringify(data, null, 2)); console.error("========================"); const errorData = data as KintoneErrorResponse; let errorMessage = `Error ${response.status}: ${errorData.message || 'Unknown error'}`; return { content: [{ type: "text" as const, text: errorMessage }], }; } return { content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }], }; } };

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-oauth-mcp-server-cfw'

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