@thallylabs/mcp 0.10.27 → 0.10.28

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/README.md CHANGED
@@ -2,10 +2,9 @@
2
2
 
3
3
  A [Model Context Protocol](https://modelcontextprotocol.io) server that lets AI
4
4
  tools — Claude Code, Claude Desktop, Cursor, Windsurf — manage
5
- [Thally](https://github.com/thallylabs/thally) knowledge surfaces through
6
- natural language. Tools can create, read, update, search, and migrate
7
- documentation, then trace a product-repository change into reviewable docs
8
- work.
5
+ [Thally](https://github.com/thallylabs/thally) docs through natural language.
6
+ Tools can create, read, update, search, and migrate documentation, then trace a
7
+ product change into an evidence-backed update for human review.
9
8
 
10
9
  ## Setup
11
10
 
package/dist/index.js CHANGED
@@ -276,18 +276,35 @@ import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync
276
276
  import { join as join3 } from "path";
277
277
 
278
278
  // src/lib/frontmatter.ts
279
- import matter from "gray-matter";
280
- var FRONTMATTER_OPTIONS = {
281
- engines: {
282
- javascript: () => ({}),
283
- js: () => ({})
284
- }
285
- };
279
+ import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
286
280
  function parseFrontmatter(raw) {
287
- return matter(raw, FRONTMATTER_OPTIONS);
281
+ const source = raw.charCodeAt(0) === 65279 ? raw.slice(1) : raw;
282
+ const opening = /^---([^\r\n]*)\r?\n/.exec(source);
283
+ if (!opening || opening[1].startsWith("-")) return { content: source, data: {} };
284
+ const language = opening[1].trim().toLowerCase();
285
+ const remainder = source.slice(opening[0].length);
286
+ const closing = /^---[ \t]*\r?$/m.exec(remainder);
287
+ const matter = closing ? remainder.slice(0, closing.index) : remainder;
288
+ let content = closing ? remainder.slice(closing.index + closing[0].length) : "";
289
+ if (content.startsWith("\r\n")) content = content.slice(2);
290
+ else if (content.startsWith("\n")) content = content.slice(1);
291
+ if (matter.trim() === "" || !["", "yaml", "yml"].includes(language)) {
292
+ return { content, data: {} };
293
+ }
294
+ const parsed = parseYaml(matter);
295
+ return {
296
+ content,
297
+ data: parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {}
298
+ };
288
299
  }
289
300
  function stringifyFrontmatter(body, data) {
290
- return matter.stringify(body, data);
301
+ const normalizedBody = body.endsWith("\n") ? body : `${body}
302
+ `;
303
+ const serialized = stringifyYaml(data, { lineWidth: 0 }).trimEnd();
304
+ return serialized === "{}" ? normalizedBody : `---
305
+ ${serialized}
306
+ ---
307
+ ${normalizedBody}`;
291
308
  }
292
309
 
293
310
  // src/tools/update-page.ts
@@ -1589,7 +1606,7 @@ async function handleReadApiSpec(input) {
1589
1606
  import { writeFileSync as writeFileSync6 } from "fs";
1590
1607
  import { extname as extname2 } from "path";
1591
1608
  import { z as z17 } from "zod";
1592
- import { parse as parseYaml } from "yaml";
1609
+ import { parse as parseYaml2 } from "yaml";
1593
1610
  var updateApiSpecSchema = z17.object({
1594
1611
  projectDir: z17.string().describe("Path to the Thally project root"),
1595
1612
  source: z17.string().optional().describe("Configured OpenAPI source; omit when the project has one"),
@@ -1597,7 +1614,7 @@ var updateApiSpecSchema = z17.object({
1597
1614
  });
1598
1615
  function parseDocument(source, content) {
1599
1616
  try {
1600
- return extname2(source).toLowerCase() === ".json" ? JSON.parse(content) : parseYaml(content);
1617
+ return extname2(source).toLowerCase() === ".json" ? JSON.parse(content) : parseYaml2(content);
1601
1618
  } catch {
1602
1619
  throw new Error(
1603
1620
  `OpenAPI source is not valid ${extname2(source).toLowerCase() === ".json" ? "JSON" : "YAML"}.`
package/dist/tools.d.ts CHANGED
@@ -5,8 +5,8 @@ import { z } from 'zod';
5
5
  * - `project` — reads/writes a local Thally project directory (`projectDir`).
6
6
  * - `site` — queries a deployed Thally site over HTTP (`siteUrl`).
7
7
  *
8
- * The remote MCP endpoint (A6) exposes only what's safe over HTTP; the docs
9
- * agent (A1) drives the `project` tools against a checked-out docs repo. Both
8
+ * The remote MCP endpoint exposes only what's safe over HTTP; the docs
9
+ * agent drives the `project` tools against a checked-out docs repo. Both
10
10
  * consume this one registry instead of re-declaring the tools.
11
11
  */
12
12
  type ToolScope = "project" | "site";
package/dist/tools.js CHANGED
@@ -267,18 +267,35 @@ import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync
267
267
  import { join as join3 } from "path";
268
268
 
269
269
  // src/lib/frontmatter.ts
270
- import matter from "gray-matter";
271
- var FRONTMATTER_OPTIONS = {
272
- engines: {
273
- javascript: () => ({}),
274
- js: () => ({})
275
- }
276
- };
270
+ import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
277
271
  function parseFrontmatter(raw) {
278
- return matter(raw, FRONTMATTER_OPTIONS);
272
+ const source = raw.charCodeAt(0) === 65279 ? raw.slice(1) : raw;
273
+ const opening = /^---([^\r\n]*)\r?\n/.exec(source);
274
+ if (!opening || opening[1].startsWith("-")) return { content: source, data: {} };
275
+ const language = opening[1].trim().toLowerCase();
276
+ const remainder = source.slice(opening[0].length);
277
+ const closing = /^---[ \t]*\r?$/m.exec(remainder);
278
+ const matter = closing ? remainder.slice(0, closing.index) : remainder;
279
+ let content = closing ? remainder.slice(closing.index + closing[0].length) : "";
280
+ if (content.startsWith("\r\n")) content = content.slice(2);
281
+ else if (content.startsWith("\n")) content = content.slice(1);
282
+ if (matter.trim() === "" || !["", "yaml", "yml"].includes(language)) {
283
+ return { content, data: {} };
284
+ }
285
+ const parsed = parseYaml(matter);
286
+ return {
287
+ content,
288
+ data: parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {}
289
+ };
279
290
  }
280
291
  function stringifyFrontmatter(body, data) {
281
- return matter.stringify(body, data);
292
+ const normalizedBody = body.endsWith("\n") ? body : `${body}
293
+ `;
294
+ const serialized = stringifyYaml(data, { lineWidth: 0 }).trimEnd();
295
+ return serialized === "{}" ? normalizedBody : `---
296
+ ${serialized}
297
+ ---
298
+ ${normalizedBody}`;
282
299
  }
283
300
 
284
301
  // src/tools/update-page.ts
@@ -1580,7 +1597,7 @@ async function handleReadApiSpec(input) {
1580
1597
  import { writeFileSync as writeFileSync6 } from "fs";
1581
1598
  import { extname as extname2 } from "path";
1582
1599
  import { z as z17 } from "zod";
1583
- import { parse as parseYaml } from "yaml";
1600
+ import { parse as parseYaml2 } from "yaml";
1584
1601
  var updateApiSpecSchema = z17.object({
1585
1602
  projectDir: z17.string().describe("Path to the Thally project root"),
1586
1603
  source: z17.string().optional().describe("Configured OpenAPI source; omit when the project has one"),
@@ -1588,7 +1605,7 @@ var updateApiSpecSchema = z17.object({
1588
1605
  });
1589
1606
  function parseDocument(source, content) {
1590
1607
  try {
1591
- return extname2(source).toLowerCase() === ".json" ? JSON.parse(content) : parseYaml(content);
1608
+ return extname2(source).toLowerCase() === ".json" ? JSON.parse(content) : parseYaml2(content);
1592
1609
  } catch {
1593
1610
  throw new Error(
1594
1611
  `OpenAPI source is not valid ${extname2(source).toLowerCase() === ".json" ? "JSON" : "YAML"}.`
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@thallylabs/mcp",
3
- "version": "0.10.27",
4
- "description": "MCP server for managing Thally knowledge surfaces and tracing product changes into documentation work.",
3
+ "version": "0.10.28",
4
+ "description": "MCP server for managing Thally docs and tracing product changes into evidence-backed updates for human review.",
5
5
  "type": "module",
6
6
  "engines": {
7
7
  "node": ">=18"
@@ -38,8 +38,7 @@
38
38
  "dependencies": {
39
39
  "@anthropic-ai/sdk": "^0.36.0",
40
40
  "@modelcontextprotocol/sdk": "^1.15.0",
41
- "create-thally-docs": "0.10.25",
42
- "gray-matter": "^4.0.3",
41
+ "create-thally-docs": "0.10.26",
43
42
  "p-limit": "^6.1.0",
44
43
  "yaml": "^2.8.2",
45
44
  "zod": "^3.0.0"