sophos-central-mcp-server 0.1.1 → 0.1.3

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.
@@ -1,6 +1,5 @@
1
1
  /**
2
- * Tool: sophos_get_account_health
3
- * Retrieves account health check scores from the Sophos Common API.
2
+ * Tools: sophos_get_account_health, sophos_list_account_health
4
3
  */
5
4
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
6
5
  import type { SophosClient } from "../client/sophos-client.js";
@@ -1 +1 @@
1
- {"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../src/tools/health.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAGnE,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,YAAY,EACpB,cAAc,EAAE,cAAc,GAC7B,IAAI,CAuCN"}
1
+ {"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../src/tools/health.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAyBnE,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,YAAY,EACpB,cAAc,EAAE,cAAc,GAC7B,IAAI,CAyIN"}
@@ -1,18 +1,39 @@
1
1
  /**
2
- * Tool: sophos_get_account_health
3
- * Retrieves account health check scores from the Sophos Common API.
2
+ * Tools: sophos_get_account_health, sophos_list_account_health
4
3
  */
5
4
  import { z } from "zod";
6
5
  import { jsonResult, withErrorHandling } from "./helpers.js";
6
+ const HEALTH_PATH = "/account-health-check/v1/health-check";
7
+ const CONCURRENCY = 10;
8
+ /**
9
+ * Extracts the minimum overall score from a health check response.
10
+ * Checks both endpoint and server protection globalDetail scores.
11
+ * Returns null if no health data is available.
12
+ */
13
+ function extractOverallScore(data) {
14
+ if (!data)
15
+ return null;
16
+ const scores = [];
17
+ for (const section of ["endpoint", "server"]) {
18
+ const s = data[section];
19
+ const protection = s?.["protection"];
20
+ const globalDetail = protection?.["globalDetail"];
21
+ if (typeof globalDetail?.["score"] === "number") {
22
+ scores.push(globalDetail["score"]);
23
+ }
24
+ }
25
+ return scores.length > 0 ? Math.min(...scores) : null;
26
+ }
7
27
  export function registerHealthTools(server, client, tenantResolver) {
8
28
  server.registerTool("sophos_get_account_health", {
9
29
  title: "Get Sophos Account Health",
10
- description: `Get the account health check scores for a Sophos Central tenant.
30
+ description: `Get the account health check scores for a single Sophos Central tenant.
11
31
 
12
32
  Returns protection percentages and status for endpoints and servers,
13
33
  including policy compliance, exclusion health, and tamper protection status.
14
34
 
15
- Useful for a quick overview of tenant security posture.
35
+ For partner/org callers who need to compare health across multiple tenants,
36
+ use sophos_list_account_health instead — it fetches all tenants in parallel.
16
37
 
17
38
  Args:
18
39
  - tenant_id (string, optional): Tenant ID. Required for partner/org callers.
@@ -33,8 +54,86 @@ Returns:
33
54
  },
34
55
  }, withErrorHandling(async ({ tenant_id }) => {
35
56
  const resolvedTenantId = tenantResolver.resolveTenantId(tenant_id);
36
- const data = await client.tenantRequest(resolvedTenantId, "/account-health-check/v1/health-check");
57
+ const data = await client.tenantRequest(resolvedTenantId, HEALTH_PATH);
37
58
  return jsonResult(data);
38
59
  }));
