@craft-ts/mcp 0.7.0-beta.13
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 +71 -0
- package/content/agents.md +35 -0
- package/content/best-practices.md +79 -0
- package/content/docs-index.json +658 -0
- package/dist/catalog.d.ts +27 -0
- package/dist/catalog.js +67 -0
- package/dist/catalog.js.map +1 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +13 -0
- package/dist/main.js.map +1 -0
- package/dist/mcp-server.d.ts +3 -0
- package/dist/mcp-server.js +144 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/resources.d.ts +10 -0
- package/dist/resources.js +63 -0
- package/dist/resources.js.map +1 -0
- package/mcp.json +10 -0
- package/package.json +62 -0
- package/plugin.json +19 -0
- package/skills/craft-ts/SKILL.md +43 -0
- package/skills/craft-ts-architecture-tests/SKILL.md +110 -0
- package/skills/craft-ts-effect-v4/SKILL.md +31 -0
- package/skills/craft-ts-routes/SKILL.md +135 -0
- package/skills/craft-ts-routes/references/di-checks.md +101 -0
- package/skills/craft-ts-routes/references/eslint-workflow.md +52 -0
- package/skills/craft-ts-routes/references/pending-and-exceptions.md +93 -0
- package/skills/craft-ts-routes/references/scaling-and-pitfalls.md +111 -0
- package/skills/craft-ts-service-migration/SKILL.md +86 -0
- package/skills/migrate-to-craft-ts/SKILL.md +135 -0
- package/skills/translate-spec-to-craft-ts/SKILL.md +86 -0
- package/skills/translate-spec-to-craft-ts/references/lexical-map.md +322 -0
- package/skills/translate-spec-to-craft-ts/references/pattern-recipes.md +123 -0
- package/skills/translate-spec-to-craft-ts/references/project-index.md +52 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export declare const DOCS_ORIGIN = "https://craft-ts.github.io/craft";
|
|
2
|
+
export type DocPage = {
|
|
3
|
+
path: string;
|
|
4
|
+
title: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
body: string;
|
|
7
|
+
};
|
|
8
|
+
export type SkillRecord = {
|
|
9
|
+
name: string;
|
|
10
|
+
description: string;
|
|
11
|
+
markdown: string;
|
|
12
|
+
references: Record<string, string>;
|
|
13
|
+
};
|
|
14
|
+
export type SearchHit = {
|
|
15
|
+
path: string;
|
|
16
|
+
title: string;
|
|
17
|
+
description?: string;
|
|
18
|
+
url: string;
|
|
19
|
+
score: number;
|
|
20
|
+
snippet: string;
|
|
21
|
+
};
|
|
22
|
+
export declare function pageUrl(path: string): string;
|
|
23
|
+
export declare function searchPages(pages: readonly DocPage[], query: string, options?: {
|
|
24
|
+
limit?: number;
|
|
25
|
+
section?: string;
|
|
26
|
+
}): SearchHit[];
|
|
27
|
+
export declare function findPage(pages: readonly DocPage[], path: string): DocPage | undefined;
|
package/dist/catalog.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export const DOCS_ORIGIN = 'https://craft-ts.github.io/craft';
|
|
2
|
+
function tokenize(value) {
|
|
3
|
+
return value
|
|
4
|
+
.toLowerCase()
|
|
5
|
+
.split(/[^a-z0-9_+*/-]+/)
|
|
6
|
+
.filter((token) => token.length > 1);
|
|
7
|
+
}
|
|
8
|
+
function countHits(haystack, terms) {
|
|
9
|
+
return terms.reduce((score, term) => score + (haystack.split(term).length - 1), 0);
|
|
10
|
+
}
|
|
11
|
+
function snippetAround(body, terms) {
|
|
12
|
+
const lower = body.toLowerCase();
|
|
13
|
+
const index = terms
|
|
14
|
+
.map((term) => lower.indexOf(term))
|
|
15
|
+
.filter((value) => value >= 0)
|
|
16
|
+
.sort((a, b) => a - b)[0];
|
|
17
|
+
if (index === undefined) {
|
|
18
|
+
return body.slice(0, 280).trim();
|
|
19
|
+
}
|
|
20
|
+
const start = Math.max(0, index - 80);
|
|
21
|
+
const excerpt = body.slice(start, start + 280).replace(/\s+/g, ' ').trim();
|
|
22
|
+
return `${start > 0 ? '…' : ''}${excerpt}${start + 280 < body.length ? '…' : ''}`;
|
|
23
|
+
}
|
|
24
|
+
export function pageUrl(path) {
|
|
25
|
+
return `${DOCS_ORIGIN}${path === '/' ? '/' : path}`;
|
|
26
|
+
}
|
|
27
|
+
export function searchPages(pages, query, options = {}) {
|
|
28
|
+
const terms = tokenize(query);
|
|
29
|
+
if (terms.length === 0)
|
|
30
|
+
return [];
|
|
31
|
+
const section = options.section?.replace(/^\//, '');
|
|
32
|
+
const limit = Math.min(Math.max(options.limit ?? 8, 1), 20);
|
|
33
|
+
return pages
|
|
34
|
+
.filter((page) => {
|
|
35
|
+
if (!section)
|
|
36
|
+
return true;
|
|
37
|
+
if (section === 'examples') {
|
|
38
|
+
return (page.path.startsWith('/learn/') ||
|
|
39
|
+
page.path.startsWith('/resources/examples'));
|
|
40
|
+
}
|
|
41
|
+
return page.path === `/${section}` || page.path.startsWith(`/${section}/`);
|
|
42
|
+
})
|
|
43
|
+
.map((page) => {
|
|
44
|
+
const titleHits = countHits(page.title.toLowerCase(), terms);
|
|
45
|
+
const pathHits = countHits(page.path.toLowerCase(), terms);
|
|
46
|
+
const descriptionHits = countHits((page.description ?? '').toLowerCase(), terms);
|
|
47
|
+
const bodyHits = countHits(page.body.toLowerCase(), terms);
|
|
48
|
+
const score = titleHits * 12 + pathHits * 8 + descriptionHits * 6 + bodyHits;
|
|
49
|
+
return {
|
|
50
|
+
path: page.path,
|
|
51
|
+
title: page.title,
|
|
52
|
+
description: page.description,
|
|
53
|
+
url: pageUrl(page.path),
|
|
54
|
+
score,
|
|
55
|
+
snippet: snippetAround(page.body, terms),
|
|
56
|
+
};
|
|
57
|
+
})
|
|
58
|
+
.filter((hit) => hit.score > 0)
|
|
59
|
+
.sort((a, b) => b.score - a.score || a.path.localeCompare(b.path))
|
|
60
|
+
.slice(0, limit);
|
|
61
|
+
}
|
|
62
|
+
export function findPage(pages, path) {
|
|
63
|
+
const normalised = path.startsWith('/') ? path : `/${path}`;
|
|
64
|
+
return pages.find((page) => page.path === normalised ||
|
|
65
|
+
page.path === `${normalised.replace(/\/$/, '')}`);
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG,kCAAkC,CAAC;AAyB9D,SAAS,QAAQ,CAAC,KAAa;IAC7B,OAAO,KAAK;SACT,WAAW,EAAE;SACb,KAAK,CAAC,iBAAiB,CAAC;SACxB,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACzC,CAAC;AAED,SAAS,SAAS,CAAC,QAAgB,EAAE,KAAe;IAClD,OAAO,KAAK,CAAC,MAAM,CACjB,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,EAC1D,CAAC,CACF,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,IAAY,EAAE,KAAe;IAClD,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IACjC,MAAM,KAAK,GAAG,KAAK;SAChB,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;SAClC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,IAAI,CAAC,CAAC;SAC7B,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACnC,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,EAAE,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IAC3E,OAAO,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,GAAG,KAAK,GAAG,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AACpF,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,IAAY;IAClC,OAAO,GAAG,WAAW,GAAG,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,WAAW,CACzB,KAAyB,EACzB,KAAa,EACb,OAAO,GAAyC,EAAE;IAElD,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC9B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAElC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACpD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAE5D,OAAO,KAAK;SACT,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;QACf,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QAC1B,IAAI,OAAO,KAAK,UAAU,EAAE,CAAC;YAC3B,OAAO,CACL,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;gBAC/B,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,qBAAqB,CAAC,CAC5C,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,CAAC,IAAI,KAAK,IAAI,OAAO,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,OAAO,GAAG,CAAC,CAAC;IAC7E,CAAC,CAAC;SACD,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACZ,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,KAAK,CAAC,CAAC;QAC7D,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,KAAK,CAAC,CAAC;QAC3D,MAAM,eAAe,GAAG,SAAS,CAC/B,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,EACtC,KAAK,CACN,CAAC;QACF,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,KAAK,CAAC,CAAC;QAC3D,MAAM,KAAK,GACT,SAAS,GAAG,EAAE,GAAG,QAAQ,GAAG,CAAC,GAAG,eAAe,GAAG,CAAC,GAAG,QAAQ,CAAC;QACjE,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,GAAG,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;YACvB,KAAK;YACL,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC;SACzC,CAAC;IACJ,CAAC,CAAC;SACD,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC;SAC9B,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;SACjE,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,QAAQ,CACtB,KAAyB,EACzB,IAAY;IAEZ,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;IAC5D,OAAO,KAAK,CAAC,IAAI,CACf,CAAC,IAAI,EAAE,EAAE,CACP,IAAI,CAAC,IAAI,KAAK,UAAU;QACxB,IAAI,CAAC,IAAI,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,CACnD,CAAC;AACJ,CAAC"}
|
package/dist/main.d.ts
ADDED
package/dist/main.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
+
import { createCraftMcpServer } from './mcp-server.js';
|
|
4
|
+
import { loadCraftMcpResources } from './resources.js';
|
|
5
|
+
const resources = loadCraftMcpResources();
|
|
6
|
+
const server = createCraftMcpServer(resources);
|
|
7
|
+
await server.connect(new StdioServerTransport());
|
|
8
|
+
const shutdown = async () => {
|
|
9
|
+
await server.close();
|
|
10
|
+
};
|
|
11
|
+
process.once('SIGINT', () => void shutdown());
|
|
12
|
+
process.once('SIGTERM', () => void shutdown());
|
|
13
|
+
//# sourceMappingURL=main.js.map
|
package/dist/main.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,MAAM,SAAS,GAAG,qBAAqB,EAAE,CAAC;AAC1C,MAAM,MAAM,GAAG,oBAAoB,CAAC,SAAS,CAAC,CAAC;AAE/C,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,oBAAoB,EAAE,CAAC,CAAC;AAEjD,MAAM,QAAQ,GAAG,KAAK,IAAmB,EAAE;IACzC,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;AACvB,CAAC,CAAC;AAEF,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,EAAE,CAAC,CAAC;AAC9C,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,EAAE,CAAC,CAAC"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { findPage, pageUrl, searchPages } from './catalog.js';
|
|
4
|
+
import { LLMS_FULL_TXT_URL, LLMS_TXT_URL, } from './resources.js';
|
|
5
|
+
export function createCraftMcpServer(resources) {
|
|
6
|
+
const server = new McpServer({ name: 'craft-ts', version: '0.7.0' });
|
|
7
|
+
server.registerTool('get_best_practices', {
|
|
8
|
+
description: 'Return the CraftTS coding-agent guide: which primitive to use, yield* rules, the architecture/ graph contract, services, routes, ESLint, and the AGENTS.md snippet to drop into an app that imports @craft-ts/core. Call this before writing or reviewing Craft code.',
|
|
9
|
+
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
10
|
+
}, async () => toolResult({
|
|
11
|
+
bestPractices: resources.bestPractices,
|
|
12
|
+
agentsMd: resources.agentsMd,
|
|
13
|
+
llmsTxt: LLMS_TXT_URL,
|
|
14
|
+
llmsFullTxt: LLMS_FULL_TXT_URL,
|
|
15
|
+
}));
|
|
16
|
+
server.registerTool('search_documentation', {
|
|
17
|
+
description: 'Search the bundled CraftTS documentation (Learn, Guide, Reference, Resources). Use it when you need the current API, a decision page, or a recipe. Prefer this over guessing from training data.',
|
|
18
|
+
inputSchema: {
|
|
19
|
+
query: z.string().min(1).describe('Keywords, API names, or a task'),
|
|
20
|
+
section: z
|
|
21
|
+
.enum(['learn', 'guide', 'reference', 'resources', 'examples'])
|
|
22
|
+
.optional()
|
|
23
|
+
.describe('Limit results to one docs section. `examples` covers Learn plus /resources/examples.'),
|
|
24
|
+
limit: z.number().int().positive().max(20).optional(),
|
|
25
|
+
},
|
|
26
|
+
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
27
|
+
}, async ({ query, section, limit }) => toolResult({
|
|
28
|
+
query,
|
|
29
|
+
hits: searchPages(resources.pages, query, { section, limit }),
|
|
30
|
+
}));
|
|
31
|
+
server.registerTool('get_documentation_page', {
|
|
32
|
+
description: 'Return one documentation page as markdown. Use a path from search_documentation, such as /guide/state/local-state or /learn/01-first-state.',
|
|
33
|
+
inputSchema: {
|
|
34
|
+
path: z
|
|
35
|
+
.string()
|
|
36
|
+
.min(1)
|
|
37
|
+
.describe('Docs path, for example /guide/concepts/mental-model'),
|
|
38
|
+
},
|
|
39
|
+
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
40
|
+
}, async ({ path }) => {
|
|
41
|
+
const page = findPage(resources.pages, path);
|
|
42
|
+
if (!page) {
|
|
43
|
+
return toolResult({
|
|
44
|
+
error: `No documentation page at ${path}. Call search_documentation first.`,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return toolResult(serializePage(page));
|
|
48
|
+
});
|
|
49
|
+
server.registerTool('find_examples', {
|
|
50
|
+
description: 'Find Learn tutorials and demo examples that match a task (list, form, pagination, routing, optimistic update, …).',
|
|
51
|
+
inputSchema: {
|
|
52
|
+
query: z.string().min(1),
|
|
53
|
+
limit: z.number().int().positive().max(20).optional(),
|
|
54
|
+
},
|
|
55
|
+
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
56
|
+
}, async ({ query, limit }) => toolResult({
|
|
57
|
+
query,
|
|
58
|
+
hits: searchPages(resources.pages, query, {
|
|
59
|
+
section: 'examples',
|
|
60
|
+
limit,
|
|
61
|
+
}),
|
|
62
|
+
}));
|
|
63
|
+
server.registerTool('list_skills', {
|
|
64
|
+
description: 'List Agent Skills shipped with @craft-ts/mcp (architecture tests, routes, spec translation, service migration, full-app migration). Load one with get_skill before following a workflow.',
|
|
65
|
+
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
66
|
+
}, async () => toolResult({
|
|
67
|
+
skills: resources.skills.map(({ name, description, references }) => ({
|
|
68
|
+
name,
|
|
69
|
+
description,
|
|
70
|
+
references: Object.keys(references),
|
|
71
|
+
})),
|
|
72
|
+
}));
|
|
73
|
+
server.registerTool('get_skill', {
|
|
74
|
+
description: 'Return a CraftTS Agent Skill. Omit `reference` to get SKILL.md; pass a reference filename from list_skills to load that file only.',
|
|
75
|
+
inputSchema: {
|
|
76
|
+
name: z
|
|
77
|
+
.string()
|
|
78
|
+
.min(1)
|
|
79
|
+
.describe('Skill directory name, for example craft-ts-routes or translate-spec-to-craft-ts'),
|
|
80
|
+
reference: z
|
|
81
|
+
.string()
|
|
82
|
+
.min(1)
|
|
83
|
+
.optional()
|
|
84
|
+
.describe('Optional references/*.md filename'),
|
|
85
|
+
},
|
|
86
|
+
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
87
|
+
}, async ({ name, reference }) => {
|
|
88
|
+
const skill = resources.skills.find((entry) => entry.name === name);
|
|
89
|
+
if (!skill) {
|
|
90
|
+
return toolResult({
|
|
91
|
+
error: `Unknown skill "${name}". Call list_skills.`,
|
|
92
|
+
available: resources.skills.map((entry) => entry.name),
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
if (!reference) {
|
|
96
|
+
return toolResult({
|
|
97
|
+
name: skill.name,
|
|
98
|
+
description: skill.description,
|
|
99
|
+
markdown: skill.markdown,
|
|
100
|
+
references: Object.keys(skill.references),
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
const markdown = skill.references[reference];
|
|
104
|
+
if (!markdown) {
|
|
105
|
+
return toolResult({
|
|
106
|
+
error: `Skill "${name}" has no reference "${reference}".`,
|
|
107
|
+
available: Object.keys(skill.references),
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
return toolResult({ name: skill.name, reference, markdown });
|
|
111
|
+
});
|
|
112
|
+
server.registerTool('get_llms_txt', {
|
|
113
|
+
description: 'Return the public llms.txt / llms-full.txt URLs and a short index of bundled documentation paths. Use llms.txt as the internet entry point; use search_documentation for offline lookup.',
|
|
114
|
+
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
115
|
+
}, async () => toolResult({
|
|
116
|
+
llmsTxt: LLMS_TXT_URL,
|
|
117
|
+
llmsFullTxt: LLMS_FULL_TXT_URL,
|
|
118
|
+
markdownPages: resources.pages.map((page) => ({
|
|
119
|
+
path: page.path,
|
|
120
|
+
title: page.title,
|
|
121
|
+
url: `${pageUrl(page.path)}.md`,
|
|
122
|
+
})),
|
|
123
|
+
}));
|
|
124
|
+
return server;
|
|
125
|
+
}
|
|
126
|
+
function serializePage(page) {
|
|
127
|
+
return {
|
|
128
|
+
path: page.path,
|
|
129
|
+
title: page.title,
|
|
130
|
+
description: page.description,
|
|
131
|
+
url: pageUrl(page.path),
|
|
132
|
+
markdownUrl: `${pageUrl(page.path)}.md`,
|
|
133
|
+
markdown: page.body,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
function toolResult(result) {
|
|
137
|
+
return {
|
|
138
|
+
content: [
|
|
139
|
+
{ type: 'text', text: JSON.stringify(result, null, 2) },
|
|
140
|
+
],
|
|
141
|
+
structuredContent: { result },
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=mcp-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-server.js","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type DocPage, type SkillRecord } from './catalog.js';
|
|
2
|
+
export declare const LLMS_TXT_URL = "https://craft-ts.github.io/craft/llms.txt";
|
|
3
|
+
export declare const LLMS_FULL_TXT_URL = "https://craft-ts.github.io/craft/llms-full.txt";
|
|
4
|
+
export type CraftMcpResources = {
|
|
5
|
+
pages: DocPage[];
|
|
6
|
+
skills: SkillRecord[];
|
|
7
|
+
bestPractices: string;
|
|
8
|
+
agentsMd: string;
|
|
9
|
+
};
|
|
10
|
+
export declare function loadCraftMcpResources(moduleUrl?: string): CraftMcpResources;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { dirname, join } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { DOCS_ORIGIN } from './catalog.js';
|
|
5
|
+
export const LLMS_TXT_URL = `${DOCS_ORIGIN}/llms.txt`;
|
|
6
|
+
export const LLMS_FULL_TXT_URL = `${DOCS_ORIGIN}/llms-full.txt`;
|
|
7
|
+
function packageRootFrom(moduleUrl) {
|
|
8
|
+
return join(dirname(fileURLToPath(moduleUrl)), '..');
|
|
9
|
+
}
|
|
10
|
+
function parseSkillFrontmatter(markdown) {
|
|
11
|
+
if (!markdown.startsWith('---')) {
|
|
12
|
+
throw new Error('Skill is missing YAML frontmatter.');
|
|
13
|
+
}
|
|
14
|
+
const end = markdown.indexOf('\n---', 3);
|
|
15
|
+
if (end === -1) {
|
|
16
|
+
throw new Error('Skill frontmatter is not closed.');
|
|
17
|
+
}
|
|
18
|
+
const frontmatter = markdown.slice(3, end);
|
|
19
|
+
const name = /^name:\s*(.+)$/m.exec(frontmatter)?.[1]?.trim();
|
|
20
|
+
const description = /^description:\s*(.+)$/m
|
|
21
|
+
.exec(frontmatter)?.[1]
|
|
22
|
+
?.trim();
|
|
23
|
+
if (!name || !description) {
|
|
24
|
+
throw new Error('Skill frontmatter must include name and description.');
|
|
25
|
+
}
|
|
26
|
+
return { name, description, body: markdown };
|
|
27
|
+
}
|
|
28
|
+
function loadSkill(directory) {
|
|
29
|
+
const markdown = readFileSync(join(directory, 'SKILL.md'), 'utf8');
|
|
30
|
+
const parsed = parseSkillFrontmatter(markdown);
|
|
31
|
+
const references = {};
|
|
32
|
+
const referencesDir = join(directory, 'references');
|
|
33
|
+
if (existsSync(referencesDir)) {
|
|
34
|
+
for (const file of readdirSync(referencesDir)) {
|
|
35
|
+
if (!file.endsWith('.md'))
|
|
36
|
+
continue;
|
|
37
|
+
references[file] = readFileSync(join(referencesDir, file), 'utf8');
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
name: parsed.name,
|
|
42
|
+
description: parsed.description,
|
|
43
|
+
markdown: parsed.body,
|
|
44
|
+
references,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
export function loadCraftMcpResources(moduleUrl = import.meta.url) {
|
|
48
|
+
const root = packageRootFrom(moduleUrl);
|
|
49
|
+
const pages = JSON.parse(readFileSync(join(root, 'content/docs-index.json'), 'utf8'));
|
|
50
|
+
const skillsRoot = join(root, 'skills');
|
|
51
|
+
const skills = readdirSync(skillsRoot)
|
|
52
|
+
.map((name) => join(skillsRoot, name))
|
|
53
|
+
.filter((directory) => existsSync(join(directory, 'SKILL.md')))
|
|
54
|
+
.map(loadSkill)
|
|
55
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
56
|
+
return {
|
|
57
|
+
pages,
|
|
58
|
+
skills,
|
|
59
|
+
bestPractices: readFileSync(join(root, 'content/best-practices.md'), 'utf8'),
|
|
60
|
+
agentsMd: readFileSync(join(root, 'content/agents.md'), 'utf8'),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=resources.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resources.js","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"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"}
|
package/mcp.json
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@craft-ts/mcp",
|
|
3
|
+
"version": "0.7.0-beta.13",
|
|
4
|
+
"description": "MCP server, Agent Skills, and LLM files for coding agents using @craft-ts/core",
|
|
5
|
+
"author": "Romain Geffrault",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"homepage": "https://craft-ts.github.io/craft/resources/ai-agents",
|
|
8
|
+
"bugs": {
|
|
9
|
+
"url": "https://github.com/craft-ts/craft-ts/issues"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "https://github.com/craft-ts/craft-ts.git",
|
|
14
|
+
"directory": "packages/mcp"
|
|
15
|
+
},
|
|
16
|
+
"type": "module",
|
|
17
|
+
"bin": {
|
|
18
|
+
"craft-ts-mcp": "dist/main.js"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist",
|
|
22
|
+
"skills",
|
|
23
|
+
"content",
|
|
24
|
+
"plugin.json",
|
|
25
|
+
"mcp.json",
|
|
26
|
+
"README.md",
|
|
27
|
+
"!dist/**/*.spec.js",
|
|
28
|
+
"!dist/**/*.spec.d.ts",
|
|
29
|
+
"!dist/**/*.spec.js.map"
|
|
30
|
+
],
|
|
31
|
+
"scripts": {
|
|
32
|
+
"bundle-docs": "node scripts/bundle-docs.mjs",
|
|
33
|
+
"build": "node scripts/build.mjs",
|
|
34
|
+
"start": "npm run build && node dist/main.js",
|
|
35
|
+
"test": "vitest run"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@modelcontextprotocol/sdk": "1.26.0",
|
|
39
|
+
"zod": "4.3.6"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/node": "20.19.9",
|
|
43
|
+
"typescript": "6.0.3",
|
|
44
|
+
"vitest": "^4.0.8"
|
|
45
|
+
},
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": ">=20.19.0"
|
|
48
|
+
},
|
|
49
|
+
"publishConfig": {
|
|
50
|
+
"access": "public"
|
|
51
|
+
},
|
|
52
|
+
"keywords": [
|
|
53
|
+
"craft-ts",
|
|
54
|
+
"craft-ts",
|
|
55
|
+
"angular",
|
|
56
|
+
"mcp",
|
|
57
|
+
"mcp-server",
|
|
58
|
+
"llms.txt",
|
|
59
|
+
"agent-skills",
|
|
60
|
+
"ai"
|
|
61
|
+
]
|
|
62
|
+
}
|
package/plugin.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
|
|
3
|
+
"name": "craft-ts",
|
|
4
|
+
"description": "Agent Skills and MCP server for writing framework-independent @craft-ts/core apps: primitives, API boundaries, architecture tests, services, routes, forms, Effect v4, and migration.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Romain Geffrault",
|
|
7
|
+
"url": "https://github.com/craft-ts/craft-ts"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://craft-ts.github.io/craft/resources/ai-agents",
|
|
10
|
+
"repository": "https://github.com/craft-ts/craft-ts",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"keywords": [
|
|
13
|
+
"angular",
|
|
14
|
+
"craft-ts",
|
|
15
|
+
"craft-ts",
|
|
16
|
+
"mcp",
|
|
17
|
+
"agent-skills"
|
|
18
|
+
]
|
|
19
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: craft-ts
|
|
3
|
+
description: Write and review framework-independent @craft-ts/core applications, including CSR and SSR. Use when creating or evolving a CraftTS project, adding state, query, mutation, queryParams, asyncProcess, craftService, craftComponent, craftRoutes, forms, SSR rendering or hydration, API boundaries, or coding-agent setup.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# CraftTS
|
|
7
|
+
|
|
8
|
+
You are working in a framework-independent application that depends on
|
|
9
|
+
`@craft-ts/core`. The default renderer is `@craft-ts/component`; Angular is not
|
|
10
|
+
required and must not be introduced just to solve a Craft problem.
|
|
11
|
+
|
|
12
|
+
## First steps
|
|
13
|
+
|
|
14
|
+
1. Call the CraftTS MCP tool `get_best_practices` when it is available.
|
|
15
|
+
2. Search docs with `search_documentation` before inventing an API.
|
|
16
|
+
3. Load a workflow skill with `get_skill` when the task matches:
|
|
17
|
+
- `craft-ts-architecture-tests` — scaffold or run `architecture/`, or freeze a graph smell. Not before every feature.
|
|
18
|
+
- `translate-spec-to-craft-ts` — map a spec onto primitives
|
|
19
|
+
- `craft-ts-routes` — type-safe routes and DI checks
|
|
20
|
+
- `craft-ts-service-migration` — Angular services → `craftService`
|
|
21
|
+
- `migrate-to-craft-ts` — run `craft-migrate`, then finish diagnostics
|
|
22
|
+
- `craft-ts-effect-v4` — use Effect v4 services, Layers and `queryEffect`
|
|
23
|
+
|
|
24
|
+
If MCP is not configured, read https://ng-angular-stack.github.io/craft/llms.txt and the `AGENTS.md` snippet in this package (`content/agents.md`).
|
|
25
|
+
|
|
26
|
+
## Hard rules
|
|
27
|
+
|
|
28
|
+
- `yield*` every Craft reader. Use `craftUse` only at synchronous boundaries.
|
|
29
|
+
- `state` / `query` / `mutation` / `queryParams` / `asyncProcess` — not `signal()`.
|
|
30
|
+
- One insertion per primitive; compose with `craftPipe`.
|
|
31
|
+
- `craftService` + generated `X()` helpers. No new `inject()` / `@Injectable`.
|
|
32
|
+
- `craftRoutes` + `componentDeps` + a per-file DI check. Split on `TS2589`.
|
|
33
|
+
- Use `startCraft` and `provideCraftRouter` for a browser app that may receive
|
|
34
|
+
SSR HTML. It hydrates a host marked by Craft SSR and mounts a fresh client
|
|
35
|
+
tree otherwise. Use `bootstrapCraft` when a fresh client mount is explicitly
|
|
36
|
+
required, and `hydrateCraft` when hydration must be forced or customized.
|
|
37
|
+
- Use `renderCraft` for one isolated SSR request. Create a new render per
|
|
38
|
+
request; never reuse its injector, platform, primitive registry, or history.
|
|
39
|
+
- Keep SSR data behavior explicit with `pendingBlock({ ssr: 'block' | 'fallback' | 'client' })`
|
|
40
|
+
or a route-level `ssr` policy. Do not let a suspended source reach SSR
|
|
41
|
+
without a policy.
|
|
42
|
+
- Run existing architecture tests. Do not add an architecture rule for the feature.
|
|
43
|
+
- Confirm symbols against the installed `node_modules/@craft-ts/core`.
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: craft-ts-architecture-tests
|
|
3
|
+
description: Use when scaffolding or running a CraftTS architecture suite (architecture/, craft-migrate-architecture, nx architecture, assertRouteDiProofs, assertDeclarativeArchitecture), when a graph smell must not recur (duplicate HTTP, feature leak, mutation without insertReactOnMutation, unarmed CanRun, craftUnique clash), or when an app that imported @craft-ts/core has no architecture/ folder at bootstrap or after craft-migrate.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# CraftTS architecture tests
|
|
7
|
+
|
|
8
|
+
The `architecture/` suite is the app's **graph contract**. It proves who may
|
|
9
|
+
depend on whom, which HTTP endpoint is owned once, which identity appears
|
|
10
|
+
once — without booting a browser framework. It works for framework-independent
|
|
11
|
+
CraftTS apps as well as migrated Angular apps.
|
|
12
|
+
|
|
13
|
+
Setup and helpers: https://ng-angular-stack.github.io/craft/guide/testing/architecture
|
|
14
|
+
Do not copy that page. Load it with `get_documentation_page` when you need a
|
|
15
|
+
signature.
|
|
16
|
+
|
|
17
|
+
## When not to use
|
|
18
|
+
|
|
19
|
+
Do **not** add an architecture rule for the feature. A new `it()` is not part
|
|
20
|
+
of mapping a spec onto primitives. Write application code, then **run** the
|
|
21
|
+
suite that already exists.
|
|
22
|
+
|
|
23
|
+
## 1. Bootstrap a new project
|
|
24
|
+
|
|
25
|
+
Prefer `craft create`, which asks for Effect v4 and agent integrations and
|
|
26
|
+
generates the application, API/page example, routes, ESLint, unit tests,
|
|
27
|
+
architecture suite and Playwright commands together:
|
|
28
|
+
|
|
29
|
+
```shell
|
|
30
|
+
npx craft create my-app --effect=none --agents=codex,cursor,cloud-code
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
For an Effect v4 starter:
|
|
34
|
+
|
|
35
|
+
```shell
|
|
36
|
+
npx craft create my-app --effect=v4 --agents=codex
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The generated `README.md` is the command contract. The starter's architecture
|
|
40
|
+
suite is ready at bootstrap; do not postpone it until after the first feature.
|
|
41
|
+
|
|
42
|
+
## 2. Bootstrap an existing project
|
|
43
|
+
|
|
44
|
+
Use at app start or as the last `craft-migrate` step, when `architecture/` is
|
|
45
|
+
missing.
|
|
46
|
+
|
|
47
|
+
```shell
|
|
48
|
+
npx craft-migrate-architecture --project tsconfig.app.json --root src --write
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
That writes the Vitest/Node suite, catalog, baseline rules, and an Nx
|
|
52
|
+
`architecture` target or package script. Enable the scaffolded helpers
|
|
53
|
+
(`assertDeclarativeArchitecture`, `assertRouteDiProofs`, and the files under
|
|
54
|
+
`architecture/rules/`). Point CI at `npx nx architecture <app>` (or
|
|
55
|
+
`npx vitest run --config vitest.architecture.config.ts`).
|
|
56
|
+
|
|
57
|
+
If this comes up **mid-feature**, report the gap and offer the scaffold. Do
|
|
58
|
+
not impose it.
|
|
59
|
+
|
|
60
|
+
## 3. During a feature
|
|
61
|
+
|
|
62
|
+
Run the existing suite. A failure is a graph slip in the **code** (or a
|
|
63
|
+
disarmed DI proof), not a missing `it()`.
|
|
64
|
+
|
|
65
|
+
```shell
|
|
66
|
+
npx nx architecture <app>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Do not add an architecture rule for the feature.
|
|
70
|
+
|
|
71
|
+
## 4. Encode a smell
|
|
72
|
+
|
|
73
|
+
When a pattern should not recur — duplicate HTTP, feature leak, mutation
|
|
74
|
+
with no `insertReactOnMutation`, duplicate `craftUnique`, commented `CanRun`,
|
|
75
|
+
`craftEffect` pushing into another primitive — freeze it.
|
|
76
|
+
|
|
77
|
+
- If `architecture/` exists, add the matching helper (or a neighbourhood
|
|
78
|
+
`it()`) under `architecture/rules/`.
|
|
79
|
+
- If it does not, propose workflow 1 first, then the rule.
|
|
80
|
+
|
|
81
|
+
Keep the assertion next to a comment that states the **product** invariant.
|
|
82
|
+
|
|
83
|
+
| Smell | Helper |
|
|
84
|
+
| --- | --- |
|
|
85
|
+
| Duplicate `craftUnique` identity, or a non-literal argument | `assertCraftUnique` |
|
|
86
|
+
| Same HTTP verb+URL from two sites | `assertHttpEndpointUnique` |
|
|
87
|
+
| `craftComputed` calls a method or writes `source$` | `assertCraftComputedPure` |
|
|
88
|
+
| `depends-on` cycle | `assertNoDependencyCycles` |
|
|
89
|
+
| Mutation with no `insertReactOnMutation` | `assertMutationHasReactOn` |
|
|
90
|
+
| The five declarative checks together | `assertDeclarativeArchitecture` |
|
|
91
|
+
| Unarmed `CanRun` / missing route or error-screen proof | `assertRouteDiProofs` |
|
|
92
|
+
| `depends-on` crosses a folder allowlist | `assertPathBoundaries` |
|
|
93
|
+
| Two feature branches leak into each other | `noExclusiveLink` |
|
|
94
|
+
| Persister without `craftUnique` | `assertPersistedPrimitiveHasUnique` |
|
|
95
|
+
| Same `insertSelect` key twice on one host | `assertInsertSelectUnique` |
|
|
96
|
+
| `craftEffect` calls HTTP or a mutation | `assertCraftEffectNoNetwork` |
|
|
97
|
+
| Duplicate `data-craft-name` on interactive elements, or a missing / non-literal first-argument name | `assertInteractiveElementNamed` |
|
|
98
|
+
|
|
99
|
+
Custom lookups (`graph.route`, `graph.providedOn`, `outgoing`) are for
|
|
100
|
+
invariants the helpers do not cover.
|
|
101
|
+
|
|
102
|
+
## Red flags
|
|
103
|
+
|
|
104
|
+
| Excuse | Reality |
|
|
105
|
+
| --- | --- |
|
|
106
|
+
| "I'll add a rule for this feature first" | Rules are baseline or anti-regression, not TDD-before-feature. |
|
|
107
|
+
| "Too small to encode" | If it must not recur, it is a rule. |
|
|
108
|
+
| "We'll add architecture tests after the PR" | The smell will ship. Encode it now or say you are not encoding it. |
|
|
109
|
+
| "ESLint already covers this" | ESLint is local. The suite is graph-wide. |
|
|
110
|
+
| "The suite is missing, I'll skip it" | Offer the scaffold. Do not pretend the contract exists. |
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: craft-ts-effect-v4
|
|
3
|
+
description: Build Effect v4 integrations in framework-independent CraftTS applications with typed services, Layers, queryEffect and Effect diagnostics. Use when a project selected EffectTS during craft create or when editing Effect domain code.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# CraftTS + Effect v4
|
|
7
|
+
|
|
8
|
+
Use this skill only when the project has selected EffectTS. The project must
|
|
9
|
+
use the Effect v4 line (`effect@4.0.0-rc.*` or a later v4 release), never v3
|
|
10
|
+
examples copied from older documentation.
|
|
11
|
+
|
|
12
|
+
## Boundary
|
|
13
|
+
|
|
14
|
+
- Domain operations return `Effect.Effect` and depend on `Context.Service`.
|
|
15
|
+
- Production implementations are supplied by `Layer` and registered once in
|
|
16
|
+
the Craft app config.
|
|
17
|
+
- UI data loading uses `queryEffect`; do not call `Effect.runPromise` from a
|
|
18
|
+
component or bypass the Craft reactive lifecycle.
|
|
19
|
+
- Install `installCraftEffectBridge()` once during bootstrap.
|
|
20
|
+
- Run the Effect diagnostics command from `package.json` after changing an
|
|
21
|
+
Effect generator, service, schema or Layer.
|
|
22
|
+
|
|
23
|
+
## Verification
|
|
24
|
+
|
|
25
|
+
Run the focused test, `npm run effect-check`, `npm run lint`,
|
|
26
|
+
`npm run typecheck`, `npm run architecture`, and the E2E flow when the browser
|
|
27
|
+
contract changed. The architecture suite checks that Effect resources keep a
|
|
28
|
+
typed service boundary and that the declarative Craft graph remains intact.
|
|
29
|
+
|
|
30
|
+
Confirm symbols against the installed v4 package. Do not “fix” a v4 diagnostic
|
|
31
|
+
by downgrading the dependency or importing an Angular adapter.
|