@tenonhq/dovetail-servicenow 0.0.15 → 0.0.16
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/mcp/registry.d.ts +2 -0
- package/dist/mcp/registry.js +27 -1
- package/package.json +1 -1
package/dist/mcp/registry.d.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* a client is injected via RegistryDeps (used by tests).
|
|
8
8
|
*/
|
|
9
9
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
10
|
+
import type { ToolAnnotations } from "@modelcontextprotocol/sdk/types.js";
|
|
10
11
|
import { z } from "zod";
|
|
11
12
|
import type { ServiceNowClient } from "../client";
|
|
12
13
|
export declare var TOOL_NAMES: readonly ["create_view", "set_list_layout", "set_form_layout", "set_related_lists", "add_choices_to_field", "flow_view", "action_view", "flow_publish", "flow_copy", "flow_create", "flow_test", "flow_edit"];
|
|
@@ -19,6 +20,7 @@ export interface ToolDescriptor {
|
|
|
19
20
|
name: ToolName;
|
|
20
21
|
description: string;
|
|
21
22
|
shape: z.ZodRawShape;
|
|
23
|
+
annotations: ToolAnnotations;
|
|
22
24
|
handler: (args: any) => Promise<any>;
|
|
23
25
|
}
|
|
24
26
|
export declare function buildDescriptors(deps?: RegistryDeps): Array<ToolDescriptor>;
|
package/dist/mcp/registry.js
CHANGED
|
@@ -39,6 +39,20 @@ exports.TOOL_NAMES = [
|
|
|
39
39
|
"flow_test",
|
|
40
40
|
"flow_edit"
|
|
41
41
|
];
|
|
42
|
+
// MCP tool annotations (spec 2025-11-25) — untrusted behavioural hints that let a
|
|
43
|
+
// host parallelize reads and gate writes; never a security boundary. Five presets
|
|
44
|
+
// cover every tool's safety profile:
|
|
45
|
+
// READ_ONLY — no writes; safe to auto-approve and run concurrently.
|
|
46
|
+
// WRITE_ADDITIVE_IDEMPOTENT — additive write, safe to repeat (idempotent upsert/create).
|
|
47
|
+
// WRITE_CREATE — additive write, NOT idempotent (each call mints a new record).
|
|
48
|
+
// WRITE_OVERWRITE — destructive but idempotent (prune/overwrite: same end state).
|
|
49
|
+
// WRITE_EXECUTE — destructive AND non-idempotent (runs a flow; repeating repeats the effect).
|
|
50
|
+
// openWorldHint is left at its spec default (true) — every tool reaches a ServiceNow instance.
|
|
51
|
+
var READ_ONLY = { readOnlyHint: true };
|
|
52
|
+
var WRITE_ADDITIVE_IDEMPOTENT = { readOnlyHint: false, destructiveHint: false, idempotentHint: true };
|
|
53
|
+
var WRITE_CREATE = { readOnlyHint: false, destructiveHint: false, idempotentHint: false };
|
|
54
|
+
var WRITE_OVERWRITE = { readOnlyHint: false, destructiveHint: true, idempotentHint: true };
|
|
55
|
+
var WRITE_EXECUTE = { readOnlyHint: false, destructiveHint: true, idempotentHint: false };
|
|
42
56
|
function buildDescriptors(deps = {}) {
|
|
43
57
|
function client() {
|
|
44
58
|
return deps.client || (0, client_1.createClient)({});
|
|
@@ -46,6 +60,7 @@ function buildDescriptors(deps = {}) {
|
|
|
46
60
|
return [
|
|
47
61
|
{
|
|
48
62
|
name: "create_view",
|
|
63
|
+
annotations: WRITE_ADDITIVE_IDEMPOTENT,
|
|
49
64
|
description: "Create a ServiceNow custom view (sys_ui_view). Idempotent — an existing view of the "
|
|
50
65
|
+ "same name is returned unchanged. Every write is captured in the supplied update set.",
|
|
51
66
|
shape: schemas_1.createViewSchema.shape,
|
|
@@ -55,6 +70,7 @@ function buildDescriptors(deps = {}) {
|
|
|
55
70
|
},
|
|
56
71
|
{
|
|
57
72
|
name: "set_list_layout",
|
|
73
|
+
annotations: WRITE_OVERWRITE,
|
|
58
74
|
description: "Declaratively set a ServiceNow list layout — which columns appear in a list, and their "
|
|
59
75
|
+ "order — for a table + view. Idempotent; prune (default true) removes columns not in "
|
|
60
76
|
+ "the spec; dryRun previews without writing. Writes are captured in the update set.",
|
|
@@ -65,6 +81,7 @@ function buildDescriptors(deps = {}) {
|
|
|
65
81
|
},
|
|
66
82
|
{
|
|
67
83
|
name: "set_form_layout",
|
|
84
|
+
annotations: WRITE_OVERWRITE,
|
|
68
85
|
description: "Declaratively set a ServiceNow form layout — sections and the fields within them — for "
|
|
69
86
|
+ "a table + view. The first section is the primary section (omit its caption). "
|
|
70
87
|
+ "Idempotent; prune (default true) removes sections/fields not in the spec; dryRun "
|
|
@@ -76,6 +93,7 @@ function buildDescriptors(deps = {}) {
|
|
|
76
93
|
},
|
|
77
94
|
{
|
|
78
95
|
name: "set_related_lists",
|
|
96
|
+
annotations: WRITE_OVERWRITE,
|
|
79
97
|
description: "Declaratively set which related lists appear on a ServiceNow form for a table + view. "
|
|
80
98
|
+ "Related-list ids are \"<table>.<field>\" or \"REL:<sys_relationship>\". Idempotent; "
|
|
81
99
|
+ "prune (default true); dryRun previews. Writes are captured in the update set.",
|
|
@@ -86,6 +104,7 @@ function buildDescriptors(deps = {}) {
|
|
|
86
104
|
},
|
|
87
105
|
{
|
|
88
106
|
name: "add_choices_to_field",
|
|
107
|
+
annotations: WRITE_ADDITIVE_IDEMPOTENT,
|
|
89
108
|
description: "Upsert sys_choice values for a ServiceNow table.column and (optionally) flip "
|
|
90
109
|
+ "sys_dictionary.choice so the field renders as a dropdown. Idempotent. Writes are "
|
|
91
110
|
+ "captured in the supplied update set.",
|
|
@@ -96,6 +115,7 @@ function buildDescriptors(deps = {}) {
|
|
|
96
115
|
},
|
|
97
116
|
{
|
|
98
117
|
name: "flow_view",
|
|
118
|
+
annotations: READ_ONLY,
|
|
99
119
|
description: "Read a ServiceNow Flow Designer flow or subflow's compiled step graph, headless. "
|
|
100
120
|
+ "Returns the ordered, nesting-aware list of action + flow-logic steps plus the flow "
|
|
101
121
|
+ "variables, via GET /api/now/processflow/flow/{sysId}. Read-only. Pass raw:true to "
|
|
@@ -108,6 +128,7 @@ function buildDescriptors(deps = {}) {
|
|
|
108
128
|
},
|
|
109
129
|
{
|
|
110
130
|
name: "action_view",
|
|
131
|
+
annotations: READ_ONLY,
|
|
111
132
|
description: "Read a ServiceNow Custom Action Type's compiled model (identity, inputs, outputs), "
|
|
112
133
|
+ "headless, via GET /api/now/processflow/action/action_types/{sysId}. Read-only. "
|
|
113
134
|
+ "sysId is the sys_hub_action_type_definition sys_id; scopeSysId is the application "
|
|
@@ -120,6 +141,7 @@ function buildDescriptors(deps = {}) {
|
|
|
120
141
|
},
|
|
121
142
|
{
|
|
122
143
|
name: "flow_publish",
|
|
144
|
+
annotations: WRITE_OVERWRITE,
|
|
123
145
|
description: "Publish (compile the snapshot of) a ServiceNow Flow Designer flow or subflow via "
|
|
124
146
|
+ "POST /api/now/processflow/flow/{sysId}/snapshot. This is a WRITE that recompiles the "
|
|
125
147
|
+ "flow's current design — use after editing in the Designer. sysId is the sys_hub_flow "
|
|
@@ -132,6 +154,7 @@ function buildDescriptors(deps = {}) {
|
|
|
132
154
|
},
|
|
133
155
|
{
|
|
134
156
|
name: "flow_copy",
|
|
157
|
+
annotations: WRITE_CREATE,
|
|
135
158
|
description: "Copy a ServiceNow flow/subflow via the Designer's Copy endpoint — a complete, faithful "
|
|
136
159
|
+ "clone created as an INACTIVE DRAFT in the target scope. sourceSysId is the sys_hub_flow "
|
|
137
160
|
+ "to copy; newName is the copy's name; scopeSysId defaults to the source's scope. Publish "
|
|
@@ -145,6 +168,7 @@ function buildDescriptors(deps = {}) {
|
|
|
145
168
|
},
|
|
146
169
|
{
|
|
147
170
|
name: "flow_create",
|
|
171
|
+
annotations: WRITE_CREATE,
|
|
148
172
|
description: "Create a NEW ServiceNow Flow Designer flow (sys_hub_flow, type=flow) from scratch and "
|
|
149
173
|
+ "PUBLISH it, headless. Mints a fresh flow via POST /processflow/flow, grafts the trigger + "
|
|
150
174
|
+ "action graph from an existing published template flow (templateSysId), then compiles the "
|
|
@@ -174,6 +198,7 @@ function buildDescriptors(deps = {}) {
|
|
|
174
198
|
},
|
|
175
199
|
{
|
|
176
200
|
name: "flow_test",
|
|
201
|
+
annotations: WRITE_EXECUTE,
|
|
177
202
|
description: "Test or run a ServiceNow flow/subflow. mode='validate' (default) is a safe, read-only "
|
|
178
203
|
+ "pre-flight — checks the flow is published and that supplied inputs match its declared "
|
|
179
204
|
+ "variables; it never runs the flow. mode='execute' actually runs it via the server-side "
|
|
@@ -194,6 +219,7 @@ function buildDescriptors(deps = {}) {
|
|
|
194
219
|
},
|
|
195
220
|
{
|
|
196
221
|
name: "flow_edit",
|
|
222
|
+
annotations: WRITE_OVERWRITE,
|
|
197
223
|
description: "Edit a ServiceNow flow/subflow in place. Supports rename (name/internalName), description, "
|
|
198
224
|
+ "and patchStepInputs (set named input values on steps by uiId or label). apply=false "
|
|
199
225
|
+ "(default) is a dry-run that returns the diff; apply=true persists the edit (a write). "
|
|
@@ -221,7 +247,7 @@ function registerAllTools(server, deps = {}) {
|
|
|
221
247
|
}
|
|
222
248
|
}
|
|
223
249
|
function registerOne(server, desc) {
|
|
224
|
-
server.registerTool(desc.name, { description: desc.description, inputSchema: desc.shape }, async function (args) {
|
|
250
|
+
server.registerTool(desc.name, { description: desc.description, inputSchema: desc.shape, annotations: desc.annotations }, async function (args) {
|
|
225
251
|
try {
|
|
226
252
|
var result = await desc.handler(args);
|
|
227
253
|
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|