@enfyra/mcp-server 0.1.65 → 0.1.67

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.
Files changed (51) hide show
  1. package/README.md +1 -0
  2. package/dist/lib/extension-search-tools.d.ts +15 -0
  3. package/dist/lib/extension-search-tools.js +32 -6
  4. package/dist/lib/extension-search-tools.js.map +1 -1
  5. package/dist/lib/mcp-instructions.js +3 -1
  6. package/dist/lib/mcp-instructions.js.map +1 -1
  7. package/dist/lib/model-eval.d.ts +4 -0
  8. package/dist/lib/model-eval.js +354 -0
  9. package/dist/lib/model-eval.js.map +1 -0
  10. package/dist/lib/pagination.d.ts +16 -0
  11. package/dist/lib/pagination.js +41 -0
  12. package/dist/lib/pagination.js.map +1 -0
  13. package/dist/lib/platform-operation-tools.d.ts +1 -0
  14. package/dist/lib/record-contracts.d.ts +13 -0
  15. package/dist/lib/record-contracts.js +33 -0
  16. package/dist/lib/record-contracts.js.map +1 -0
  17. package/dist/lib/required-knowledge.js +4 -2
  18. package/dist/lib/required-knowledge.js.map +1 -1
  19. package/dist/lib/response-format.d.ts +3 -1
  20. package/dist/lib/response-format.js +47 -17
  21. package/dist/lib/response-format.js.map +1 -1
  22. package/dist/lib/runtime-zone-tools.d.ts +30 -0
  23. package/dist/lib/runtime-zone-tools.js +26 -6
  24. package/dist/lib/runtime-zone-tools.js.map +1 -1
  25. package/dist/lib/session-safety.js +3 -26
  26. package/dist/lib/session-safety.js.map +1 -1
  27. package/dist/lib/source-artifacts.d.ts +7 -0
  28. package/dist/lib/source-artifacts.js +38 -2
  29. package/dist/lib/source-artifacts.js.map +1 -1
  30. package/dist/lib/tool-catalog.d.ts +7 -0
  31. package/dist/lib/tool-catalog.js +141 -0
  32. package/dist/lib/tool-catalog.js.map +1 -0
  33. package/dist/lib/tool-contracts.d.ts +6 -0
  34. package/dist/lib/tool-contracts.js +99 -0
  35. package/dist/lib/tool-contracts.js.map +1 -0
  36. package/dist/lib/tool-output-contracts.d.ts +7 -0
  37. package/dist/lib/tool-output-contracts.js +175 -0
  38. package/dist/lib/tool-output-contracts.js.map +1 -0
  39. package/dist/lib/tool-routing.d.ts +22 -2
  40. package/dist/lib/tool-routing.js +36 -9
  41. package/dist/lib/tool-routing.js.map +1 -1
  42. package/dist/lib/toolset-filter.d.ts +7 -6
  43. package/dist/lib/toolset-filter.js +79 -21
  44. package/dist/lib/toolset-filter.js.map +1 -1
  45. package/dist/lib/types.d.ts +77 -0
  46. package/dist/lib/workflow-tool-packs.d.ts +2 -0
  47. package/dist/lib/workflow-tool-packs.js +55 -0
  48. package/dist/lib/workflow-tool-packs.js.map +1 -0
  49. package/dist/mcp-server-entry.js +85 -13
  50. package/dist/mcp-server-entry.js.map +1 -1
  51. package/package.json +5 -2
@@ -1,6 +1,6 @@
1
1
  export const MCP_TOOLSETS = ['guided', 'full'];
2
2
  export const MCP_PROFILES = ['all', 'extension', 'schema', 'runtime', 'operations'];
