@sassoftware/sas-score-mcp-serverjs 0.4.1 → 1.0.1-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.
Files changed (72) hide show
  1. package/.skills/agents/sas-viya-scoring-expert.md +58 -0
  2. package/.skills/copilot-instructions.md +155 -0
  3. package/.skills/skills/sas-find-library-smart/SKILL.md +154 -0
  4. package/.skills/skills/sas-list-tables-smart/SKILL.md +127 -0
  5. package/.skills/skills/sas-read-and-score/SKILL.md +111 -0
  6. package/.skills/skills/sas-read-strategy/SKILL.md +156 -0
  7. package/.skills/skills/sas-request-classifier/SKILL.md +69 -0
  8. package/.skills/skills/sas-score-workflow/SKILL.md +314 -0
  9. package/cli.js +311 -70
  10. package/package.json +7 -7
  11. package/scripts/docs/SCORE_SKILL_REFERENCE.md +142 -0
  12. package/scripts/docs/TOOL_DESCRIPTION_TEMPLATE.md +157 -0
  13. package/scripts/docs/TOOL_UPDATES_SUMMARY.md +208 -0
  14. package/scripts/docs/mcp-localhost-config-guide.md +184 -0
  15. package/scripts/docs/oauth-http-transport.md +96 -0
  16. package/scripts/docs/sas-mcp-tools-reference.md +600 -0
  17. package/scripts/getViyaca.sh +1 -0
  18. package/scripts/optimize_final.py +140 -0
  19. package/scripts/optimize_tools.py +99 -0
  20. package/scripts/setup-skills.js +34 -0
  21. package/scripts/update_descriptions.py +46 -0
  22. package/scripts/viyatls.sh +3 -0
  23. package/src/authpkce.js +219 -0
  24. package/src/createMcpServer.js +16 -5
  25. package/src/expressMcpServer.js +350 -308
  26. package/src/handleGetDelete.js +6 -3
  27. package/src/hapiMcpServer.js +10 -18
  28. package/src/oauthHandlers/authorize.js +46 -0
  29. package/src/oauthHandlers/baseUrl.js +8 -0
  30. package/src/oauthHandlers/callback.js +96 -0
  31. package/src/oauthHandlers/getMetadata.js +27 -0
  32. package/src/oauthHandlers/index.js +7 -0
  33. package/src/oauthHandlers/token.js +37 -0
  34. package/src/processHeaders.js +88 -0
  35. package/src/setupSkills.js +46 -0
  36. package/src/toolHelpers/_jobSubmit.js +2 -0
  37. package/src/toolHelpers/_listLibrary.js +55 -39
  38. package/src/toolHelpers/getLogonPayload.js +7 -1
  39. package/src/toolHelpers/readCerts.js +4 -4
  40. package/src/toolHelpers/refreshToken.js +3 -2
  41. package/src/toolHelpers/refreshTokenOauth.js +3 -3
  42. package/src/toolSet/.claude/settings.local.json +13 -0
  43. package/src/toolSet/devaScore.js +61 -69
  44. package/src/toolSet/findJob.js +38 -71
  45. package/src/toolSet/findJobdef.js +28 -59
  46. package/src/toolSet/findLibrary.js +68 -100
  47. package/src/toolSet/findModel.js +35 -58
  48. package/src/toolSet/findTable.js +31 -60
  49. package/src/toolSet/getEnv.js +30 -45
  50. package/src/toolSet/listJobdefs.js +61 -96
  51. package/src/toolSet/listJobs.js +61 -110
  52. package/src/toolSet/listLibraries.js +78 -90
  53. package/src/toolSet/listModels.js +56 -83
  54. package/src/toolSet/listTables.js +66 -95
  55. package/src/toolSet/makeTools.js +1 -0
  56. package/src/toolSet/modelInfo.js +22 -54
  57. package/src/toolSet/modelScore.js +35 -77
  58. package/src/toolSet/readTable.js +63 -104
  59. package/src/toolSet/runCasProgram.js +32 -52
  60. package/src/toolSet/runJob.js +24 -24
  61. package/src/toolSet/runJobdef.js +26 -29
  62. package/src/toolSet/runMacro.js +82 -82
  63. package/src/toolSet/runProgram.js +32 -84
  64. package/src/toolSet/sasQuery.js +77 -126
  65. package/src/toolSet/sasQueryTemplate.js +4 -5
  66. package/src/toolSet/sasQueryTemplate2.js +4 -5
  67. package/src/toolSet/scrInfo.js +4 -7
  68. package/src/toolSet/scrScore.js +69 -70
  69. package/src/toolSet/searchAssets.js +5 -6
  70. package/src/toolSet/setContext.js +65 -92
  71. package/src/toolSet/superstat.js +61 -60
  72. package/src/toolSet/tableInfo.js +58 -102
