@runcontext/mcp 0.1.1 → 0.2.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/dist/index.cjs CHANGED
@@ -1,410 +1,442 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/server.ts
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/server.ts
2
2
  var _mcpjs = require('@modelcontextprotocol/sdk/server/mcp.js');
3
- var _zod = require('zod');
3
+ var _stdiojs = require('@modelcontextprotocol/sdk/server/stdio.js');
4
+ var _core = require('@runcontext/core');
4
5
 
5
6
  // src/resources/manifest.ts
6
- function readManifest(manifest) {
7
- return {
8
- contents: [
9
- {
10
- uri: "context://manifest",
11
- mimeType: "application/json",
12
- text: JSON.stringify(manifest, null, 2)
13
- }
14
- ]
15
- };
16
- }
17
-
18
- // src/resources/concept.ts
19
- function readConcept(manifest, id) {
20
- const concept = manifest.concepts.find((c) => c.id === id);
21
- if (!concept) {
22
- return {
7
+ function registerManifestResource(server, manifest) {
8
+ server.resource(
9
+ "manifest",
10
+ "context://manifest",
11
+ { description: "Full ContextKit manifest JSON (models, governance, rules, lineage, terms, owners, tiers)" },
12
+ async (uri) => ({
23
13
  contents: [
24
14
  {
25
- uri: `context://concept/${id}`,
15
+ uri: uri.href,
26
16
  mimeType: "application/json",
27
- text: JSON.stringify({ error: `Concept not found: ${id}` })
17
+ text: JSON.stringify(manifest, null, 2)
28
18
  }
29
19
  ]
30
- };
31
- }
32
- return {
33
- contents: [
34
- {
35
- uri: `context://concept/${id}`,
36
- mimeType: "application/json",
37
- text: JSON.stringify(concept, null, 2)
38
- }
39
- ]
40
- };
41
- }
42
- function listConcepts(manifest) {
43
- return {
44
- resources: manifest.concepts.map((c) => ({
45
- uri: `context://concept/${c.id}`,
46
- name: c.id,
47
- description: c.definition,
48
- mimeType: "application/json"
49
- }))
50
- };
20
+ })
21
+ );
51
22
  }
52
23
 
53
- // src/resources/product.ts
54
- function readProduct(manifest, id) {
55
- const product = manifest.products.find((p) => p.id === id);
56
- if (!product) {
57
- return {
58
- contents: [
59
- {
60
- uri: `context://product/${id}`,
61
- mimeType: "application/json",
62
- text: JSON.stringify({ error: `Product not found: ${id}` })
63
- }
64
- ]
65
- };
66
- }
24
+ // src/resources/model.ts
25
+
26
+ function buildModelView(name, manifest) {
27
+ const model = manifest.models[name];
28
+ if (!model) return null;
67
29
  return {
68
- contents: [
69
- {
70
- uri: `context://product/${id}`,
71
- mimeType: "application/json",
72
- text: JSON.stringify(product, null, 2)
73
- }
74
- ]
30
+ model,
31
+ governance: _nullishCoalesce(manifest.governance[name], () => ( null)),
32
+ rules: _nullishCoalesce(manifest.rules[name], () => ( null)),
33
+ lineage: _nullishCoalesce(manifest.lineage[name], () => ( null)),
34
+ tier: _nullishCoalesce(manifest.tiers[name], () => ( null))
75
35
  };
76
36
  }
77
- function listProducts(manifest) {
78
- return {
79
- resources: manifest.products.map((p) => ({
80
- uri: `context://product/${p.id}`,
81
- name: p.id,
82
- description: p.description,
83
- mimeType: "application/json"
84
- }))
85
- };
37
+ function registerModelResource(server, manifest) {
38
+ server.resource(
39
+ "model",
40
+ new (0, _mcpjs.ResourceTemplate)("context://model/{name}", {
41
+ list: async () => ({
42
+ resources: Object.keys(manifest.models).map((name) => ({
43
+ uri: `context://model/${name}`,
44
+ name,
45
+ description: _nullishCoalesce(_optionalChain([manifest, 'access', _ => _.models, 'access', _2 => _2[name], 'optionalAccess', _3 => _3.description]), () => ( `Model: ${name}`))
46
+ }))
47
+ })
48
+ }),
49
+ { description: "OSI semantic model merged with governance, rules, lineage, and tier" },
50
+ async (uri, { name }) => {
51
+ const modelName = String(name);
52
+ const view = buildModelView(modelName, manifest);
53
+ if (!view) {
54
+ throw new Error(`Model '${modelName}' not found`);
55
+ }
56
+ return {
57
+ contents: [
58
+ {
59
+ uri: uri.href,
60
+ mimeType: "application/json",
61
+ text: JSON.stringify(view, null, 2)
62
+ }
63
+ ]
64
+ };
65
+ }
66
+ );
86
67
  }
87
68
 
88
- // src/resources/policy.ts
89
- function readPolicy(manifest, id) {
90
- const policy = manifest.policies.find((p) => p.id === id);
91
- if (!policy) {
92
- return {
69
+ // src/resources/glossary.ts
70
+ function registerGlossaryResource(server, manifest) {
71
+ server.resource(
72
+ "glossary",
73
+ "context://glossary",
74
+ { description: "All ContextKit glossary terms with definitions, synonyms, and mappings" },
75
+ async (uri) => ({
93
76
  contents: [
94
77
  {
95
- uri: `context://policy/${id}`,
78
+ uri: uri.href,
96
79
  mimeType: "application/json",
97
- text: JSON.stringify({ error: `Policy not found: ${id}` })
80
+ text: JSON.stringify(manifest.terms, null, 2)
98
81
  }
99
82
  ]
100
- };
101
- }
102
- return {
103
- contents: [
104
- {
105
- uri: `context://policy/${id}`,
106
- mimeType: "application/json",
107
- text: JSON.stringify(policy, null, 2)
108
- }
109
- ]
110
- };
111
- }
112
- function listPolicies(manifest) {
113
- return {
114
- resources: manifest.policies.map((p) => ({
115
- uri: `context://policy/${p.id}`,
116
- name: p.id,
117
- description: p.description,
118
- mimeType: "application/json"
119
- }))
120
- };
83
+ })
84
+ );
121
85
  }
122
86
 
123
- // src/resources/glossary.ts
124
- function readGlossary(manifest) {
125
- const glossary = manifest.terms.map((t) => ({
126
- id: t.id,
127
- definition: t.definition,
128
- synonyms: _nullishCoalesce(t.synonyms, () => ( [])),
129
- mapsTo: _nullishCoalesce(t.mapsTo, () => ( []))
130
- }));
131
- return {
132
- contents: [
133
- {
134
- uri: "context://glossary",
135
- mimeType: "application/json",
136
- text: JSON.stringify(glossary, null, 2)
87
+ // src/resources/tier.ts
88
+
89
+ function registerTierResource(server, manifest) {
90
+ server.resource(
91
+ "tier",
92
+ new (0, _mcpjs.ResourceTemplate)("context://tier/{name}", {
93
+ list: async () => ({
94
+ resources: Object.keys(manifest.tiers).map((name) => ({
95
+ uri: `context://tier/${name}`,
96
+ name,
97
+ description: `Tier scorecard for model: ${name} (${_nullishCoalesce(_optionalChain([manifest, 'access', _4 => _4.tiers, 'access', _5 => _5[name], 'optionalAccess', _6 => _6.tier]), () => ( "unknown"))})`
98
+ }))
99
+ })
100
+ }),
101
+ { description: "Tier scorecard for a model (bronze/silver/gold checks and results)" },
102
+ async (uri, { name }) => {
103
+ const modelName = String(name);
104
+ const tier = manifest.tiers[modelName];
105
+ if (!tier) {
106
+ throw new Error(`Tier data for model '${modelName}' not found`);
137
107
  }
138
- ]
139
- };
108
+ return {
109
+ contents: [
110
+ {
111
+ uri: uri.href,
112
+ mimeType: "application/json",
113
+ text: JSON.stringify(tier, null, 2)
114
+ }
115
+ ]
116
+ };
117
+ }
118
+ );
140
119
  }
141
120
 
142
121
  // src/tools/search.ts
143
- function searchContext(manifest, query) {
122
+ var _zod = require('zod');
123
+ function searchManifest(manifest, query) {
124
+ const results = [];
144
125
  const q = query.toLowerCase();
145
- const items = [
146
- ...manifest.concepts.map((c) => ({
147
- kind: "concept",
148
- id: c.id,
149
- definition: c.definition,
150
- tags: c.tags
151
- })),
152
- ...manifest.products.map((p) => ({
153
- kind: "product",
154
- id: p.id,
155
- description: p.description,
156
- tags: p.tags
157
- })),
158
- ...manifest.policies.map((p) => ({
159
- kind: "policy",
160
- id: p.id,
161
- description: p.description,
162
- tags: p.tags
163
- })),
164
- ...manifest.entities.map((e) => ({
165
- kind: "entity",
166
- id: e.id,
167
- definition: e.definition,
168
- tags: e.tags
169
- })),
170
- ...manifest.terms.map((t) => ({
171
- kind: "term",
172
- id: t.id,
173
- definition: t.definition,
174
- tags: t.tags
175
- }))
176
- ];
177
- const matches = items.filter((item) => {
178
- if (item.id.toLowerCase().includes(q)) return true;
179
- if (item.definition && item.definition.toLowerCase().includes(q)) return true;
180
- if (item.description && item.description.toLowerCase().includes(q)) return true;
181
- if (item.tags && item.tags.some((tag) => tag.toLowerCase().includes(q))) return true;
182
- return false;
183
- });
184
- return {
185
- content: [
186
- {
187
- type: "text",
188
- text: JSON.stringify({ query, resultCount: matches.length, results: matches }, null, 2)
126
+ for (const [name, model] of Object.entries(manifest.models)) {
127
+ if (name.toLowerCase().includes(q) || _optionalChain([model, 'access', _7 => _7.description, 'optionalAccess', _8 => _8.toLowerCase, 'call', _9 => _9(), 'access', _10 => _10.includes, 'call', _11 => _11(q)])) {
128
+ results.push({
129
+ type: "model",
130
+ name,
131
+ description: model.description
132
+ });
133
+ }
134
+ for (const ds of _nullishCoalesce(model.datasets, () => ( []))) {
135
+ if (ds.name.toLowerCase().includes(q) || _optionalChain([ds, 'access', _12 => _12.description, 'optionalAccess', _13 => _13.toLowerCase, 'call', _14 => _14(), 'access', _15 => _15.includes, 'call', _16 => _16(q)])) {
136
+ results.push({
137
+ type: "dataset",
138
+ name: ds.name,
139
+ description: ds.description,
140
+ model: name
141
+ });
189
142
  }
190
- ]
191
- };
192
- }
193
-
194
- // src/tools/explain.ts
195
- function explainNode(manifest, id) {
196
- const index = manifest.indexes.byId[id];
197
- if (!index) {
198
- return {
199
- content: [
200
- {
201
- type: "text",
202
- text: JSON.stringify({ error: `Node not found: ${id}` }, null, 2)
203
- }
204
- ]
205
- };
206
- }
207
- let node;
208
- switch (index.kind) {
209
- case "concept":
210
- node = manifest.concepts[index.index];
211
- break;
212
- case "product":
213
- node = manifest.products[index.index];
214
- break;
215
- case "policy":
216
- node = manifest.policies[index.index];
217
- break;
218
- case "entity":
219
- node = manifest.entities[index.index];
220
- break;
221
- case "term":
222
- node = manifest.terms[index.index];
223
- break;
224
- case "owner":
225
- node = manifest.owners[index.index];
226
- break;
227
- }
228
- if (!node) {
229
- return {
230
- content: [
231
- {
232
- type: "text",
233
- text: JSON.stringify({ error: `Node data not found for: ${id}` }, null, 2)
143
+ if (ds.fields) {
144
+ for (const field of ds.fields) {
145
+ if (field.name.toLowerCase().includes(q) || _optionalChain([field, 'access', _17 => _17.description, 'optionalAccess', _18 => _18.toLowerCase, 'call', _19 => _19(), 'access', _20 => _20.includes, 'call', _21 => _21(q)]) || _optionalChain([field, 'access', _22 => _22.label, 'optionalAccess', _23 => _23.toLowerCase, 'call', _24 => _24(), 'access', _25 => _25.includes, 'call', _26 => _26(q)])) {
146
+ results.push({
147
+ type: "field",
148
+ name: field.name,
149
+ description: field.description,
150
+ model: name,
151
+ dataset: ds.name
152
+ });
153
+ }
234
154
  }
235
- ]
236
- };
237
- }
238
- const dependencies = [];
239
- const dependsOn = node.dependsOn;
240
- if (dependsOn) {
241
- for (const depId of dependsOn) {
242
- const depIndex = manifest.indexes.byId[depId];
243
- if (depIndex) {
244
- dependencies.push({ id: depId, kind: depIndex.kind });
245
155
  }
246
156
  }
247
157
  }
248
- const dependents = [];
249
- for (const concept of manifest.concepts) {
250
- if (_optionalChain([concept, 'access', _ => _.dependsOn, 'optionalAccess', _2 => _2.includes, 'call', _3 => _3(id)])) {
251
- dependents.push({ id: concept.id, kind: "concept" });
158
+ for (const [id, term] of Object.entries(manifest.terms)) {
159
+ if (id.toLowerCase().includes(q) || term.definition.toLowerCase().includes(q) || _optionalChain([term, 'access', _27 => _27.synonyms, 'optionalAccess', _28 => _28.some, 'call', _29 => _29((s) => s.toLowerCase().includes(q))])) {
160
+ results.push({
161
+ type: "term",
162
+ name: id,
163
+ description: term.definition
164
+ });
252
165
  }
253
166
  }
254
- const applicablePolicies = [];
255
- const nodeTags = _nullishCoalesce(node.tags, () => ( []));
256
- for (const policy of manifest.policies) {
257
- const applies = policy.rules.some((rule) => {
258
- if (_optionalChain([rule, 'access', _4 => _4.when, 'access', _5 => _5.conceptIds, 'optionalAccess', _6 => _6.includes, 'call', _7 => _7(id)])) return true;
259
- if (_optionalChain([rule, 'access', _8 => _8.when, 'access', _9 => _9.tagsAny, 'optionalAccess', _10 => _10.some, 'call', _11 => _11((tag) => nodeTags.includes(tag))])) return true;
260
- return false;
261
- });
262
- if (applies) {
263
- applicablePolicies.push({ id: policy.id, description: policy.description });
167
+ for (const [id, owner] of Object.entries(manifest.owners)) {
168
+ if (id.toLowerCase().includes(q) || owner.display_name.toLowerCase().includes(q) || _optionalChain([owner, 'access', _30 => _30.description, 'optionalAccess', _31 => _31.toLowerCase, 'call', _32 => _32(), 'access', _33 => _33.includes, 'call', _34 => _34(q)])) {
169
+ results.push({
170
+ type: "owner",
171
+ name: id,
172
+ description: owner.display_name
173
+ });
264
174
  }
265
175
  }
266
- let ownerInfo;
267
- const ownerId = node.owner;
268
- if (ownerId) {
269
- ownerInfo = manifest.owners.find((o) => o.id === ownerId);
176
+ return results;
177
+ }
178
+ function registerSearchTool(server, manifest) {
179
+ server.tool(
180
+ "context_search",
181
+ "Search across all ContextKit nodes (models, datasets, fields, terms, owners) by keyword",
182
+ { query: _zod.z.string().describe("Keyword to search for") },
183
+ async ({ query }) => {
184
+ const results = searchManifest(manifest, query);
185
+ return {
186
+ content: [
187
+ {
188
+ type: "text",
189
+ text: JSON.stringify(results, null, 2)
190
+ }
191
+ ]
192
+ };
193
+ }
194
+ );
195
+ }
196
+
197
+ // src/tools/explain.ts
198
+
199
+ function explainModel(name, manifest) {
200
+ const model = manifest.models[name];
201
+ if (!model) return null;
202
+ const governance = _nullishCoalesce(manifest.governance[name], () => ( null));
203
+ const rules = _nullishCoalesce(manifest.rules[name], () => ( null));
204
+ const lineage = _nullishCoalesce(manifest.lineage[name], () => ( null));
205
+ const tier = _nullishCoalesce(manifest.tiers[name], () => ( null));
206
+ const ownerKey = _optionalChain([governance, 'optionalAccess', _35 => _35.owner]);
207
+ const owner = ownerKey ? _nullishCoalesce(manifest.owners[ownerKey], () => ( null)) : null;
208
+ const modelTags = _nullishCoalesce(_optionalChain([governance, 'optionalAccess', _36 => _36.tags]), () => ( []));
209
+ const relatedTerms = [];
210
+ for (const [, term] of Object.entries(manifest.terms)) {
211
+ const termTags = _nullishCoalesce(term.tags, () => ( []));
212
+ const hasOverlap = modelTags.some((t) => termTags.includes(t));
213
+ const mapsToModel = _optionalChain([term, 'access', _37 => _37.maps_to, 'optionalAccess', _38 => _38.some, 'call', _39 => _39((m) => m === name)]);
214
+ if (hasOverlap || mapsToModel) {
215
+ relatedTerms.push(term);
216
+ }
270
217
  }
271
- const result = {
272
- kind: index.kind,
273
- node,
274
- dependencies,
275
- dependents,
276
- applicablePolicies,
277
- owner: _nullishCoalesce(ownerInfo, () => ( null))
278
- };
279
218
  return {
280
- content: [
281
- {
282
- type: "text",
283
- text: JSON.stringify(result, null, 2)
284
- }
285
- ]
219
+ model,
220
+ governance,
221
+ rules,
222
+ lineage,
223
+ tier,
224
+ owner,
225
+ relatedTerms
286
226
  };
287
227
  }
228
+ function registerExplainTool(server, manifest) {
229
+ server.tool(
230
+ "context_explain",
231
+ "Deep lookup of a model with all related governance, rules, lineage, tier, owner, and glossary terms",
232
+ { model: _zod.z.string().describe("Name of the model to explain") },
233
+ async ({ model }) => {
234
+ const result = explainModel(model, manifest);
235
+ if (!result) {
236
+ return {
237
+ content: [
238
+ {
239
+ type: "text",
240
+ text: JSON.stringify({ error: `Model '${model}' not found` })
241
+ }
242
+ ]
243
+ };
244
+ }
245
+ return {
246
+ content: [
247
+ {
248
+ type: "text",
249
+ text: JSON.stringify(result, null, 2)
250
+ }
251
+ ]
252
+ };
253
+ }
254
+ );
255
+ }
288
256
 
289
257
  // src/tools/validate.ts
290
- async function validateContext(rootDir) {
291
- try {
292
- const { compile, LintEngine, ALL_RULES } = await Promise.resolve().then(() => _interopRequireWildcard(require("@runcontext/core")));
293
- const contextDir = _nullishCoalesce(rootDir, () => ( process.cwd()));
294
- const compileResult = await compile({
295
- contextDir,
296
- config: {}
297
- });
298
- const engine = new LintEngine();
299
- for (const rule of ALL_RULES) {
300
- engine.register(rule);
301
- }
302
- const lintDiagnostics = engine.run(compileResult.graph);
303
- const allDiagnostics = [...compileResult.diagnostics, ...lintDiagnostics];
304
- const summary = {
305
- contextDir,
306
- compileDiagnostics: compileResult.diagnostics.length,
307
- lintDiagnostics: lintDiagnostics.length,
308
- totalDiagnostics: allDiagnostics.length,
309
- errors: allDiagnostics.filter((d) => d.severity === "error").length,
310
- warnings: allDiagnostics.filter((d) => d.severity === "warning").length,
311
- diagnostics: allDiagnostics
312
- };
313
- return {
314
- content: [
315
- {
316
- type: "text",
317
- text: JSON.stringify(summary, null, 2)
318
- }
319
- ]
320
- };
321
- } catch (err) {
322
- const message = err instanceof Error ? err.message : String(err);
323
- return {
324
- content: [
325
- {
326
- type: "text",
327
- text: JSON.stringify({ error: `Validation failed: ${message}` }, null, 2)
328
- }
329
- ],
330
- isError: true
331
- };
258
+
259
+ function validateGraph(graph) {
260
+ const engine = new (0, _core.LintEngine)();
261
+ for (const rule of _core.ALL_RULES) {
262
+ engine.register(rule);
332
263
  }
264
+ const diagnostics = engine.run(graph);
265
+ const errors = diagnostics.filter((d) => d.severity === "error").length;
266
+ const warnings = diagnostics.filter((d) => d.severity === "warning").length;
267
+ return {
268
+ totalDiagnostics: diagnostics.length,
269
+ errors,
270
+ warnings,
271
+ diagnostics
272
+ };
333
273
  }
334
-
335
- // src/server.ts
336
- function createContextMcpServer(manifest) {
337
- const server = new (0, _mcpjs.McpServer)(
338
- {
339
- name: "contextkit",
340
- version: "0.1.0"
341
- },
342
- {
343
- capabilities: {
344
- resources: {},
345
- tools: {}
346
- }
274
+ function registerValidateTool(server, graph) {
275
+ server.tool(
276
+ "context_validate",
277
+ "Run ContextKit linter against the context graph and return diagnostics",
278
+ {},
279
+ async () => {
280
+ const result = validateGraph(graph);
281
+ return {
282
+ content: [
283
+ {
284
+ type: "text",
285
+ text: JSON.stringify(result, null, 2)
286
+ }
287
+ ]
288
+ };
347
289
  }
348
290
  );
349
- server.resource(
350
- "manifest",
351
- "context://manifest",
352
- { description: "The full ContextKit manifest", mimeType: "application/json" },
353
- () => readManifest(manifest)
354
- );
355
- server.resource(
356
- "glossary",
357
- "context://glossary",
358
- { description: "Glossary of all terms", mimeType: "application/json" },
359
- () => readGlossary(manifest)
360
- );
361
- server.resource(
362
- "concept",
363
- new (0, _mcpjs.ResourceTemplate)("context://concept/{id}", {
364
- list: () => listConcepts(manifest)
365
- }),
366
- { description: "A single concept by ID", mimeType: "application/json" },
367
- (uri, variables) => readConcept(manifest, String(variables.id))
368
- );
369
- server.resource(
370
- "product",
371
- new (0, _mcpjs.ResourceTemplate)("context://product/{id}", {
372
- list: () => listProducts(manifest)
373
- }),
374
- { description: "A single product by ID", mimeType: "application/json" },
375
- (uri, variables) => readProduct(manifest, String(variables.id))
376
- );
377
- server.resource(
378
- "policy",
379
- new (0, _mcpjs.ResourceTemplate)("context://policy/{id}", {
380
- list: () => listPolicies(manifest)
381
- }),
382
- { description: "A single policy by ID", mimeType: "application/json" },
383
- (uri, variables) => readPolicy(manifest, String(variables.id))
384
- );
291
+ }
292
+
293
+ // src/tools/tier.ts
294
+
295
+
296
+ function computeModelTier(modelName, graph) {
297
+ if (!graph.models.has(modelName)) return null;
298
+ return _core.computeTier.call(void 0, modelName, graph);
299
+ }
300
+ function registerTierTool(server, graph) {
385
301
  server.tool(
386
- "context_search",
387
- "Search across all concepts, products, policies, entities, and terms",
388
- { query: _zod.z.string().describe("The search query (case-insensitive substring match)") },
389
- ({ query }) => searchContext(manifest, query)
302
+ "context_tier",
303
+ "Compute the metadata tier (none/bronze/silver/gold) for a model with detailed check results",
304
+ { model: _zod.z.string().describe("Name of the model to tier") },
305
+ async ({ model }) => {
306
+ const result = computeModelTier(model, graph);
307
+ if (!result) {
308
+ return {
309
+ content: [
310
+ {
311
+ type: "text",
312
+ text: JSON.stringify({ error: `Model '${model}' not found` })
313
+ }
314
+ ]
315
+ };
316
+ }
317
+ return {
318
+ content: [
319
+ {
320
+ type: "text",
321
+ text: JSON.stringify(result, null, 2)
322
+ }
323
+ ]
324
+ };
325
+ }
390
326
  );
327
+ }
328
+
329
+ // src/tools/golden-query.ts
330
+
331
+ function findGoldenQueries(manifest, question) {
332
+ const stopWords = /* @__PURE__ */ new Set(["a", "an", "the", "is", "in", "on", "at", "to", "of", "for", "and", "or", "not"]);
333
+ const qWords = question.toLowerCase().split(/\s+/).filter((w) => w.length > 0 && !stopWords.has(w));
334
+ const matches = [];
335
+ for (const [modelName, rules] of Object.entries(manifest.rules)) {
336
+ if (!rules.golden_queries) continue;
337
+ for (const gq of rules.golden_queries) {
338
+ const gqWords = gq.question.toLowerCase().split(/\s+/);
339
+ const overlap = qWords.filter((w) => gqWords.some((gw) => gw.includes(w))).length;
340
+ if (overlap > 0) {
341
+ matches.push({
342
+ model: modelName,
343
+ query: gq,
344
+ score: overlap / Math.max(qWords.length, 1)
345
+ });
346
+ }
347
+ }
348
+ }
349
+ matches.sort((a, b) => b.score - a.score);
350
+ return matches;
351
+ }
352
+ function registerGoldenQueryTool(server, manifest) {
391
353
  server.tool(
392
- "context_explain",
393
- "Get comprehensive info about a node: the node itself, dependencies, dependents, applicable policies, and owner",
394
- { id: _zod.z.string().describe("The ID of the node to explain") },
395
- ({ id }) => explainNode(manifest, id)
354
+ "context_golden_query",
355
+ "Find golden SQL queries that match a natural-language question",
356
+ { question: _zod.z.string().describe("Natural-language question to match against golden queries") },
357
+ async ({ question }) => {
358
+ const results = findGoldenQueries(manifest, question);
359
+ return {
360
+ content: [
361
+ {
362
+ type: "text",
363
+ text: JSON.stringify(results, null, 2)
364
+ }
365
+ ]
366
+ };
367
+ }
396
368
  );
369
+ }
370
+
371
+ // src/tools/guardrails.ts
372
+
373
+ function findGuardrails(manifest, tables) {
374
+ const matches = [];
375
+ const tableSet = new Set(tables.map((t) => t.toLowerCase()));
376
+ for (const [modelName, rules] of Object.entries(manifest.rules)) {
377
+ if (!rules.guardrail_filters) continue;
378
+ for (const gf of rules.guardrail_filters) {
379
+ const applies = !gf.tables || gf.tables.length === 0 || gf.tables.some((t) => tableSet.has(t.toLowerCase()));
380
+ if (applies) {
381
+ matches.push({
382
+ model: modelName,
383
+ filter: gf
384
+ });
385
+ }
386
+ }
387
+ }
388
+ return matches;
389
+ }
390
+ function registerGuardrailsTool(server, manifest) {
397
391
  server.tool(
398
- "context_validate",
399
- "Run compile and lint validation on the context directory and return diagnostics",
400
- { rootDir: _zod.z.string().optional().describe("Root directory to validate (defaults to cwd)") },
401
- async ({ rootDir }) => validateContext(rootDir)
392
+ "context_guardrails",
393
+ "Return guardrail filters that apply to the specified tables",
394
+ {
395
+ tables: _zod.z.array(_zod.z.string()).describe("List of table names to check guardrails for")
396
+ },
397
+ async ({ tables }) => {
398
+ const results = findGuardrails(manifest, tables);
399
+ return {
400
+ content: [
401
+ {
402
+ type: "text",
403
+ text: JSON.stringify(results, null, 2)
404
+ }
405
+ ]
406
+ };
407
+ }
402
408
  );
403
- return server;
404
409
  }
405
410
 
406
- // src/index.ts
407
- var MCP_VERSION = "0.1.0";
411
+ // src/server.ts
412
+ function createServer(manifest, graph) {
413
+ const server = new (0, _mcpjs.McpServer)({
414
+ name: "contextkit",
415
+ version: "0.2.0"
416
+ });
417
+ registerManifestResource(server, manifest);
418
+ registerModelResource(server, manifest);
419
+ registerGlossaryResource(server, manifest);
420
+ registerTierResource(server, manifest);
421
+ registerSearchTool(server, manifest);
422
+ registerExplainTool(server, manifest);
423
+ registerValidateTool(server, graph);
424
+ registerTierTool(server, graph);
425
+ registerGoldenQueryTool(server, manifest);
426
+ registerGuardrailsTool(server, manifest);
427
+ return server;
428
+ }
429
+ async function startServer(options) {
430
+ const rootDir = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _40 => _40.rootDir]), () => ( process.cwd()));
431
+ const config = _core.loadConfig.call(void 0, rootDir);
432
+ const contextDir = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _41 => _41.contextDir]), () => ( config.context_dir));
433
+ const { graph } = await _core.compile.call(void 0, { contextDir, config });
434
+ const manifest = _core.emitManifest.call(void 0, graph, config);
435
+ const server = createServer(manifest, graph);
436
+ const transport = new (0, _stdiojs.StdioServerTransport)();
437
+ await server.connect(transport);
438
+ return server;
439
+ }
408
440
 
409
441
 
410
442
 
@@ -419,5 +451,5 @@ var MCP_VERSION = "0.1.0";
419
451
 
420
452
 
421
453
 
422
- exports.MCP_VERSION = MCP_VERSION; exports.createContextMcpServer = createContextMcpServer; exports.explainNode = explainNode; exports.listConcepts = listConcepts; exports.listPolicies = listPolicies; exports.listProducts = listProducts; exports.readConcept = readConcept; exports.readGlossary = readGlossary; exports.readManifest = readManifest; exports.readPolicy = readPolicy; exports.readProduct = readProduct; exports.searchContext = searchContext; exports.validateContext = validateContext;
454
+ exports.buildModelView = buildModelView; exports.computeModelTier = computeModelTier; exports.createServer = createServer; exports.explainModel = explainModel; exports.findGoldenQueries = findGoldenQueries; exports.findGuardrails = findGuardrails; exports.registerGlossaryResource = registerGlossaryResource; exports.registerManifestResource = registerManifestResource; exports.registerModelResource = registerModelResource; exports.registerTierResource = registerTierResource; exports.searchManifest = searchManifest; exports.startServer = startServer; exports.validateGraph = validateGraph;
423
455
  //# sourceMappingURL=index.cjs.map