@roottale/cms-mcp 0.66.0 → 0.67.1

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,23 @@
1
1
  # @roottale/cms-mcp
2
2
 
3
+ ## 0.67.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 7eeb714: 공통 메타데이터·주소 이동 편집 조건 문서에 루트테일의 사이트별 기능 허용·제한을 반영하고, 메타데이터 수정 API의 403 코드(`upgrade_required`·`site_denied`·`billing_locked`)를 명시한다.
8
+
9
+ ## 0.67.0
10
+
11
+ ### Minor Changes
12
+
13
+ - 30d26ac: 공통 메타데이터 해석기·고유 경로 조회·Next SSR 빌더와 캐시 태그를 추가합니다. 기존 canonical과 강제 robots 정책을 보존하고 공유 이미지 대체 텍스트를 OG·X에 동일하게 적용합니다. 분류의 공유 전용 설정과 메타데이터 조회·수정 MCP 도구, Pro 하향 후 공개 적용 유지 계약을 문서와 예제에 반영합니다. 분류 색인 전환을 선언한 사이트가 공개 분류 응답의 `category_index_activated`를 확인한 뒤에만 분류 검색 제외를 적용하도록 안내합니다.
14
+
15
+ ### Patch Changes
16
+
17
+ - ddaa23f: 고정 페이지에서 검색 제목·설명·공유 이미지를 편집하고 저장값을 복원하도록 연결한다. 공개 사이트의 페이지 SEO 조회와 캐시 갱신 계약을 안내한다.
18
+ - 6c8785c: 사이트 코드에 고정 연결된 이미지 블록의 관리자 미리보기·편집 범위 선언과 배포 순서를 안내한다. 배치 규칙을 사용하는 기존 사이트의 동작은 유지한다.
19
+ - 94af63e: 문의 폼 설정을 루트테일 관리자 전용 메뉴로 분리하고, 고객은 받은 문의에서 접수 내용을 관리하도록 연동 안내와 예제를 갱신합니다.
20
+
3
21
  ## 0.66.0
4
22
 
5
23
  ### Minor Changes
package/README.md CHANGED
@@ -98,6 +98,9 @@ npx -y @roottale/cms-mcp cli entries publish "<post-id>"
98
98
  | `getTopSeoKeywords` | Google Search Console 상위 검색어 조회 |
99
99
  | `analyzeCmsPostSeo` | ROOT-ADMIN과 같은 규칙으로 글 SEO·가독성 분석 |
100
100
  | `getCmsPostSeoScores` | 발행 글의 최신 SEO 점수·등급 조회 |
101
+ | `listCmsMetadata` | 메타데이터 대상 검색·페이지 조회 |
102
+ | `getCmsMetadata` | 직접 설정·자동값·지원 필드·수정 버전 조회 |
103
+ | `updateCmsMetadata` | Pro/Premium 메타데이터 부분 변경·자동값 복귀 |
101
104
 
102
105
  ## 사람용 문서 (브라우저 열람)
103
106
 
package/dist/index.js CHANGED
@@ -1045,8 +1045,8 @@ async function callManagementTool(name, args) {
1045
1045
  return assertNever2(name);
1046
1046
  }
1047
1047
  }
