@zivis/mcp 0.1.11 → 0.1.17

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 (36) hide show
  1. package/dist/api-client.js +18 -9
  2. package/dist/pattern-packs/zivis-public-0.2.0/manifest.json +1 -1
  3. package/dist/project-binding.d.ts +1 -0
  4. package/dist/project-binding.js +50 -6
  5. package/dist/prompts/audit-dependencies.js +9 -21
  6. package/dist/server.js +0 -15
  7. package/dist/tools/check-project.js +7 -12
  8. package/dist/tools/create-diagram.d.ts +3 -73
  9. package/dist/tools/create-diagram.js +8 -100
  10. package/dist/tools/devx-run.d.ts +1 -1
  11. package/dist/tools/devx-run.js +1 -1
  12. package/dist/tools/discover-local-infra.d.ts +1 -1
  13. package/dist/tools/discover-local-infra.js +9 -16
  14. package/dist/tools/get-diagram.d.ts +1 -1
  15. package/dist/tools/get-diagram.js +2 -52
  16. package/dist/tools/get-started.d.ts +1 -1
  17. package/dist/tools/get-started.js +110 -94
  18. package/dist/tools/get-trust-keys.d.ts +1 -1
  19. package/dist/tools/get-trust-keys.js +1 -1
  20. package/dist/tools/inspect-zat.d.ts +1 -1
  21. package/dist/tools/inspect-zat.js +2 -2
  22. package/dist/tools/list-diagrams.d.ts +1 -1
  23. package/dist/tools/list-diagrams.js +2 -3
  24. package/dist/tools/manage-diagram.d.ts +1 -64
  25. package/dist/tools/manage-diagram.js +2 -211
  26. package/dist/tools/security-review.d.ts +2 -7
  27. package/dist/tools/security-review.js +12 -91
  28. package/dist/tools/update-mermaid-source.d.ts +1 -1
  29. package/dist/tools/update-mermaid-source.js +1 -3
  30. package/package.json +3 -2
  31. package/dist/tools/check-repo-trust.d.ts +0 -18
  32. package/dist/tools/check-repo-trust.js +0 -221
  33. package/dist/tools/generate-diagram.d.ts +0 -30
  34. package/dist/tools/generate-diagram.js +0 -161
  35. package/dist/tools/get-oss-zat.d.ts +0 -22
  36. package/dist/tools/get-oss-zat.js +0 -98
@@ -1,6 +1,19 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { fileURLToPath } from "node:url";
1
4
  import { resolveAuth } from "./auth/index.js";
2
- import { detectProjectBinding, resolveConfigFromBinding, resolveMcpSessionForWorkspace, } from "./project-binding.js";
5
+ import { detectProjectBinding, resolveConfigFromBinding, resolveMcpSessionForWorkspace, sanitizeBindingOverrides, } from "./project-binding.js";
3
6
  import { DEFAULT_CONFIG } from "./types.js";
