@stratta/mcp 0.5.0 → 0.7.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/README.md +63 -13
- package/dist/errors.d.ts +6 -0
- package/dist/errors.js +55 -0
- package/dist/index.js +69 -119
- package/dist/tools/define.d.ts +45 -0
- package/dist/tools/define.js +4 -0
- package/dist/tools/ingest.d.ts +140 -243
- package/dist/tools/ingest.js +225 -238
- package/dist/tools/read.d.ts +51 -0
- package/dist/tools/read.js +247 -0
- package/package.json +9 -9
- package/skills/ingest-norm/SKILL.md +140 -128
- package/dist/tools/get-cross-refs.d.ts +0 -24
- package/dist/tools/get-cross-refs.js +0 -23
- package/dist/tools/get-figure.d.ts +0 -24
- package/dist/tools/get-figure.js +0 -50
- package/dist/tools/get-methodology.d.ts +0 -18
- package/dist/tools/get-methodology.js +0 -21
- package/dist/tools/get-section.d.ts +0 -24
- package/dist/tools/get-section.js +0 -34
- package/dist/tools/get-subtree.d.ts +0 -29
- package/dist/tools/get-subtree.js +0 -39
- package/dist/tools/get-toc.d.ts +0 -24
- package/dist/tools/get-toc.js +0 -32
- package/dist/tools/list-norms.d.ts +0 -11
- package/dist/tools/list-norms.js +0 -17
- package/dist/tools/search-in-norm.d.ts +0 -29
- package/dist/tools/search-in-norm.js +0 -31
package/dist/tools/get-figure.js
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { api } from '../client.js';
|
|
2
|
-
import { requireApiKey } from '../auth.js';
|
|
3
|
-
export const getFigureTool = {
|
|
4
|
-
name: 'get_figure',
|
|
5
|
-
description: 'Retrieve a figure (image) referenced in a section. Returns the image inline (base64) so you can see and reason about it, plus a public `url` for full-size viewing. Use the `id` returned by get_section in its `figures` array.',
|
|
6
|
-
inputSchema: {
|
|
7
|
-
type: 'object',
|
|
8
|
-
properties: {
|
|
9
|
-
norm: { type: 'string', description: 'Norm code, e.g. "SIA 261".' },
|
|
10
|
-
figureId: {
|
|
11
|
-
type: 'string',
|
|
12
|
-
description: 'Figure ID from get_section response (figures[].id).',
|
|
13
|
-
},
|
|
14
|
-
},
|
|
15
|
-
required: ['norm', 'figureId'],
|
|
16
|
-
additionalProperties: false,
|
|
17
|
-
},
|
|
18
|
-
};
|
|
19
|
-
export async function handleGetFigure(client, args) {
|
|
20
|
-
const apiKey = requireApiKey();
|
|
21
|
-
const meta = (await client.action(api._mcp.getFigureMeta, {
|
|
22
|
-
apiKey,
|
|
23
|
-
code: args.norm,
|
|
24
|
-
figureId: args.figureId,
|
|
25
|
-
}));
|
|
26
|
-
if (!meta) {
|
|
27
|
-
return { error: `Figure not found.` };
|
|
28
|
-
}
|
|
29
|
-
const url = (await client.action(api._mcp.getStorageUrl, {
|
|
30
|
-
apiKey,
|
|
31
|
-
code: args.norm,
|
|
32
|
-
figureId: args.figureId,
|
|
33
|
-
}));
|
|
34
|
-
if (!url) {
|
|
35
|
-
return { error: 'Figure storage is unavailable.' };
|
|
36
|
-
}
|
|
37
|
-
const response = await fetch(url);
|
|
38
|
-
if (!response.ok) {
|
|
39
|
-
return { error: `Failed to download figure: HTTP ${response.status}` };
|
|
40
|
-
}
|
|
41
|
-
const buffer = await response.arrayBuffer();
|
|
42
|
-
const base64 = Buffer.from(buffer).toString('base64');
|
|
43
|
-
const mimeType = response.headers.get('content-type') ?? 'image/png';
|
|
44
|
-
return {
|
|
45
|
-
caption: meta.caption,
|
|
46
|
-
figureNumber: meta.figureNumber,
|
|
47
|
-
url,
|
|
48
|
-
image: { base64, mimeType },
|
|
49
|
-
};
|
|
50
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { ConvexHttpClient } from 'convex/browser';
|
|
2
|
-
export declare const getMethodologyTool: {
|
|
3
|
-
readonly name: "get_methodology";
|
|
4
|
-
readonly description: "MANDATORY FIRST CALL when answering any technical question about Swiss civil engineering norms via Stratta. Returns the canonical persona, navigation workflow, meta-routing hints (which SIA norms cover which topics), tree-navigation rules (where to look for formulas vs coefficients vs definitions), citation format and answer rules. Adopt these rules verbatim for the rest of the consultation. If you skip this call you WILL produce lower-quality answers (wrong citation format, missing cross-norm dependencies, hallucinated values).";
|
|
5
|
-
readonly inputSchema: {
|
|
6
|
-
readonly type: "object";
|
|
7
|
-
readonly properties: {
|
|
8
|
-
readonly norm: {
|
|
9
|
-
readonly type: "string";
|
|
10
|
-
readonly description: "Optional: norm code the user is asking about, if already known. Used to scope methodology hints (currently informational only).";
|
|
11
|
-
};
|
|
12
|
-
};
|
|
13
|
-
readonly additionalProperties: false;
|
|
14
|
-
};
|
|
15
|
-
};
|
|
16
|
-
export declare function handleGetMethodology(client: ConvexHttpClient, args: {
|
|
17
|
-
norm?: string;
|
|
18
|
-
}): Promise<unknown>;
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { api } from '../client.js';
|
|
2
|
-
export const getMethodologyTool = {
|
|
3
|
-
name: 'get_methodology',
|
|
4
|
-
description: "MANDATORY FIRST CALL when answering any technical question about Swiss civil engineering norms via Stratta. Returns the canonical persona, navigation workflow, meta-routing hints (which SIA norms cover which topics), tree-navigation rules (where to look for formulas vs coefficients vs definitions), citation format and answer rules. Adopt these rules verbatim for the rest of the consultation. If you skip this call you WILL produce lower-quality answers (wrong citation format, missing cross-norm dependencies, hallucinated values).",
|
|
5
|
-
inputSchema: {
|
|
6
|
-
type: 'object',
|
|
7
|
-
properties: {
|
|
8
|
-
norm: {
|
|
9
|
-
type: 'string',
|
|
10
|
-
description: "Optional: norm code the user is asking about, if already known. Used to scope methodology hints (currently informational only).",
|
|
11
|
-
},
|
|
12
|
-
},
|
|
13
|
-
additionalProperties: false,
|
|
14
|
-
},
|
|
15
|
-
};
|
|
16
|
-
export async function handleGetMethodology(client, args) {
|
|
17
|
-
const result = await client.query(api._mcp.getMethodology, {
|
|
18
|
-
norm: args.norm,
|
|
19
|
-
});
|
|
20
|
-
return result;
|
|
21
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { ConvexHttpClient } from 'convex/browser';
|
|
2
|
-
export declare const getSectionTool: {
|
|
3
|
-
readonly name: "get_section";
|
|
4
|
-
readonly description: "Fetch the full enriched content of a section: markdown text with formulas in LaTeX and tables inline, pageStart/pageEnd, figures (call get_figure for the image), attached tables/formulas, and cross-references to other norms. ALL technical claims in your answer MUST be backed by a [<norm> <path>, p. <pageStart>] citation pointing to a section you actually fetched via get_section — never cite from memory. When a section's crossRefs list non-empty targets, follow them with another get_section call if the answer depends on them.";
|
|
5
|
-
readonly inputSchema: {
|
|
6
|
-
readonly type: "object";
|
|
7
|
-
readonly properties: {
|
|
8
|
-
readonly norm: {
|
|
9
|
-
readonly type: "string";
|
|
10
|
-
readonly description: "Norm code, e.g. \"SIA 261\".";
|
|
11
|
-
};
|
|
12
|
-
readonly path: {
|
|
13
|
-
readonly type: "string";
|
|
14
|
-
readonly description: "Section path as it appears in the document, e.g. \"4.2.1\" or \"Annexe A\".";
|
|
15
|
-
};
|
|
16
|
-
};
|
|
17
|
-
readonly required: readonly ["norm", "path"];
|
|
18
|
-
readonly additionalProperties: false;
|
|
19
|
-
};
|
|
20
|
-
};
|
|
21
|
-
export declare function handleGetSection(client: ConvexHttpClient, args: {
|
|
22
|
-
norm: string;
|
|
23
|
-
path: string;
|
|
24
|
-
}): Promise<unknown>;
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { api } from '../client.js';
|
|
2
|
-
import { requireApiKey } from '../auth.js';
|
|
3
|
-
export const getSectionTool = {
|
|
4
|
-
name: 'get_section',
|
|
5
|
-
description: "Fetch the full enriched content of a section: markdown text with formulas in LaTeX and tables inline, pageStart/pageEnd, figures (call get_figure for the image), attached tables/formulas, and cross-references to other norms. ALL technical claims in your answer MUST be backed by a [<norm> <path>, p. <pageStart>] citation pointing to a section you actually fetched via get_section — never cite from memory. When a section's crossRefs list non-empty targets, follow them with another get_section call if the answer depends on them.",
|
|
6
|
-
inputSchema: {
|
|
7
|
-
type: 'object',
|
|
8
|
-
properties: {
|
|
9
|
-
norm: {
|
|
10
|
-
type: 'string',
|
|
11
|
-
description: 'Norm code, e.g. "SIA 261".',
|
|
12
|
-
},
|
|
13
|
-
path: {
|
|
14
|
-
type: 'string',
|
|
15
|
-
description: 'Section path as it appears in the document, e.g. "4.2.1" or "Annexe A".',
|
|
16
|
-
},
|
|
17
|
-
},
|
|
18
|
-
required: ['norm', 'path'],
|
|
19
|
-
additionalProperties: false,
|
|
20
|
-
},
|
|
21
|
-
};
|
|
22
|
-
export async function handleGetSection(client, args) {
|
|
23
|
-
const result = await client.action(api._mcp.getSection, {
|
|
24
|
-
apiKey: requireApiKey(),
|
|
25
|
-
code: args.norm,
|
|
26
|
-
path: args.path,
|
|
27
|
-
});
|
|
28
|
-
if (result === null) {
|
|
29
|
-
return {
|
|
30
|
-
error: `Section "${args.path}" not found in norm "${args.norm}".`,
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
return { norm: args.norm, section: result };
|
|
34
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import type { ConvexHttpClient } from 'convex/browser';
|
|
2
|
-
export declare const getSubtreeTool: {
|
|
3
|
-
readonly name: "get_subtree";
|
|
4
|
-
readonly description: "Drill down into a specific chapter or section. Returns the subtree rooted at `path` with optional depth limit (relative to the root). Use this after get_toc to explore one chapter in detail without fetching the entire TOC. Each node has nodeId, path, title, summary, depth, pageStart, pageEnd, and recursive children.";
|
|
5
|
-
readonly inputSchema: {
|
|
6
|
-
readonly type: "object";
|
|
7
|
-
readonly properties: {
|
|
8
|
-
readonly norm: {
|
|
9
|
-
readonly type: "string";
|
|
10
|
-
readonly description: "Norm code, e.g. \"SIA 261-1\".";
|
|
11
|
-
};
|
|
12
|
-
readonly path: {
|
|
13
|
-
readonly type: "string";
|
|
14
|
-
readonly description: "Section path to root the subtree at, e.g. \"14\" or \"14.2\".";
|
|
15
|
-
};
|
|
16
|
-
readonly maxDepth: {
|
|
17
|
-
readonly type: "number";
|
|
18
|
-
readonly description: "Max nesting depth relative to the root. Default: unlimited. depth=1 returns the root + direct children only.";
|
|
19
|
-
};
|
|
20
|
-
};
|
|
21
|
-
readonly required: readonly ["norm", "path"];
|
|
22
|
-
readonly additionalProperties: false;
|
|
23
|
-
};
|
|
24
|
-
};
|
|
25
|
-
export declare function handleGetSubtree(client: ConvexHttpClient, args: {
|
|
26
|
-
norm: string;
|
|
27
|
-
path: string;
|
|
28
|
-
maxDepth?: number;
|
|
29
|
-
}): Promise<unknown>;
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { api } from '../client.js';
|
|
2
|
-
import { requireApiKey } from '../auth.js';
|
|
3
|
-
export const getSubtreeTool = {
|
|
4
|
-
name: 'get_subtree',
|
|
5
|
-
description: 'Drill down into a specific chapter or section. Returns the subtree rooted at `path` with optional depth limit (relative to the root). Use this after get_toc to explore one chapter in detail without fetching the entire TOC. Each node has nodeId, path, title, summary, depth, pageStart, pageEnd, and recursive children.',
|
|
6
|
-
inputSchema: {
|
|
7
|
-
type: 'object',
|
|
8
|
-
properties: {
|
|
9
|
-
norm: {
|
|
10
|
-
type: 'string',
|
|
11
|
-
description: 'Norm code, e.g. "SIA 261-1".',
|
|
12
|
-
},
|
|
13
|
-
path: {
|
|
14
|
-
type: 'string',
|
|
15
|
-
description: 'Section path to root the subtree at, e.g. "14" or "14.2".',
|
|
16
|
-
},
|
|
17
|
-
maxDepth: {
|
|
18
|
-
type: 'number',
|
|
19
|
-
description: 'Max nesting depth relative to the root. Default: unlimited. depth=1 returns the root + direct children only.',
|
|
20
|
-
},
|
|
21
|
-
},
|
|
22
|
-
required: ['norm', 'path'],
|
|
23
|
-
additionalProperties: false,
|
|
24
|
-
},
|
|
25
|
-
};
|
|
26
|
-
export async function handleGetSubtree(client, args) {
|
|
27
|
-
const result = await client.action(api._mcp.getSubtree, {
|
|
28
|
-
apiKey: requireApiKey(),
|
|
29
|
-
code: args.norm,
|
|
30
|
-
path: args.path,
|
|
31
|
-
maxDepth: args.maxDepth,
|
|
32
|
-
});
|
|
33
|
-
if (result === null) {
|
|
34
|
-
return {
|
|
35
|
-
error: `Section "${args.path}" not found in norm "${args.norm}".`,
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
return { norm: args.norm, root: args.path, tree: result };
|
|
39
|
-
}
|
package/dist/tools/get-toc.d.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { ConvexHttpClient } from 'convex/browser';
|
|
2
|
-
export declare const getTocTool: {
|
|
3
|
-
readonly name: "get_toc";
|
|
4
|
-
readonly description: "Get the high-level table of contents for a norm. By default returns only top-level chapters (depth=1) to stay light. Call get_subtree on a specific chapter's path to drill into sections + subsections. Increase maxDepth if you need a wider overview (cost: response size grows fast). Each node has nodeId, path, title, summary, pageStart, pageEnd, depth, and children (empty at the maxDepth boundary).";
|
|
5
|
-
readonly inputSchema: {
|
|
6
|
-
readonly type: "object";
|
|
7
|
-
readonly properties: {
|
|
8
|
-
readonly norm: {
|
|
9
|
-
readonly type: "string";
|
|
10
|
-
readonly description: "Norm code, e.g. \"SIA 261\", \"SIA 263\", \"EN 1992-1-1\".";
|
|
11
|
-
};
|
|
12
|
-
readonly maxDepth: {
|
|
13
|
-
readonly type: "number";
|
|
14
|
-
readonly description: "Maximum nesting depth to include. Defaults to 1 (chapters only). depth=2 includes sections X.Y. depth=3 includes sub-subsections X.Y.Z (may exceed response size limit on large norms).";
|
|
15
|
-
};
|
|
16
|
-
};
|
|
17
|
-
readonly required: readonly ["norm"];
|
|
18
|
-
readonly additionalProperties: false;
|
|
19
|
-
};
|
|
20
|
-
};
|
|
21
|
-
export declare function handleGetToc(client: ConvexHttpClient, args: {
|
|
22
|
-
norm: string;
|
|
23
|
-
maxDepth?: number;
|
|
24
|
-
}): Promise<unknown>;
|
package/dist/tools/get-toc.js
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { api } from '../client.js';
|
|
2
|
-
import { requireApiKey } from '../auth.js';
|
|
3
|
-
export const getTocTool = {
|
|
4
|
-
name: 'get_toc',
|
|
5
|
-
description: "Get the high-level table of contents for a norm. By default returns only top-level chapters (depth=1) to stay light. Call get_subtree on a specific chapter's path to drill into sections + subsections. Increase maxDepth if you need a wider overview (cost: response size grows fast). Each node has nodeId, path, title, summary, pageStart, pageEnd, depth, and children (empty at the maxDepth boundary).",
|
|
6
|
-
inputSchema: {
|
|
7
|
-
type: 'object',
|
|
8
|
-
properties: {
|
|
9
|
-
norm: {
|
|
10
|
-
type: 'string',
|
|
11
|
-
description: 'Norm code, e.g. "SIA 261", "SIA 263", "EN 1992-1-1".',
|
|
12
|
-
},
|
|
13
|
-
maxDepth: {
|
|
14
|
-
type: 'number',
|
|
15
|
-
description: 'Maximum nesting depth to include. Defaults to 1 (chapters only). depth=2 includes sections X.Y. depth=3 includes sub-subsections X.Y.Z (may exceed response size limit on large norms).',
|
|
16
|
-
},
|
|
17
|
-
},
|
|
18
|
-
required: ['norm'],
|
|
19
|
-
additionalProperties: false,
|
|
20
|
-
},
|
|
21
|
-
};
|
|
22
|
-
export async function handleGetToc(client, args) {
|
|
23
|
-
const result = await client.action(api._mcp.getDocumentToc, {
|
|
24
|
-
apiKey: requireApiKey(),
|
|
25
|
-
code: args.norm,
|
|
26
|
-
maxDepth: args.maxDepth,
|
|
27
|
-
});
|
|
28
|
-
if (result === null) {
|
|
29
|
-
return { error: `Norm "${args.norm}" not found or not published.` };
|
|
30
|
-
}
|
|
31
|
-
return { norm: args.norm, maxDepth: args.maxDepth ?? 1, tree: result };
|
|
32
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { ConvexHttpClient } from 'convex/browser';
|
|
2
|
-
export declare const listNormsTool: {
|
|
3
|
-
readonly name: "list_norms";
|
|
4
|
-
readonly description: "List all engineering norms (SIA, Eurocodes, etc.) currently available in Stratta. Returns code, year, title, and language for each. Workflow: call get_methodology FIRST (persona + rules), then list_norms to know what is queryable, then meta-route the user's question to the relevant norms before drilling in.";
|
|
5
|
-
readonly inputSchema: {
|
|
6
|
-
readonly type: "object";
|
|
7
|
-
readonly properties: {};
|
|
8
|
-
readonly additionalProperties: false;
|
|
9
|
-
};
|
|
10
|
-
};
|
|
11
|
-
export declare function handleListNorms(client: ConvexHttpClient): Promise<unknown>;
|
package/dist/tools/list-norms.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { api } from '../client.js';
|
|
2
|
-
import { requireApiKey } from '../auth.js';
|
|
3
|
-
export const listNormsTool = {
|
|
4
|
-
name: 'list_norms',
|
|
5
|
-
description: "List all engineering norms (SIA, Eurocodes, etc.) currently available in Stratta. Returns code, year, title, and language for each. Workflow: call get_methodology FIRST (persona + rules), then list_norms to know what is queryable, then meta-route the user's question to the relevant norms before drilling in.",
|
|
6
|
-
inputSchema: {
|
|
7
|
-
type: 'object',
|
|
8
|
-
properties: {},
|
|
9
|
-
additionalProperties: false,
|
|
10
|
-
},
|
|
11
|
-
};
|
|
12
|
-
export async function handleListNorms(client) {
|
|
13
|
-
const result = await client.action(api._mcp.listPublishedNorms, {
|
|
14
|
-
apiKey: requireApiKey(),
|
|
15
|
-
});
|
|
16
|
-
return { norms: result };
|
|
17
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import type { ConvexHttpClient } from 'convex/browser';
|
|
2
|
-
export declare const searchInNormTool: {
|
|
3
|
-
readonly name: "search_in_norm";
|
|
4
|
-
readonly description: "Search for sections within a norm by keyword (case-insensitive). Returns up to `limit` matches with path, title, and a snippet of matching content. Use this when you do not yet know which section to read — e.g. \"charges variables\" or \"béton armé\".";
|
|
5
|
-
readonly inputSchema: {
|
|
6
|
-
readonly type: "object";
|
|
7
|
-
readonly properties: {
|
|
8
|
-
readonly norm: {
|
|
9
|
-
readonly type: "string";
|
|
10
|
-
readonly description: "Norm code, e.g. \"SIA 261\".";
|
|
11
|
-
};
|
|
12
|
-
readonly keyword: {
|
|
13
|
-
readonly type: "string";
|
|
14
|
-
readonly description: "Search term. Searches both section titles and content.";
|
|
15
|
-
};
|
|
16
|
-
readonly limit: {
|
|
17
|
-
readonly type: "number";
|
|
18
|
-
readonly description: "Max results to return (default 20).";
|
|
19
|
-
};
|
|
20
|
-
};
|
|
21
|
-
readonly required: readonly ["norm", "keyword"];
|
|
22
|
-
readonly additionalProperties: false;
|
|
23
|
-
};
|
|
24
|
-
};
|
|
25
|
-
export declare function handleSearchInNorm(client: ConvexHttpClient, args: {
|
|
26
|
-
norm: string;
|
|
27
|
-
keyword: string;
|
|
28
|
-
limit?: number;
|
|
29
|
-
}): Promise<unknown>;
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { api } from '../client.js';
|
|
2
|
-
import { requireApiKey } from '../auth.js';
|
|
3
|
-
export const searchInNormTool = {
|
|
4
|
-
name: 'search_in_norm',
|
|
5
|
-
description: 'Search for sections within a norm by keyword (case-insensitive). Returns up to `limit` matches with path, title, and a snippet of matching content. Use this when you do not yet know which section to read — e.g. "charges variables" or "béton armé".',
|
|
6
|
-
inputSchema: {
|
|
7
|
-
type: 'object',
|
|
8
|
-
properties: {
|
|
9
|
-
norm: { type: 'string', description: 'Norm code, e.g. "SIA 261".' },
|
|
10
|
-
keyword: {
|
|
11
|
-
type: 'string',
|
|
12
|
-
description: 'Search term. Searches both section titles and content.',
|
|
13
|
-
},
|
|
14
|
-
limit: {
|
|
15
|
-
type: 'number',
|
|
16
|
-
description: 'Max results to return (default 20).',
|
|
17
|
-
},
|
|
18
|
-
},
|
|
19
|
-
required: ['norm', 'keyword'],
|
|
20
|
-
additionalProperties: false,
|
|
21
|
-
},
|
|
22
|
-
};
|
|
23
|
-
export async function handleSearchInNorm(client, args) {
|
|
24
|
-
const result = await client.action(api._mcp.searchInNorm, {
|
|
25
|
-
apiKey: requireApiKey(),
|
|
26
|
-
code: args.norm,
|
|
27
|
-
keyword: args.keyword,
|
|
28
|
-
limit: args.limit,
|
|
29
|
-
});
|
|
30
|
-
return { norm: args.norm, keyword: args.keyword, hits: result };
|
|
31
|
-
}
|