1048
- function get(pathname, query) {
1049
- return requestRootTaleApi({ method: "GET", pathname, query: optionalQuery2(query) });
1048
+ function get(pathname, query2) {
1049
+ return requestRootTaleApi({ method: "GET", pathname, query: optionalQuery2(query2) });
1050
1050
  }
1051
1051
  function modelPath(modelKey) {
1052
1052
  return `/v1/cms/content-models/${encodeURIComponent(modelKey)}`;
@@ -1329,7 +1329,7 @@ import {
1329
1329
  ListToolsRequestSchema,
1330
1330
  McpError
1331
1331
  } from "@modelcontextprotocol/sdk/types.js";
1332
- import { z as z5 } from "zod";
1332
+ import { z as z6 } from "zod";
1333
1333
 
1334
1334
  // src/docs.ts
1335
1335
  import { readdir, readFile as readFile3 } from "fs/promises";
@@ -1384,8 +1384,8 @@ async function readDoc(relPath) {
1384
1384
  return null;
1385
1385
  }
1386
1386
  }
1387
- async function searchDocs(query) {
1388
- const regex = new RegExp(query, "i");
1387
+ async function searchDocs(query2) {
1388
+ const regex = new RegExp(query2, "i");
1389
1389
  const matches = [];
1390
1390
  for (const doc of await listDocs()) {
1391
1391
  const content = await readDoc(doc.path);
@@ -1550,16 +1550,132 @@ function optionalQuery3(values) {
1550
1550
  );
1551
1551
  }
1552
1552
 
1553
- // src/tools.ts
1554
- var ReadDocInput = z5.object({ path: z5.string().min(1) }).strict();
1555
- var SearchDocsInput = z5.object({ query: z5.string().min(1) }).strict();
1556
- var ListPostsInput = z5.object({
1553
+ // src/metadata-tools.ts
1554
+ import { z as z5 } from "zod";
1555
+ var scopeProperties = {
1556
+ siteId: { type: "string", description: "\uC0AC\uC774\uD2B8 ID" },
1557
+ locale: { type: "string", description: "locale, \uC0DD\uB7B5\uD558\uBA74 \uC0AC\uC774\uD2B8 \uAE30\uBCF8 \uC5B8\uC5B4" }
1558
+ };
1559
+ var targetProperties = {
1560
+ ...scopeProperties,
1561
+ kind: { type: "string", enum: ["route", "post", "term"] },
1562
+ key: { type: "string", description: "routeKey \uB610\uB294 \uAE00\xB7\uBD84\uB958 ID. \uBAA9\uB85D \uC751\uB2F5\uC758 key\uB97C \uC0AC\uC6A9" }
1563
+ };
1564
+ var METADATA_TOOL_DEFINITIONS = [
1565
+ {
1566
+ name: "listCmsMetadata",
1567
+ description: "\uC0AC\uC774\uD2B8 \uBA54\uD0C0\uB370\uC774\uD130 \uB300\uC0C1\uC744 \uAC80\uC0C9\uD558\uACE0 cursor\uB85C \uC870\uD68C\uD569\uB2C8\uB2E4. \uAE30\uBCF8 \uC694\uAE08\uC81C\uC5D0\uC11C\uB3C4 \uC870\uD68C\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.",
1568
+ inputSchema: {
1569
+ type: "object",
1570
+ additionalProperties: false,
1571
+ properties: {
1572
+ ...scopeProperties,
1573
+ kind: targetProperties.kind,
1574
+ query: { type: "string", description: "\uC81C\uBAA9\xB7\uACF5\uAC1C \uC8FC\uC18C \uAC80\uC0C9" },
1575
+ cursor: { type: "string" },
1576
+ limit: { type: "integer", minimum: 1, maximum: 100 },
1577
+ customized: { type: "boolean", description: "\uC9C1\uC811 \uC124\uC815 \uC5EC\uBD80 \uD544\uD130" }
1578
+ }
1579
+ }
1580
+ },
1581
+ {
1582
+ name: "getCmsMetadata",
1583
+ description: "\uBA54\uD0C0\uB370\uC774\uD130 \uC9C1\uC811 \uC124\uC815\xB7\uC790\uB3D9\uAC12\xB7\uCD5C\uC885\uAC12\xB7\uC9C0\uC6D0 \uD544\uB4DC\uC640 \uC218\uC815 \uBC84\uC804\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4. \uC218\uC815 \uC804\uC5D0 \uC774 \uC751\uB2F5\uC744 \uD655\uC778\uD558\uC138\uC694.",
1584
+ inputSchema: { type: "object", properties: targetProperties, required: ["kind", "key"], additionalProperties: false }
1585
+ },
1586
+ {
1587
+ name: "updateCmsMetadata",
1588
+ description: "Pro/Premium \uC0AC\uC774\uD2B8\uC758 \uD5C8\uC6A9\uB41C \uBA54\uD0C0\uB370\uC774\uD130\uB97C \uBD80\uBD84 \uBCC0\uACBD\uD569\uB2C8\uB2E4. expectedVersion\uC740 \uC9C1\uC804 \uC870\uD68C\uAC12\uC744 \uC4F0\uC138\uC694. null\uC740 \uC790\uB3D9\uAC12 \uBCF5\uADC0, \uBBF8\uC804\uC1A1\uC740 \uC720\uC9C0\uC774\uBA70 false\uB3C4 \uC800\uC7A5\uB429\uB2C8\uB2E4. \uACF5\uAC1C \uC0AC\uC774\uD2B8\uC5D0 \uBC18\uC601\uB420 \uC218 \uC788\uC2B5\uB2C8\uB2E4.",
1589
+ inputSchema: {
1590
+ type: "object",
1591
+ additionalProperties: false,
1592
+ required: ["kind", "key", "expectedVersion", "patch"],
1593
+ properties: {
1594
+ ...targetProperties,
1595
+ expectedVersion: { type: "string", description: "\uC870\uD68C\uD55C \uB300\uC0C1\uC758 version. \uC9C1\uC811 \uB9CC\uB4E4\uAC70\uB098 \uC99D\uAC00\uC2DC\uD0A4\uC9C0 \uC54A\uC74C" },
1596
+ patch: {
1597
+ type: "object",
1598
+ additionalProperties: false,
1599
+ properties: {
1600
+ title: { type: ["string", "null"], maxLength: 300 },
1601
+ description: { type: ["string", "null"], maxLength: 2e3 },
1602
+ ogImage: { type: ["string", "null"], maxLength: 2048 },
1603
+ ogImageAlt: { type: ["string", "null"], maxLength: 500 },
1604
+ noindex: { type: ["boolean", "null"] },
1605
+ nofollow: { type: ["boolean", "null"] }
1606
+ }
1607
+ }
1608
+ }
1609
+ }
1610
+ }
1611
+ ];
1612
+ function isMetadataToolName(name) {
1613
+ return METADATA_TOOL_DEFINITIONS.some((tool4) => tool4.name === name);
1614
+ }
1615
+ var Scope = z5.object({ siteId: z5.string().optional(), locale: z5.string().optional() });
1616
+ var Kind = z5.enum(["route", "post", "term"]);
1617
+ var Target = Scope.extend({ kind: Kind, key: z5.string().min(1) });
1618
+ var List = Scope.extend({
1619
+ kind: Kind.optional(),
1620
+ query: z5.string().optional(),
1621
+ cursor: z5.string().optional(),
1557
1622
  limit: z5.number().int().min(1).max(100).optional(),
1558
- type: z5.enum(["post", "page"]).optional(),
1559
- cursor: z5.string().optional()
1623
+ customized: z5.boolean().optional()
1560
1624
  }).strict();
1561
- var GetPostInput = z5.object({ slugOrId: z5.string().min(1) }).strict();
1562
- var GetSiteKnowledgeInput = z5.object({ siteId: z5.string().optional() }).strict();
1625
+ var nullableText = (max) => z5.string().trim().min(1).max(max).nullable().optional();
1626
+ var Update = Target.extend({
1627
+ expectedVersion: z5.string().min(1),
1628
+ patch: z5.object({
1629
+ title: nullableText(300),
1630
+ description: nullableText(2e3),
1631
+ ogImage: nullableText(2048),
1632
+ ogImageAlt: nullableText(500),
1633
+ noindex: z5.boolean().nullable().optional(),
1634
+ nofollow: z5.boolean().nullable().optional()
1635
+ }).strict()
1636
+ }).strict();
1637
+ async function callMetadataTool(name, args) {
1638
+ if (name === "listCmsMetadata") {
1639
+ const input2 = List.parse(args);
1640
+ return requestRootTaleApi({ method: "GET", pathname: "/v1/cms/metadata", query: query({
1641
+ site_id: input2.siteId,
1642
+ locale: input2.locale,
1643
+ kind: input2.kind,
1644
+ q: input2.query,
1645
+ cursor: input2.cursor,
1646
+ limit: input2.limit,
1647
+ customized: input2.customized
1648
+ }) });
1649
+ }
1650
+ if (name === "getCmsMetadata") {
1651
+ const input2 = Target.strict().parse(args);
1652
+ return requestRootTaleApi({ method: "GET", pathname: targetPath(input2), query: query({ site_id: input2.siteId, locale: input2.locale }) });
1653
+ }
1654
+ const input = Update.parse(args);
1655
+ return requestRootTaleApi({ method: "PATCH", pathname: targetPath(input), body: {
1656
+ ...input.siteId !== void 0 ? { site_id: input.siteId } : {},
1657
+ ...input.locale !== void 0 ? { locale: input.locale } : {},
1658
+ expected_version: input.expectedVersion,
1659
+ patch: input.patch
1660
+ } });
1661
+ }
1662
+ function targetPath(input) {
1663
+ return `/v1/cms/metadata/${input.kind}/${encodeURIComponent(input.key)}`;
1664
+ }
1665
+ function query(input) {
1666
+ return Object.fromEntries(Object.entries(input).flatMap(([key, value]) => value === void 0 ? [] : [[key, String(value)]]));
1667
+ }
1668
+
1669
+ // src/tools.ts
1670
+ var ReadDocInput = z6.object({ path: z6.string().min(1) }).strict();
1671
+ var SearchDocsInput = z6.object({ query: z6.string().min(1) }).strict();
1672
+ var ListPostsInput = z6.object({
1673
+ limit: z6.number().int().min(1).max(100).optional(),
1674
+ type: z6.enum(["post", "page"]).optional(),
1675
+ cursor: z6.string().optional()
1676
+ }).strict();
1677
+ var GetPostInput = z6.object({ slugOrId: z6.string().min(1) }).strict();
1678
+ var GetSiteKnowledgeInput = z6.object({ siteId: z6.string().optional() }).strict();
1563
1679
  var DOCUMENTATION_TOOL_DEFINITIONS = [
1564
1680
  {
1565
1681
  name: "listRootTaleDocs",
@@ -1639,7 +1755,8 @@ var TOOL_DEFINITIONS = [
1639
1755
  ...DOCUMENTATION_TOOL_DEFINITIONS,
1640
1756
  ...AUTOMATION_TOOL_DEFINITIONS,
1641
1757
  ...MANAGEMENT_TOOL_DEFINITIONS,
1642
- ...SEO_TOOL_DEFINITIONS
1758
+ ...SEO_TOOL_DEFINITIONS,
1759
+ ...METADATA_TOOL_DEFINITIONS
1643
1760
  ];
1644
1761
  function textResponse(text) {
1645
1762
  return { content: [{ type: "text", text }] };
@@ -1662,6 +1779,9 @@ function registerTools(server) {
1662
1779
  if (isSeoToolName(request.params.name)) {
1663
1780
  return jsonResponse(await callSeoTool(request.params.name, args));
1664
1781
  }
1782
+ if (isMetadataToolName(request.params.name)) {
1783
+ return jsonResponse(await callMetadataTool(request.params.name, args));
1784
+ }
1665
1785
  if (isManagementToolName(request.params.name)) {
1666
1786
  return jsonResponse(await callManagementTool(request.params.name, args));
1667
1787
  }
@@ -1735,7 +1855,7 @@ function registerTools(server) {
1735
1855
  }
1736
1856
 
1737
1857
  // src/server.ts
1738
- var VERSION = true ? "0.66.0" : "dev";
1858
+ var VERSION = true ? "0.67.1" : "dev";
1739
1859
  var SERVER_INSTRUCTIONS = `
1740
1860
  roottale-cms-mcp\uB294 RootTale CMS\uB97C \uC678\uBD80 \uC0AC\uC774\uD2B8(\uC8FC\uB85C Next.js)\uC5D0 \uC5F0\uB3D9\uD558\uACE0
1741
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.