60
+ // Bulk health tool: only useful for partner/org callers who manage multiple tenants
61
+ if (tenantResolver.getIdentity().idType !== "tenant") {
62
+ server.registerTool("sophos_list_account_health", {
63
+ title: "List Account Health for All Tenants",
64
+ description: `Fetch account health scores for all managed tenants in parallel and return a ranked summary.
65
+
66
+ Use this when you need to compare health across tenants or find tenants with the lowest
67
+ scores. Much faster than calling sophos_get_account_health per tenant — fetches all
68
+ tenants concurrently server-side in a single tool call.
69
+
70
+ Results are sorted by overall score ascending (lowest/worst first).
71
+ Tenants with no health data (no enrolled products) are listed last.
72
+
73
+ Args:
74
+ - limit (number, optional): Return only the N lowest-scoring tenants. Useful for
75
+ "show me the 10 worst tenants". Omit to return all tenants.
76
+
77
+ Returns:
78
+ Array of tenants with their health scores and full health detail, sorted worst-first.`,
79
+ inputSchema: {
80
+ limit: z
81
+ .number()
82
+ .int()
83
+ .min(1)
84
+ .max(500)
85
+ .optional()
86
+ .describe("Return only the N lowest-scoring tenants (default: all)."),
87
+ },
88
+ annotations: {
89
+ readOnlyHint: true,
90
+ destructiveHint: false,
91
+ idempotentHint: true,
92
+ openWorldHint: true,
93
+ },
94
+ }, withErrorHandling(async ({ limit }) => {
95
+ const tenants = tenantResolver.getCachedTenants();
96
+ const results = [];
97
+ for (let i = 0; i < tenants.length; i += CONCURRENCY) {
98
+ const batch = tenants.slice(i, i + CONCURRENCY);
99
+ const batchResults = await Promise.all(batch.map(async (tenant) => {
100
+ try {
101
+ const data = await client.tenantRequest(tenant.id, HEALTH_PATH);
102
+ return {
103
+ tenant_id: tenant.id,
104
+ tenant_name: tenant.name,
105
+ overall_score: extractOverallScore(data),
106
+ health: data,
107
+ };
108
+ }
109
+ catch {
110
+ return {
111
+ tenant_id: tenant.id,
112
+ tenant_name: tenant.name,
113
+ overall_score: null,
114
+ health: null,
115
+ };
116
+ }
117
+ }));
118
+ results.push(...batchResults);
119
+ }
120
+ // Sort: lowest score first, null (no data) last
121
+ results.sort((a, b) => {
122
+ if (a.overall_score === null && b.overall_score === null)
123
+ return 0;
124
+ if (a.overall_score === null)
125
+ return 1;
126
+ if (b.overall_score === null)
127
+ return -1;
128
+ return a.overall_score - b.overall_score;
129
+ });
130
+ const limited = limit !== undefined ? results.slice(0, limit) : results;
131
+ return jsonResult({
132
+ total_tenants: tenants.length,
133
+ returned: limited.length,
134
+ tenants: limited,
135
+ });
136
+ }));
137
+ }
39
138
  }
40
139
  //# sourceMappingURL=health.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/tools/health.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAE7D,MAAM,UAAU,mBAAmB,CACjC,MAAiB,EACjB,MAAoB,EACpB,cAA8B;IAE9B,MAAM,CAAC,YAAY,CACjB,2BAA2B,EAC3B;QACE,KAAK,EAAE,2BAA2B;QAClC,WAAW,EAAE;;;;;;;;;;;yEAWsD;QACnE,WAAW,EAAE;YACX,SAAS,EAAE,CAAC;iBACT,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,8CAA8C,CAAC;SAC5D;QACD,WAAW,EAAE;YACX,YAAY,EAAE,IAAI;YAClB,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,IAAI;YACpB,aAAa,EAAE,IAAI;SACpB;KACF,EACD,iBAAiB,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE;QACxC,MAAM,gBAAgB,GAAG,cAAc,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;QACnE,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,aAAa,CACrC,gBAAgB,EAChB,uCAAuC,CACxC,CAAC;QACF,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC,CAAC,CACH,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/tools/health.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "sophos-central-mcp-server",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "MCP server for Sophos Central API - SOC monitoring, endpoint management, and admin automation",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "bin": {
8
- "sophos-central-mcp": "dist/index.js"
8
+ "sophos-central-mcp": "dist/index.js",
9
+ "sophos-central-mcp": "dist/index.js"
9
10
  },
10
11
  "scripts": {
11
12
  "build": "tsc",