@roottale/cms-mcp 0.67.1 → 0.68.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @roottale/cms-mcp
2
2
 
3
+ ## 0.68.0
4
+
5
+ ### Minor Changes
6
+
7
+ - d7130d8: 기존 고객 사이트의 검색·공유 기본값을 선언형 계약으로 보존합니다. 문자열 커스텀 필드 템플릿, 본문 문단 대체값, Unicode와 단어 경계 말줄임, 고정 이미지 기본값, 모델별 강제 robots와 분류 공개 경로를 지원합니다. 수동 SEO 설정은 우선하며 강제 검색 차단은 유지합니다.
8
+
9
+ 분류 조회 SDK에 색인 전환 상태와 추가 캐시 태그를 연결하고 외부 연동 문서·실행 예제를 함께 제공합니다.
10
+
3
11
  ## 0.67.1
4
12
 
5
13
  ### Patch Changes
package/dist/index.js CHANGED
@@ -1855,7 +1855,7 @@ function registerTools(server) {
1855
1855
  }
1856
1856
 
1857
1857
  // src/server.ts
1858
- var VERSION = true ? "0.67.1" : "dev";
1858
+ var VERSION = true ? "0.68.0" : "dev";
1859
1859
  var SERVER_INSTRUCTIONS = `
1860
1860
  roottale-cms-mcp\uB294 RootTale CMS\uB97C \uC678\uBD80 \uC0AC\uC774\uD2B8(\uC8FC\uB85C Next.js)\uC5D0 \uC5F0\uB3D9\uD558\uACE0
1861
1861
  \uAE00\xB7\uC378\uB124\uC77C\xB7\uBCF8\uBB38 \uC774\uBBF8\uC9C0\uB97C \uC790\uB3D9\uD654\uD558\uAE30 \uC704\uD55C \uBB38\uC11C\xB7\uC608\uC2DC \uCF54\uB4DC\xB7API tool\uC744 \uC81C\uACF5\uD569\uB2C8\uB2E4.
package/docs/seo.md CHANGED
@@ -63,6 +63,16 @@ export async function generateMetadata() {
63
63
 
64
64
  글은 공개 응답의 `metaJson.seo`, 분류는 `seoTitle/seoDescription/seoOgImage/seoOgImageAlt/seoNofollow`를 같은 빌더의 `overrides`에 연결합니다. 분류 색인 여부는 기존 `hubPromoted` 정책을 유지합니다. 글마다 경로 메타데이터 API를 추가 호출하지 않습니다. 본문이 있는 CMS 페이지는 `lib/page-metadata.ts` 예시처럼 기존 글 원본을 사용합니다.
65
65
 
66
+ 동적 기본값은 등록 계약의 `metadata.posts/terms.defaultRules[modelKey]`와 FRONT의 `formatMetadataDefaults(input, metadata)`에 같은 선언을 사용합니다. `title/description.source: "template"`은 `{{title}}`과 `{{field:필드이름}}`만 치환합니다. `fields`에는 공개 글의 `post.fields`를 전달하며 문자열 필드만 사용합니다. 객체·배열·누락 필드는 빈 문자열로 처리하고, 필드 안의 토큰을 다시 해석하지 않습니다. `normalizeWhitespace: true`로 비어 있는 선택 필드 사이의 공백을 정리합니다. 실행식·정규식은 받지 않습니다. 실행 가능한 연동 예시는 `examples/nextjs/lib/content-metadata.ts`입니다.
67
+
68
+ 요약이 없을 때 본문 문단을 사용하는 사이트는 `description.bodyFallback: {}`와 `bodyParagraphs: metadataBodyParagraphs(post.bodyJson)`를 연결합니다. `preferContaining`은 포함 문구가 있는 첫 문단을 우선하고, 없으면 첫 문단을 사용합니다. `stripLeadingLabel: "conclusion"`은 이 본문 대체값에서 기존 한국어 “결론부터 말씀드리면/말씀드릴게요” 도입부를 제거합니다. `maxLength`·`ellipsis`에 `lengthUnit: "code-points"`를 더하면 이모지를 중간에서 자르지 않습니다. `wordBoundaryMinLength`는 잘린 문자열의 마지막 공백이 지정한 UTF-16 위치 이상일 때 그 공백에서 자릅니다. `titleTemplateMaxLength`는 사이트 접미사를 붙인 자동 제목이 이 UTF-16 길이를 넘을 때 원래 자동 제목을 유지합니다. 직접 입력한 SEO 문구에는 이 변환을 적용하지 않습니다.
69
+
70
+ 공유 이미지 자동값은 대표 이미지 → 선언한 본문 첫 이미지·이전 이미지 순입니다. `useFeaturedImage: false` 또는 분류의 `useTermImage: false`로 기존 화면에서 사용하지 않던 콘텐츠 이미지를 제외할 수 있습니다. `defaultRules.defaults`는 콘텐츠 값이 없을 때 사용할 코드 기본값으로, 사이트 공통값보다 먼저 적용됩니다. 글에 고정 공유 이미지를 쓰려면 `useFeaturedImage: false`와 `defaults.ogImage`를 함께 선언하고 본문·이전 이미지 규칙은 켜지 않습니다. `defaultRules.fallback`은 사이트 공통값 뒤에 적용됩니다.
71
+
72
+ 검색 차단을 유지해야 하는 동적 모델은 `defaultRules[modelKey].robots: { forceNoindex: true, forceNofollow: true }`를 선언하고 같은 `robots`를 `resolveMetadata`나 페이지 빌더에 전달합니다. 직접 입력한 `false`로 이 제한을 해제할 수 없습니다. 기존 모델 소속과 실제 FRONT 분류 경로가 다른 경우 `metadata.terms.archivePaths: { notice: "/blog/:slug" }`처럼 등록 모델별 내부 경로를 선언합니다. 이 값은 메타데이터 조회·편집·재검증 주소만 맞추며 공개 라우트나 콘텐츠 소속을 변경하지 않습니다. 마지막 `:slug` 하나만 지원합니다.
73
+
74
+ `fetchCategoryCounts`는 API의 `category_index_activated`를 `categoryIndexActivated`로 보존합니다. 색인 전환을 요구하는 계약에서는 이 값이 `true`일 때만 `hubPromoted` 기반 정책을 적용하고 이전 정책은 그때까지 유지합니다. 분류 메타데이터 조회에도 `tags: [METADATA_CACHE_TAG]`를 전달할 수 있습니다.
75
+
66
76
  조회에는 `METADATA_CACHE_TAG`, `SITE_METADATA_DEFAULTS_CACHE_TAG`, `routeMetadataCacheTag(routeKey, locale)`가 자동 부착됩니다. 기본 재조회 주기는 300초이며 `revalidate`로 조정할 수 있습니다. 기존 서명 `theme.updated`와 `createRevalidateRoute`가 공통 메타데이터 태그·루트 layout·영향 경로를 무효화합니다. 수신부에 `(tag) => revalidateTag(tag, { expire: 0 })`를 전달해야 합니다. 공개 읽기·SSR·Proxy에는 요금제 조건을 넣지 마세요.
67
77
 
68
78
  사이트맵도 같은 최종 `noindex`·대표 경로 정책을 사용하고 활성 리다이렉트 출발 주소를 제외해야 합니다. 목록의 페이지 번호·필터별 정책은 사이트 라우트에서 계산합니다. 메타데이터 저장 성공·웹훅 수신 성공·실제 HTML 반영 확인은 서로 다른 상태입니다.
@@ -0,0 +1,43 @@
1
+ import {
2
+ formatMetadataDefaults,
3
+ metadataBodyParagraphs,
4
+ readMetadataValues,
5
+ resolveMetadata,
6
+ type CmsPostContent,
7
+ type MetadataDefaultsDeclaration,
8
+ type MetadataValues,
9
+ } from "@roottale/cms-client/server";
10
+
11
+ /** Register this same declaration in the deployed site's metadata.posts contract. */
12
+ export const contentMetadataDefaults: MetadataDefaultsDeclaration = {
13
+ posts: {
14
+ titleTemplates: { expert: "%s | 예시 사무소", blog: "%s | 예시 사무소" },
15
+ defaultRules: {
16
+ expert: {
17
+ title: { source: "template", template: "{{title}} {{field:role}}" },
18
+ description: { source: "template", template: "{{field:summary}} {{title}}의 담당 분야", normalizeWhitespace: true },
19
+ useFeaturedImage: false,
20
+ defaults: { ogImage: "/images/logo.png", ogImageAlt: "사무소 로고" },
21
+ },
22
+ blog: {
23
+ description: {
24
+ normalizeWhitespace: true, maxLength: 160, lengthUnit: "code-points", ellipsis: "…",
25
+ bodyFallback: {}, fallback: "%s에 관한 안내입니다.",
26
+ },
27
+ },
28
+ },
29
+ },
30
+ };
31
+
32
+ /** Metadata cleanup applies to automatic values only. Stored SEO and canonical remain separate. */
33
+ export function contentMetadata(post: CmsPostContent, siteUrl: string, siteDefaults: MetadataValues): MetadataValues {
34
+ const modelKey = post.modelKey ?? post.collectionKey ?? "blog";
35
+ const rule = contentMetadataDefaults.posts?.defaultRules?.[modelKey];
36
+ const defaults = formatMetadataDefaults({
37
+ kind: "posts", modelKey, title: post.title, description: post.excerpt,
38
+ fields: post.fields, bodyParagraphs: metadataBodyParagraphs(post.bodyJson),
39
+ featuredImage: post.featuredImageUrl,
40
+ }, contentMetadataDefaults);
41
+ return resolveMetadata({ defaults, siteDefaults, overrides: readMetadataValues(post.metaJson.seo),
42
+ fallback: rule?.fallback, robots: rule?.robots, imageBaseUrl: siteUrl });
43
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@roottale/cms-mcp",
3
- "version": "0.67.1",
3
+ "version": "0.68.0",
4
4
  "type": "module",
5
5
  "description": "RootTale CMS MCP server and CLI for models, entries, exposures, media, integration docs, and public API access.",
6
6
  "bin": {