@mattral/agent-interface 1.2.0 → 1.2.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/dist/health-summary.d.ts +30 -0
- package/dist/health-summary.d.ts.map +1 -0
- package/dist/health-summary.js +38 -0
- package/dist/health-summary.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +26 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +37 -0
- package/dist/server.js.map +1 -0
- package/dist/tools.d.ts +5 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +100 -0
- package/dist/tools.js.map +1 -0
- package/package.json +5 -4
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type ErrorCategorySummary, type HealthScore, type Server } from "@mattral/core";
|
|
2
|
+
import type { ReliabilityStore } from "@mattral/storage";
|
|
3
|
+
export interface AgentHealthSummary {
|
|
4
|
+
reachable: boolean | null;
|
|
5
|
+
healthScore: HealthScore | null;
|
|
6
|
+
unresolvedAlertCount: number;
|
|
7
|
+
recentDriftCount: number;
|
|
8
|
+
recentHighSeverityDriftCount: number;
|
|
9
|
+
/** Classified breakdown of proxy-observed failures in the trailing window. Empty if there were none. */
|
|
10
|
+
errorSummary: ErrorCategorySummary[];
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Computes reachability + a trailing-window tool health score for a
|
|
14
|
+
* server, the same shape of computation `@mattral/server`'s
|
|
15
|
+
* `/api/servers/:id/health` endpoint and the CLI's `report` command both
|
|
16
|
+
* do — but deliberately **read-only**: it never calls
|
|
17
|
+
* `store.recordHealthScore`.
|
|
18
|
+
*
|
|
19
|
+
* This is not the same kind of duplication `decisions/0006` and `0008`
|
|
20
|
+
* accept for lack of a better option — it's an intentional behavioral
|
|
21
|
+
* difference. `report` runs are human- or cron-initiated, at a bounded
|
|
22
|
+
* frequency; an agent deciding "should I use this tool" might query this
|
|
23
|
+
* before *every* tool call, automatically, at a frequency nothing else in
|
|
24
|
+
* this project produces. Persisting a snapshot on every such read would
|
|
25
|
+
* give the `health_scores` table (and the dashboard's history chart) a
|
|
26
|
+
* completely different write profile than intended — see
|
|
27
|
+
* `decisions/0011-agent-interface-design.md`.
|
|
28
|
+
*/
|
|
29
|
+
export declare function computeAgentHealthSummary(store: ReliabilityStore, server: Server, windowMs: number): AgentHealthSummary;
|
|
30
|
+
//# sourceMappingURL=health-summary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health-summary.d.ts","sourceRoot":"","sources":["../src/health-summary.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgD,KAAK,oBAAoB,EAAE,KAAK,WAAW,EAAE,KAAK,MAAM,EAAE,MAAM,eAAe,CAAC;AACvI,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAIzD,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,OAAO,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,WAAW,GAAG,IAAI,CAAC;IAChC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,gBAAgB,EAAE,MAAM,CAAC;IACzB,4BAA4B,EAAE,MAAM,CAAC;IACrC,wGAAwG;IACxG,YAAY,EAAE,oBAAoB,EAAE,CAAC;CACtC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,gBAAgB,EACvB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,kBAAkB,CAuBpB"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { computeHealthScore, summarizeErrorCategories } from "@mattral/core";
|
|
2
|
+
const HEALTH_CHECK_TOOL_NAME = "__health_check__";
|
|
3
|
+
/**
|
|
4
|
+
* Computes reachability + a trailing-window tool health score for a
|
|
5
|
+
* server, the same shape of computation `@mattral/server`'s
|
|
6
|
+
* `/api/servers/:id/health` endpoint and the CLI's `report` command both
|
|
7
|
+
* do — but deliberately **read-only**: it never calls
|
|
8
|
+
* `store.recordHealthScore`.
|
|
9
|
+
*
|
|
10
|
+
* This is not the same kind of duplication `decisions/0006` and `0008`
|
|
11
|
+
* accept for lack of a better option — it's an intentional behavioral
|
|
12
|
+
* difference. `report` runs are human- or cron-initiated, at a bounded
|
|
13
|
+
* frequency; an agent deciding "should I use this tool" might query this
|
|
14
|
+
* before *every* tool call, automatically, at a frequency nothing else in
|
|
15
|
+
* this project produces. Persisting a snapshot on every such read would
|
|
16
|
+
* give the `health_scores` table (and the dashboard's history chart) a
|
|
17
|
+
* completely different write profile than intended — see
|
|
18
|
+
* `decisions/0011-agent-interface-design.md`.
|
|
19
|
+
*/
|
|
20
|
+
export function computeAgentHealthSummary(store, server, windowMs) {
|
|
21
|
+
const windowEnd = Date.now();
|
|
22
|
+
const windowStart = windowEnd - windowMs;
|
|
23
|
+
const mostRecentCheck = store.listExecutions({ serverId: server.id, toolName: HEALTH_CHECK_TOOL_NAME, limit: 1 })[0];
|
|
24
|
+
const reachable = mostRecentCheck ? mostRecentCheck.success : null;
|
|
25
|
+
const proxyExecutions = store
|
|
26
|
+
.listExecutions({ serverId: server.id, since: windowStart, until: windowEnd, limit: 10_000 })
|
|
27
|
+
.filter((e) => e.source === "proxy");
|
|
28
|
+
const driftEvents = store.listDriftEvents({ serverId: server.id, since: windowStart });
|
|
29
|
+
const healthScore = proxyExecutions.length > 0
|
|
30
|
+
? computeHealthScore({ serverId: server.id, windowStart, windowEnd, executions: proxyExecutions, driftEvents })
|
|
31
|
+
: null;
|
|
32
|
+
const unresolvedAlertCount = store.listAlerts({ serverId: server.id, onlyUnresolved: true }).length;
|
|
33
|
+
const recentDriftCount = driftEvents.length;
|
|
34
|
+
const recentHighSeverityDriftCount = driftEvents.filter((e) => e.severity === "high").length;
|
|
35
|
+
const errorSummary = summarizeErrorCategories(proxyExecutions);
|
|
36
|
+
return { reachable, healthScore, unresolvedAlertCount, recentDriftCount, recentHighSeverityDriftCount, errorSummary };
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=health-summary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health-summary.js","sourceRoot":"","sources":["../src/health-summary.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,wBAAwB,EAA4D,MAAM,eAAe,CAAC;AAGvI,MAAM,sBAAsB,GAAG,kBAAkB,CAAC;AAYlD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,yBAAyB,CACvC,KAAuB,EACvB,MAAc,EACd,QAAgB;IAEhB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC7B,MAAM,WAAW,GAAG,SAAS,GAAG,QAAQ,CAAC;IAEzC,MAAM,eAAe,GAAG,KAAK,CAAC,cAAc,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,sBAAsB,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACrH,MAAM,SAAS,GAAG,eAAe,CAAC,CAAC,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;IAEnE,MAAM,eAAe,GAAG,KAAK;SAC1B,cAAc,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;SAC5F,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC;IACvC,MAAM,WAAW,GAAG,KAAK,CAAC,eAAe,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;IAEvF,MAAM,WAAW,GACf,eAAe,CAAC,MAAM,GAAG,CAAC;QACxB,CAAC,CAAC,kBAAkB,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,EAAE,WAAW,EAAE,CAAC;QAC/G,CAAC,CAAC,IAAI,CAAC;IAEX,MAAM,oBAAoB,GAAG,KAAK,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;IACpG,MAAM,gBAAgB,GAAG,WAAW,CAAC,MAAM,CAAC;IAC5C,MAAM,4BAA4B,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,MAAM,CAAC;IAC7F,MAAM,YAAY,GAAG,wBAAwB,CAAC,eAAe,CAAC,CAAC;IAE/D,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,4BAA4B,EAAE,YAAY,EAAE,CAAC;AACxH,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import type { ReliabilityStore } from "@mattral/storage";
|
|
3
|
+
export interface CreateAgentServerOptions {
|
|
4
|
+
name?: string;
|
|
5
|
+
version?: string;
|
|
6
|
+
}
|
|
7
|
+
/** Builds (but does not connect) an MCP server exposing mcp-reliable's own data. Connect it to whatever transport fits — stdio via `runAgentServerOnStdio` below, or an in-memory transport for tests. */
|
|
8
|
+
export declare function createAgentServer(store: ReliabilityStore, options?: CreateAgentServerOptions): McpServer;
|
|
9
|
+
/**
|
|
10
|
+
* Runs the agent-facing MCP interface over stdio until the client
|
|
11
|
+
* disconnects — the shape the CLI's `mcp` command needs. Kept here rather
|
|
12
|
+
* than duplicated in `packages/cli` so that package doesn't need a direct
|
|
13
|
+
* `@modelcontextprotocol/sdk` dependency of its own; see
|
|
14
|
+
* `decisions/0011-agent-interface-design.md`.
|
|
15
|
+
*
|
|
16
|
+
* `server.connect(transport)` resolves once the initial handshake
|
|
17
|
+
* completes, not when the session ends — awaiting only that (an earlier
|
|
18
|
+
* version of this function did exactly that) let the CLI's `finally {
|
|
19
|
+
* store.close() }` run immediately after connecting, before any tool call
|
|
20
|
+
* had a chance to execute. This waits for the underlying `Server`'s
|
|
21
|
+
* `onclose` callback (fired once, for any reason the connection ends,
|
|
22
|
+
* including an explicit `close()`) so the promise doesn't resolve until
|
|
23
|
+
* the client actually disconnects.
|
|
24
|
+
*/
|
|
25
|
+
export declare function runAgentServerOnStdio(store: ReliabilityStore): Promise<void>;
|
|
26
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAGzD,MAAM,WAAW,wBAAwB;IACvC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,0MAA0M;AAC1M,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,gBAAgB,EAAE,OAAO,GAAE,wBAA6B,GAAG,SAAS,CAO5G;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,qBAAqB,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAQlF"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { registerAgentTools } from "./tools.js";
|
|
4
|
+
/** Builds (but does not connect) an MCP server exposing mcp-reliable's own data. Connect it to whatever transport fits — stdio via `runAgentServerOnStdio` below, or an in-memory transport for tests. */
|
|
5
|
+
export function createAgentServer(store, options = {}) {
|
|
6
|
+
const server = new McpServer({
|
|
7
|
+
name: options.name ?? "mcp-reliable",
|
|
8
|
+
version: options.version ?? "1.0.0"
|
|
9
|
+
});
|
|
10
|
+
registerAgentTools(server, store);
|
|
11
|
+
return server;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Runs the agent-facing MCP interface over stdio until the client
|
|
15
|
+
* disconnects — the shape the CLI's `mcp` command needs. Kept here rather
|
|
16
|
+
* than duplicated in `packages/cli` so that package doesn't need a direct
|
|
17
|
+
* `@modelcontextprotocol/sdk` dependency of its own; see
|
|
18
|
+
* `decisions/0011-agent-interface-design.md`.
|
|
19
|
+
*
|
|
20
|
+
* `server.connect(transport)` resolves once the initial handshake
|
|
21
|
+
* completes, not when the session ends — awaiting only that (an earlier
|
|
22
|
+
* version of this function did exactly that) let the CLI's `finally {
|
|
23
|
+
* store.close() }` run immediately after connecting, before any tool call
|
|
24
|
+
* had a chance to execute. This waits for the underlying `Server`'s
|
|
25
|
+
* `onclose` callback (fired once, for any reason the connection ends,
|
|
26
|
+
* including an explicit `close()`) so the promise doesn't resolve until
|
|
27
|
+
* the client actually disconnects.
|
|
28
|
+
*/
|
|
29
|
+
export async function runAgentServerOnStdio(store) {
|
|
30
|
+
const server = createAgentServer(store);
|
|
31
|
+
const transport = new StdioServerTransport();
|
|
32
|
+
await server.connect(transport);
|
|
33
|
+
await new Promise((resolve) => {
|
|
34
|
+
server.server.onclose = resolve;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAOhD,0MAA0M;AAC1M,MAAM,UAAU,iBAAiB,CAAC,KAAuB,EAAE,UAAoC,EAAE;IAC/F,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,cAAc;QACpC,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,OAAO;KACpC,CAAC,CAAC;IACH,kBAAkB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAClC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,KAAuB;IACjE,MAAM,MAAM,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;IACxC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEhC,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QAClC,MAAM,CAAC,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC;IAClC,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/tools.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import type { ReliabilityStore } from "@mattral/storage";
|
|
3
|
+
/** Registers every mcp-reliable agent-facing tool on `server`, reading from `store`. Kept as a plain function (not a class) so it can be called once per MCP session by the CLI's `mcp` command, or reused directly by tests via InMemoryTransport. */
|
|
4
|
+
export declare function registerAgentTools(server: McpServer, store: ReliabilityStore): void;
|
|
5
|
+
//# sourceMappingURL=tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAazD,uPAAuP;AACvP,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAqHnF"}
|
package/dist/tools.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { buildRecommendation } from "@mattral/core";
|
|
3
|
+
import { computeAgentHealthSummary } from "./health-summary.js";
|
|
4
|
+
const DEFAULT_WINDOW_MS = 3_600_000; // 1h, matching `monitor --window`'s default
|
|
5
|
+
function textResult(value) {
|
|
6
|
+
return { content: [{ type: "text", text: JSON.stringify(value) }] };
|
|
7
|
+
}
|
|
8
|
+
function errorResult(message) {
|
|
9
|
+
return { content: [{ type: "text", text: message }], isError: true };
|
|
10
|
+
}
|
|
11
|
+
/** Registers every mcp-reliable agent-facing tool on `server`, reading from `store`. Kept as a plain function (not a class) so it can be called once per MCP session by the CLI's `mcp` command, or reused directly by tests via InMemoryTransport. */
|
|
12
|
+
export function registerAgentTools(server, store) {
|
|
13
|
+
server.registerTool("list_servers", {
|
|
14
|
+
description: "List every MCP server mcp-reliable is currently tracking, with its id, name, tags, and transport type. Use the returned id with the other tools.",
|
|
15
|
+
inputSchema: {}
|
|
16
|
+
}, async () => {
|
|
17
|
+
const servers = store.listServers().map((s) => ({
|
|
18
|
+
id: s.id,
|
|
19
|
+
name: s.name,
|
|
20
|
+
tags: s.tags,
|
|
21
|
+
transportType: s.transport.type
|
|
22
|
+
}));
|
|
23
|
+
return textResult({ servers });
|
|
24
|
+
});
|
|
25
|
+
server.registerTool("get_server_health", {
|
|
26
|
+
description: "Get the current reachability and tool health score for one server. Reachability reflects the most recent health check; healthScore (0-100, null if no traffic yet) reflects real tool calls observed via `mcp-reliable proxy` over the trailing window. Also includes errorSummary: a classified breakdown of recent failures (e.g. rate-limit, auth, timeout) by likely cause, sorted by frequency, to help decide whether an issue is worth working around before falling back to another tool.",
|
|
27
|
+
inputSchema: {
|
|
28
|
+
serverId: z.string().describe("A server id from list_servers"),
|
|
29
|
+
windowMs: z.number().int().positive().optional().describe("Trailing window in milliseconds (default 1h)")
|
|
30
|
+
}
|
|
31
|
+
}, async ({ serverId, windowMs }) => {
|
|
32
|
+
const server = store.getServer(serverId);
|
|
33
|
+
if (!server)
|
|
34
|
+
return errorResult(`No server registered with id "${serverId}".`);
|
|
35
|
+
const summary = computeAgentHealthSummary(store, server, windowMs ?? DEFAULT_WINDOW_MS);
|
|
36
|
+
return textResult({ serverId, ...summary });
|
|
37
|
+
});
|
|
38
|
+
server.registerTool("list_drift_events", {
|
|
39
|
+
description: "List detected schema, output-shape, or statistical (e.g. latency distribution) changes for one server — a tool's contract or behavior changing out from under callers.",
|
|
40
|
+
inputSchema: {
|
|
41
|
+
serverId: z.string().describe("A server id from list_servers"),
|
|
42
|
+
sinceMs: z.number().int().nonnegative().optional().describe("Only events at/after this epoch-ms timestamp"),
|
|
43
|
+
limit: z.number().int().positive().max(500).optional()
|
|
44
|
+
}
|
|
45
|
+
}, async ({ serverId, sinceMs, limit }) => {
|
|
46
|
+
if (!store.getServer(serverId))
|
|
47
|
+
return errorResult(`No server registered with id "${serverId}".`);
|
|
48
|
+
const driftEvents = store.listDriftEvents({ serverId, since: sinceMs, limit });
|
|
49
|
+
return textResult({ serverId, driftEvents });
|
|
50
|
+
});
|
|
51
|
+
server.registerTool("list_alerts", {
|
|
52
|
+
description: "List reliability alerts (unreachable, health-degradation, drift) recorded for one server.",
|
|
53
|
+
inputSchema: {
|
|
54
|
+
serverId: z.string().describe("A server id from list_servers"),
|
|
55
|
+
onlyUnresolved: z.boolean().optional().describe("If true, only currently-open alerts")
|
|
56
|
+
}
|
|
57
|
+
}, async ({ serverId, onlyUnresolved }) => {
|
|
58
|
+
if (!store.getServer(serverId))
|
|
59
|
+
return errorResult(`No server registered with id "${serverId}".`);
|
|
60
|
+
const alerts = store.listAlerts({ serverId, onlyUnresolved });
|
|
61
|
+
return textResult({ serverId, alerts });
|
|
62
|
+
});
|
|
63
|
+
server.registerTool("get_recommendation", {
|
|
64
|
+
description: "Get a should-I-use-this-right-now verdict (avoid/caution/healthy/unknown) for one server, synthesized from its current reachability, tool health score, and recent drift.",
|
|
65
|
+
inputSchema: {
|
|
66
|
+
serverId: z.string().describe("A server id from list_servers"),
|
|
67
|
+
windowMs: z.number().int().positive().optional().describe("Trailing window in milliseconds (default 1h)")
|
|
68
|
+
}
|
|
69
|
+
}, async ({ serverId, windowMs }) => {
|
|
70
|
+
const server = store.getServer(serverId);
|
|
71
|
+
if (!server)
|
|
72
|
+
return errorResult(`No server registered with id "${serverId}".`);
|
|
73
|
+
const summary = computeAgentHealthSummary(store, server, windowMs ?? DEFAULT_WINDOW_MS);
|
|
74
|
+
const recommendation = buildRecommendation({
|
|
75
|
+
reachable: summary.reachable,
|
|
76
|
+
healthScore: summary.healthScore?.score ?? null,
|
|
77
|
+
recentHighSeverityDrift: summary.recentHighSeverityDriftCount > 0
|
|
78
|
+
});
|
|
79
|
+
return textResult({ serverId, ...recommendation });
|
|
80
|
+
});
|
|
81
|
+
server.registerTool("list_recommendations", {
|
|
82
|
+
description: "Get a should-I-use-this-right-now verdict for every tracked server in one call — the fastest way for an agent to decide which of several available MCP servers to route a task to.",
|
|
83
|
+
inputSchema: {
|
|
84
|
+
windowMs: z.number().int().positive().optional().describe("Trailing window in milliseconds (default 1h)")
|
|
85
|
+
}
|
|
86
|
+
}, async ({ windowMs }) => {
|
|
87
|
+
const servers = store.listServers();
|
|
88
|
+
const recommendations = servers.map((server) => {
|
|
89
|
+
const summary = computeAgentHealthSummary(store, server, windowMs ?? DEFAULT_WINDOW_MS);
|
|
90
|
+
const recommendation = buildRecommendation({
|
|
91
|
+
reachable: summary.reachable,
|
|
92
|
+
healthScore: summary.healthScore?.score ?? null,
|
|
93
|
+
recentHighSeverityDrift: summary.recentHighSeverityDriftCount > 0
|
|
94
|
+
});
|
|
95
|
+
return { serverId: server.id, serverName: server.name, ...recommendation };
|
|
96
|
+
});
|
|
97
|
+
return textResult({ recommendations });
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEpD,OAAO,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAEhE,MAAM,iBAAiB,GAAG,SAAS,CAAC,CAAC,4CAA4C;AAEjF,SAAS,UAAU,CAAC,KAAc;IAChC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;AAC/E,CAAC;AAED,SAAS,WAAW,CAAC,OAAe;IAClC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAChF,CAAC;AAED,uPAAuP;AACvP,MAAM,UAAU,kBAAkB,CAAC,MAAiB,EAAE,KAAuB;IAC3E,MAAM,CAAC,YAAY,CACjB,cAAc,EACd;QACE,WAAW,EACT,kJAAkJ;QACpJ,WAAW,EAAE,EAAE;KAChB,EACD,KAAK,IAAI,EAAE;QACT,MAAM,OAAO,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC9C,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,aAAa,EAAE,CAAC,CAAC,SAAS,CAAC,IAAI;SAChC,CAAC,CAAC,CAAC;QACJ,OAAO,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;IACjC,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,mBAAmB,EACnB;QACE,WAAW,EACT,meAAme;QACre,WAAW,EAAE;YACX,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;YAC9D,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8CAA8C,CAAC;SAC1G;KACF,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE;QAC/B,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACzC,IAAI,CAAC,MAAM;YAAE,OAAO,WAAW,CAAC,iCAAiC,QAAQ,IAAI,CAAC,CAAC;QAC/E,MAAM,OAAO,GAAG,yBAAyB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,IAAI,iBAAiB,CAAC,CAAC;QACxF,OAAO,UAAU,CAAC,EAAE,QAAQ,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;IAC9C,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,mBAAmB,EACnB;QACE,WAAW,EACT,wKAAwK;QAC1K,WAAW,EAAE;YACX,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;YAC9D,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8CAA8C,CAAC;YAC3G,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;SACvD;KACF,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE;QACrC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC;YAAE,OAAO,WAAW,CAAC,iCAAiC,QAAQ,IAAI,CAAC,CAAC;QAClG,MAAM,WAAW,GAAG,KAAK,CAAC,eAAe,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QAC/E,OAAO,UAAU,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC;IAC/C,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,aAAa,EACb;QACE,WAAW,EAAE,2FAA2F;QACxG,WAAW,EAAE;YACX,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;YAC9D,cAAc,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qCAAqC,CAAC;SACvF;KACF,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,cAAc,EAAE,EAAE,EAAE;QACrC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC;YAAE,OAAO,WAAW,CAAC,iCAAiC,QAAQ,IAAI,CAAC,CAAC;QAClG,MAAM,MAAM,GAAG,KAAK,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC,CAAC;QAC9D,OAAO,UAAU,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IAC1C,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,oBAAoB,EACpB;QACE,WAAW,EACT,2KAA2K;QAC7K,WAAW,EAAE;YACX,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;YAC9D,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8CAA8C,CAAC;SAC1G;KACF,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE;QAC/B,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACzC,IAAI,CAAC,MAAM;YAAE,OAAO,WAAW,CAAC,iCAAiC,QAAQ,IAAI,CAAC,CAAC;QAC/E,MAAM,OAAO,GAAG,yBAAyB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,IAAI,iBAAiB,CAAC,CAAC;QACxF,MAAM,cAAc,GAAG,mBAAmB,CAAC;YACzC,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,KAAK,IAAI,IAAI;YAC/C,uBAAuB,EAAE,OAAO,CAAC,4BAA4B,GAAG,CAAC;SAClE,CAAC,CAAC;QACH,OAAO,UAAU,CAAC,EAAE,QAAQ,EAAE,GAAG,cAAc,EAAE,CAAC,CAAC;IACrD,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,sBAAsB,EACtB;QACE,WAAW,EACT,oLAAoL;QACtL,WAAW,EAAE;YACX,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8CAA8C,CAAC;SAC1G;KACF,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;QACrB,MAAM,OAAO,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;QACpC,MAAM,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;YAC7C,MAAM,OAAO,GAAG,yBAAyB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,IAAI,iBAAiB,CAAC,CAAC;YACxF,MAAM,cAAc,GAAG,mBAAmB,CAAC;gBACzC,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,KAAK,IAAI,IAAI;gBAC/C,uBAAuB,EAAE,OAAO,CAAC,4BAA4B,GAAG,CAAC;aAClE,CAAC,CAAC;YACH,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,IAAI,EAAE,GAAG,cAAc,EAAE,CAAC;QAC7E,CAAC,CAAC,CAAC;QACH,OAAO,UAAU,CAAC,EAAE,eAAe,EAAE,CAAC,CAAC;IACzC,CAAC,CACF,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mattral/agent-interface",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "Agent-facing MCP interface exposing mcp-reliable's own health, drift, and recommendation data as MCP tools",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -40,11 +40,12 @@
|
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|
|
42
42
|
"build": "tsc -b",
|
|
43
|
-
"clean": "rimraf dist *.tsbuildinfo"
|
|
43
|
+
"clean": "rimraf dist *.tsbuildinfo",
|
|
44
|
+
"prepublishOnly": "npm run build"
|
|
44
45
|
},
|
|
45
46
|
"dependencies": {
|
|
46
|
-
"@mattral/core": "^1.
|
|
47
|
-
"@mattral/storage": "^1.
|
|
47
|
+
"@mattral/core": "^1.2.1",
|
|
48
|
+
"@mattral/storage": "^1.2.1",
|
|
48
49
|
"@modelcontextprotocol/sdk": "^1.32.2",
|
|
49
50
|
"zod": "^4.6.7"
|
|
50
51
|
},
|