@@ -9,69 +9,45 @@ import _listModels from '../toolHelpers/_listModels.js';
9
9
 
10
10
  function findModel(_appContext) {
11
11
  let description = `
12
- ## find-model — locate a specific model deployed to MAS (Model Publish / Scoring service)
13
-
14
- LLM Invocation Guidance (When to use)
15
- Use THIS tool when the user wants to know whether ONE model exists or is deployed:
16
- - "find model cancerRisk"
17
- - "does model churn_tree exist"
18
- - "is model sales_forecast deployed"
19
- - "lookup model claimFraud"
20
- - "verify model credit_score_v2 exists"
21
-
22
- Do NOT use this tool for:
23
- - Listing many / browsing models (use list-models)
24
- - Retrieving detailed input/output variable metadata (use model-info)
25
- - Scoring or running a model (use model-score)
26
- - Searching model execution containers or SCR endpoints (use scr-info / scr-score if appropriate)
27
- - Finding a table (use find-table)
28
- - Finding a library (use find-library)
29
- - Finding a job or jobdef (use find-job / find-jobdef)
30
-
31
- Purpose
32
- Quick existence / lookup check for a MAS‑published model. Returns a list with zero or more matches (typically 0 or 1 for an exact name).
33
-
34
- Parameters
35
- - name (string, required): Exact model name. If user supplies phrases like "model named X" extract X. If multiple names are given (comma or space separated), prefer the first and (optionally) ask for a single name.
36
-
37
- Matching Rules
38
- - Attempt exact match first. If backend supports partial search, a substring match MAY return multiple models; preserve order.
39
- - Do not fabricate models. Empty array means not found.
40
-
41
- Response Contract
42
- - Always: { models: Array<object|string> }
43
- - Never return prose when invoked programmatically; only the JSON structure.
44
- - On error: surface backend error object directly (no rewriting) so the caller can display/log it.
45
-
46
- Disambiguation & Clarification
47
- - Missing name (e.g., "find model") → ask: "Which model name would you like to find?"
48
- - Plural intent (e.g., "find models" / "list models") → use list-models instead.
49
- - If user requests scoring ("score model X") → route to model-score not find-model.
50
-
51
- Examples (→ mapped params)
52
- - "find model myModel" → { name: "myModel" }
53
- - "does model churn_score exist" → { name: "churn_score" }
54
- - "is model riskModel deployed" → { name: "riskModel" }
55
- - "lookup model claims_fraud_v1" → { name: "claims_fraud_v1" }
56
-
57
- Negative Examples (should NOT call find-model)
58
- - "list models" (list-models)
59
- - "score model myModel" (model-score)
60
- - "describe model myModel" (model-info)
61
-
62
- Notes
63
- - Chain usage: find-model → model-info → model-score.
64
- - For batch existence checks iterate over a list and call find-model per entry.
12
+ find-model — locate a specific MAS model deployed to MAS server
13
+
14
+ USE when: find model, does model exist, is model deployed, lookup model, verify model exists
15
+ DO NOT USE for: list models (use list-models), model info/variables (use model-info), score model (use model-score), find table/job/lib (use respective tools), scr models (use scr-info/scr-score)
16
+
17
+ PARAMETERS
18
+ - name: string (required) — model name to locate; if multiple supplied, use first
19
+
20
+ ROUTING RULES
21
+ - "find model <name>" → { name: "<name>" }
22
+ - "does model <name> exist" → { name: "<name>" }
23
+ - "is model <name> deployed" { name: "<name>" }
24
+ - "lookup/verify model <name>" { name: "<name>" }
25
+ - "find model" with no name → ask "Which model name would you like to find?"
26
+ - "find all models / list models" use list-models instead
27
+ - "score model <name>" use model-score instead
28
+ - "describe model / model info" → use model-info instead
29
+
30
+ EXAMPLES
31
+ - "find model myModel" → { name: "myModel" }
32
+ - "does model churn_score exist" { name: "churn_score" }
33
+ - "is model riskModel deployed" → { name: "riskModel" }
34
+ - "lookup model claims_fraud_v1" → { name: "claims_fraud_v1" }
35
+
36
+ NEGATIVE EXAMPLES (do not route here)
37
+ - "list models" (use list-models)
38
+ - "score model myModel" (use model-score)
39
+ - "model info for churnRisk" (use model-info)
40
+
41
+ ERRORS
42
+ Returns { models: [] } if not found; { models: [name, ...] } if found. Never hallucinate model names.
65
43
  `;
66
44
 
67
45
  let spec = {
68
46
  name: 'find-model',
69
- aliases: ['findModel','find model','find_model'],
70
47
  description: description,
71
- schema: {
72
- 'name': z.string()
73
- },
74
- required: ['name'],
48
+ inputSchema: z.object({
49
+ name: z.string()
50
+ }),
75
51
  handler: async (params) => {
76
52
  let r = await _listModels(params);
77
53
  return r;
@@ -81,3 +57,4 @@ function findModel(_appContext) {
81
57
  }
82
58
 
83
59
  export default findModel;
60
+
@@ -9,79 +9,49 @@ import _listTables from '../toolHelpers/_listTables.js';
9
9
 
10
10
  function findTable(_appContext) {
11
11
  let description = `
12
- ## find-table — locate a specific table in a CAS or SAS library
12
+ find-table — locate a specific table in a CAS or SAS library.
13
13
 
14
- LLM Invocation Guidance (When to use)
15
- Use THIS tool when the user wants to find or verify a table in a specific library:
16
- - "find table iris in Public library in cas"
17
- - "find table cars in sashelp in sas server"
18
- - "does table customers exist in mylib?"
19
- - "is there a table named sales in the Samples library?"
20
- - "verify table orders exists in Public"
14
+ USE when: find table, does table exist, is table in library, verify table exists, locate table
15
+ DO NOT USE for: list tables (use list-tables), table schema/columns (use table-info), read table data (use read-table), find lib/job/model (use respective tools)
21
16
 
22
- Do NOT use this tool when the user wants:
23
- - find lib -> use find-library
24
- - find model -> use find-model
25
- - find job -> use find-job
26
- - find jobdef -> use find-jobdef
27
- - Columns or schema of a table (use table-info)
28
- - Reading data from a table (use read-table)
29
- - Listing all tables in a library (use list-tables)
17
+ PARAMETERS
18
+ - lib: string (required) library name (e.g., 'Public', 'sashelp')
19
+ - name: string (required) table name to locate
20
+ - server: 'cas' | 'sas' . If not specified set it to 'cas' — target environment
30
21
 
31
- Purpose
32
- Locate a table contained in a specified library (caslib or libref) on a CAS or SAS server. Returns matching table names or empty array if not found.
22
+ ROUTING RULES
23
+ - "find table <name> in <lib>" { lib: "<lib>", name: "<name>", server: "cas" }
24
+ - "find table <name> in <lib> in sas" → { lib: "<lib>", name: "<name>", server: "sas" }
25
+ - "does table <name> exist in <lib>" → { lib: "<lib>", name: "<name>", server: "cas" }
26
+ - "find table" with missing lib → ask "Which library contains the table?"
27
+ - "find table" with missing name → ask "Which table name would you like to find?"
28
+ - "list tables in <lib>" → use list-tables instead
33
29
 
34
- Parameters
35
- - lib (string, required): The library to search in (e.g., 'Public', 'sashelp', or a caslib name)
36
- - name (string, required): Table name or substring to search for. Matching is case-insensitive.
37
- - server (string, default 'cas'): Either 'cas' or 'sas'. Defaults to 'cas' when omitted.
38
-
39
- Response Contract
40
- Returns a JSON object with:
41
- - tables: Array of matching table names (strings)
42
- - Empty array { tables: [] } when no matches found
43
- - Do not fabricate table names; only return actual matches
44
-
45
- Disambiguation & Clarification
46
- - Missing library: ask "Which library do you want to search in?"
47
- - Missing table name: ask "Which table name would you like to find?"
48
- - Server ambiguous: ask "Do you mean CAS or SAS?"
49
- - If user wants multiple tables: suggest "Use list-tables to see all tables in a library"
50
-
51
- Examples (→ mapped params)
52
- - "find table iris in Public library in cas" → { lib: "Public", name: "iris", server: "cas" }
53
- - "find table cars in sashelp in sas server" → { lib: "sashelp", name: "cars", server: "sas" }
30
+ EXAMPLES
31
+ - "find table iris in Public" { lib: "Public", name: "iris", server: "cas" }
32
+ - "find table cars in sashelp in sas" { lib: "sashelp", name: "cars", server: "sas" }
54
33
  - "does customers exist in mylib" → { lib: "mylib", name: "customers", server: "cas" }
55
34
  - "verify table orders in Samples" → { lib: "Samples", name: "orders", server: "cas" }
56
35
 
57
- Negative Examples (should NOT call find-table)
58
- - "list tables in Public" (use list-tables instead)
59
- - "find library Public" (use find-library instead)
60
- - "what columns in cars table?" (use table-info instead)
61
- - "read data from customers" (use read-table instead)
36
+ NEGATIVE EXAMPLES (do not route here)
37
+ - "list tables in Public" (use list-tables)
38
+ - "find library Public" (use find-library)
39
+ - "what columns in cars?" (use table-info)
40
+ - "read data from customers" (use read-table)
62
41
 
63
- Usage Tips
64
- - Use this tool to verify table existence before reading or querying
65
- - For discovery of multiple tables, use list-tables instead
66
- - After finding a table, use table-info for schema or read-table for data
67
-
68
- Related Tools
69
- - find-table → table-info → read-table (typical workflow)
70
- - list-tables — to discover all tables in a library
71
- - find-library — to verify library exists
72
- - table-info — to inspect table structure after finding it
73
- `;
42
+ ERRORS
43
+ Returns { tables: [] } if not found; { tables: [name, ...] } if found. Never hallucinate table names.
44
+ `;
74
45
 
75
46
  let spec = {
76
47
  name: 'find-table',
77
- aliases: ['findTable','find table','find_table'],
78
48
  description: description,
79
- schema: {
80
- server: z.string().default('cas'), // default server is 'cas',
49
+ inputSchema: z.object({
50
+ lib: z.string(),
81
51
  name: z.string(),
82
- lib: z.string()
83
- },
84
- required: ['name', 'lib'],
52
+ server: z.string()
53
+ }),
54
+
85
55
  handler: async (params) => {
86
56
  // Check if the params.scenario is a string and parse it
87
57
  let r = await _listTables(params);
@@ -92,3 +62,4 @@ Related Tools
92
62
  }
93
63
 
94
64
  export default findTable;
65
+
@@ -7,66 +7,51 @@ import {z} from 'zod';
7
7
  import _getEnv from '../toolHelpers/_getEnv.js';
8
8
  function getEnv(_appContext) {
9
9
  let description = `
10
- ## get-env — retrieve a variable value from the runtime environment
10
+ get-env — retrieve a variable value from the runtime environment.
11
11
 
12
- LLM Invocation Guidance (When to use)
13
- Use THIS tool when:
14
- - The user wants to access a specific environment variable or context value
15
- - "What is the value of [variable name]?"
16
- - "Get me the [variable] value"
17
- - "Show the current [variable]"
12
+ USE when: what is the value of, get me, show current, what's the, retrieve environment variable
13
+ DO NOT USE for: read table data (use read-table), model info (use model-info), find/run job (use find-job/run-job), set context (use set-context)
18
14
 
19
- Do NOT use this tool for:
20
- - Retrieving table data (use read-table)
21
- - Getting model information (use model-info)
22
- - Looking up job status (use find-job or run-job)
23
- - Setting environment variables (use set-context to set CAS/SAS contexts)
15
+ PARAMETERS
16
+ - name: string (required) — variable name to retrieve (case-sensitive)
24
17
 
25
- Purpose
26
- Retrieve the current value of a named variable from the runtime environment. This is useful for debugging, accessing context information, or verifying current configuration values.
18
+ ROUTING RULES
19
+ - "what is the value of <var>" { name: "<var>" }
20
+ - "get me <var>" → { name: "<var>" }
21
+ - "show <var>" → { name: "<var>" }
22
+ - "get" with no variable → ask "Which variable would you like to retrieve?"
23
+ - "what context am I using" → use set-context instead (no params)
24
+ - "set <var> to <value>" → use set-context or run-sas-program instead
27
25
 
28
- Parameters
29
- - name (string, required): The name of the variable to retrieve. Variable names are case-sensitive.
30
-
31
- Response Contract
32
- Returns a JSON object containing:
33
- - The requested variable name as a key
34
- - The current value of that variable
35
- - If the variable does not exist, returns null or an error message
36
-
37
- Disambiguation & Clarification
38
- - If variable name is missing: ask "Which variable would you like to retrieve?"
39
- - If user says "context" without specifying which variable: clarify "Do you mean the CAS context, SAS context, or a specific variable?"
40
- - Multiple variable request: handle one at a time or ask for clarification
41
-
42
- Examples (→ mapped params)
26
+ EXAMPLES
43
27
  - "What's the value of myVar" → { name: "myVar" }
44
28
  - "Get me the configuration variable" → { name: "configuration" }
45
29
  - "Show the current server setting" → { name: "server" }
46
30
 
47
- Negative Examples (should NOT call get-env)
48
- - "Read all rows from the customers table" (use read-table instead)
49
- - "Get model details for myModel" (use model-info instead)
50
- - "Set the CAS server to finance-prod" (use set-context instead)
31
+ NEGATIVE EXAMPLES (do not route here)
32
+ - "Read rows from customers" (use read-table)
33
+ - "Get model details for myModel" (use model-info)
34
+ - "Set the CAS server to finance-prod" (use set-context)
51
35
 
52
- Related Tools
53
- - setContext to set environment context values (CAS and SAS servers)
54
- - readTable — to retrieve table data
55
- - modelInfo — to retrieve model metadata
56
- `;
36
+ ERRORS
37
+ Returns variable name with current value, or null if not found. Return structured error with message field.
38
+ `;
57
39
 
58
40
  let spec = {
59
- name: 'get-env',
60
- aliases: ['get-env','get env','get environment'],
61
- description: description,
62
- schema: {
63
- name: z.string()
41
+ name: 'get-env',
42
+ description: description,
43
+ inputSchema: {
44
+ type: 'object',
45
+ properties: {
46
+ name: { type: 'string' }
47
+ },
48
+ required: ['name']
64
49
  },
65
-
66
- handler: async (params) => {
50
+ handler: async (params) => {
67
51
  return await _getEnv(params);
68
52
  }
69
53
  }
70
54
  return spec;
71
55
  }
72
56
  export default getEnv;
57
+
@@ -1,96 +1,61 @@
1
- /*
2
- * Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
3
- * SPDX-License-Identifier: Apache-2.0
4
- */
5
- import { z } from 'zod';
6
- import _listJobdefs from '../toolHelpers/_listJobdefs.js';
7
- function listJobdefs(_appContext) {
8
-
9
- let description = `
10
- ## list-jobdefs — enumerate SAS Viya job definitions assets(jobdefs)
11
-
12
- LLM Invocation Guidance (When to use)
13
- jobdef and jobdefs are used interchangeably here to refer to job definitions.
14
- Use THIS tool when the user wants to browse or list many job definitions assets
15
- - "list jobdefs"
16
- - "show jobdefs"
17
- - "list available jobdefs"
18
- - "browse jobdefs"
19
- - "next jobdefs" (after a previous page)
20
- - "list 25 jobdefs" / "list jobdefs limit 25"
21
- Do NOT use this tool for:
22
- - Checking existence of ONE job (use find-job)
23
- - Executing/running a job (use run-job)
24
- - Running a job definition (use run-jobdef)
25
- - Submitting SAS code (use run-sas-program)
26
-
27
-
28
- Purpose
29
- Page through jobdef assets deployed/registered in SAS Viya.
30
-
31
- Parameters
32
- - limit (number, default 10): Number of jobs to return.
33
- - start (number, default 1): 1-based offset for paging.
34
- - where (string, optional): Filter expression (future use / passthrough; empty string by default). If unsupported, it may be ignored gracefully.
35
-
36
- Response Contract
37
- - Returns an array of jobdef names or objects (backend-dependent) inside structuredContent.
38
- - If items.length === limit, caller may request next page using start + limit.
39
- - Provide optional hint start = start + limit when page might continue.
40
-
41
- Pagination Examples
42
- - First page: { start:1, limit:10 }
43
- - Next page: { start:11, limit:10 }
44
-
45
- Disambiguation & Clarification
46
- - Input only "list" → ask: "Specify asset to list? (Say 'Please specify what to listlist' to proceed)" unless prior context indicates job definition listing.
47
- - Input contains "run"/"execute" plus job name → route to job/jobdef.
48
-
49
- Negative Examples (should NOT call list-jobdefs)
50
- - "list libraries" (use list-libraries)
51
- - "list tables" (use list-tables)
52
- - "list models" (use list-models)
53
- - "list jobs" (use list-jobs)
54
- - "find job abc" (findJob)
55
- - "run job abc" (job)
56
- - "job abc" (job)
57
- - "find model xyz" (findModel)
58
- - "list models" (listModels)
59
- - "list tables in lib xyz" (listTables)
60
- - "show me libraries" (listLibraries)
61
- - "describe job abc" (findJob then possibly job for execution)
62
-
63
- Error Handling
64
- - On backend error: surface structured error payload (do not fabricate job names).
65
- - Empty page (items.length === 0) with start > 1 may mean caller paged past end.
66
-
67
- Usage Tips
68
- - Increase limit for fewer round trips; keep reasonable to avoid large payloads.
69
- - Combine with findJobdeffor confirmation before execution.
70
-
71
- Examples (→ mapped params)
72
- - "list jobdefs" → { start:1, limit:10 }
73
- - "list 25 jobdefs" → { start:1, limit:25 }
74
- - "next jobdefs" (after prior {start:1,limit:10}) → { start:11, limit:10 }
75
- `;
76
-
77
- let spec = {
78
- name: 'list-jobdefs',
79
- aliases: ['listJobdefs','list jobdefs','list_jobdefs'],
80
- description: description,
81
- schema: {
82
- limit: z.number().default(10),
83
- start: z.number().default(1),
84
- where: z.string().default('')
85
- },
86
- // No 'server' required; backend context is implicit in helper
87
- required: [],
88
- handler: async (params) => {
89
- // _listJobdefs handles all validation and defaults
90
- const result = await _listJobdefs(params);
91
- return result;
92
- }
93
- }
94
- return spec;
95
- }
96
- export default listJobdefs;
1
+ /*
2
+ * Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ import { z } from 'zod';
6
+ import _listJobdefs from '../toolHelpers/_listJobdefs.js';
7
+ function listJobdefs(_appContext) {
8
+
9
+ let description = `
10
+ list-jobdefs — enumerate SAS Viya job definitions (jobdefs) assets.
11
+
12
+ USE when: list jobdefs, show jobdefs, browse jobdefs, list available jobdefs, next page
13
+ DO NOT USE for: find single jobdef (use find-jobdef), execute jobdef (use run-jobdef), find job (use find-job), sas code (use run-sas-program)
14
+
15
+ PARAMETERS
16
+ - limit: number (default: 10) — number of jobdefs per page
17
+ - start: number (default: 1) — 1-based page offset
18
+ - where: string (default: '') — optional filter expression
19
+
20
+ ROUTING RULES
21
+ - list jobdefs { start: 1, limit: 10 }
22
+ - show me 25 jobdefs { start: 1, limit: 25 }
23
+ - next jobdefs { start: previousStart + previousLimit, limit: previousLimit }
24
+
25
+ EXAMPLES
26
+ - list jobdefs → { start: 1, limit: 10 }
27
+ - list 25 jobdefs → { start: 1, limit: 25 }
28
+ - next jobdefs → { start: 11, limit: 10 }
29
+
30
+ NEGATIVE EXAMPLES (do not route here)
31
+ - find jobdef abc (use find-jobdef)
32
+ - list jobs (use list-jobs)
33
+ - run jobdef abc (use run-jobdef)
34
+ - list models (use list-models)
35
+
36
+ PAGINATION
37
+ If returned length === limit, hint: next start = start + limit. Empty result with start > 1 means paged past end.
38
+
39
+ ERRORS
40
+ Surface backend error directly; never fabricate jobdef names.
41
+ `;
42
+
43
+ let spec = {
44
+ name: 'list-jobdefs',
45
+ description: description,
46
+ inputSchema: z.object({
47
+ limit: z.number().optional(),
48
+ start: z.number().optional(),
49
+ where: z.string().optional()
50
+ }),
51
+ // No 'server' required; backend context is implicit in helper
52
+ handler: async (params) => {
53
+ // _listJobdefs handles all validation and defaults
54
+ const result = await _listJobdefs(params);
55
+ return result;
56
+ }
57
+ }
58
+ return spec;
59
+ }
60
+ export default listJobdefs;
61
+