3
- const CORE_TOOL_NAMES = [
3
+ export const CORE_TOOL_NAMES = [
4
4
  'get_enfyra_required_knowledge',
5
5
  'get_enfyra_examples',
6
6
  'discover_enfyra_workflows',
@@ -11,15 +11,17 @@ const CORE_TOOL_NAMES = [
11
11
  'get_enfyra_api_context',
12
12
  'get_current_user',
13
13
  'get_permission_profile',
14
+ 'search_enfyra_tools',
15
+ 'execute_enfyra_tool',
16
+ 'select_enfyra_workflow',
14
17
  ];
18
+ const CORE_TOOL_SET = new Set(CORE_TOOL_NAMES);
15
19
  const PROFILE_TOOL_NAMES = {
16
20
  extension: [
17
21
  ...CORE_TOOL_NAMES,
18
22
  'search_admin_extensions',
19
23
  'search_runtime_zone',
20
24
  'inspect_table',
21
- 'inspect_feature',
22
- 'trace_metadata_usage',
23
25
  'get_table_metadata',
24
26
  'query_table',
25
27
  'count_records',
@@ -44,8 +46,6 @@ const PROFILE_TOOL_NAMES = {
44
46
  'debug_field_exposure',
45
47
  'inspect_table',
46
48
  'inspect_route',
47
- 'inspect_feature',
48
- 'trace_metadata_usage',
49
49
  'get_table_metadata',
50
50
  'get_all_tables',
51
51
  'get_schema_design_context',
@@ -72,7 +72,6 @@ const PROFILE_TOOL_NAMES = {
72
72
  'search_runtime_zone',
73
73
  'inspect_table',
74
74
  'inspect_route',
75
- 'get_script_source',
76
75
  'patch_script_source',
77
76
  'update_script_source',
78
77
  'validate_dynamic_script',
@@ -103,9 +102,6 @@ const PROFILE_TOOL_NAMES = {
103
102
  'search_runtime_zone',
104
103
  'inspect_table',
105
104
  'inspect_route',
106
- 'inspect_feature',
107
- 'trace_metadata_usage',
108
- 'get_all_routes',
109
105
  'query_table',
110
106
  'count_records',
111
107
  'find_one_record',
@@ -141,6 +137,16 @@ export function normalizeMcpProfile(value) {
141
137
  const raw = String(value || '').trim().toLowerCase();
142
138
  return MCP_PROFILES.includes(raw) ? raw : 'all';
143
139
  }
140
+ export function normalizeDynamicToolPacks(value, toolset, profile) {
141
+ if (toolset === 'full' || profile !== 'all')
142
+ return false;
143
+ const raw = String(value ?? '').trim().toLowerCase();
144
+ if (['0', 'false', 'off', 'no'].includes(raw))
145
+ return false;
146
+ if (['1', 'true', 'on', 'yes'].includes(raw))
147
+ return true;
148
+ return true;
149
+ }
144
150
  export function isToolVisibleInToolset(toolName, toolset, profile = 'all') {
145
151
  if (toolset === 'full')
146
152
  return true;
@@ -148,23 +154,65 @@ export function isToolVisibleInToolset(toolName, toolset, profile = 'all') {
148
154
  return GUIDED_TOOL_NAMES.has(toolName);
149
155
  return PROFILE_TOOL_SETS[profile].has(toolName);
150
156
  }
151
- export function installToolsetFilter(server, toolset, profile = 'all') {
157
+ export function installToolsetFilter(server, toolset, profile = 'all', { dynamic = false } = {}) {
152
158
  const registerTool = server.tool.bind(server);
153
159
  const hiddenTools = [];
154
- server.tool = (name, description, schema, handler) => {
155
- if (!isToolVisibleInToolset(name, toolset, profile)) {
156
- hiddenTools.push(name);
157
- return undefined;
158
- }
159
- return registerTool(name, description, schema, handler);
160
+ const registrations = new Map();
161
+ const refreshHiddenTools = () => {
162
+ hiddenTools.splice(0, hiddenTools.length, ...[...registrations.values()]
163
+ .filter((tool) => !tool.visible)
164
+ .map((tool) => tool.name));
165
+ };
166
+ server.tool = (...args) => {
167
+ const name = String(args[0]);
168
+ const description = typeof args[1] === 'string' ? args[1] : '';
169
+ const inputSchema = (typeof args[1] === 'string' ? args[2] : args[1]) || {};
170
+ const handler = args.at(-1);
171
+ const annotations = args.length >= 5 ? args.at(-2) : undefined;
172
+ const eligible = isToolVisibleInToolset(name, toolset, profile);
173
+ const visible = eligible && (!dynamic || CORE_TOOL_SET.has(name));
174
+ const registration = registerTool(...args);
175
+ if (registration && !visible)
176
+ registration.enabled = false;
177
+ registrations.set(name, { name, description, inputSchema, annotations, handler, visible, registration });
178
+ refreshHiddenTools();
179
+ return registration;
160
180
  };
161
- return {
181
+ const state = {
162
182
  toolset,
163
183
  profile,
184
+ dynamic,
164
185
  hiddenTools,
186
+ getTool: (name) => registrations.get(name),
187
+ listTools: () => [...registrations.values()],
188
+ listVisibleToolNames: () => [...registrations.values()]
189
+ .filter((tool) => tool.visible)
190
+ .map((tool) => tool.name),
191
+ setActiveTools: (toolNames) => {
192
+ const requested = new Set(toolNames);
193
+ for (const coreTool of CORE_TOOL_NAMES)
194
+ requested.add(coreTool);
195
+ let changed = false;
196
+ for (const tool of registrations.values()) {
197
+ const visible = isToolVisibleInToolset(tool.name, toolset, profile)
198
+ && (!dynamic || requested.has(tool.name));
199
+ if (tool.visible === visible)
200
+ continue;
201
+ tool.visible = visible;
202
+ if (tool.registration)
203
+ tool.registration.enabled = visible;
204
+ changed = true;
205
+ }
206
+ refreshHiddenTools();
207
+ if (changed)
208
+ server.sendToolListChanged?.();
209
+ const visibleToolNames = state.listVisibleToolNames();
210
+ return { changed, visibleToolNames, hiddenToolCount: hiddenTools.length };
211
+ },
165
212
  };
213
+ return state;
166
214
  }
167
- export function summarizeToolsetForInstructions(toolset, profile = 'all') {
215
+ export function summarizeToolsetForInstructions(toolset, profile = 'all', dynamic = false) {
168
216
  if (toolset === 'full') {
169
217
  return 'Toolset mode: full. All Enfyra MCP tools are visible, including low-level escape hatches; domain profile filtering is disabled.';
170
218
  }
@@ -172,13 +220,23 @@ export function summarizeToolsetForInstructions(toolset, profile = 'all') {
172
220
  return [
173
221
  `Toolset mode: guided, domain profile: ${profile}. Only normal ${profile} workflow tools and shared discovery/context tools are visible.`,
174
222
  'Use this focused surface when the task belongs to one domain and lower context overhead is important.',
223
+ 'Use search_enfyra_tools for hidden long-tail read-only tools; hidden mutations require the full toolset.',
175
224
  'Set ENFYRA_MCP_PROFILE=all for the complete guided surface, or ENFYRA_MCP_TOOLSET=full only for expert debugging or compatibility work.',
176
225
  ].join(' ');
177
226
  }
227
+ if (!dynamic) {
228
+ return [
229
+ 'Toolset mode: guided, domain profile: all. The complete curated guided surface is visible.',
230
+ 'Use discover_enfyra_workflows for routing and search_enfyra_tools for hidden long-tail read-only tools.',
231
+ 'Set ENFYRA_MCP_DYNAMIC_TOOLS=on to start with a compact routing surface on hosts that refresh tools/list_changed.',
232
+ 'Low-level escape hatches require ENFYRA_MCP_TOOLSET=full.',
233
+ ].join(' ');
234
+ }
178
235
  return [
179
- 'Toolset mode: guided, domain profile: all. The visible tool surface is curated for broad model compatibility.',
180
- 'Prefer discover_enfyra_workflows, search_runtime_zone, inspect_* tools, and operation-level ensure/workflow tools.',
181
- 'Use ENFYRA_MCP_PROFILE=extension, schema, runtime, or operations to reduce context for a known domain. Low-level escape hatches require ENFYRA_MCP_TOOLSET=full.',
236
+ 'Toolset mode: guided, domain profile: all. Dynamic workflow packs start with a compact routing surface.',
237
+ 'Call select_enfyra_workflow with the task surface to expose the exact direct workflow tools for this session.',
238
+ 'Use search_enfyra_tools for hidden long-tail read-only tools; hidden mutations require the full toolset.',
239
+ 'Set ENFYRA_MCP_DYNAMIC_TOOLS=off or use ENFYRA_MCP_PROFILE=extension, schema, runtime, or operations as a static fallback for hosts that do not refresh tools/list_changed. Low-level escape hatches require ENFYRA_MCP_TOOLSET=full.',
182
240
  ].join(' ');
183
241
  }
184
242
  //# sourceMappingURL=toolset-filter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"toolset-filter.js","sourceRoot":"","sources":["../../src/lib/toolset-filter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"toolset-filter.js","sourceRoot":"","sources":["../../src/lib/toolset-filter.ts"],"names":[],"mappings":"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"}
@@ -15,6 +15,83 @@ export interface ToolResult {
15
15
  _meta?: Record<string, unknown>;
16
16
  }
17
17
  export type UnknownRecord = Record<string, unknown>;
18
+ export interface McpToolAnnotations {
19
+ title: string;
20
+ readOnlyHint: boolean;
21
+ destructiveHint: boolean;
22
+ idempotentHint: boolean;
23
+ openWorldHint: boolean;
24
+ }
25
+ export interface McpToolContract {
26
+ name: string;
27
+ annotations: McpToolAnnotations;
28
+ catalogExecutable: boolean;
29
+ }
30
+ export interface RegisteredToolDefinition {
31
+ name: string;
32
+ description: string;
33
+ inputSchema: Record<string, unknown>;
34
+ annotations?: McpToolAnnotations;
35
+ handler: (...args: any[]) => any;
36
+ visible: boolean;
37
+ registration?: {
38
+ enabled: boolean;
39
+ };
40
+ }
41
+ export interface ToolsetRegistrationState {
42
+ toolset: string;
43
+ profile: string;
44
+ dynamic: boolean;
45
+ hiddenTools: string[];
46
+ getTool(name: string): RegisteredToolDefinition | undefined;
47
+ listTools(): RegisteredToolDefinition[];
48
+ listVisibleToolNames(): string[];
49
+ setActiveTools(toolNames: Iterable<string>): {
50
+ changed: boolean;
51
+ visibleToolNames: string[];
52
+ hiddenToolCount: number;
53
+ };
54
+ }
55
+ export type ToolAvailabilityStatus = 'allowed' | 'denied' | 'unknown';
56
+ export interface ToolAvailability {
57
+ status: ToolAvailabilityStatus;
58
+ reason: string;
59
+ }
60
+ export interface ModelEvalTraceEvent {
61
+ tool: string;
62
+ arguments?: Record<string, unknown>;
63
+ result?: unknown;
64
+ isError?: boolean;
65
+ }
66
+ export interface ModelEvalRun {
67
+ scenarioId: string;
68
+ model: string;
69
+ events: ModelEvalTraceEvent[];
70
+ }
71
+ export interface ModelEvalScenario {
72
+ id: string;
73
+ prompt: string;
74
+ surface: string;
75
+ requiredToolGroups: string[][];
76
+ verificationTools: string[];
77
+ maxToolCalls: number;
78
+ mutationExpected: boolean;
79
+ destructiveExpected?: boolean;
80
+ }
81
+ export interface ModelEvalCheck {
82
+ key: string;
83
+ passed: boolean;
84
+ detail: string;
85
+ blocking?: boolean;
86
+ }
87
+ export interface ModelEvalScore {
88
+ scenarioId: string;
89
+ model: string;
90
+ score: number;
91
+ optimizationScore: number;
92
+ recommended: boolean;
93
+ checks: ModelEvalCheck[];
94
+ }
18
95
  export interface MetadataContext {
19
96
  dbType: "postgres" | "mysql" | "mongodb" | "mariadb" | "sqlite" | null;
20
97
  enfyraVersion: string | null;
@@ -0,0 +1,2 @@
1
+ import type { ToolsetRegistrationState } from './types.js';
2
+ export declare function registerWorkflowToolPack(server: any, state: ToolsetRegistrationState): any;
@@ -0,0 +1,55 @@
1
+ import { z } from 'zod';
2
+ import { jsonContent } from './response-format.js';
3
+ import { WORKFLOW_SURFACES, workflowToolNames } from './tool-routing.js';
4
+ const MAX_ACTIVE_WORKFLOWS = 2;
5
+ export function registerWorkflowToolPack(server, state) {
6
+ const activeSurfaces = new Set();
7
+ return server.tool('select_enfyra_workflow', [
8
+ 'Select a workflow surface and expose its exact direct MCP tools for this stdio session.',
9
+ 'Use replace for normal tasks, add only when one task genuinely spans two surfaces, and reset to return to the compact routing surface.',
10
+ 'This changes tool visibility only; it does not grant permissions or bypass Enfyra PAT/RBAC.',
11
+ ].join(' '), {
12
+ surface: z.enum(WORKFLOW_SURFACES).optional().describe('Required for replace/add. Omit only with mode=reset.'),
13
+ mode: z.enum(['replace', 'add', 'reset']).optional().default('replace'),
14
+ }, async ({ surface, mode }) => {
15
+ if (mode !== 'reset' && !surface)
16
+ throw new Error('surface is required when mode is replace or add.');
17
+ if (mode === 'reset') {
18
+ activeSurfaces.clear();
19
+ }
20
+ else if (mode === 'replace') {
21
+ activeSurfaces.clear();
22
+ activeSurfaces.add(surface);
23
+ }
24
+ else {
25
+ activeSurfaces.add(surface);
26
+ if (activeSurfaces.size > MAX_ACTIVE_WORKFLOWS) {
27
+ activeSurfaces.delete(surface);
28
+ throw new Error(`At most ${MAX_ACTIVE_WORKFLOWS} workflow surfaces may be active. Use mode=replace or reset first.`);
29
+ }
30
+ }
31
+ const packTools = [...activeSurfaces].flatMap(workflowToolNames);
32
+ const result = state.setActiveTools(packTools);
33
+ return jsonContent({
34
+ action: 'enfyra_workflow_selected',
35
+ mode,
36
+ dynamic: state.dynamic,
37
+ activeSurfaces: [...activeSurfaces],
38
+ visibleToolCount: result.visibleToolNames.length,
39
+ visibleTools: result.visibleToolNames,
40
+ hiddenToolCount: result.hiddenToolCount,
41
+ changed: result.changed,
42
+ guidance: state.dynamic
43
+ ? [
44
+ 'Refresh tools/list after this response if the host has not already processed notifications/tools/list_changed.',
45
+ 'Call the newly visible workflow tools directly so their exact schemas, annotations, and safety gates remain active.',
46
+ 'Use search_enfyra_tools only for hidden read-only long-tail helpers.',
47
+ ]
48
+ : [
49
+ 'Dynamic packs are disabled for this static profile/toolset; the configured profile remains visible.',
50
+ 'Use ENFYRA_MCP_DYNAMIC_TOOLS=on with guided/all on hosts that support tools/list_changed.',
51
+ ],
52
+ });
53
+ });
54
+ }
55
+ //# sourceMappingURL=workflow-tool-packs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-tool-packs.js","sourceRoot":"","sources":["../../src/lib/workflow-tool-packs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAwB,MAAM,mBAAmB,CAAC;AAG/F,MAAM,oBAAoB,GAAG,CAAC,CAAC;AAE/B,MAAM,UAAU,wBAAwB,CAAC,MAAW,EAAE,KAA+B;IACnF,MAAM,cAAc,GAAG,IAAI,GAAG,EAAmB,CAAC;IAElD,OAAO,MAAM,CAAC,IAAI,CAChB,wBAAwB,EACxB;QACE,yFAAyF;QACzF,wIAAwI;QACxI,6FAA6F;KAC9F,CAAC,IAAI,CAAC,GAAG,CAAC,EACX;QACE,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,sDAAsD,CAAC;QAC9G,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC;KACxE,EACD,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAoE,EAAE,EAAE;QAC5F,IAAI,IAAI,KAAK,OAAO,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;QACtG,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;YACrB,cAAc,CAAC,KAAK,EAAE,CAAC;QACzB,CAAC;aAAM,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YAC9B,cAAc,CAAC,KAAK,EAAE,CAAC;YACvB,cAAc,CAAC,GAAG,CAAC,OAAQ,CAAC,CAAC;QAC/B,CAAC;aAAM,CAAC;YACN,cAAc,CAAC,GAAG,CAAC,OAAQ,CAAC,CAAC;YAC7B,IAAI,cAAc,CAAC,IAAI,GAAG,oBAAoB,EAAE,CAAC;gBAC/C,cAAc,CAAC,MAAM,CAAC,OAAQ,CAAC,CAAC;gBAChC,MAAM,IAAI,KAAK,CAAC,WAAW,oBAAoB,oEAAoE,CAAC,CAAC;YACvH,CAAC;QACH,CAAC;QAED,MAAM,SAAS,GAAG,CAAC,GAAG,cAAc,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;QACjE,MAAM,MAAM,GAAG,KAAK,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;QAC/C,OAAO,WAAW,CAAC;YACjB,MAAM,EAAE,0BAA0B;YAClC,IAAI;YACJ,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,cAAc,EAAE,CAAC,GAAG,cAAc,CAAC;YACnC,gBAAgB,EAAE,MAAM,CAAC,gBAAgB,CAAC,MAAM;YAChD,YAAY,EAAE,MAAM,CAAC,gBAAgB;YACrC,eAAe,EAAE,MAAM,CAAC,eAAe;YACvC,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,QAAQ,EAAE,KAAK,CAAC,OAAO;gBACrB,CAAC,CAAC;oBACE,gHAAgH;oBAChH,qHAAqH;oBACrH,sEAAsE;iBACvE;gBACH,CAAC,CAAC;oBACE,qGAAqG;oBACrG,2FAA2F;iBAC5F;SACN,CAAC,CAAC;IACL,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import { config } from 'dotenv';
5
5
  config();
6
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
6
+ import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
7
7
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
8
8
  import { z } from 'zod';
9
9
  import { createHash } from 'node:crypto';
@@ -68,17 +68,23 @@ import { assertCreateHandlerRouteBoundary } from './lib/dynamic-endpoint-contrac
68
68
  import { assertGenericRecordMutationAllowed, parseRecordBatchData, parseRecordData, prepareRecordBatchMutation, prepareRecordMutation, validatePortableScriptSource, validateScriptSourceIfPresent } from './lib/mutation-guards.js';
69
69
  import { assertDynamicCodeKnowledgeAck, assertDynamicCodeKnowledgeAckIf, assertExtensionKnowledgeAckIf, assertGlobalRulesAck, acknowledgeRequiredKnowledge, buildRequiredKnowledgePayload, dynamicCodeKnowledgeAckParam, extensionKnowledgeAckParam, globalRulesAckParam, } from './lib/required-knowledge.js';
70
70
  import { validateMainTableRoutePath } from './lib/route-guards.js';
71
+ import { buildDeletePostcondition, buildQuerySchemaReceipt } from './lib/record-contracts.js';
71
72
  import { installColumnarToolFormatter, jsonContent } from './lib/response-format.js';
72
73
  import { startMcpUsageTelemetry } from './lib/mcp-usage-telemetry.js';
73
74
  import { startRuntimeCacheSocket } from './lib/runtime-cache-socket.js';
74
75
  import { executeSequentialBatch } from './lib/sequential-batch.js';
75
- import { compactSourceFields, writeSourceArtifact } from './lib/source-artifacts.js';
76
- import { installToolsetFilter, normalizeMcpProfile, normalizeMcpToolset, summarizeToolsetForInstructions } from './lib/toolset-filter.js';
76
+ import { compactSourceFields, readSourceArtifactResource, writeSourceArtifact } from './lib/source-artifacts.js';
77
+ import { installToolsetFilter, normalizeDynamicToolPacks, normalizeMcpProfile, normalizeMcpToolset, summarizeToolsetForInstructions } from './lib/toolset-filter.js';
78
+ import { installToolAnnotations } from './lib/tool-contracts.js';
79
+ import { installToolOutputContracts } from './lib/tool-output-contracts.js';
80
+ import { registerToolCatalogTools } from './lib/tool-catalog.js';
81
+ import { registerWorkflowToolPack } from './lib/workflow-tool-packs.js';
77
82
  import { findRoutePermission, mergeMethodNames, normalizeMethodNames, resolveRoleByNameOrId, routeAvailableMethodNames, routePublicMethodNames, summarizeRouteAccess, summarizeRoutePermission, validateMethodsForRoute, } from './lib/route-permission-tools.js';
78
83
  // Initialize auth module
79
84
  initAuth(ENFYRA_API_URL, ENFYRA_API_TOKEN);
80
85
  const MCP_TOOLSET = normalizeMcpToolset(process.env.ENFYRA_MCP_TOOLSET);
81
86
  const MCP_PROFILE = normalizeMcpProfile(process.env.ENFYRA_MCP_PROFILE);
87
+ const MCP_DYNAMIC_TOOLS = normalizeDynamicToolPacks(process.env.ENFYRA_MCP_DYNAMIC_TOOLS, MCP_TOOLSET, MCP_PROFILE);
82
88
  const CAPABILITY_AREAS = [
83
89
  {
84
90
  area: 'Schema and metadata',
@@ -418,6 +424,30 @@ function summarizePermissionProfile(user) {
418
424
  })),
419
425
  };
420
426
  }
427
+ async function resolveCatalogToolAvailability(toolNames) {
428
+ const fields = DEFAULT_ME_PERMISSION_FIELDS.join(',');
429
+ const result = await fetchAPI(ENFYRA_API_URL, `/me?fields=${encodeURIComponent(fields)}`);
430
+ const user = firstDataRecord(result);
431
+ if (user?.isRootAdmin) {
432
+ return Object.fromEntries(toolNames.map((name) => [name, {
433
+ status: 'allowed',
434
+ reason: 'The configured PAT belongs to a root administrator.',
435
+ }]));
436
+ }
437
+ const requirements = summarizePermissionProfile(user).mcpRequirements;
438
+ return Object.fromEntries(toolNames.map((name) => {
439
+ const requirement = requirements.find((item) => item.tools.includes(name));
440
+ if (!requirement) {
441
+ return [name, {
442
+ status: 'unknown',
443
+ reason: 'No static admin-route capability mapping exists for this tool; Enfyra PAT/RBAC remains authoritative at execution time.',
444
+ }];
445
+ }
446
+ return [name, requirement.allowed
447
+ ? { status: 'allowed', reason: `Current PAT grants ${requirement.methods.map((item) => item.method).join(', ')} ${requirement.route}.` }
448
+ : { status: 'denied', reason: `Current PAT lacks one or more required methods on ${requirement.route}.` }];
449
+ }));
450
+ }
421
451
  function parseJsonArg(value, fallback = undefined) {
422
452
  if (value === undefined || value === null || value === '')
423
453
  return fallback;
@@ -503,10 +533,10 @@ function summarizeMutationResult(result, action, tableName) {
503
533
  async function getTableSummary(tableName) {
504
534
  return summarizeTable(await fetchTableMetadata(ENFYRA_API_URL, tableName));
505
535
  }
506
- async function getPrimaryFieldName(tableName) {
507
- const table = await getTableSummary(tableName);
508
- if (table?.primaryKey)
509
- return table.primaryKey;
536
+ async function getPrimaryFieldName(tableName, table = null) {
537
+ const resolvedTable = table ?? await getTableSummary(tableName);
538
+ if (resolvedTable?.primaryKey)
539
+ return resolvedTable.primaryKey;
510
540
  const metadata = await fetchMetadataContext(ENFYRA_API_URL);
511
541
  return metadata.dbType === 'mongodb' ? '_id' : 'id';
512
542
  }
@@ -810,12 +840,19 @@ const server = new McpServer({
810
840
  version: '1.0.0',
811
841
  }, {
812
842
  instructions: buildMcpServerInstructions(ENFYRA_API_URL, {
813
- toolsetSummary: summarizeToolsetForInstructions(MCP_TOOLSET, MCP_PROFILE),
843
+ toolsetSummary: summarizeToolsetForInstructions(MCP_TOOLSET, MCP_PROFILE, MCP_DYNAMIC_TOOLS),
814
844
  }),
815
845
  });
846
+ installToolOutputContracts(server);
816
847
  installColumnarToolFormatter(server);
817
- installToolsetFilter(server, MCP_TOOLSET, MCP_PROFILE);
848
+ const toolsetState = installToolsetFilter(server, MCP_TOOLSET, MCP_PROFILE, { dynamic: MCP_DYNAMIC_TOOLS });
849
+ installToolAnnotations(server);
818
850
  startMcpUsageTelemetry(ENFYRA_API_URL, `${MCP_TOOLSET}:${MCP_PROFILE}`);
851
+ server.registerResource('enfyra-source-artifact', new ResourceTemplate('enfyra-source://artifact/{artifactId}', { list: undefined }), {
852
+ title: 'Enfyra source artifact',
853
+ description: 'Process-scoped source or diff artifact created by an Enfyra MCP inspect or preview tool.',
854
+ mimeType: 'text/plain',
855
+ }, async (uri) => ({ contents: [readSourceArtifactResource(uri.href)] }));
819
856
  // ============================================================================
820
857
  // METADATA TOOLS
821
858
  // ============================================================================
@@ -904,7 +941,7 @@ server.tool('discover_enfyra_workflows', [
904
941
  risk: z.string().optional().default('unknown').describe('Highest expected operation risk. Preferred values: read, write, destructive, debug, unknown. Natural terms such as low, medium, or high are accepted and normalized.'),
905
942
  detail: z.enum(['summary', 'plan', 'full']).optional().default('summary').describe('summary lists candidate workflows; plan adds tool sequence and avoidTools; full also includes matching keywords.'),
906
943
  limit: z.number().int().positive().max(10).optional().default(5).describe('Maximum workflows to return.'),
907
- }, async (input) => jsonContent(discoverWorkflowRoutes(input, MCP_PROFILE)));
944
+ }, async (input) => jsonContent(discoverWorkflowRoutes(input, MCP_PROFILE, MCP_DYNAMIC_TOOLS)));
908
945
  server.tool('discover_enfyra_system', [
909
946
  'Call this first when you need to understand the live Enfyra instance.',
910
947
  'Returns a concise capability map from live metadata/routes/method rows, including schema management, REST route behavior, GraphQL enablement, and relation handling.',
@@ -1344,7 +1381,7 @@ server.tool('get_enfyra_api_context', [
1344
1381
  };
1345
1382
  return jsonContent(payload);
1346
1383
  });
1347
- server.tool('query_table', 'Query any route-backed table. Response is minimal unless fields is explicit. Every call must pass either limit or all=true. Use count_records or meta=filterCount/totalCount for counts; call discover_query_capabilities before using aggregate objects instead of guessing _sum/_count operators. For enfyra_extension, editable extension source is `code`, not `sourceCode`; prefer search_admin_extensions and patch_extension_code/update_extension_code for admin UI.', {
1384
+ server.tool('query_table', 'Query any route-backed table with a live metadata preflight. Explicit fields are validated before the REST read and the result includes schemaReceipt, so a separate metadata call is optional unless the schema itself must be inspected. Response is minimal unless fields is explicit. Every call must pass either limit or all=true. Use count_records or meta=filterCount/totalCount for counts; call discover_query_capabilities before using aggregate objects instead of guessing _sum/_count operators. For enfyra_extension, editable extension source is `code`, not `sourceCode`; prefer search_admin_extensions and patch_extension_code/update_extension_code for admin UI.', {
1348
1385
  tableName: z.string().describe('Table name to query'),
1349
1386
  filter: jsonObjectParam(z, 'Filter object').optional().describe('Filter object. Example: {"status": {"_eq": "active"}}.'),
1350
1387
  sort: z.string().optional().describe('Sort field. Prefix with - for descending (e.g., "createdAt", "-id")'),
@@ -1371,9 +1408,12 @@ server.tool('query_table', 'Query any route-backed table. Response is minimal un
1371
1408
  parseJsonArg(deep, undefined);
1372
1409
  parseJsonArg(aggregate, undefined);
1373
1410
  const queryParams = new URLSearchParams();
1374
- const requestedFields = fields && fields.length > 0 ? fields : [await getPrimaryFieldName(tableName)];
1411
+ const table = await getTableSummary(tableName);
1412
+ const primaryKey = await getPrimaryFieldName(tableName, table);
1413
+ const requestedFields = fields && fields.length > 0 ? fields : [primaryKey];
1375
1414
  const deepFieldSelection = applyDeepFieldSelections(requestedFields, deep);
1376
1415
  const selectedFields = deepFieldSelection.fields;
1416
+ const schemaReceipt = buildQuerySchemaReceipt({ ...table, primaryKey }, selectedFields);
1377
1417
  if (filterParam)
1378
1418
  queryParams.set('filter', filterParam);
1379
1419
  const normalizedSort = normalizeSortParam(sort);
@@ -1407,6 +1447,7 @@ server.tool('query_table', 'Query any route-backed table. Response is minimal un
1407
1447
  aggregate: aggregate ? parseJsonArg(aggregate, null) : null,
1408
1448
  },
1409
1449
  minimalDefaultApplied: !(fields && fields.length > 0),
1450
+ schemaReceipt,
1410
1451
  meta: result?.meta,
1411
1452
  data: compactSourceFields(result?.data || [], { tableName }),
1412
1453
  detailHint: fields && fields.length > 0
@@ -1753,7 +1794,7 @@ function isNotFoundDeleteError(error) {
1753
1794
  || message.includes('not exists')
1754
1795
  || message.includes('does not exist');
1755
1796
  }
1756
- server.tool('delete_records', 'Delete one or more route-backed records in one MCP call. Pass items as a native JSON array; for one delete, pass one item. The tool previews every target when confirm=false, rejects duplicate ids, and deletes sequentially when confirm=true. By default, confirm=true skips records that were already removed by cascade or a previous cleanup step.', {
1797
+ server.tool('delete_records', 'Delete one or more route-backed records in one MCP call. Pass items as a native JSON array; for one delete, pass one item. The tool previews every target when confirm=false, rejects duplicate ids, and deletes sequentially when confirm=true. Confirmed deletes automatically re-read the requested primary keys and return postcondition.confirmedAbsent plus remainingIds, so a separate absence query is optional. By default, confirm=true skips records that were already removed by cascade or a previous cleanup step.', {
1757
1798
  tableName: z.string().describe('Table name'),
1758
1799
  items: bulkObjectArrayParam(z, 'Delete items').describe('Native JSON array of delete items: [{ "id": "...", "queryParams": { ... }? }].'),
1759
1800
  maxItems: z.number().int().min(1).max(100).optional().default(100).describe('Safety cap for one MCP batch. Default/max is 100.'),
@@ -1795,6 +1836,12 @@ server.tool('delete_records', 'Delete one or more route-backed records in one MC
1795
1836
  duplicateIdsRejected: true,
1796
1837
  destructive: true,
1797
1838
  previews,
1839
+ postcondition: {
1840
+ verificationMethod: 'not_run_preview',
1841
+ requestedIds: parsedItems.map((item) => item.id),
1842
+ remainingIds: previews.filter((item) => item.preview).map((item) => item.id),
1843
+ confirmedAbsent: false,
1844
+ },
1798
1845
  next: 'Call delete_records again with the same items and confirm=true to delete these route-backed records sequentially.',
1799
1846
  }, null, 2) }] };
1800
1847
  }
@@ -1825,6 +1872,26 @@ server.tool('delete_records', 'Delete one or more route-backed records in one MC
1825
1872
  throw error;
1826
1873
  }
1827
1874
  }
1875
+ const requestedIds = parsedItems.map((item) => item.id);
1876
+ let postcondition;
1877
+ try {
1878
+ const verificationQuery = new URLSearchParams({
1879
+ filter: JSON.stringify({ [primaryKey]: { _in: requestedIds } }),
1880
+ limit: String(parsedItems.length),
1881
+ fields: primaryKey,
1882
+ });
1883
+ const verification = await fetchAPI(ENFYRA_API_URL, `/${tableName}?${verificationQuery.toString()}`);
1884
+ postcondition = buildDeletePostcondition(requestedIds, verification?.data ?? [], primaryKey);
1885
+ }
1886
+ catch (error) {
1887
+ postcondition = {
1888
+ verificationMethod: 'route_read_by_primary_keys',
1889
+ requestedIds,
1890
+ remainingIds: [],
1891
+ confirmedAbsent: false,
1892
+ verificationError: String(error?.message || error),
1893
+ };
1894
+ }
1828
1895
  return { content: [{ type: 'text', text: JSON.stringify({
1829
1896
  action: 'deleted_records',
1830
1897
  tableName,
@@ -1836,6 +1903,7 @@ server.tool('delete_records', 'Delete one or more route-backed records in one MC
1836
1903
  skipNotFound,
1837
1904
  deleted,
1838
1905
  skippedNotFound,
1906
+ postcondition,
1839
1907
  }, null, 2) }] };
1840
1908
  });
1841
1909
  server.tool('list_methods', 'List enfyra_method records with their UI colors. Use this before creating route methods or method-colored UI.', {}, async () => {
@@ -3150,6 +3218,10 @@ server.tool('install_package', [
3150
3218
  result,
3151
3219
  });
3152
3220
  });
3221
+ registerToolCatalogTools(server, toolsetState, {
3222
+ resolveAvailability: resolveCatalogToolAvailability,
3223
+ });
3224
+ registerWorkflowToolPack(server, toolsetState);
3153
3225
  // ============================================================================
3154
3226
  // MAIN
3155
3227
  // ============================================================================