7
+ const USER_AGENT = (() => {
8
+ try {
9
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
10
+ const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, "../package.json"), "utf-8"));
11
+ return `@zivis/mcp/${pkg.version ?? "0.0.0"}`;
12
+ }
13
+ catch {
14
+ return "@zivis/mcp/0.0.0";
15
+ }
16
+ })();
4
17
  export class ApiClient {
5
18
  config;
6
19
  constructor(config = DEFAULT_CONFIG) {
@@ -12,16 +25,12 @@ export class ApiClient {
12
25
  if (!detected) {
13
26
  return this.config;
14
27
  }
15
- const { binding } = detected;
28
+ const { binding, filePath } = detected;
16
29
  const fromBinding = resolveConfigFromBinding(ws);
17
30
  return {
18
31
  ...this.config,
19
32
  session: resolveMcpSessionForWorkspace(this.config, ws, detected, fromBinding),
20
- ...(binding.apiBaseUrl ? { apiBaseUrl: binding.apiBaseUrl } : {}),
21
- ...(binding.oauthApiUrl ? { oauthApiUrl: binding.oauthApiUrl } : {}),
22
- ...(binding.oauthClientId ? { oauthClientId: binding.oauthClientId } : {}),
23
- ...(binding.keychainPrefix ? { keychainPrefix: binding.keychainPrefix } : {}),
24
- ...(binding.configDir ? { configDir: binding.configDir } : {}),
33
+ ...sanitizeBindingOverrides(binding, filePath),
25
34
  };
26
35
  }
27
36
  buildAuthHeaders(creds) {
@@ -50,7 +59,7 @@ export class ApiClient {
50
59
  const url = `${apiBaseUrl}${path}`;
51
60
  const headers = {
52
61
  "Content-Type": "application/json",
53
- "User-Agent": "@zivis-ai/cli",
62
+ "User-Agent": USER_AGENT,
54
63
  ...this.buildAuthHeaders(creds),
55
64
  };
56
65
  const fetchOptions = { method, headers };
@@ -88,7 +97,7 @@ export class ApiClient {
88
97
  }
89
98
  const url = `${effectiveConfig.apiBaseUrl}${path}`;
90
99
  const headers = {
91
- "User-Agent": "@zivis-ai/cli",
100
+ "User-Agent": USER_AGENT,
92
101
  ...this.buildAuthHeaders(creds),
93
102
  };
94
103
  const response = await fetch(url, { method: "GET", headers });
@@ -3,7 +3,7 @@
3
3
  "pack_id": "zivis-public",
4
4
  "pack_name": "ZIVIS Public Pattern Pack",
5
5
  "version": "0.2.0",
6
- "built_at": "2026-08-31T22:32:10.810Z",
6
+ "built_at": "2026-09-08T13:37:26.490Z",
7
7
  "tier": "customer_safe",
8
8
  "description": "ZIVIS-curated public pattern pack — capsules + inference prompts evaluated locally on the user's machine.",
9
9
  "capsules": [
@@ -3,6 +3,7 @@ export declare function detectProjectBinding(cwd: string): {
3
3
  binding: ProjectBinding;
4
4
  filePath: string;
5
5
  } | null;
6
+ export declare function sanitizeBindingOverrides(binding: ProjectBinding, filePath: string): Partial<Pick<ZivisConfig, "apiBaseUrl" | "oauthApiUrl" | "oauthClientId">>;
6
7
  export declare function resolveConfigFromBinding(cwd?: string): ZivisConfig;
7
8
  export declare function resolveMcpSessionForWorkspace(incoming: ZivisConfig, workspacePath: string, detected: ReturnType<typeof detectProjectBinding>, fromBinding: ZivisConfig): string;
8
9
  export declare function validateProjectBinding(binding: ProjectBinding, filePath: string, config: ZivisConfig): void;
@@ -27,19 +27,63 @@ export function detectProjectBinding(cwd) {
27
27
  }
28
28
  return null;
29
29
  }
30
+ const TRUSTED_BINDING_HOST = "zivis.ai";
31
+ const TRUSTED_BINDING_HOST_SUFFIX = ".zivis.ai";
32
+ const LOOPBACK_HOSTS = new Set(["localhost", "127.0.0.1", "::1", "[::1]"]);
33
+ function isTrustedBindingUrl(raw, envAnchor) {
34
+ if (envAnchor && raw === envAnchor)
35
+ return true;
36
+ let parsed;
37
+ try {
38
+ parsed = new URL(raw);
39
+ }
40
+ catch {
41
+ return false;
42
+ }
43
+ const host = parsed.hostname.toLowerCase();
44
+ if (LOOPBACK_HOSTS.has(host))
45
+ return true;
46
+ if (parsed.protocol !== "https:")
47
+ return false;
48
+ return host === TRUSTED_BINDING_HOST || host.endsWith(TRUSTED_BINDING_HOST_SUFFIX);
49
+ }
50
+ function describeHost(raw) {
51
+ try {
52
+ return new URL(raw).host;
53
+ }
54
+ catch {
55
+ return "<unparseable url>";
56
+ }
57
+ }
58
+ export function sanitizeBindingOverrides(binding, filePath) {
59
+ const out = {};
60
+ const gate = (field, value, envName) => {
61
+ if (!value)
62
+ return;
63
+ if (isTrustedBindingUrl(value, process.env[envName])) {
64
+ out[field] = value;
65
+ return;
66
+ }
67
+ console.error(`[zivis] WARNING: ignoring untrusted "${field}" in ${filePath} ` +
68
+ `(host: ${describeHost(value)}). A repo binding may only point at ` +
69
+ `https://*.zivis.ai, localhost, or the exact value of ${envName}. ` +
70
+ `Falling back to the configured/default host.`);
71
+ };
72
+ gate("apiBaseUrl", binding.apiBaseUrl, "ZIVIS_API_URL");
73
+ gate("oauthApiUrl", binding.oauthApiUrl, "ZIVIS_OAUTH_API_URL");
74
+ if (binding.oauthClientId)
75
+ out.oauthClientId = binding.oauthClientId;
76
+ return out;
77
+ }
30
78
  export function resolveConfigFromBinding(cwd) {
31
79
  const detected = detectProjectBinding(cwd ?? process.cwd());
32
80
  if (!detected)
33
81
  return DEFAULT_CONFIG;
34
- const { binding } = detected;
82
+ const { binding, filePath } = detected;
35
83
  return {
36
84
  ...DEFAULT_CONFIG,
37
85
  ...(binding.session ? { session: binding.session } : {}),
38
- ...(binding.apiBaseUrl ? { apiBaseUrl: binding.apiBaseUrl } : {}),
39
- ...(binding.oauthApiUrl ? { oauthApiUrl: binding.oauthApiUrl } : {}),
40
- ...(binding.oauthClientId ? { oauthClientId: binding.oauthClientId } : {}),
41
- ...(binding.keychainPrefix ? { keychainPrefix: binding.keychainPrefix } : {}),
42
- ...(binding.configDir ? { configDir: binding.configDir } : {}),
86
+ ...sanitizeBindingOverrides(binding, filePath),
43
87
  };
44
88
  }
45
89
  export function resolveMcpSessionForWorkspace(incoming, workspacePath, detected, fromBinding) {
@@ -1,6 +1,6 @@
1
1
  export function registerAuditDependenciesPrompt(server) {
2
2
  server.registerPrompt("audit-dependencies", {
3
- description: "Check the open source libraries this project depends on for security risks. No account setup needed.",
3
+ description: "Check the open source libraries this project depends on for security risks (requires a connected ZIVIS project — run `zivis init` first if needed).",
4
4
  argsSchema: {},
5
5
  }, async () => ({
6
6
  messages: [
@@ -12,33 +12,21 @@ export function registerAuditDependenciesPrompt(server) {
12
12
 
13
13
  Please do the following:
14
14
 
15
- 1. Look at the dependency files in this project. In priority order, check:
16
- - package.json (look for the "dependencies" and "devDependencies" keys)
17
- - requirements.txt or pyproject.toml
18
- - go.mod
19
- - Any other manifest files you can see
15
+ 1. Check whether this repo is connected to ZIVIS: look for \`.zivis/project.json\`. If it's missing, run \`zivis init\` in the terminal first (interactive login + one-time setup) and only continue once that succeeds.
20
16
 
21
- 2. From those files, find all external dependencies that have a GitHub repository.
22
- - Skip internal packages (those starting with "@my-company/" or similar private namespaces).
23
- - Skip built-in packages (e.g. node built-ins like "fs", "path").
17
+ 2. Run \`zivis test dependencies\` in the terminal. This loads the ZIVIS dependency-risk methodology (reachability triage against the resolved lockfile — not just a CVE list) plus this project's prior ZIVIS security context, and hands you the grounding to do the actual analysis yourself.
24
18
 
25
- 3. For each external dependency that has a public GitHub repo, call \`zivis_check_repo_trust\`
26
- with the owner/repo string (e.g. "openai/openai-node").
19
+ 3. Follow the methodology it prints: build the dependency worklist from your lockfile, trace direct-runtime dependencies for reachability (is the vulnerable function actually imported, called, and fed attacker-controlled input?), and classify each as reachable-confirmed / reachable-but-contingent / not-imported / not-applicable / indeterminate.
27
20
 
28
- 4. After checking each one, give me a summary table with columns:
29
- - Package name
30
- - Trust grade (A+ through F)
31
- - Risk level (Safe / Low risk / Moderate / High / Critical)
32
- - Any critical or high findings (one line each)
21
+ 4. Give me a summary table with columns: package, installed version, CVE(s), reachability verdict, and one-line reasoning.
33
22
 
34
- 5. Flag any package with grade C or below and explain in plain English why it's risky.
23
+ 5. For anything reachable-confirmed, record it as a finding through the run's normal reporting flow so it's durable ZIVIS history, not just terminal output.
35
24
 
36
- 6. At the end, suggest the two highest-priority actions to take based on the results.
25
+ 6. At the end, name any transitive-only dependencies you didn't trace this pass (an explicit coverage gap, not a silent pass) and suggest the two highest-priority actions.
37
26
 
38
27
  Ground rules:
39
- - Process dependencies one at a time so I can follow along.
40
- - If a package doesn't have a GitHub repo, skip it and say "(no GitHub repo found)".
41
- - Don't make up trust data — only use what zivis_check_repo_trust returns.
28
+ - This requires a connected ZIVIS project — do not fabricate a trust score or skip straight to a verdict if \`zivis init\`/\`zivis test dependencies\` fails; report what went wrong instead.
29
+ - A CVE with no confirmed reachable call site is not the same as a confirmed vulnerability — say so explicitly rather than flattening the distinction.
42
30
  - Speak in plain English. "High risk" is better than "critical severity threat vector".`,
43
31
  },
44
32
  },
package/dist/server.js CHANGED
@@ -55,8 +55,6 @@ import { THREAT_LIST_RELEVANT_CAPSULES_NAME, THREAT_LIST_RELEVANT_CAPSULES_DESCR
55
55
  import { THREAT_GET_CAPSULE_NAME, THREAT_GET_CAPSULE_DESCRIPTION, THREAT_GET_CAPSULE_SCHEMA, createThreatGetCapsuleHandler, } from "./tools/threat-get-capsule.js";
56
56
  import { THREAT_GET_INFERENCE_PROMPT_NAME, THREAT_GET_INFERENCE_PROMPT_DESCRIPTION, THREAT_GET_INFERENCE_PROMPT_SCHEMA, createThreatGetInferencePromptHandler, } from "./tools/threat-get-inference-prompt.js";
57
57
  import { THREAT_RUN_MATCHER_NAME, THREAT_RUN_MATCHER_DESCRIPTION, THREAT_RUN_MATCHER_SCHEMA, createThreatRunMatcherHandler, } from "./tools/threat-run-matcher.js";
58
- import { CHECK_REPO_TRUST_NAME, CHECK_REPO_TRUST_DESCRIPTION, CHECK_REPO_TRUST_SCHEMA, createCheckRepoTrustHandler, } from "./tools/check-repo-trust.js";
59
- import { GET_OSS_ZAT_NAME, GET_OSS_ZAT_DESCRIPTION, GET_OSS_ZAT_SCHEMA, createGetOssZatHandler, } from "./tools/get-oss-zat.js";
60
58
  import { VERIFY_TRUST_MARK_NAME, VERIFY_TRUST_MARK_DESCRIPTION, VERIFY_TRUST_MARK_SCHEMA, createVerifyTrustMarkHandler, } from "./tools/verify-trust-mark.js";
61
59
  import { GET_TRUST_KEYS_NAME, GET_TRUST_KEYS_DESCRIPTION, GET_TRUST_KEYS_SCHEMA, createGetTrustKeysHandler, } from "./tools/get-trust-keys.js";
62
60
  import { INSPECT_ZAT_NAME, INSPECT_ZAT_DESCRIPTION, INSPECT_ZAT_SCHEMA, createInspectZatHandler, } from "./tools/inspect-zat.js";
@@ -73,7 +71,6 @@ import { UPDATE_ENDPOINT_NAME, UPDATE_ENDPOINT_DESCRIPTION, UPDATE_ENDPOINT_SCHE
73
71
  import { MANAGE_APPLICATION_NAME, MANAGE_APPLICATION_DESCRIPTION, MANAGE_APPLICATION_SCHEMA, createManageApplicationHandler, } from "./tools/manage-application.js";
74
72
  import { MANAGE_ENDPOINT_LIFECYCLE_NAME, MANAGE_ENDPOINT_LIFECYCLE_DESCRIPTION, MANAGE_ENDPOINT_LIFECYCLE_SCHEMA, createManageEndpointLifecycleHandler, } from "./tools/manage-endpoint-lifecycle.js";
75
73
  import { DISCOVER_LOCAL_INFRA_NAME, DISCOVER_LOCAL_INFRA_DESCRIPTION, DISCOVER_LOCAL_INFRA_SCHEMA, createDiscoverLocalInfraHandler, } from "./tools/discover-local-infra.js";
76
- import { GENERATE_DIAGRAM_NAME, GENERATE_DIAGRAM_DESCRIPTION, GENERATE_DIAGRAM_SCHEMA, createGenerateDiagramHandler, } from "./tools/generate-diagram.js";
77
74
  import { LIST_DIAGRAMS_NAME, LIST_DIAGRAMS_DESCRIPTION, LIST_DIAGRAMS_SCHEMA, createListDiagramsHandler, } from "./tools/list-diagrams.js";
78
75
  import { GET_DIAGRAM_NAME, GET_DIAGRAM_DESCRIPTION, GET_DIAGRAM_SCHEMA, createGetDiagramHandler, } from "./tools/get-diagram.js";
79
76
  import { CREATE_DIAGRAM_NAME, CREATE_DIAGRAM_DESCRIPTION, CREATE_DIAGRAM_SCHEMA, createCreateDiagramHandler, } from "./tools/create-diagram.js";
@@ -143,14 +140,6 @@ export async function startServer(incoming = DEFAULT_CONFIG) {
143
140
  description: THREAT_RUN_MATCHER_DESCRIPTION,
144
141
  inputSchema: THREAT_RUN_MATCHER_SCHEMA,
145
142
  }, createThreatRunMatcherHandler());
146
- server.registerTool(CHECK_REPO_TRUST_NAME, {
147
- description: CHECK_REPO_TRUST_DESCRIPTION,
148
- inputSchema: CHECK_REPO_TRUST_SCHEMA,
149
- }, createCheckRepoTrustHandler(config));
150
- server.registerTool(GET_OSS_ZAT_NAME, {
151
- description: GET_OSS_ZAT_DESCRIPTION,
152
- inputSchema: GET_OSS_ZAT_SCHEMA,
153
- }, createGetOssZatHandler(config));
154
143
  server.registerTool(VERIFY_TRUST_MARK_NAME, {
155
144
  description: VERIFY_TRUST_MARK_DESCRIPTION,
156
145
  inputSchema: VERIFY_TRUST_MARK_SCHEMA,
@@ -215,10 +204,6 @@ export async function startServer(incoming = DEFAULT_CONFIG) {
215
204
  description: DISCOVER_LOCAL_INFRA_DESCRIPTION,
216
205
  inputSchema: DISCOVER_LOCAL_INFRA_SCHEMA,
217
206
  }, createDiscoverLocalInfraHandler());
218
- server.registerTool(GENERATE_DIAGRAM_NAME, {
219
- description: GENERATE_DIAGRAM_DESCRIPTION,
220
- inputSchema: GENERATE_DIAGRAM_SCHEMA,
221
- }, createGenerateDiagramHandler(apiClient));
222
207
  server.registerTool(LIST_DIAGRAMS_NAME, {
223
208
  description: LIST_DIAGRAMS_DESCRIPTION,
224
209
  inputSchema: LIST_DIAGRAMS_SCHEMA,
@@ -44,18 +44,12 @@ export function createCheckProjectHandler(apiClient, _config) {
44
44
  {
45
45
  id: "run_auth_init",
46
46
  label: "Connect this project to your ZIVIS org",
47
- tool: "zivis_check_project",
48
- why: "Run 'zivis auth init' in your terminal to create the binding, then re-check.",
47
+ tool: "cli_command",
48
+ args_hint: { command: "zivis init" },
49
+ why: "Every ZIVIS command requires a bound Application — this creates the binding, then re-check.",
49
50
  requires_tier: "free",
50
51
  },
51
- {
52
- id: "check_deps_no_auth",
53
- label: "Check dependencies without a binding (no auth needed)",
54
- tool: "zivis_check_repo_trust",
55
- why: "You can check any GitHub repo for security issues right now — no binding required.",
56
- requires_tier: "free",
57
- },
58
- ], "Project is not bound to a ZIVIS org. Run 'zivis auth init' in your terminal to fix this.");
52
+ ], "Project is not bound to a ZIVIS org. Run 'zivis init' in your terminal to fix this.");
59
53
  }
60
54
  const { binding, filePath } = detected;
61
55
  const sessionMatches = currentSession === binding.session;
@@ -161,8 +155,9 @@ export function createCheckProjectHandler(apiClient, _config) {
161
155
  {
162
156
  id: "check_deps",
163
157
  label: "Check the open source libraries you depend on",
164
- tool: "zivis_check_repo_trust",
165
- why: "Free and fast catches risky AI SDKs and known-bad dependencies.",
158
+ tool: "cli_command",
159
+ args_hint: { command: "zivis test dependencies" },
160
+ why: "Runs the ZIVIS dependency-risk methodology against your resolved lockfile — reachability triage, not just a CVE list.",
166
161
  requires_tier: "free",
167
162
  },
168
163
  ], `Project is correctly connected to ${binding.orgName ?? "your ZIVIS org"}.`);
@@ -1,7 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import type { ApiClient } from "../api-client.js";
3
3
  export declare const CREATE_DIAGRAM_NAME = "zivis_create_diagram";
4
- export declare const CREATE_DIAGRAM_DESCRIPTION = "Create a new canvas diagram with nodes, connections, and boundaries in a single call.\n\nUse this to build system architecture diagrams, data flow diagrams, attack chains, etc. from code analysis.\n\n**Temp IDs:** When creating nodes and connections together, assign each node a temp_id (e.g., \"node_0\", \"node_1\") and reference them in connections via source_temp_id / target_temp_id. Similarly, assign boundaries a temp_id and reference them in nodes via boundary_temp_id.\n\n**Positioning:** Nodes default to (0,0). For readable layouts, space nodes apart (e.g., 250px horizontal, 150px vertical gaps). Default node size is 200x100px. Boundaries should be sized to contain their child nodes with padding.\n\n**Tags:** Use tags to annotate nodes with metadata (e.g., [\"database\", \"postgres\", \"port:5432\", \"pii\"]). These are searchable and displayed in the UI.\n\n**Colors:** Use hex colors (e.g., \"#336791\" for databases, \"#DC382D\" for caches, \"#009639\" for proxies).";
4
+ export declare const CREATE_DIAGRAM_DESCRIPTION = "Create a new diagram from Mermaid source.\n\nUse this to record system architecture diagrams, data flow diagrams, attack chains, sequence diagrams, etc. from code analysis. Content is Mermaid syntax (flowchart, sequenceDiagram, etc.) \u2014 see zivis_update_mermaid_source for editing an existing diagram's source.";
5
5
  export declare const CREATE_DIAGRAM_SCHEMA: {
6
6
  name: z.ZodString;
7
7
  description: z.ZodOptional<z.ZodString>;
@@ -15,84 +15,14 @@ export declare const CREATE_DIAGRAM_SCHEMA: {
15
15
  trust_boundary: "trust_boundary";
16
16
  network: "network";
17
17
  }>;
18
- nodes: z.ZodOptional<z.ZodArray<z.ZodObject<{
19
- temp_id: z.ZodOptional<z.ZodString>;
20
- name: z.ZodString;
21
- description: z.ZodOptional<z.ZodString>;
22
- tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
23
- icon: z.ZodOptional<z.ZodString>;
24
- color: z.ZodOptional<z.ZodString>;
25
- position_x: z.ZodOptional<z.ZodNumber>;
26
- position_y: z.ZodOptional<z.ZodNumber>;
27
- width: z.ZodOptional<z.ZodNumber>;
28
- height: z.ZodOptional<z.ZodNumber>;
29
- step_order: z.ZodOptional<z.ZodNumber>;
30
- boundary_temp_id: z.ZodOptional<z.ZodString>;
31
- metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
32
- }, z.core.$strip>>>;
33
- connections: z.ZodOptional<z.ZodArray<z.ZodObject<{
34
- source_temp_id: z.ZodOptional<z.ZodString>;
35
- target_temp_id: z.ZodOptional<z.ZodString>;
36
- source_node_id: z.ZodOptional<z.ZodString>;
37
- target_node_id: z.ZodOptional<z.ZodString>;
38
- label: z.ZodOptional<z.ZodString>;
39
- description: z.ZodOptional<z.ZodString>;
40
- tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
41
- bidirectional: z.ZodOptional<z.ZodBoolean>;
42
- metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
43
- }, z.core.$strip>>>;
44
- boundaries: z.ZodOptional<z.ZodArray<z.ZodObject<{
45
- temp_id: z.ZodOptional<z.ZodString>;
46
- label: z.ZodString;
47
- description: z.ZodOptional<z.ZodString>;
48
- color: z.ZodOptional<z.ZodString>;
49
- position_x: z.ZodOptional<z.ZodNumber>;
50
- position_y: z.ZodOptional<z.ZodNumber>;
51
- width: z.ZodOptional<z.ZodNumber>;
52
- height: z.ZodOptional<z.ZodNumber>;
53
- }, z.core.$strip>>>;
18
+ content: z.ZodString;
54
19
  linked_threat_model_id: z.ZodOptional<z.ZodString>;
55
20
  };
56
21
  export declare function createCreateDiagramHandler(apiClient: ApiClient): (params: {
57
22
  name: string;
58
23
  description?: string;
59
24
  diagram_type: string;
60
- nodes?: Array<{
61
- temp_id?: string;
62
- name: string;
63
- description?: string;
64
- tags?: string[];
65
- icon?: string;
66
- color?: string;
67
- position_x?: number;
68
- position_y?: number;
69
- width?: number;
70
- height?: number;
71
- step_order?: number;
72
- boundary_temp_id?: string;
73
- metadata?: Record<string, unknown>;
74
- }>;
75
- connections?: Array<{
76
- source_temp_id?: string;
77
- target_temp_id?: string;
78
- source_node_id?: string;
79
- target_node_id?: string;
80
- label?: string;
81
- description?: string;
82
- tags?: string[];
83
- bidirectional?: boolean;
84
- metadata?: Record<string, unknown>;
85
- }>;
86
- boundaries?: Array<{
87
- temp_id?: string;
88
- label: string;
89
- description?: string;
90
- color?: string;
91
- position_x?: number;
92
- position_y?: number;
93
- width?: number;
94
- height?: number;
95
- }>;
25
+ content: string;
96
26
  linked_threat_model_id?: string;
97
27
  }) => Promise<{
98
28
  content: {
@@ -1,17 +1,9 @@
1
1
  import { z } from "zod";
2
2
  import { sanitizeResponse } from "../sanitize.js";
3
3
  export const CREATE_DIAGRAM_NAME = "zivis_create_diagram";
4
- export const CREATE_DIAGRAM_DESCRIPTION = `Create a new canvas diagram with nodes, connections, and boundaries in a single call.
4
+ export const CREATE_DIAGRAM_DESCRIPTION = `Create a new diagram from Mermaid source.
5
5
 
6
- Use this to build system architecture diagrams, data flow diagrams, attack chains, etc. from code analysis.
7
-
8
- **Temp IDs:** When creating nodes and connections together, assign each node a temp_id (e.g., "node_0", "node_1") and reference them in connections via source_temp_id / target_temp_id. Similarly, assign boundaries a temp_id and reference them in nodes via boundary_temp_id.
9
-
10
- **Positioning:** Nodes default to (0,0). For readable layouts, space nodes apart (e.g., 250px horizontal, 150px vertical gaps). Default node size is 200x100px. Boundaries should be sized to contain their child nodes with padding.
11
-
12
- **Tags:** Use tags to annotate nodes with metadata (e.g., ["database", "postgres", "port:5432", "pii"]). These are searchable and displayed in the UI.
13
-
14
- **Colors:** Use hex colors (e.g., "#336791" for databases, "#DC382D" for caches, "#009639" for proxies).`;
6
+ Use this to record system architecture diagrams, data flow diagrams, attack chains, sequence diagrams, etc. from code analysis. Content is Mermaid syntax (flowchart, sequenceDiagram, etc.) — see zivis_update_mermaid_source for editing an existing diagram's source.`;
15
7
  export const CREATE_DIAGRAM_SCHEMA = {
16
8
  name: z
17
9
  .string()
@@ -23,51 +15,9 @@ export const CREATE_DIAGRAM_SCHEMA = {
23
15
  diagram_type: z
24
16
  .enum(["architecture", "data_flow", "attack_chain", "sequence", "trust_boundary", "network", "deployment", "custom"])
25
17
  .describe("Type of diagram"),
26
- nodes: z
27
- .array(z.object({
28
- temp_id: z.string().optional().describe("Temporary ID for referencing in connections (e.g., 'node_0')"),
29
- name: z.string().describe("Node name (e.g., 'PostgreSQL', 'API Gateway')"),
30
- description: z.string().optional().describe("Node description"),
31
- tags: z.array(z.string()).optional().describe("Tags (e.g., ['database', 'port:5432'])"),
32
- icon: z.string().optional().describe("Icon name (e.g., 'database', 'server', 'shield', 'globe')"),
33
- color: z.string().optional().describe("Hex color (e.g., '#336791')"),
34
- position_x: z.number().optional().describe("X position on canvas (default 0)"),
35
- position_y: z.number().optional().describe("Y position on canvas (default 0)"),
36
- width: z.number().optional().describe("Node width (default 200)"),
37
- height: z.number().optional().describe("Node height (default 100)"),
38
- step_order: z.number().optional().describe("Step order for attack chain diagrams"),
39
- boundary_temp_id: z.string().optional().describe("Temp ID of boundary this node belongs to"),
40
- metadata: z.record(z.string(), z.unknown()).optional().describe("Custom metadata"),
41
- }))
42
- .optional()
43
- .describe("Nodes to create"),
44
- connections: z
45
- .array(z.object({
46
- source_temp_id: z.string().optional().describe("Source node temp ID"),
47
- target_temp_id: z.string().optional().describe("Target node temp ID"),
48
- source_node_id: z.string().optional().describe("Source node UUID (if referencing existing node)"),
49
- target_node_id: z.string().optional().describe("Target node UUID (if referencing existing node)"),
50
- label: z.string().optional().describe("Connection label (e.g., 'HTTPS', 'depends on')"),
51
- description: z.string().optional().describe("Connection description"),
52
- tags: z.array(z.string()).optional().describe("Connection tags"),
53
- bidirectional: z.boolean().optional().describe("Whether connection goes both ways (default false)"),
54
- metadata: z.record(z.string(), z.unknown()).optional().describe("Custom metadata"),
55
- }))
56
- .optional()
57
- .describe("Connections between nodes"),
58
- boundaries: z
59
- .array(z.object({
60
- temp_id: z.string().optional().describe("Temporary ID for referencing in nodes (e.g., 'boundary_0')"),
61
- label: z.string().describe("Boundary label (e.g., 'DMZ', 'Internal Network')"),
62
- description: z.string().optional().describe("Boundary description"),
63
- color: z.string().optional().describe("Hex color"),
64
- position_x: z.number().optional().describe("X position (default 0)"),
65
- position_y: z.number().optional().describe("Y position (default 0)"),
66
- width: z.number().optional().describe("Boundary width (default 400)"),
67
- height: z.number().optional().describe("Boundary height (default 300)"),
68
- }))
69
- .optional()
70
- .describe("Boundary groups (trust boundaries, network segments)"),
18
+ content: z
19
+ .string()
20
+ .describe("Mermaid diagram source (e.g., 'flowchart TD\\n A[Client] --> B[Server]')"),
71
21
  linked_threat_model_id: z
72
22
  .string()
73
23
  .optional()
@@ -76,51 +26,13 @@ export const CREATE_DIAGRAM_SCHEMA = {
76
26
  export function createCreateDiagramHandler(apiClient) {
77
27
  return async (params) => {
78
28
  try {
79
- const apiNodes = params.nodes?.map((n) => ({
80
- tempId: n.temp_id,
81
- name: n.name,
82
- description: n.description,
83
- tags: n.tags,
84
- icon: n.icon,
85
- color: n.color,
86
- positionX: n.position_x,
87
- positionY: n.position_y,
88
- width: n.width,
89
- height: n.height,
90
- stepOrder: n.step_order,
91
- boundaryTempId: n.boundary_temp_id,
92
- metadata: n.metadata,
93
- }));
94
- const apiConnections = params.connections?.map((c) => ({
95
- sourceTempId: c.source_temp_id,
96
- targetTempId: c.target_temp_id,
97
- sourceNodeId: c.source_node_id,
98
- targetNodeId: c.target_node_id,
99
- label: c.label,
100
- description: c.description,
101
- tags: c.tags,
102
- bidirectional: c.bidirectional,
103
- metadata: c.metadata,
104
- }));
105
- const apiBoundaries = params.boundaries?.map((b) => ({
106
- tempId: b.temp_id,
107
- label: b.label,
108
- description: b.description,
109
- color: b.color,
110
- positionX: b.position_x,
111
- positionY: b.position_y,
112
- width: b.width,
113
- height: b.height,
114
- }));
115
29
  const data = await apiClient.post("/api/diagrams", {
116
30
  name: params.name,
117
31
  description: params.description,
118
32
  diagramType: params.diagram_type,
119
- contentType: "canvas",
33
+ contentType: "mermaid",
34
+ content: params.content,
120
35
  sourceType: "manual",
121
- nodes: apiNodes,
122
- connections: apiConnections,
123
- boundaries: apiBoundaries,
124
36
  });
125
37
  const sanitized = sanitizeResponse(data);
126
38
  const diagramId = sanitized.id;
@@ -135,16 +47,12 @@ export function createCreateDiagramHandler(apiClient) {
135
47
  catch {
136
48
  }
137
49
  }
138
- const nodeCount = Array.isArray(sanitized.nodes) ? sanitized.nodes.length : 0;
139
- const connCount = Array.isArray(sanitized.connections) ? sanitized.connections.length : 0;
140
- const boundaryCount = Array.isArray(sanitized.boundaries) ? sanitized.boundaries.length : 0;
141
50
  const result = {
142
51
  diagram_id: diagramId,
143
52
  name: sanitized.name,
144
53
  diagram_type: sanitized.diagramType,
145
- stats: { nodes: nodeCount, connections: connCount, boundaries: boundaryCount },
146
54
  linked_threat_model_id: linkedThreatModelId,
147
- _instruction: "Diagram created. Use zivis_get_diagram to see full content, or zivis_manage_diagram to modify.",
55
+ _instruction: "Diagram created. Use zivis_get_diagram to see full content, or zivis_manage_diagram to modify metadata/links, or zivis_update_mermaid_source to change the diagram source.",
148
56
  };
149
57
  return {
150
58
  content: [
@@ -54,7 +54,7 @@ export declare function createRunReportHandler(apiClient: ApiClient): (params: R
54
54
  }[];
55
55
  }>;
56
56
  export declare const RUN_COMPLETE_NAME = "zivis_run_complete";
57
- export declare const RUN_COMPLETE_DESCRIPTION = "Complete a pending run with its final result envelope (ZIV-219 + ZIV-32) \u2014 the run's immutable close-out.\n\n`result` is the SAME envelope shape `zivis run complete --input` accepts: { summary?, coverage[]?, findings[]?, retests[]?, evidence[]?, observations[]?, generatedArtifacts?, risk_candidates? } \u2014 validated server-side, not here. It may safely repeat items already posted via zivis_run_report; the shared fingerprint/content-hash/observation-key upserts converge instead of duplicating. The response reports what was created/updated/matched, plus (on a fresh completion) the Application's Trust Room link, when one is provisioned.";
57
+ export declare const RUN_COMPLETE_DESCRIPTION = "Complete a pending run with its final result envelope (ZIV-219 + ZIV-32) \u2014 the run's immutable close-out.\n\n`result` is the SAME envelope shape `zivis run complete --input` accepts: { summary?, coverage[]?, findings[]?, retests[]?, evidence[]?, observations[]?, generatedArtifacts?, risk_candidates? } \u2014 validated server-side, not here. It may safely repeat items already posted via zivis_run_report; the shared fingerprint/content-hash/observation-key upserts converge instead of duplicating. The response reports what was created/updated/matched, plus the Application's stable Assurance Overview URL (`applicationAssuranceUrl`).";
58
58
  export declare const RUN_COMPLETE_SCHEMA: {
59
59
  run_id: z.ZodString;
60
60
  result: z.ZodRecord<z.ZodString, z.ZodUnknown>;
@@ -124,7 +124,7 @@ export function createRunReportHandler(apiClient) {
124
124
  export const RUN_COMPLETE_NAME = "zivis_run_complete";
125
125
  export const RUN_COMPLETE_DESCRIPTION = `Complete a pending run with its final result envelope (ZIV-219 + ZIV-32) — the run's immutable close-out.
126
126
 
127
- \`result\` is the SAME envelope shape \`zivis run complete --input\` accepts: { summary?, coverage[]?, findings[]?, retests[]?, evidence[]?, observations[]?, generatedArtifacts?, risk_candidates? } — validated server-side, not here. It may safely repeat items already posted via zivis_run_report; the shared fingerprint/content-hash/observation-key upserts converge instead of duplicating. The response reports what was created/updated/matched, plus (on a fresh completion) the Application's Trust Room link, when one is provisioned.`;
127
+ \`result\` is the SAME envelope shape \`zivis run complete --input\` accepts: { summary?, coverage[]?, findings[]?, retests[]?, evidence[]?, observations[]?, generatedArtifacts?, risk_candidates? } — validated server-side, not here. It may safely repeat items already posted via zivis_run_report; the shared fingerprint/content-hash/observation-key upserts converge instead of duplicating. The response reports what was created/updated/matched, plus the Application's stable Assurance Overview URL (\`applicationAssuranceUrl\`).`;
128
128
  export const RUN_COMPLETE_SCHEMA = {
129
129
  run_id: z.string().min(1).describe("The runId returned by zivis_run_start. Must be pending — completing an already-completed run replays idempotently."),
130
130
  result: z
@@ -1,6 +1,6 @@
1
1
  import { z } from "zod";
2
2
  export declare const DISCOVER_LOCAL_INFRA_NAME = "zivis_discover_local_infra";
3
- export declare const DISCOVER_LOCAL_INFRA_DESCRIPTION = "Discover AI infrastructure in a local project directory by reading Docker, compose, and dependency files.\n\nAnalyzes the project to understand what services are defined, which are running, and what AI/LLM frameworks are in use. Returns structured recommendations for red team testing via zivis_local_scan.\n\nWhat it reads:\n- docker-compose.yml / docker-compose.yaml / compose.yml / compose.yaml\n- Dockerfile(s) in the project root and subdirectories\n- .env files (structure only \u2014 values are redacted for safety)\n- package.json, requirements.txt, pyproject.toml, go.mod (to detect AI frameworks)\n\nWhat it checks:\n- Docker daemon status\n- Currently running containers (docker compose ps)\n- Port mappings and exposed services\n\nWhat it returns:\n- List of services with ports and images\n- Running vs stopped status per service\n- Detected AI/LLM patterns (OpenAI, Anthropic, LangChain, etc.)\n- Suggested target_url, chat_endpoint, target_type for zivis_local_scan\n- Whether the zivis-local-runner Docker image is available\n\nThis tool makes NO network requests and requires NO authentication. It only reads local files and queries the Docker daemon.";
3
+ export declare const DISCOVER_LOCAL_INFRA_DESCRIPTION = "Discover AI infrastructure in a local project directory by reading Docker, compose, and dependency files.\n\nAnalyzes the project to understand what services are defined, which are running, and what AI/LLM frameworks are in use. Returns a suggested target shape (URL, chat endpoint) for the coding agent to use as grounding context before running `zivis test ai`.\n\nWhat it reads:\n- docker-compose.yml / docker-compose.yaml / compose.yml / compose.yaml\n- Dockerfile(s) in the project root and subdirectories\n- .env files (structure only \u2014 values are redacted for safety)\n- package.json, requirements.txt, pyproject.toml, go.mod (to detect AI frameworks)\n\nWhat it checks:\n- Docker daemon status\n- Currently running containers (docker compose ps)\n- Port mappings and exposed services\n\nWhat it returns:\n- List of services with ports and images\n- Running vs stopped status per service\n- Detected AI/LLM patterns (OpenAI, Anthropic, LangChain, etc.)\n- Suggested target_url/target_type/chat_endpoint \u2014 informational context, not a tool call to make\n- Whether the zivis-local-runner Docker image is available\n\nFor actually testing the discovered AI system, run `zivis test ai` in the terminal \u2014 this tool only maps what's running locally.\n\nThis tool makes NO network requests and requires NO authentication. It only reads local files and queries the Docker daemon.";
4
4
  export declare const DISCOVER_LOCAL_INFRA_SCHEMA: {
5
5
  project_dir: z.ZodOptional<z.ZodString>;
6
6
  };
@@ -7,7 +7,7 @@ const execAsync = promisify(exec);
7
7
  export const DISCOVER_LOCAL_INFRA_NAME = "zivis_discover_local_infra";
8
8
  export const DISCOVER_LOCAL_INFRA_DESCRIPTION = `Discover AI infrastructure in a local project directory by reading Docker, compose, and dependency files.
9
9
 
10
- Analyzes the project to understand what services are defined, which are running, and what AI/LLM frameworks are in use. Returns structured recommendations for red team testing via zivis_local_scan.
10
+ Analyzes the project to understand what services are defined, which are running, and what AI/LLM frameworks are in use. Returns a suggested target shape (URL, chat endpoint) for the coding agent to use as grounding context before running \`zivis test ai\`.
11
11
 
12
12
  What it reads:
13
13
  - docker-compose.yml / docker-compose.yaml / compose.yml / compose.yaml
@@ -24,9 +24,11 @@ What it returns:
24
24
  - List of services with ports and images
25
25
  - Running vs stopped status per service
26
26
  - Detected AI/LLM patterns (OpenAI, Anthropic, LangChain, etc.)
27
- - Suggested target_url, chat_endpoint, target_type for zivis_local_scan
27
+ - Suggested target_url/target_type/chat_endpoint — informational context, not a tool call to make
28
28
  - Whether the zivis-local-runner Docker image is available
29
29
 
30
+ For actually testing the discovered AI system, run \`zivis test ai\` in the terminal — this tool only maps what's running locally.
31
+
30
32
  This tool makes NO network requests and requires NO authentication. It only reads local files and queries the Docker daemon.`;
31
33
  export const DISCOVER_LOCAL_INFRA_SCHEMA = {
32
34
  project_dir: z
@@ -127,7 +129,7 @@ export function createDiscoverLocalInfraHandler() {
127
129
  aiFrameworks: { detected: [], envHints: [] },
128
130
  runnerImage: { available: false },
129
131
  suggestion: null,
130
- localScanCommand: null,
132
+ nextStep: null,
131
133
  };
132
134
  try {
133
135
  const { stdout } = await execAsync("docker version --format '{{.Server.Version}}'", {
@@ -344,19 +346,10 @@ export function createDiscoverLocalInfraHandler() {
344
346
  }
345
347
  result.suggestion = generateSuggestion(result.compose.services, result.aiFrameworks.detected, result.aiFrameworks.envHints, result.dockerfiles);
346
348
  if (result.suggestion) {
347
- const parts = [`target_url="${result.suggestion.target_url}"`];
348
- parts.push(`target_type="${result.suggestion.target_type}"`);
349
- if (result.suggestion.chat_endpoint) {
350
- parts.push(`chat_endpoint="${result.suggestion.chat_endpoint}"`);
351
- }
352
- if (result.suggestion.request_template) {
353
- parts.push(`request_template='${result.suggestion.request_template}'`);
354
- }
355
- if (result.suggestion.response_path) {
356
- parts.push(`response_path="${result.suggestion.response_path}"`);
357
- }
358
- parts.push(`scan_depth="standard"`);
359
- result.localScanCommand = `zivis_local_scan(${parts.join(", ")})`;
349
+ result.nextStep =
350
+ `Detected ${result.suggestion.target_type} target at ${result.suggestion.target_url}` +
351
+ (result.suggestion.chat_endpoint ? ` (chat endpoint: ${result.suggestion.chat_endpoint})` : "") +
352
+ `. Run \`zivis test ai\` to test it.`;
360
353
  }
361
354
  return {
362
355
  content: [
@@ -1,7 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import type { ApiClient } from "../api-client.js";
3
3
  export declare const GET_DIAGRAM_NAME = "zivis_get_diagram";
4
- export declare const GET_DIAGRAM_DESCRIPTION = "Get the full content of a diagram including all nodes, connections, boundaries, and Mermaid source.\n\nReturns node IDs, names, tags, positions, boundary assignments, and metadata. Connection IDs include source/target node references and labels. Boundary IDs include labels and positions.\n\nFor mermaid-type diagrams, the `content` field contains the full Mermaid source string \u2014 use it to read or render the diagram. For canvas-type diagrams, `content` is null and the structure is expressed via nodes/connections/boundaries.\n\nUse this before modifying a diagram \u2014 you need node/connection/boundary IDs for zivis_manage_diagram (canvas) or the Mermaid source for zivis_update_mermaid_source (mermaid).";
4
+ export declare const GET_DIAGRAM_DESCRIPTION = "Get the full content of a diagram, including its Mermaid source.\n\nUse this before modifying a diagram \u2014 you need the current Mermaid source for zivis_update_mermaid_source.";
5
5
  export declare const GET_DIAGRAM_SCHEMA: {
6
6
  diagram_id: z.ZodString;
7
7
  };