@roottale/cms-mcp
Version:
RootTale CMS integration MCP server — bundled integration docs, Next.js example code, and public API lookup tools. Run with: npx @roottale/cms-mcp
74 lines (67 loc) • 1.99 kB
text/typescript
// RootTale CMS 블로그 데이터 레이어 — 서버 전용.
// 사이트 UI에 맞는 메타 형태로 변환하는 wrapper. API 키는 env에서만 읽는다.
import {
fetchPosts,
fetchPost,
type CmsPostContent,
} from "@roottale/cms-client/server";
function getApiKey(): string {
const key = process.env.ROOTTALE_API_KEY;
if (!key) throw new Error("ROOTTALE_API_KEY is not set");
return key;
}
const baseUrl = process.env.ROOTTALE_API_BASE;
export interface BlogPostMeta {
id: string;
slug: string;
title: string;
description: string;
date: string; // publishedAt ISO
category: string;
tags: { name: string; slug: string }[];
image: string | null;
authorName?: string;
seo?: {
title?: string;
description?: string;
canonical?: string;
ogImage?: string;
noindex?: boolean;
nofollow?: boolean;
};
}
function toMeta(post: CmsPostContent): BlogPostMeta {
const category = post.terms?.find((t) => t.taxonomy === "category");
const meta = (post.metaJson ?? {}) as Record<string, unknown>;
return {
id: post.id,
slug: post.slug,
title: post.title,
description: post.excerpt ?? "",
date: post.publishedAt ?? "",
category: category?.name ?? "",
tags:
post.terms
?.filter((t) => t.taxonomy === "tag")
.map((t) => ({ name: t.name, slug: t.slug })) ?? [],
image: post.featuredImageUrl ?? null,
authorName: post.authorName ?? undefined,
seo: meta.seo as BlogPostMeta["seo"],
};
}
export async function getAllPosts(): Promise<BlogPostMeta[]> {
const page = await fetchPosts({
apiKey: getApiKey(),
baseUrl,
type: "post",
limit: 100,
});
return page.items.map(toMeta);
}
export async function getPost(
slug: string,
): Promise<(BlogPostMeta & { bodyJson: unknown }) | null> {
const post = await fetchPost({ apiKey: getApiKey(), baseUrl, slugOrId: slug });
if (!post) return null;
return { ...toMeta(post), bodyJson: post.bodyJson };
}