@sassoftware/sas-score-mcp-serverjs 0.4.0 → 0.4.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/cli.js +9 -127
- package/package.json +2 -3
- package/src/createMcpServer.js +0 -1
- package/src/expressMcpServer.js +27 -53
- package/src/handleGetDelete.js +3 -6
- package/src/hapiMcpServer.js +18 -10
- package/src/toolHelpers/_jobSubmit.js +0 -2
- package/src/toolHelpers/_listLibrary.js +39 -56
- package/src/toolHelpers/getLogonPayload.js +1 -3
- package/src/toolSet/devaScore.js +36 -28
- package/src/toolSet/findJob.js +49 -23
- package/src/toolSet/findJobdef.js +54 -24
- package/src/toolSet/findLibrary.js +57 -25
- package/src/toolSet/findModel.js +53 -31
- package/src/toolSet/findTable.js +54 -25
- package/src/toolSet/getEnv.js +38 -20
- package/src/toolSet/listJobdefs.js +58 -24
- package/src/toolSet/listJobs.js +72 -24
- package/src/toolSet/listLibraries.js +47 -37
- package/src/toolSet/listModels.js +47 -20
- package/src/toolSet/listTables.js +58 -29
- package/src/toolSet/makeTools.js +0 -3
- package/src/toolSet/modelInfo.js +49 -18
- package/src/toolSet/modelScore.js +69 -27
- package/src/toolSet/readTable.js +62 -25
- package/src/toolSet/runCasProgram.js +43 -23
- package/src/toolSet/runJob.js +19 -20
- package/src/toolSet/runJobdef.js +23 -21
- package/src/toolSet/runMacro.js +20 -20
- package/src/toolSet/runProgram.js +71 -24
- package/src/toolSet/sasQuery.js +70 -23
- package/src/toolSet/scrInfo.js +4 -3
- package/src/toolSet/setContext.js +48 -22
- package/src/toolSet/tableInfo.js +71 -28
- package/skills/mcp-tool-description-optimizer/SKILL.md +0 -129
- package/skills/mcp-tool-description-optimizer/references/examples.md +0 -123
- package/skills/sas-read-and-score/SKILL.md +0 -91
- package/skills/sas-read-strategy/SKILL.md +0 -143
- package/skills/sas-score-workflow/SKILL.md +0 -282
package/src/toolSet/sasQuery.js
CHANGED
|
@@ -5,38 +5,85 @@
|
|
|
5
5
|
import {z} from 'zod';
|
|
6
6
|
import _jobSubmit from '../toolHelpers/_jobSubmit.js';
|
|
7
7
|
|
|
8
|
+
|
|
8
9
|
function sasQuery() {
|
|
9
10
|
|
|
10
11
|
let description = `
|
|
11
|
-
sas-query — convert natural language questions into SQL queries and execute them
|
|
12
|
+
## sas-query — convert natural language questions into SQL queries and execute them
|
|
13
|
+
|
|
14
|
+
LLM Invocation Guidance (When to use)
|
|
15
|
+
Use THIS tool when:
|
|
16
|
+
- User asks a natural language question about table data: "how many customers by region?"
|
|
17
|
+
- User wants aggregated analytics: "show total sales by year"
|
|
18
|
+
- User needs complex filtering: "find all orders over $1000 from last month"
|
|
19
|
+
- User requests joined data: "show products with their category names"
|
|
20
|
+
- User wants statistical summaries: "average, min, max salary by department"
|
|
21
|
+
- User asks for specific calculations: "percentage of customers by state"
|
|
22
|
+
|
|
23
|
+
Do NOT use this tool for:
|
|
24
|
+
- Reading raw table data without filtering (use read-table)
|
|
25
|
+
- Getting table structure or column info (use table-info)
|
|
26
|
+
- Running pre-written SAS programs (use run-sas-program)
|
|
27
|
+
- Running jobs or job definitions (use run-job or run-jobdef)
|
|
28
|
+
- Executing macros (use run-macro)
|
|
29
|
+
- Simple table reads with no aggregation (use read-table)
|
|
30
|
+
|
|
31
|
+
Purpose
|
|
32
|
+
Convert natural language queries into SAS PROC SQL SELECT statements and execute them to retrieve analyzed data. The LLM generates the SQL from the natural language query, and this tool executes it against the specified table.
|
|
33
|
+
|
|
34
|
+
Parameters
|
|
35
|
+
- table (string, required): Table name in lib.table format (e.g., "Public.cars", "sashelp.class")
|
|
36
|
+
- query (string, required): Natural language description of what data you want
|
|
37
|
+
- sql (string, optional): Pre-generated SQL SELECT statement (LLM should generate this from the query)
|
|
38
|
+
- job (string, default 'program'): Job name to execute the query (default is 'program')
|
|
39
|
+
|
|
40
|
+
Behavior & Processing
|
|
41
|
+
- LLM converts the natural language query into a valid SAS PROC SQL SELECT statement
|
|
42
|
+
- Do not add semicolons to the end of SQL statements
|
|
43
|
+
- SQL reference: https://go.documentation.sas.com/doc/en/pgmsascdc/v_067/sqlproc/n0w2pkrm208upln11i9r4ogwyvow.htm
|
|
44
|
+
- Tool executes the generated SQL against the specified table
|
|
45
|
+
- Returns data in JSON format
|
|
12
46
|
|
|
13
|
-
|
|
14
|
-
|
|
47
|
+
Response Contract
|
|
48
|
+
Returns a JSON object containing:
|
|
49
|
+
- rows: Array of row objects with query results
|
|
50
|
+
- columns: Column metadata from the query result
|
|
51
|
+
- log: Execution log if available
|
|
52
|
+
- If error: structured error message
|
|
53
|
+
- If more than 10 rows: only first 10 displayed (ask user if they want more)
|
|
15
54
|
|
|
16
|
-
|
|
17
|
-
- table:
|
|
18
|
-
- query:
|
|
19
|
-
-
|
|
20
|
-
-
|
|
55
|
+
Disambiguation & Clarification
|
|
56
|
+
- If table missing: ask "Which table should I query (format: lib.tablename)?"
|
|
57
|
+
- If query too vague: ask "Can you be more specific about what data or calculation you want?"
|
|
58
|
+
- If table format unclear: ask "Please specify table as library.tablename (e.g., Public.cars)"
|
|
59
|
+
- If ambiguous calculation: ask for clarification on what to aggregate or filter
|
|
21
60
|
|
|
22
|
-
|
|
23
|
-
- "how many cars by make in sashelp.cars" → { table: "sashelp.cars", query: "how many cars by make", sql: "SELECT make, COUNT(*) FROM sashelp.cars GROUP BY make" }
|
|
24
|
-
- "average
|
|
61
|
+
Examples (→ mapped params)
|
|
62
|
+
- "how many cars by make in sashelp.cars" → { table: "sashelp.cars", query: "how many cars by make", sql: "SELECT make, COUNT(*) AS count FROM sashelp.cars GROUP BY make" }
|
|
63
|
+
- "average horsepower by origin" → { table: "sashelp.cars", query: "average horsepower by origin", sql: "SELECT origin, AVG(horsepower) AS avg_hp FROM sashelp.cars GROUP BY origin" }
|
|
64
|
+
- "total sales over $1000 by region" → { table: "mylib.sales", query: "total sales over $1000 by region", sql: "SELECT region, SUM(amount) AS total FROM mylib.sales WHERE amount > 1000 GROUP BY region" }
|
|
65
|
+
- "percentage of students by year in Public.students" → { table: "Public.students", query: "percentage by year", sql: "SELECT year, COUNT(*) * 100.0 / (SELECT COUNT(*) FROM Public.students) AS pct FROM Public.students GROUP BY year" }
|
|
25
66
|
|
|
26
|
-
|
|
27
|
-
- "
|
|
28
|
-
- "
|
|
67
|
+
Negative Examples (should NOT call sas-query)
|
|
68
|
+
- "read table cars from sashelp" (use read-table instead)
|
|
69
|
+
- "show me 10 rows from customers" (use read-table instead)
|
|
70
|
+
- "what columns are in the sales table?" (use table-info instead)
|
|
71
|
+
- "run this SAS code: proc sql; select * from..." (use run-sas-program instead)
|
|
72
|
+
- "execute job monthly_report" (use run-job instead)
|
|
73
|
+
- "run macro summarize_data" (use run-macro instead)
|
|
29
74
|
|
|
30
|
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
- "run job/macro" (use run-job/run-macro)
|
|
75
|
+
Usage Tips
|
|
76
|
+
- Ensure table is specified in lib.tablename format
|
|
77
|
+
- Be specific in natural language queries for better SQL generation
|
|
78
|
+
- Use table-info first to understand column names and types
|
|
79
|
+
- For simple reads without filtering/aggregation, prefer read-table
|
|
36
80
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
81
|
+
Related Tools
|
|
82
|
+
- read-table — for simple data reading without SQL queries
|
|
83
|
+
- table-info — to inspect table schema before querying
|
|
84
|
+
- run-sas-program — for executing pre-written SAS/SQL code
|
|
85
|
+
- find-table — to verify table exists before querying
|
|
86
|
+
`;
|
|
40
87
|
|
|
41
88
|
|
|
42
89
|
let spec = {
|
package/src/toolSet/scrInfo.js
CHANGED
|
@@ -15,7 +15,7 @@ Purpose
|
|
|
15
15
|
Return the input/output schema and metadata for an SCR (Score Code Runtime) model.
|
|
16
16
|
|
|
17
17
|
Inputs
|
|
18
|
-
-
|
|
18
|
+
- name (string): The SCR model identifier.
|
|
19
19
|
What it returns
|
|
20
20
|
- A JSON object describing the model's interface, typically including:
|
|
21
21
|
- Input variables (names, types, required/optional)
|
|
@@ -23,6 +23,7 @@ What it returns
|
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
Usage notes
|
|
26
|
+
- If no local mapping exists and \`name\` looks like a URL, the tool will attempt to fetch the schema from that URL.
|
|
26
27
|
- Ensure network connectivity and credentials for the remote SCR service when needed.
|
|
27
28
|
- Use scr-score to score data after inspecting the schema.
|
|
28
29
|
|
|
@@ -36,9 +37,9 @@ Examples
|
|
|
36
37
|
aliases: ['scrInfo','scr info','scr_info'],
|
|
37
38
|
description: description,
|
|
38
39
|
schema: {
|
|
39
|
-
|
|
40
|
+
name: z.string(),
|
|
40
41
|
},
|
|
41
|
-
required: ['
|
|
42
|
+
required: ['name'],
|
|
42
43
|
handler: async (params) => {
|
|
43
44
|
let {url, _appContext} = params;
|
|
44
45
|
if (url === null) {
|
|
@@ -7,34 +7,60 @@ import {z} from 'zod';
|
|
|
7
7
|
|
|
8
8
|
function setContext(_appContext) {
|
|
9
9
|
let description = `
|
|
10
|
-
set-context — set the CAS and SAS server contexts for subsequent tool calls
|
|
10
|
+
## set-context — set the CAS and SAS server contexts for subsequent tool calls
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
LLM Invocation Guidance (When to use)
|
|
13
|
+
Use THIS tool when:
|
|
14
|
+
- User wants to switch to a different CAS server: "Use the finance-cas-server"
|
|
15
|
+
- User wants to change the compute context: "Switch to 'SAS Studio Compute Context'"
|
|
16
|
+
- User wants to check current context: "What context am I using?"
|
|
17
|
+
- User wants to set both: "Use finance-cas-server for CAS and my-compute for SAS"
|
|
14
18
|
|
|
15
|
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
19
|
+
Do NOT use this tool for:
|
|
20
|
+
- Retrieving variable values (use get-env)
|
|
21
|
+
- Reading table data (use read-table)
|
|
22
|
+
- Running programs or queries (use run-sas-program or sas-query)
|
|
23
|
+
- Listing available servers or contexts (no tool for this; would require backend support)
|
|
18
24
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
- "switch to SAS Studio Compute Context" → { sas: "SAS Studio Compute Context" }
|
|
22
|
-
- "use finance-cas for CAS and batch-compute for SAS" → { cas: "finance-cas", sas: "batch-compute" }
|
|
23
|
-
- "what context am I using" → { } (no params, returns current)
|
|
25
|
+
Purpose
|
|
26
|
+
Set the active CAS server and/or SAS compute context for all subsequent tool calls in this session. This allows switching between different server environments. If neither parameter is provided, the tool returns the current context values.
|
|
24
27
|
|
|
25
|
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
- "what's my current context" → { }
|
|
28
|
+
Parameters
|
|
29
|
+
- cas (string, optional): The name of the CAS server to use for subsequent CAS operations. Examples: 'cas-shared-default', 'finance-cas-server', 'analytics-cas'
|
|
30
|
+
- sas (string, optional): The name of the SAS compute context to use for subsequent SAS operations. Examples: 'SAS Studio Compute Context', 'my-compute', 'batch-compute'
|
|
29
31
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
32
|
+
Response Contract
|
|
33
|
+
Returns a JSON object containing:
|
|
34
|
+
- cas: The current/new CAS server name (string or null)
|
|
35
|
+
- sas: The current/new SAS compute context name (string or null)
|
|
36
|
+
- If no parameters provided, returns the current context values
|
|
37
|
+
- If parameters provided, updates and returns the new context values
|
|
38
|
+
- On error: error message if context cannot be set (e.g., invalid server name)
|
|
34
39
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
40
|
+
Disambiguation & Clarification
|
|
41
|
+
- If user says "switch servers" without specifying which: ask "Which server would you like to use: CAS, SAS, or both?"
|
|
42
|
+
- If user provides a server name that may not exist: proceed with setting it (the backend will validate)
|
|
43
|
+
- If user says "reset context": ask "Should I reset the CAS context, SAS context, or both?"
|
|
44
|
+
- If user only says "context": ask "Would you like to check the current context or set a new one?"
|
|
45
|
+
|
|
46
|
+
Examples (→ mapped params)
|
|
47
|
+
- "Use the finance-cas-server" → { cas: "finance-cas-server" }
|
|
48
|
+
- "Switch to SAS Studio Compute Context" → { sas: "SAS Studio Compute Context" }
|
|
49
|
+
- "Set CAS to prod-cas and SAS to batch-compute" → { cas: "prod-cas", sas: "batch-compute" }
|
|
50
|
+
- "What's my current context?" → { } (no parameters returns current context)
|
|
51
|
+
- "Show me the active CAS server" → { } (no parameters returns current context)
|
|
52
|
+
|
|
53
|
+
Negative Examples (should NOT call set-context)
|
|
54
|
+
- "Read 10 rows from the customers table" (use read-table instead)
|
|
55
|
+
- "What's the value of myVariable?" (use get-env instead)
|
|
56
|
+
- "Run this SAS program" (use run-sas-program instead)
|
|
57
|
+
|
|
58
|
+
Related Tools
|
|
59
|
+
- get-env — to retrieve individual environment variable values
|
|
60
|
+
- read-table — to read data using the current context
|
|
61
|
+
- run-sas-program — to execute SAS programs in the current context
|
|
62
|
+
- sas-query — to execute SQL queries in the current context
|
|
63
|
+
`;
|
|
38
64
|
|
|
39
65
|
let spec = {
|
|
40
66
|
name: 'set-context',
|
package/src/toolSet/tableInfo.js
CHANGED
|
@@ -9,34 +9,77 @@ import _tableInfo from '../toolHelpers/_tableInfo.js';
|
|
|
9
9
|
function tableInfo(_appContext) {
|
|
10
10
|
|
|
11
11
|
let describe = `
|
|
12
|
-
table-info — retrieve metadata about a table in a CAS or SAS library
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
Returns
|
|
39
|
-
|
|
12
|
+
## table-info — retrieve metadata about a table in a CAS or SAS library
|
|
13
|
+
|
|
14
|
+
LLM Invocation Guidance (When to use)
|
|
15
|
+
Use THIS tool when:
|
|
16
|
+
- User wants table structure/schema: "what columns are in the cars table?"
|
|
17
|
+
- User wants column metadata: "describe the structure of customers table"
|
|
18
|
+
- User wants to see data types: "show me the schema for sales table in Public"
|
|
19
|
+
- User wants table statistics: "how many rows in the orders table?"
|
|
20
|
+
- User wants column information: "what are the columns in the iris table?"
|
|
21
|
+
|
|
22
|
+
Do NOT use this tool for:
|
|
23
|
+
- Reading actual data rows (use read-table)
|
|
24
|
+
- Listing tables in a library (use list-tables)
|
|
25
|
+
- Checking if a table exists (use find-table)
|
|
26
|
+
- Running queries (use sas-query)
|
|
27
|
+
- Reading sample data (use read-table)
|
|
28
|
+
|
|
29
|
+
Purpose
|
|
30
|
+
Return metadata about a table in a specified library (caslib or libref). This includes column names, data types, labels, formats, and table-level statistics such as row count, file size, and timestamps.
|
|
31
|
+
|
|
32
|
+
Parameters
|
|
33
|
+
- table (string, required): The name of the table to inspect.
|
|
34
|
+
- lib (string, required): The caslib or libref containing the table.
|
|
35
|
+
- server (string, default 'cas'): Target server, either 'cas' or 'sas'. Defaults to 'cas' when omitted.
|
|
36
|
+
|
|
37
|
+
Response Contract
|
|
38
|
+
Returns a JSON object containing:
|
|
39
|
+
- columns: Array of column objects with:
|
|
40
|
+
- name: Column name (string)
|
|
41
|
+
- type: Data type (string) - e.g., 'numeric', 'character'
|
|
42
|
+
- label: Column label if defined (string)
|
|
43
|
+
- format: Display format if defined (string)
|
|
44
|
+
- length: Column length for character fields (number)
|
|
45
|
+
- tableInfo: Table-level metadata including:
|
|
46
|
+
- rowCount: Number of rows (number)
|
|
47
|
+
- fileSize: File size if available (number)
|
|
48
|
+
- created: Creation timestamp if available (string)
|
|
49
|
+
- modified: Last modified timestamp if available (string)
|
|
50
|
+
- Empty object if table not found or accessible
|
|
51
|
+
|
|
52
|
+
Disambiguation & Clarification
|
|
53
|
+
- Missing library: ask "Which library contains the table you want to inspect?"
|
|
54
|
+
- Missing table: ask "Which table would you like information about?"
|
|
55
|
+
- If user wants data: clarify "Do you want the table structure (use table-info) or actual data rows (use read-table)?"
|
|
56
|
+
- Ambiguous lib.table format: parse and use as separate parameters
|
|
57
|
+
|
|
58
|
+
Examples (→ mapped params)
|
|
59
|
+
- "describe table cars in sashelp" → { table: "cars", lib: "sashelp", server: "sas" }
|
|
60
|
+
- "what columns are in orders from Public" → { table: "orders", lib: "Public", server: "cas" }
|
|
61
|
+
- "show schema for sales in mylib" → { table: "sales", lib: "mylib", server: "cas" }
|
|
62
|
+
- "table info for iris in Samples" → { table: "iris", lib: "Samples", server: "cas" }
|
|
63
|
+
- "how many rows in customers on cas" → { table: "customers", lib: <lib>, server: "cas" }
|
|
64
|
+
|
|
65
|
+
Negative Examples (should NOT call table-info)
|
|
66
|
+
- "read 10 rows from cars" (use read-table instead)
|
|
67
|
+
- "list tables in sashelp" (use list-tables instead)
|
|
68
|
+
- "does table cars exist in Public?" (use find-table instead)
|
|
69
|
+
- "run query on customers table" (use sas-query instead)
|
|
70
|
+
- "show me data from the sales table" (use read-table instead)
|
|
71
|
+
|
|
72
|
+
Usage Tips
|
|
73
|
+
- Use this tool to inspect schema and column types before scoring or reading data.
|
|
74
|
+
- After inspecting structure, use read-table to fetch actual data.
|
|
75
|
+
- Combine with find-table to verify existence before inspection.
|
|
76
|
+
|
|
77
|
+
Related Tools
|
|
78
|
+
- find-table → table-info → read-table (typical workflow)
|
|
79
|
+
- list-tables — to discover tables before inspecting
|
|
80
|
+
- read-table — to fetch actual data after inspecting structure
|
|
81
|
+
- find-table — to verify a table exists before inspection
|
|
82
|
+
`;
|
|
40
83
|
|
|
41
84
|
let specs = {
|
|
42
85
|
name: 'table-info',
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: mcp-tool-description-optimizer
|
|
3
|
-
description: >
|
|
4
|
-
Optimize MCP (Model Context Protocol) tool descriptions for token efficiency and LLM routing accuracy.
|
|
5
|
-
Use this skill whenever a user shares a raw, verbose, or poorly structured MCP tool description and wants
|
|
6
|
-
it improved, rewritten, or reviewed. Trigger on phrases like: "optimize this tool description",
|
|
7
|
-
"rewrite my MCP tool description", "make this tool description more efficient", "clean up my tool spec",
|
|
8
|
-
"improve how Claude picks my tool", or when a user pastes a JavaScript/TypeScript tool description string
|
|
9
|
-
and asks for help with it. Also trigger when the user mentions token efficiency, tool routing,
|
|
10
|
-
or LLM disambiguation in the context of MCP servers.
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
# MCP Tool Description Optimizer
|
|
14
|
-
|
|
15
|
-
Rewrites verbose or poorly structured MCP tool descriptions into compact, signal-rich versions that
|
|
16
|
-
improve LLM tool selection accuracy while reducing token usage.
|
|
17
|
-
|
|
18
|
-
## Why this matters
|
|
19
|
-
|
|
20
|
-
Claude and other LLMs select MCP tools based entirely on the `description` field. Descriptions that are
|
|
21
|
-
too long, redundant, or badly structured waste context tokens and reduce routing precision.
|
|
22
|
-
A well-optimized description:
|
|
23
|
-
- States what the tool does and when to use it upfront
|
|
24
|
-
- Eliminates redundancy (same info repeated across sections)
|
|
25
|
-
- Uses a compact, scannable format (labeled blocks, not nested markdown)
|
|
26
|
-
- Includes clear negative examples to prevent mis-routing
|
|
27
|
-
- Keeps parameters terse — name, type, default, one-line purpose
|
|
28
|
-
|
|
29
|
-
---
|
|
30
|
-
|
|
31
|
-
## Optimization Process
|
|
32
|
-
|
|
33
|
-
### Step 1 — Analyze the input description
|
|
34
|
-
|
|
35
|
-
Before rewriting, identify these problems in the original:
|
|
36
|
-
|
|
37
|
-
| Problem | Example |
|
|
38
|
-
|---|---|
|
|
39
|
-
| **Redundancy** | Trigger phrases listed in 3+ places |
|
|
40
|
-
| **Filler sections** | "Rationale", "Behavior Summary", "Response Contract" with no routing signal |
|
|
41
|
-
| **Orphaned syntax** | Arrows (`→`) or bullets with no target |
|
|
42
|
-
| **Overlong examples** | Long prose examples when one-liners suffice |
|
|
43
|
-
| **Heavy markdown** | `##` headers for every minor point |
|
|
44
|
-
| **Duplicated parameter docs** | Same param described in both a table and prose |
|
|
45
|
-
|
|
46
|
-
Call out 2–4 of the most impactful issues before writing the new version.
|
|
47
|
-
|
|
48
|
-
### Step 2 — Rewrite using the standard template
|
|
49
|
-
|
|
50
|
-
Use this exact block structure for the output. Omit blocks that don't apply.
|
|
51
|
-
|
|
52
|
-
```
|
|
53
|
-
<tool-name> — <one-line purpose>.
|
|
54
|
-
|
|
55
|
-
USE when: <comma-separated user intents or trigger phrases>
|
|
56
|
-
DO NOT USE for: <comma-separated anti-patterns with → redirect where applicable>
|
|
57
|
-
|
|
58
|
-
PARAMETERS
|
|
59
|
-
- <name>: <type> (default: <val>) — <one-line purpose>
|
|
60
|
-
...
|
|
61
|
-
|
|
62
|
-
ROUTING RULES
|
|
63
|
-
- "<trigger phrase>" → { param: value }
|
|
64
|
-
- "<trigger phrase>" → { param: value }
|
|
65
|
-
- <ambiguous case> → <ask for clarification | default behavior>
|
|
66
|
-
|
|
67
|
-
EXAMPLES
|
|
68
|
-
- "<user utterance>" → { param: value, ... }
|
|
69
|
-
- "<user utterance>" → { param: value, ... }
|
|
70
|
-
|
|
71
|
-
NEGATIVE EXAMPLES (do not route here)
|
|
72
|
-
- "<user utterance>" → <correct tool>
|
|
73
|
-
|
|
74
|
-
PAGINATION (include only if tool is paginated)
|
|
75
|
-
If returned count === limit → hint: next start = start + limit.
|
|
76
|
-
If start > 1 and result empty → note paging may exceed available items.
|
|
77
|
-
|
|
78
|
-
ERRORS
|
|
79
|
-
<One or two lines: return structure, hallucination policy>
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
### Step 3 — Apply these rules consistently
|
|
83
|
-
|
|
84
|
-
**USE/DO NOT USE block**
|
|
85
|
-
- Write as comma-separated inline list, not a bullet list
|
|
86
|
-
- DO NOT USE entries should name the redirect tool in parentheses where known
|
|
87
|
-
|
|
88
|
-
**ROUTING RULES block**
|
|
89
|
-
- One rule per line; quote the trigger phrase; use `→ { }` for param mapping
|
|
90
|
-
- Consolidate synonyms on one line: `"cas libs / cas libraries / in cas" → { server: 'cas' }`
|
|
91
|
-
- List the default/fallback rule last
|
|
92
|
-
|
|
93
|
-
**PARAMETERS block**
|
|
94
|
-
- One line per param: `- name: type (default: val) — purpose`
|
|
95
|
-
- Skip obvious params (e.g. don't explain what `limit` means if it's standard pagination)
|
|
96
|
-
|
|
97
|
-
**EXAMPLES block**
|
|
98
|
-
- Each example fits on one line
|
|
99
|
-
- For "next page" examples, include the prior call's state inline: `"next" (prev: start:1, limit:10) → { start: 11, limit: 10 }`
|
|
100
|
-
|
|
101
|
-
**NEGATIVE EXAMPLES block**
|
|
102
|
-
- Only include when mis-routing is a real risk
|
|
103
|
-
- Format: `"<utterance>" → <correct-tool-name>`
|
|
104
|
-
|
|
105
|
-
**Tone**
|
|
106
|
-
- Imperative, terse. No filler words ("Please note that...", "It is important to...")
|
|
107
|
-
- Never include a "Rationale" or "Behavior Summary" section — if behavior matters, encode it as a rule
|
|
108
|
-
|
|
109
|
-
### Step 4 — Validate before returning
|
|
110
|
-
|
|
111
|
-
Check the rewritten description against this list:
|
|
112
|
-
|
|
113
|
-
- [ ] No trigger phrase appears in more than one block
|
|
114
|
-
- [ ] No orphaned `→` arrows or dangling bullets
|
|
115
|
-
- [ ] Parameter defaults are stated explicitly
|
|
116
|
-
- [ ] Negative examples cover the tool's most common mis-routing risks
|
|
117
|
-
- [ ] Total length is ≤ 50% of the original (target: 30–40% reduction)
|
|
118
|
-
|
|
119
|
-
---
|
|
120
|
-
|
|
121
|
-
## Output format
|
|
122
|
-
|
|
123
|
-
Always return:
|
|
124
|
-
|
|
125
|
-
1. **Analysis** — 2–4 bullet points naming the key issues found in the original
|
|
126
|
-
2. **Rewritten description** — inside a JavaScript code block (matching the user's original code style)
|
|
127
|
-
3. **Change summary** — a short table or bullet list of what changed and why
|
|
128
|
-
|
|
129
|
-
See `references/examples.md` for before/after examples of real tool descriptions.
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
# Before / After Examples
|
|
2
|
-
|
|
3
|
-
## Example 1 — list-libraries (SAS Viya MCP)
|
|
4
|
-
|
|
5
|
-
### BEFORE (~620 tokens)
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
## list-libraries — enumerate CAS or SAS libraries
|
|
9
|
-
|
|
10
|
-
LLM Invocation Guidance (critical)
|
|
11
|
-
Use THIS tool when the user asks for: "list libs", "list libraries", "show cas libs", "show sas libs",
|
|
12
|
-
"what libraries are available", "list caslib(s)", "enumerate libraries", "libraries in cas", "libraries in sas".
|
|
13
|
-
DO NOT use this tool when the user asks for: tables inside a specific library (choose listTables),
|
|
14
|
-
columns/metadata of a table, job/program execution, models, or scoring.
|
|
15
|
-
|
|
16
|
-
Trigger Phrase → Parameter Mapping
|
|
17
|
-
- "cas libs" / "in cas" / "cas libraries" → { server: 'cas' }
|
|
18
|
-
- "sas libs" / "in sas" / "base sas libraries" → { server: 'sas' }
|
|
19
|
-
- "all libs" / "all libs" -> {server: 'all'}
|
|
20
|
-
→ { server: 'all' }
|
|
21
|
-
- "next" (after prior call) → { start: previous.start + previous.limit }
|
|
22
|
-
- "first 20 cas libs" → { server: 'cas', limit: 20 }
|
|
23
|
-
- If server unspecified: default to all.
|
|
24
|
-
|
|
25
|
-
Parameters
|
|
26
|
-
- server (cas|sas|all, default 'all')
|
|
27
|
-
- limit (integer > 0, default 10)
|
|
28
|
-
- start (1-based offset, default 1)
|
|
29
|
-
- where (optional filter expression, default '')
|
|
30
|
-
|
|
31
|
-
Response Contract
|
|
32
|
-
Return JSON-like structure from helper; consumers may extract an array of library objects/names.
|
|
33
|
-
If number of returned items === limit supply a pagination hint: start = start + limit.
|
|
34
|
-
|
|
35
|
-
Behavior Summary
|
|
36
|
-
- Pure listing; no side effects.
|
|
37
|
-
- If ambiguous short request like "list" or "libs" and no prior context: assume { server: 'cas' }.
|
|
38
|
-
- If user explicitly asks for ALL (e.g. "all cas libs") and count likely large, honor limit=50 unless
|
|
39
|
-
user supplies a value; include note about paging.
|
|
40
|
-
|
|
41
|
-
Disambiguation Rules
|
|
42
|
-
- If user mentions a singular library name plus desire for tables ("list tables in SASHELP") choose
|
|
43
|
-
listTables (not this tool).
|
|
44
|
-
- If user mixes "tables" and "libraries" ask for clarification unless clearly about libraries.
|
|
45
|
-
|
|
46
|
-
Examples
|
|
47
|
-
- "list libraries" → { server: 'all', start:1, limit:10 }
|
|
48
|
-
- "list libs" → { server: 'all', start:1, limit:10 }
|
|
49
|
-
- "list sas libs" → { server: 'sas' }
|
|
50
|
-
- "list cas libraries" → { server: 'cas' }
|
|
51
|
-
- "show me 25 cas libraries" → { server:'cas', limit:25 }
|
|
52
|
-
- "next" (after prior call {start:1,limit:10}) → { start:11, limit:10 }
|
|
53
|
-
- "filter cas libs" (no criterion) → ask: "Provide a filter or continue without one?"
|
|
54
|
-
|
|
55
|
-
Negative Examples (do not route here)
|
|
56
|
-
- "list tables in public" (route to list-tables)
|
|
57
|
-
- "list models, list tables, list jobs, list jobdef and similar request"
|
|
58
|
-
- "describe library" (likely list-tables or table-info depending on follow-up)
|
|
59
|
-
- "run program to make a lib" (run-sas-program tool)
|
|
60
|
-
|
|
61
|
-
Error Handling
|
|
62
|
-
- On backend error: return structured error with message field; do not hallucinate libraries.
|
|
63
|
-
- Empty result set → return empty list plus (if start>1) a hint that paging may have exceeded available items.
|
|
64
|
-
|
|
65
|
-
Rationale
|
|
66
|
-
Concise, signal-rich description increases probability this spec is selected for generic library
|
|
67
|
-
enumeration intents.
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
### AFTER (~210 tokens)
|
|
71
|
-
|
|
72
|
-
```
|
|
73
|
-
list-libraries — enumerate CAS or SAS libraries.
|
|
74
|
-
|
|
75
|
-
USE when: list/show/enumerate libraries, caslibs, sas libs, available libraries
|
|
76
|
-
DO NOT USE for: listing tables in a library (→ list-tables), column/table metadata, job execution, models, scoring
|
|
77
|
-
|
|
78
|
-
PARAMETERS
|
|
79
|
-
- server: 'cas' | 'sas' | 'all' (default: 'all')
|
|
80
|
-
- limit: integer > 0 (default: 10)
|
|
81
|
-
- start: 1-based offset (default: 1)
|
|
82
|
-
- where: optional filter expression (default: '')
|
|
83
|
-
|
|
84
|
-
ROUTING RULES
|
|
85
|
-
- "cas libs / cas libraries / in cas" → { server: 'cas' }
|
|
86
|
-
- "sas libs / sas libraries / in sas" → { server: 'sas' }
|
|
87
|
-
- "all libs / all libraries" → { server: 'all' }
|
|
88
|
-
- "all cas libs" with no limit given → { server: 'cas', limit: 50 } + paging note
|
|
89
|
-
- "next" after prior call (start:S, limit:L) → { start: S + L, limit: L }
|
|
90
|
-
- "filter cas libs" with no filter given → ask: "What filter expression should I apply?"
|
|
91
|
-
- server unspecified / ambiguous "list"/"libs" → { server: 'cas' }
|
|
92
|
-
|
|
93
|
-
EXAMPLES
|
|
94
|
-
- "list libraries" → { server: 'all', start: 1, limit: 10 }
|
|
95
|
-
- "list cas libraries" → { server: 'cas', start: 1, limit: 10 }
|
|
96
|
-
- "show me 25 sas libs" → { server: 'sas', limit: 25, start: 1 }
|
|
97
|
-
- "next" (prev: start:1,limit:10) → { server: <same>, start: 11, limit: 10 }
|
|
98
|
-
|
|
99
|
-
NEGATIVE EXAMPLES (do not route here)
|
|
100
|
-
- "list tables in SASHELP" → list-tables
|
|
101
|
-
- "list models / jobs / jobdefs" → respective tools
|
|
102
|
-
- "run a program to create a lib" → run-sas-program
|
|
103
|
-
|
|
104
|
-
PAGINATION
|
|
105
|
-
If returned count === limit → hint: next start = start + limit.
|
|
106
|
-
If start > 1 and result empty → note paging may exceed available items.
|
|
107
|
-
|
|
108
|
-
ERRORS
|
|
109
|
-
Return structured error with message field. Never hallucinate library names.
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
**Token reduction: ~66%**
|
|
113
|
-
|
|
114
|
-
---
|
|
115
|
-
|
|
116
|
-
## Key patterns illustrated
|
|
117
|
-
|
|
118
|
-
- Trigger phrases consolidated from 3 blocks → 1 ROUTING RULES block
|
|
119
|
-
- "Rationale", "Behavior Summary", "Response Contract" sections eliminated
|
|
120
|
-
- Orphaned `→ { server: 'all' }` arrow removed
|
|
121
|
-
- Parameter defaults made explicit inline
|
|
122
|
-
- Examples trimmed to one line each
|
|
123
|
-
- Negative examples now name the redirect tool explicitly
|