@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.mjs CHANGED
@@ -1,423 +1,455 @@
1
1
  // src/server.ts
2
- import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
3
- import { z } from "zod";
2
+ import { McpServer as McpServer3 } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { compile, emitManifest, loadConfig } from "@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
+ import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
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: manifest.governance[name] ?? null,
32
+ rules: manifest.rules[name] ?? null,
33
+ lineage: manifest.lineage[name] ?? null,
34
+ tier: 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 ResourceTemplate("context://model/{name}", {
41
+ list: async () => ({
42
+ resources: Object.keys(manifest.models).map((name) => ({
43
+ uri: `context://model/${name}`,
44
+ name,
45
+ description: manifest.models[name]?.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: t.synonyms ?? [],
129
- mapsTo: 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
+ import { ResourceTemplate as ResourceTemplate2 } from "@modelcontextprotocol/sdk/server/mcp.js";
89
+ function registerTierResource(server, manifest) {
90
+ server.resource(
91
+ "tier",
92
+ new ResourceTemplate2("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} (${manifest.tiers[name]?.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
+ import { z } from "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) || model.description?.toLowerCase().includes(q)) {
128
+ results.push({
129
+ type: "model",
130
+ name,
131
+ description: model.description
132
+ });
133
+ }
134
+ for (const ds of model.datasets ?? []) {
135
+ if (ds.name.toLowerCase().includes(q) || ds.description?.toLowerCase().includes(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)
143
+ if (ds.fields) {
144
+ for (const field of ds.fields) {
145
+ if (field.name.toLowerCase().includes(q) || field.description?.toLowerCase().includes(q) || field.label?.toLowerCase().includes(q)) {
146
+ results.push({
147
+ type: "field",
148
+ name: field.name,
149
+ description: field.description,
150
+ model: name,
151
+ dataset: ds.name
152
+ });
153
+ }
203
154
  }
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)
234
- }
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 (concept.dependsOn?.includes(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) || term.synonyms?.some((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 = node.tags ?? [];
256
- for (const policy of manifest.policies) {
257
- const applies = policy.rules.some((rule) => {
258
- if (rule.when.conceptIds?.includes(id)) return true;
259
- if (rule.when.tagsAny?.some((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) || owner.description?.toLowerCase().includes(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: 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
+ import { z as z2 } from "zod";
199
+ function explainModel(name, manifest) {
200
+ const model = manifest.models[name];
201
+ if (!model) return null;
202
+ const governance = manifest.governance[name] ?? null;
203
+ const rules = manifest.rules[name] ?? null;
204
+ const lineage = manifest.lineage[name] ?? null;
205
+ const tier = manifest.tiers[name] ?? null;
206
+ const ownerKey = governance?.owner;
207
+ const owner = ownerKey ? manifest.owners[ownerKey] ?? null : null;
208
+ const modelTags = governance?.tags ?? [];
209
+ const relatedTerms = [];
210
+ for (const [, term] of Object.entries(manifest.terms)) {
211
+ const termTags = term.tags ?? [];
212
+ const hasOverlap = modelTags.some((t) => termTags.includes(t));
213
+ const mapsToModel = term.maps_to?.some((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: 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: z2.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 import("@runcontext/core");
293
- const contextDir = 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
+ import { LintEngine, ALL_RULES } from "@runcontext/core";
259
+ function validateGraph(graph) {
260
+ const engine = new LintEngine();
261
+ for (const rule of 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 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 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 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 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
+ import { z as z3 } from "zod";
295
+ import { computeTier } from "@runcontext/core";
296
+ function computeModelTier(modelName, graph) {
297
+ if (!graph.models.has(modelName)) return null;
298
+ return computeTier(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: 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: z3.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
+ import { z as z4 } from "zod";
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: 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: z4.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
+ import { z as z5 } from "zod";
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: 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: z5.array(z5.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 McpServer3({
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 = options?.rootDir ?? process.cwd();
431
+ const config = loadConfig(rootDir);
432
+ const contextDir = options?.contextDir ?? config.context_dir;
433
+ const { graph } = await compile({ contextDir, config });
434
+ const manifest = emitManifest(graph, config);
435
+ const server = createServer(manifest, graph);
436
+ const transport = new StdioServerTransport();
437
+ await server.connect(transport);
438
+ return server;
439
+ }
408
440
  export {
409
- MCP_VERSION,
410
- createContextMcpServer,
411
- explainNode,
412
- listConcepts,
413
- listPolicies,
414
- listProducts,
415
- readConcept,
416
- readGlossary,
417
- readManifest,
418
- readPolicy,
419
- readProduct,
420
- searchContext,
421
- validateContext
441
+ buildModelView,
442
+ computeModelTier,
443
+ createServer,
444
+ explainModel,
445
+ findGoldenQueries,
446
+ findGuardrails,
447
+ registerGlossaryResource,
448
+ registerManifestResource,
449
+ registerModelResource,
450
+ registerTierResource,
451
+ searchManifest,
452
+ startServer,
453
+ validateGraph
422
454
  };
423
455
  //# sourceMappingURL=index.mjs.map