@aikdna/kdna-mcp-server 0.2.4 → 0.3.0
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 +7 -5
- package/bin/kdna-mcp.mjs +21 -51
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -7,7 +7,9 @@ minimal footprint. The npm package source lives in this repository under
|
|
|
7
7
|
|
|
8
8
|
## Why MCP instead of the kdna-loader skill?
|
|
9
9
|
|
|
10
|
-
The `kdna-loader` skill teaches an agent the full
|
|
10
|
+
The `kdna-loader` skill teaches an agent the full toolchain-only protocol:
|
|
11
|
+
routing, planning, Capsule loading, application, and boundary respect. The MCP
|
|
12
|
+
server provides a lower-level bridge for structured tool calls.
|
|
11
13
|
|
|
12
14
|
| Approach | Best for |
|
|
13
15
|
|----------|----------|
|
|
@@ -18,11 +20,11 @@ The `kdna-loader` skill teaches an agent the full KDNA protocol (7-part routing,
|
|
|
18
20
|
|
|
19
21
|
| Tool | Purpose | Input | Output |
|
|
20
22
|
|------|---------|-------|--------|
|
|
21
|
-
| `kdna.inspect` | Inspect a
|
|
23
|
+
| `kdna.inspect` | Inspect a `.kdna` asset | File path | Structured metadata |
|
|
22
24
|
| `kdna.verify` | Verify asset integrity state | File path | Pass/fail with reasons |
|
|
23
25
|
| `kdna.plan-load` | Return Core LoadPlan before loading | File path, optional password or entitlement state | LoadPlan JSON |
|
|
24
|
-
| `kdna.load` | Load
|
|
25
|
-
| `kdna.available-local` | List local
|
|
26
|
+
| `kdna.load` | Load an authorized `.kdna` profile | File path, optional profile | Runtime Capsule |
|
|
27
|
+
| `kdna.available-local` | List local `.kdna` assets | Root directory | Local asset inventory |
|
|
26
28
|
| `kdna.match` | Rank candidate assets for a task string | Task description | Scored list with fit signals |
|
|
27
29
|
|
|
28
30
|
## Install & Run
|
|
@@ -101,7 +103,7 @@ node bin/kdna-mcp.mjs
|
|
|
101
103
|
# Client calls kdna.plan-load { assetPath: "./dist/writing.kdna" }
|
|
102
104
|
# Or kdna.plan-load { assetPath: "./dist/writing.kdna", entitlementStatus: "active" }
|
|
103
105
|
# Client calls kdna.load { assetPath: "./dist/writing.kdna", profile: "compact" }
|
|
104
|
-
# Agent
|
|
106
|
+
# Agent consumes only the returned Runtime Capsule context
|
|
105
107
|
```
|
|
106
108
|
|
|
107
109
|
## Relationship to kdna-loader skill
|
package/bin/kdna-mcp.mjs
CHANGED
|
@@ -9,21 +9,13 @@ import { createRequire } from 'node:module';
|
|
|
9
9
|
const require = createRequire(import.meta.url);
|
|
10
10
|
const packageInfo = require('../package.json');
|
|
11
11
|
const {
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
detectContainerFormat,
|
|
13
|
+
inspect,
|
|
14
|
+
load,
|
|
14
15
|
matchDomain,
|
|
15
16
|
planLoad,
|
|
16
|
-
|
|
17
|
-
verifyAsset,
|
|
17
|
+
validate,
|
|
18
18
|
} = require('@aikdna/kdna-core');
|
|
19
|
-
const {
|
|
20
|
-
detectContainerFormat,
|
|
21
|
-
inspect: inspectV1,
|
|
22
|
-
isV1SourceDir,
|
|
23
|
-
loadAuthorized,
|
|
24
|
-
loadV1,
|
|
25
|
-
validate: validateV1,
|
|
26
|
-
} = require('@aikdna/kdna-core/v1');
|
|
27
19
|
|
|
28
20
|
const tools = [
|
|
29
21
|
{
|
|
@@ -77,7 +69,7 @@ const tools = [
|
|
|
77
69
|
},
|
|
78
70
|
{
|
|
79
71
|
name: 'kdna.available-local',
|
|
80
|
-
description: 'List local
|
|
72
|
+
description: 'List local .kdna files without using a registry.',
|
|
81
73
|
inputSchema: {
|
|
82
74
|
type: 'object',
|
|
83
75
|
properties: {
|
|
@@ -121,11 +113,11 @@ function textResult(value) {
|
|
|
121
113
|
};
|
|
122
114
|
}
|
|
123
115
|
|
|
124
|
-
function
|
|
116
|
+
function isKdnaAsset(assetPath) {
|
|
125
117
|
if (!assetPath) return false;
|
|
126
118
|
try {
|
|
127
119
|
if (!fs.existsSync(assetPath) || !fs.statSync(assetPath).isFile()) return false;
|
|
128
|
-
return assetPath.endsWith('.kdna') && detectContainerFormat(assetPath) === '
|
|
120
|
+
return assetPath.endsWith('.kdna') && detectContainerFormat(assetPath) === 'kdna';
|
|
129
121
|
} catch {
|
|
130
122
|
return false;
|
|
131
123
|
}
|
|
@@ -153,12 +145,12 @@ function findLocalAssets(root = defaultAssetRoot(), maxDepth = 3) {
|
|
|
153
145
|
const full = path.join(dir, entry.name);
|
|
154
146
|
if (entry.isDirectory()) {
|
|
155
147
|
visit(full, depth + 1);
|
|
156
|
-
} else if (entry.isFile() && entry.name.endsWith('.kdna') && detectContainerFormat(full) === '
|
|
157
|
-
const inspection =
|
|
158
|
-
const validation =
|
|
148
|
+
} else if (entry.isFile() && entry.name.endsWith('.kdna') && detectContainerFormat(full) === 'kdna') {
|
|
149
|
+
const inspection = inspect(full);
|
|
150
|
+
const validation = validate(full);
|
|
159
151
|
found.push({
|
|
160
152
|
path: full,
|
|
161
|
-
kind: '
|
|
153
|
+
kind: 'kdna_asset',
|
|
162
154
|
asset_id: inspection.asset_id,
|
|
163
155
|
title: inspection.title,
|
|
164
156
|
version: inspection.version,
|
|
@@ -226,48 +218,26 @@ function planLoadThroughCoreOrCli(args = {}) {
|
|
|
226
218
|
return runCliPlanLoad(args);
|
|
227
219
|
}
|
|
228
220
|
|
|
229
|
-
function loadV1Authorized(assetPath, options) {
|
|
230
|
-
if (typeof loadAuthorized === 'function') return loadAuthorized(assetPath, options);
|
|
231
|
-
const plan = planLoadThroughCoreOrCli({
|
|
232
|
-
assetPath,
|
|
233
|
-
hasPassword: options.hasPassword,
|
|
234
|
-
entitlementStatus: options.entitlement && options.entitlement.status,
|
|
235
|
-
});
|
|
236
|
-
if (plan.can_load_now !== true) {
|
|
237
|
-
const error = new Error(
|
|
238
|
-
`LoadPlan denied loading: state=${plan.state || 'invalid'} required_action=${plan.required_action || 'block'}`,
|
|
239
|
-
);
|
|
240
|
-
error.code = (plan.issues && plan.issues[0] && plan.issues[0].code) || 'KDNA_LOAD_NOT_AUTHORIZED';
|
|
241
|
-
throw error;
|
|
242
|
-
}
|
|
243
|
-
return loadV1(assetPath, options);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
221
|
async function callTool(name, args = {}) {
|
|
247
222
|
if (name === 'kdna.inspect') {
|
|
248
|
-
if (
|
|
249
|
-
return textResult(
|
|
223
|
+
if (!isKdnaAsset(args.assetPath)) throw new Error('assetPath is not a current KDNA asset');
|
|
224
|
+
return textResult(inspect(args.assetPath, { verify: args.verify !== false }));
|
|
250
225
|
}
|
|
251
226
|
if (name === 'kdna.verify') {
|
|
252
|
-
if (
|
|
253
|
-
return textResult(
|
|
227
|
+
if (!isKdnaAsset(args.assetPath)) throw new Error('assetPath is not a current KDNA asset');
|
|
228
|
+
return textResult(validate(args.assetPath, {
|
|
254
229
|
asset_digest: args.asset_digest,
|
|
255
230
|
content_digest: args.content_digest,
|
|
256
231
|
requireSignature: Boolean(args.requireSignature),
|
|
257
232
|
}));
|
|
258
233
|
}
|
|
259
234
|
if (name === 'kdna.load') {
|
|
260
|
-
if (
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
}
|
|
266
|
-
const loaded = await loadKDNA(args.assetPath, { profile: args.profile || 'compact', input: args.input || '' });
|
|
267
|
-
const context = args.profile === 'index'
|
|
268
|
-
? null
|
|
269
|
-
: await renderForAgent(args.assetPath, { profile: args.profile || 'compact', input: args.input || '' });
|
|
270
|
-
return textResult({ ...loaded, context });
|
|
235
|
+
if (!isKdnaAsset(args.assetPath)) throw new Error('assetPath is not a current KDNA asset');
|
|
236
|
+
return textResult(load(args.assetPath, {
|
|
237
|
+
profile: args.profile || 'compact',
|
|
238
|
+
as: 'json',
|
|
239
|
+
input: args.input || '',
|
|
240
|
+
}));
|
|
271
241
|
}
|
|
272
242
|
if (name === 'kdna.plan-load') {
|
|
273
243
|
return textResult(planLoadThroughCoreOrCli(args));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aikdna/kdna-mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "MCP server for loading, inspecting, verifying, and matching KDNA .kdna assets.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"homepage": "https://aikdna.com",
|
|
@@ -30,14 +30,17 @@
|
|
|
30
30
|
],
|
|
31
31
|
"scripts": {
|
|
32
32
|
"test": "node --test test/*.test.mjs",
|
|
33
|
-
"prepublishOnly": "npm test"
|
|
33
|
+
"prepublishOnly": "npm test && node ../scripts/release-check.js"
|
|
34
34
|
},
|
|
35
35
|
"license": "Apache-2.0",
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@aikdna/kdna-core": "
|
|
37
|
+
"@aikdna/kdna-core": "0.15.12",
|
|
38
38
|
"ajv": "^8.20.0",
|
|
39
39
|
"ajv-formats": "^3.0.1"
|
|
40
40
|
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"cbor-x": "^1.6.4"
|
|
43
|
+
},
|
|
41
44
|
"engines": {
|
|
42
45
|
"node": ">=18"
|
|
43
46
|
}
|