@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 +3 -4
- package/dist/index.js +28 -11
- package/dist/tools.d.ts +2 -2
- package/dist/tools.js +28 -11
- package/package.json +3 -4
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)
|
|
6
|
-
|
|
7
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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) :
|
|
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
|
|
9
|
-
* agent
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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) :
|
|
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.
|
|
4
|
-
"description": "MCP server for managing Thally
|
|
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.
|
|
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"
|