@agentwares/agentguard 0.1.6 → 0.1.7
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/CHANGELOG.md +14 -0
- package/dist/cli.js +59 -9
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.js +905 -853
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/server.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,20 @@
|
|
|
3
3
|
`@agentwares/agentguard`, the CLI and MCP proxy. A tag `agentguard-v<version>` publishes the
|
|
4
4
|
GitHub Release for a version with its section below as the notes.
|
|
5
5
|
|
|
6
|
+
## 0.1.7 — 2026-10-07
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
|
|
10
|
+
- **No endless loop on an upstream that repeats its `tools/list` cursor.** The proxy followed
|
|
11
|
+
`nextCursor` with no bound, so an upstream that handed back the cursor it was given (or cycled
|
|
12
|
+
through a few) kept the proxy asking for the same page forever, its tool table growing with
|
|
13
|
+
every answer. It now reads every page to the end, stops at a cursor it has already followed, and
|
|
14
|
+
reads at most 20 pages and 2,000 tools per upstream.
|
|
15
|
+
- **A failed or partial `tools/list` no longer empties an upstream's tools.** If a refresh errors,
|
|
16
|
+
or stops at that ceiling, the proxy keeps the upstream's last good list and logs why
|
|
17
|
+
(`tools/list for "<upstream>" not applied: … ; keeping the last good list (N tools)`). It used
|
|
18
|
+
to drop every tool of that upstream on any `tools/list` error.
|
|
19
|
+
|
|
6
20
|
## 0.1.6 — 2026-10-07
|
|
7
21
|
|
|
8
22
|
### Added
|
package/dist/cli.js
CHANGED
|
@@ -1918,6 +1918,48 @@ function localhostHosts(port) {
|
|
|
1918
1918
|
return [...hosts, ...hosts.map((h) => `${h}:${port}`)];
|
|
1919
1919
|
}
|
|
1920
1920
|
|
|
1921
|
+
// ../../packages/mcp-kit/dist/chunk-M567BWMA.js
|
|
1922
|
+
var LIST_MAX_PAGES = 20;
|
|
1923
|
+
var LIST_MAX_ITEMS = 2e3;
|
|
1924
|
+
async function readAllPages(fetchPage, opts = {}) {
|
|
1925
|
+
const maxPages = opts.maxPages ?? LIST_MAX_PAGES;
|
|
1926
|
+
const maxItems = opts.maxItems ?? LIST_MAX_ITEMS;
|
|
1927
|
+
const method = opts.method ?? "tools/list";
|
|
1928
|
+
const items = [];
|
|
1929
|
+
const followed = /* @__PURE__ */ new Set();
|
|
1930
|
+
let cursor;
|
|
1931
|
+
for (let page = 1; ; page++) {
|
|
1932
|
+
const res = await fetchPage(cursor, page);
|
|
1933
|
+
if (Array.isArray(res.items)) items.push(...res.items);
|
|
1934
|
+
const next = res.nextCursor;
|
|
1935
|
+
const more = typeof next === "string" && next !== "";
|
|
1936
|
+
if (items.length > maxItems) {
|
|
1937
|
+
return {
|
|
1938
|
+
items,
|
|
1939
|
+
pages: page,
|
|
1940
|
+
truncated: {
|
|
1941
|
+
ceiling: "items",
|
|
1942
|
+
reason: `${method} listed more than ${maxItems} items in ${page} page${page === 1 ? "" : "s"}${more ? " and had more" : ""}; at most ${maxItems} are read`
|
|
1943
|
+
}
|
|
1944
|
+
};
|
|
1945
|
+
}
|
|
1946
|
+
if (!more) return { items, pages: page };
|
|
1947
|
+
if (followed.has(next)) return { items, pages: page, repeatedCursor: true };
|
|
1948
|
+
if (page >= maxPages) {
|
|
1949
|
+
return {
|
|
1950
|
+
items,
|
|
1951
|
+
pages: page,
|
|
1952
|
+
truncated: {
|
|
1953
|
+
ceiling: "pages",
|
|
1954
|
+
reason: `${method} had more than ${maxPages} pages (${items.length} items read); at most ${maxPages} pages are read`
|
|
1955
|
+
}
|
|
1956
|
+
};
|
|
1957
|
+
}
|
|
1958
|
+
followed.add(next);
|
|
1959
|
+
cursor = next;
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
|
|
1921
1963
|
// ../../packages/mcp-kit/dist/index.js
|
|
1922
1964
|
import { McpServer as McpServer2 } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
1923
1965
|
async function serveStdio(serverOrOpts) {
|
|
@@ -3557,6 +3599,13 @@ var ProxyRuntime = class {
|
|
|
3557
3599
|
}
|
|
3558
3600
|
}
|
|
3559
3601
|
}
|
|
3602
|
+
/**
|
|
3603
|
+
* Re-read an upstream's tools, every page (mcp-kit's `readAllPages`): at most 20 requests, each
|
|
3604
|
+
* under the upstream's `timeout_ms`, ending at a cursor already followed. It used to follow
|
|
3605
|
+
* `nextCursor` with no bound, so an upstream that echoed its cursor kept the proxy asking for
|
|
3606
|
+
* the same page forever. A refresh that fails, or stops at the 20-page / 2,000-tool ceiling,
|
|
3607
|
+
* changes nothing: the agent keeps the last good list, and the log says why.
|
|
3608
|
+
*/
|
|
3560
3609
|
async refreshTools(name) {
|
|
3561
3610
|
const conn = this.connections.get(name);
|
|
3562
3611
|
if (!conn?.connected) return;
|
|
@@ -3564,22 +3613,23 @@ var ProxyRuntime = class {
|
|
|
3564
3613
|
conn.tools = [];
|
|
3565
3614
|
return;
|
|
3566
3615
|
}
|
|
3616
|
+
const kept = () => `keeping the last good list (${conn.tools.length} tool${conn.tools.length === 1 ? "" : "s"})`;
|
|
3567
3617
|
try {
|
|
3568
|
-
const
|
|
3569
|
-
let cursor;
|
|
3570
|
-
do {
|
|
3618
|
+
const read = await readAllPages(async (cursor) => {
|
|
3571
3619
|
const page = await conn.client.listTools(cursor ? { cursor } : void 0, {
|
|
3572
3620
|
timeout: conn.upstream.timeout_ms
|
|
3573
3621
|
});
|
|
3574
|
-
tools
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3622
|
+
return { items: page.tools, nextCursor: page.nextCursor };
|
|
3623
|
+
});
|
|
3624
|
+
if (read.truncated) {
|
|
3625
|
+
this.log(`tools/list for "${name}" not applied: ${read.truncated.reason}; ${kept()}`);
|
|
3626
|
+
return;
|
|
3627
|
+
}
|
|
3628
|
+
conn.tools = read.items;
|
|
3578
3629
|
} catch (err) {
|
|
3579
3630
|
this.log(
|
|
3580
|
-
`tools/list failed for "${name}": ${err instanceof Error ? err.message : String(err)}`
|
|
3631
|
+
`tools/list failed for "${name}": ${err instanceof Error ? err.message : String(err)}; ${kept()}`
|
|
3581
3632
|
);
|
|
3582
|
-
conn.tools = [];
|
|
3583
3633
|
}
|
|
3584
3634
|
}
|
|
3585
3635
|
rebuildExposed() {
|