Public: anyone can read this; the crew can change it.
MCP tools/list has 3 KB of headroom: the longest tool descriptions say the same in fewer words #4185
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/4162-mcp-tools-list-has-3-kb-of-headroom-the → main 6 commits fork 5 threads · 5 unresolved
2 files
changed +88
−87
src/http/mcp.ts +81 −86
| @@ -294,11 +294,9 @@ function chipArgs(ctx: Ctx, args: Record<string, unknown>) { | ||
| 294 | 294 | |
| 295 | 295 | const str = (v: unknown): string => (typeof v === "string" ? v.trim() : ""); |
| 296 | 296 | |
| 297 | const REPO_ARG = { | |
| 298 | type: "string", | |
| 299 | } as const; | |
| 297 | const REPO_ARG = { type: "string" } as const; | |
| 300 | 298 | |
| 301 | /** A repository the caller may read, by `owner/name`. */ | |
| 299 | /** A repository the caller may read, by `owner/name`; a wrong one is answered with that form. */ | |
| 302 | 300 | function repoArg(ctx: Ctx, user: User, args: Args): Repo | Answer { |
| 303 | 301 | const [owner, name, ...rest] = str(args["repo"]).split("/"); |
| 304 | 302 | const repo = |
| @@ -382,10 +380,7 @@ function lean(schema: unknown): unknown { | ||
| 382 | 380 | ); |
| 383 | 381 | } |
| 384 | 382 | |
| 385 | const APP_ARG = { | |
| 386 | type: "string", | |
| 387 | description: "owner/name", | |
| 388 | } as const; | |
| 383 | const APP_ARG = { type: "string" } as const; | |
Not blocking: with the |
||
| 389 | 384 | |
| 390 | 385 | // A child's claim link is a live secret: whoever holds it takes the child. |
| 391 | 386 | // It stays out of an agent's conversation unless asked for there on purpose |
| @@ -433,7 +428,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 433 | 428 | { |
| 434 | 429 | name: "sizes", |
| 435 | 430 | description: |
| 436 | "What a child forge's sizes mean: small, medium and large, with CPU, memory and disk.", | |
| 431 | "What a child forge's sizes mean: small, medium and large, each with CPU, memory and disk.", | |
| 437 | 432 | inputSchema: { type: "object", properties: {} }, |
| 438 | 433 | writes: false, |
| 439 | 434 | run: () => good(sizesView()), |
| @@ -441,7 +436,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 441 | 436 | { |
| 442 | 437 | name: "apps", |
| 443 | 438 | description: |
| 444 | "The apps you can see: whether each is live, where it is served, how it runs itself, what is working.", | |
| 439 | "The apps on this forge you can see: live or not, where served, how each runs itself, what is working.", | |
| 445 | 440 | inputSchema: { type: "object", properties: {} }, |
| 446 | 441 | writes: false, |
| 447 | 442 | async run(ctx, user) { |
| @@ -530,7 +525,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 530 | 525 | { |
| 531 | 526 | name: "repo", |
| 532 | 527 | description: |
| 533 | "One repository you can read: name, description, visibility, autonomy, `audience`, `provenance`. Same as GET /api/v1/repos/:owner/:name.", | |
| 528 | "One repository you can read, as GET /api/v1/repos/:owner/:name.", | |
| 534 | 529 | inputSchema: { |
| 535 | 530 | type: "object", |
| 536 | 531 | properties: { repo: REPO_ARG }, |
| @@ -584,7 +579,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 584 | 579 | { |
| 585 | 580 | name: "tell", |
| 586 | 581 | description: |
| 587 | "Tell an app's crew what should change (first line is the title); a builder starts next tick. Without `repo` nothing is built: kept for the forge, returning a thought id.", | |
| 582 | "Tell an app's crew what should change (first line is the title). Without `repo` it is only kept, answering a thought id.", | |
| 588 | 583 | inputSchema: { |
| 589 | 584 | type: "object", |
| 590 | 585 | properties: { |
| @@ -663,7 +658,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 663 | 658 | { |
| 664 | 659 | name: "share", |
| 665 | 660 | description: |
| 666 | "Share a feed item. With no `to` it goes to the app's crew and owners, else to its followers; a daily budget applies.", | |
| 661 | "Share a feed item. With no `to` it goes to the app's crew and owners, else to its followers; daily budget each.", | |
| 667 | 662 | inputSchema: { |
| 668 | 663 | type: "object", |
| 669 | 664 | properties: { |
| @@ -690,7 +685,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 690 | 685 | { |
| 691 | 686 | name: "say", |
| 692 | 687 | description: |
| 693 | "Say something on an issue or a pull. A working builder hears it as its next step; otherwise it is feedback for the next run.", | |
| 688 | "Say something on an issue or a pull. A working builder hears it next; otherwise it is feedback for the next run.", | |
| 694 | 689 | inputSchema: { |
| 695 | 690 | type: "object", |
| 696 | 691 | properties: { |
| @@ -722,7 +717,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 722 | 717 | { |
| 723 | 718 | name: "issue", |
| 724 | 719 | description: |
| 725 | "Read one issue with its comments, `blockedBy` and `blocks`. For a crew agent, text by non-writers carries `untrusted: true`, as in the REST API. Issues you cannot see are not found.", | |
| 720 | "Read one issue with its comments, `blockedBy` and `blocks`. A crew agent sees `untrusted: true` on text by non-writers.", | |
| 726 | 721 | inputSchema: { |
| 727 | 722 | type: "object", |
| 728 | 723 | properties: { |
| @@ -793,7 +788,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 793 | 788 | { |
| 794 | 789 | name: "pull", |
| 795 | 790 | description: |
| 796 | "Read a pull: title, state, head, base, and for an open pull `mergeable`, `conflicts`, `proposal`, `checkStale` and `check`.", | |
| 791 | "Read a pull: title, state, head, base, and when open `mergeable`, `conflicts`, `proposal`, `checkStale`, `check`.", | |
| 797 | 792 | inputSchema: { |
| 798 | 793 | type: "object", |
| 799 | 794 | properties: { |
| @@ -836,7 +831,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 836 | 831 | { |
| 837 | 832 | name: "pulls", |
| 838 | 833 | description: |
| 839 | "A repository's pulls, briefly, newest first, with check, review counts and mergeable. `state` open (default) or closed; `limit` 1-50 (default 20).", | |
| 834 | "A repository's pulls, newest first, briefly. `state` open (default) or closed; `limit` 1-50 (default 20).", | |
| 840 | 835 | inputSchema: { |
| 841 | 836 | type: "object", |
| 842 | 837 | properties: { |
| @@ -880,7 +875,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 880 | 875 | { |
| 881 | 876 | name: "variant", |
| 882 | 877 | description: |
| 883 | "Like or dislike one pull among its variant siblings; a later vote replaces it. A dislike closes the pull with `reason` (one line).", | |
| 878 | "Like or dislike one pull among its variants; a later vote replaces it. A dislike closes it with `reason`.", | |
| 884 | 879 | inputSchema: { |
| 885 | 880 | type: "object", |
| 886 | 881 | properties: { |
| @@ -921,7 +916,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 921 | 916 | { |
| 922 | 917 | name: "edit", |
| 923 | 918 | description: |
| 924 | "Give an issue or pull a new title or body: your own, or anyone's where you write; an agent edits only what it wrote.", | |
| 919 | "Give an issue or a pull a new title or body: your own, or anyone's where you write; an agent edits only its own.", | |
| 925 | 920 | inputSchema: { |
| 926 | 921 | type: "object", |
| 927 | 922 | properties: { |
| @@ -1013,7 +1008,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 1013 | 1008 | { |
| 1014 | 1009 | name: "read_file", |
| 1015 | 1010 | description: |
| 1016 | "Read a file, or list a directory, of a repository at a ref (default branch); over 5 MB answers tooLarge, a binary one base64.", | |
| 1011 | "Read a file, or list a directory, of a repository at a ref (default branch); over 5 MB answers tooLarge.", | |
| 1017 | 1012 | inputSchema: { |
| 1018 | 1013 | type: "object", |
| 1019 | 1014 | properties: { |
| @@ -1065,7 +1060,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 1065 | 1060 | { |
| 1066 | 1061 | name: "asks", |
| 1067 | 1062 | description: |
| 1068 | "What waits on you, most consequential first: each row's decision, options, and cost of inaction. Your saved filter (`feed_chips`) applies.", | |
| 1063 | "What waits on you, most consequential first: decision, options, cost of inaction. Your saved filter applies.", | |
| 1069 | 1064 | inputSchema: { type: "object", properties: { ...CHIP_ARGS } }, |
| 1070 | 1065 | writes: false, |
| 1071 | 1066 | run(ctx, user, args) { |
| @@ -1077,14 +1072,14 @@ const TOOLS: readonly Tool[] = [ | ||
| 1077 | 1072 | { |
| 1078 | 1073 | name: "asks_act", |
| 1079 | 1074 | description: |
| 1080 | "Decide many asks at once: dismiss, decline, ship (never undone), close (`reason`), mute, or replan. `items` are ids from `asks`, or `issue:<id>`.", | |
| 1075 | "Decide many asks at once: dismiss, decline, ship (never undone), close (`reason`), mute, replan. `items`: ids from `asks`, or `issue:<id>`.", | |
| 1081 | 1076 | inputSchema: { |
| 1082 | 1077 | type: "object", |
| 1083 | 1078 | properties: { |
| 1084 | 1079 | action: { type: "string", enum: ["dismiss", "decline", "mute", "ship", "close", "replan"] }, |
| 1085 | 1080 | items: { type: "array", items: { type: "string" }, maxItems: 100 }, |
| 1086 | 1081 | reason: { type: "string", maxLength: 300 }, |
| 1087 | dryRun: { type: "boolean", description: "false to apply (default plans)." }, | |
| 1082 | dryRun: { type: "boolean", description: "false to apply" }, | |
| 1088 | 1083 | }, |
| 1089 | 1084 | required: ["action", "items"], |
| 1090 | 1085 | }, |
| @@ -1101,7 +1096,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 1101 | 1096 | { |
| 1102 | 1097 | name: "asks_decide", |
| 1103 | 1098 | description: |
| 1104 | "Let the decider answer a hand-over (`item` is the row's `parked:<id>`). Only a sure set_aside (70%+) takes the card off your board.", | |
| 1099 | "Let the decider answer a hand-over (`item` is the row's `parked:<id>`). Only a sure set_aside (70%+) clears the card.", | |
| 1105 | 1100 | inputSchema: { |
| 1106 | 1101 | type: "object", |
| 1107 | 1102 | properties: { item: { type: "string", maxLength: 80 } }, |
| @@ -1116,7 +1111,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 1116 | 1111 | { |
| 1117 | 1112 | name: "asks_proposal", |
| 1118 | 1113 | description: |
| 1119 | "Act on a wave proposal (an `asks` row with `proposal`): `approve`, `redirect` (`words`), or `later` (until `again`). App owner only.", | |
| 1114 | "Act on a wave proposal (an `asks` row): `approve`, `redirect` (`words`), or `later` (until `again`). Owner only.", | |
| 1120 | 1115 | inputSchema: { |
| 1121 | 1116 | type: "object", |
| 1122 | 1117 | properties: { |
| @@ -1137,7 +1132,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 1137 | 1132 | { |
| 1138 | 1133 | name: "proposal_tokens", |
| 1139 | 1134 | description: |
| 1140 | "Give a child (fork or other forge's project) a propose-only credential: `mint` (`child`, `origin`), `list`, `revoke` (`id`). Writers only.", | |
| 1135 | "Give a child a propose-only credential: `mint` (`child`, `origin`), `list`, `revoke` (`id`). Writers only.", | |
| 1141 | 1136 | inputSchema: { |
| 1142 | 1137 | type: "object", |
| 1143 | 1138 | properties: { |
| @@ -1173,7 +1168,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 1173 | 1168 | { |
| 1174 | 1169 | name: "asks_undecide", |
| 1175 | 1170 | description: |
| 1176 | "Put a card the decider set aside back on your board, within a day of its answer. `id` is the decision's id from `asks_decide`.", | |
| 1171 | "Put a card the decider set aside back on your board, within a day. `id` is from `asks_decide`.", | |
| 1177 | 1172 | inputSchema: { |
| 1178 | 1173 | type: "object", |
| 1179 | 1174 | properties: { id: { type: "string", maxLength: 80 } }, |
| @@ -1188,7 +1183,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 1188 | 1183 | { |
| 1189 | 1184 | name: "seal", |
| 1190 | 1185 | description: |
| 1191 | "Seal or unseal an issue or pull: a sealed one is seen only by people who write the app and its crew. Recorded in the app's activity.", | |
| 1186 | "Seal or unseal an issue or pull: a sealed one is seen only by the app's writers and crew.", | |
| 1192 | 1187 | inputSchema: { |
| 1193 | 1188 | type: "object", |
| 1194 | 1189 | properties: { |
| @@ -1226,7 +1221,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 1226 | 1221 | { |
| 1227 | 1222 | name: "issue_teams", |
| 1228 | 1223 | description: |
| 1229 | "Name the crew teams (design, data-science, security, platform) on an issue: at most two; the closing pull is reviewed once per team.", | |
| 1224 | "Name the crew teams (design, data-science, security, platform) on an issue: at most two; each reviews the closing pull.", | |
| 1230 | 1225 | inputSchema: { |
| 1231 | 1226 | type: "object", |
| 1232 | 1227 | properties: { |
| @@ -1373,7 +1368,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 1373 | 1368 | { |
| 1374 | 1369 | name: "health", |
| 1375 | 1370 | description: |
| 1376 | "How this forge is: version and commit (`dev` from source), whether it is draining, the platform's word on its rollout, and incidents.", | |
| 1371 | "How this forge is: version, commit, draining or not, rollout, incidents.", | |
| 1377 | 1372 | inputSchema: { type: "object", properties: {} }, |
| 1378 | 1373 | writes: false, |
| 1379 | 1374 | run: (ctx, user) => good(readHealth(ctx.app, user)), |
| @@ -1381,7 +1376,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 1381 | 1376 | { |
| 1382 | 1377 | name: "audit", |
| 1383 | 1378 | description: |
| 1384 | "Who can do what, across every app you can see, from each app's contract.json: every resource × verb answered yes, own or no.", | |
| 1379 | "Who can do what across every app you can see, from each contract.json: resource × verb answered yes, own or no.", | |
| 1385 | 1380 | inputSchema: { |
| 1386 | 1381 | type: "object", |
| 1387 | 1382 | properties: { |
| @@ -1435,7 +1430,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 1435 | 1430 | properties: { |
| 1436 | 1431 | username: { type: "string" }, |
| 1437 | 1432 | usdPerMonth: { type: "number", description: "0.01 to 10000; 0 takes it back." }, |
| 1438 | dryRun: { type: "boolean", description: "false to apply (default plans)." }, | |
| 1433 | dryRun: { type: "boolean", description: "false to apply" }, | |
| 1439 | 1434 | }, |
| 1440 | 1435 | required: ["username", "usdPerMonth"], |
| 1441 | 1436 | }, |
| @@ -1481,7 +1476,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 1481 | 1476 | { |
| 1482 | 1477 | name: "mint_invite", |
| 1483 | 1478 | description: |
| 1484 | "Mint a single-use invite link to sign up with; it expires in `days` (1–30, default 7) and is shown once. Person admins only.", | |
| 1479 | "Mint a single-use invite link; it expires in `days` (1–30, default 7) and is shown once. Person admins only.", | |
| 1485 | 1480 | inputSchema: { |
| 1486 | 1481 | type: "object", |
| 1487 | 1482 | properties: { |
| @@ -1509,7 +1504,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 1509 | 1504 | username: { type: "string" }, |
| 1510 | 1505 | role: { type: "string", enum: ["member", "guest"] }, |
| 1511 | 1506 | usdPerMonth: { type: ["number", "null"], description: "0.01 to 10000; omit or null for none." }, |
| 1512 | dryRun: { type: "boolean", description: "false to apply (default plans)." }, | |
| 1507 | dryRun: { type: "boolean", description: "false to apply" }, | |
| 1513 | 1508 | }, |
| 1514 | 1509 | required: ["username", "role"], |
| 1515 | 1510 | }, |
| @@ -1555,7 +1550,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 1555 | 1550 | username: { type: "string" }, |
| 1556 | 1551 | dailyUsd: { type: ["number", "null"], description: "0.01–10000; null with perRunUsd null clears." }, |
| 1557 | 1552 | perRunUsd: { type: ["number", "null"], description: "0.01–10000; null with dailyUsd null clears." }, |
| 1558 | dryRun: { type: "boolean", description: "false to apply (default plans)." }, | |
| 1553 | dryRun: { type: "boolean", description: "false to apply" }, | |
| 1559 | 1554 | }, |
| 1560 | 1555 | required: ["username", "dailyUsd", "perRunUsd"], |
| 1561 | 1556 | }, |
| @@ -1598,7 +1593,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 1598 | 1593 | on: { type: "boolean" }, |
| 1599 | 1594 | dryRun: { |
| 1600 | 1595 | type: "boolean", |
| 1601 | description: "false to apply (default plans).", | |
| 1596 | description: "false to apply", | |
| 1602 | 1597 | }, |
| 1603 | 1598 | }, |
| 1604 | 1599 | required: ["repo"], |
| @@ -1629,7 +1624,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 1629 | 1624 | { |
| 1630 | 1625 | name: "decisions_by", |
| 1631 | 1626 | description: |
| 1632 | "The standing rule for a repository's parked hand-over cards: `me`, `decider`, or `decider_tell`. Without `by`, says how it is set.", | |
| 1627 | "The standing rule for a repository's parked hand-over cards: `me`, `decider`, or `decider_tell`. Without `by`, reads it.", | |
| 1633 | 1628 | inputSchema: { |
| 1634 | 1629 | type: "object", |
| 1635 | 1630 | properties: { |
| @@ -1637,7 +1632,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 1637 | 1632 | by: { type: "string", enum: ["me", "decider", "decider_tell"] }, |
| 1638 | 1633 | dryRun: { |
| 1639 | 1634 | type: "boolean", |
| 1640 | description: "false to apply (default plans).", | |
| 1635 | description: "false to apply", | |
| 1641 | 1636 | }, |
| 1642 | 1637 | }, |
| 1643 | 1638 | required: ["repo"], |
| @@ -1668,7 +1663,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 1668 | 1663 | { |
| 1669 | 1664 | name: "archive", |
| 1670 | 1665 | description: |
| 1671 | "Archive a repository or wake it (`archived` true/false); nothing is deleted. Plans (dryRun false applies); repository admin token.", | |
| 1666 | "Archive a repository or wake it (`archived` true/false); nothing is deleted. Plans first; repository admin token.", | |
| 1672 | 1667 | inputSchema: { |
| 1673 | 1668 | type: "object", |
| 1674 | 1669 | properties: { |
| @@ -1682,7 +1677,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 1682 | 1677 | archived: { type: "boolean" }, |
| 1683 | 1678 | dryRun: { |
| 1684 | 1679 | type: "boolean", |
| 1685 | description: "false to apply (default plans).", | |
| 1680 | description: "false to apply", | |
| 1686 | 1681 | }, |
| 1687 | 1682 | }, |
| 1688 | 1683 | }, |
| @@ -1721,7 +1716,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 1721 | 1716 | properties: { |
| 1722 | 1717 | repo: REPO_ARG, |
| 1723 | 1718 | shown: { type: "boolean" }, |
| 1724 | dryRun: { type: "boolean", description: "false to apply (default plans)." }, | |
| 1719 | dryRun: { type: "boolean", description: "false to apply" }, | |
| 1725 | 1720 | }, |
| 1726 | 1721 | required: ["repo"], |
| 1727 | 1722 | }, |
| @@ -1767,7 +1762,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 1767 | 1762 | { |
| 1768 | 1763 | name: "branches", |
| 1769 | 1764 | description: |
| 1770 | "List a repository's branches, or with `name` and `action` create (from `from`) or delete one; the default branch is never deleted.", | |
| 1765 | "List a repository's branches, or with `name` and `action` create (from `from`) or delete one; never the default.", | |
| 1771 | 1766 | inputSchema: { |
| 1772 | 1767 | type: "object", |
| 1773 | 1768 | properties: { |
| @@ -1850,7 +1845,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 1850 | 1845 | { |
| 1851 | 1846 | name: "probe", |
| 1852 | 1847 | description: |
| 1853 | "Knock on every door of a running app as nobody, a user and an admin, and compare each answer with its contract.json. Writes nothing.", | |
| 1848 | "Try every door of a running app as nobody, a user and an admin against its contract.json. Writes nothing.", | |
| 1854 | 1849 | inputSchema: { |
| 1855 | 1850 | type: "object", |
| 1856 | 1851 | properties: { repo: REPO_ARG }, |
| @@ -1884,7 +1879,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 1884 | 1879 | { |
| 1885 | 1880 | name: "following", |
| 1886 | 1881 | description: |
| 1887 | "Where a fork stands against the repository it follows: in step, behind, ahead or diverged, and the files that need a decision.", | |
| 1882 | "Where a fork stands against what it follows: in step, behind, ahead or diverged, and files needing a decision.", | |
| 1888 | 1883 | inputSchema: { |
| 1889 | 1884 | type: "object", |
| 1890 | 1885 | properties: { repo: REPO_ARG }, |
| @@ -1966,7 +1961,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 1966 | 1961 | }, |
| 1967 | 1962 | dryRun: { |
| 1968 | 1963 | type: "boolean", |
| 1969 | description: "false to apply (default plans).", | |
| 1964 | description: "false to apply", | |
| 1970 | 1965 | }, |
| 1971 | 1966 | reveal: REVEAL_ARG, |
| 1972 | 1967 | }, |
| @@ -1999,7 +1994,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 1999 | 1994 | { |
| 2000 | 1995 | name: "forges", |
| 2001 | 1996 | description: |
| 2002 | "The forges you sent from here (an admin's list): name, address, whom for, apps given, whether claimed, and last activity.", | |
| 1997 | "The forges you sent from here (an admin's list): name, address, whom for, apps, claimed or not, last activity.", | |
| 2003 | 1998 | inputSchema: { type: "object", properties: {} }, |
| 2004 | 1999 | writes: false, |
| 2005 | 2000 | async run(ctx, user) { |
| @@ -2018,7 +2013,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 2018 | 2013 | { |
| 2019 | 2014 | name: "claim_link", |
| 2020 | 2015 | description: |
| 2021 | "A new claim link for an unclaimed child forge; the old one stops at once. Nothing changes unless you send `reveal: true`.", | |
| 2016 | "A new claim link for an unclaimed child forge, only with `reveal: true`; the old one then stops at once. Nothing changes without it.", | |
| 2022 | 2017 | inputSchema: { |
| 2023 | 2018 | type: "object", |
| 2024 | 2019 | properties: { |
| @@ -2040,7 +2035,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 2040 | 2035 | { |
| 2041 | 2036 | name: "take_updates", |
| 2042 | 2037 | description: |
| 2043 | "Take the parent forge's updates into a fork: on a spawned forge they open as one pull; otherwise a fast-forward or clean merge.", | |
| 2038 | "Take the parent forge's updates into a fork: one pull on a spawned forge; otherwise a fast-forward or clean merge.", | |
| 2044 | 2039 | inputSchema: { |
| 2045 | 2040 | type: "object", |
| 2046 | 2041 | properties: { repo: REPO_ARG }, |
| @@ -2092,7 +2087,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 2092 | 2087 | { |
| 2093 | 2088 | name: "sever", |
| 2094 | 2089 | description: |
| 2095 | "Cut a spawned forge's link to the forge its code came from (its `forge` repository's owner only). Nothing is deleted or sent.", | |
| 2090 | "Cut a spawned forge's link to the forge its code came from (its `forge` repository's owner only). Deletes nothing.", | |
| 2096 | 2091 | inputSchema: { |
| 2097 | 2092 | type: "object", |
| 2098 | 2093 | properties: { repo: REPO_ARG }, |
| @@ -2134,7 +2129,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 2134 | 2129 | { |
| 2135 | 2130 | name: "propose_to_parent_forge", |
| 2136 | 2131 | description: |
| 2137 | "Offer this forge's landed change to its parent as a pull on `child/<name>/…`; asking again for the same tip answers with that pull.", | |
| 2132 | "Offer this forge's landed change to its parent as a pull on `child/<name>/…`; the same tip answers with that pull.", | |
| 2138 | 2133 | inputSchema: { |
| 2139 | 2134 | type: "object", |
| 2140 | 2135 | properties: { repo: REPO_ARG }, |
| @@ -2165,7 +2160,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 2165 | 2160 | { |
| 2166 | 2161 | name: "forge_proposals", |
| 2167 | 2162 | description: |
| 2168 | "What this forge proposed to its parent, newest first: pull, number and state there. `reachable` is false if the parent did not answer.", | |
| 2163 | "What this forge proposed to its parent, newest first. `reachable` is false if the parent did not answer.", | |
| 2169 | 2164 | inputSchema: { |
| 2170 | 2165 | type: "object", |
| 2171 | 2166 | properties: { repo: REPO_ARG }, |
| @@ -2182,7 +2177,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 2182 | 2177 | { |
| 2183 | 2178 | name: "converge", |
| 2184 | 2179 | description: |
| 2185 | "Have a fork's crew merge the parent's updates where both sides changed the same files. The result comes back as a pull on the fork.", | |
| 2180 | "Have a fork's crew merge the parent's updates where both sides changed the same files, as a pull on the fork.", | |
| 2186 | 2181 | inputSchema: { |
| 2187 | 2182 | type: "object", |
| 2188 | 2183 | properties: { repo: REPO_ARG }, |
| @@ -2219,7 +2214,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 2219 | 2214 | { |
| 2220 | 2215 | name: "next_steps", |
| 2221 | 2216 | description: |
| 2222 | "On a spawned forge, your first three steps and whether each is done. Empty anywhere else, or for anyone but the forge's owner.", | |
| 2217 | "On a spawned forge, your first three steps and whether each is done. Empty elsewhere or for anyone but its owner.", | |
| 2223 | 2218 | inputSchema: { type: "object", properties: {} }, |
| 2224 | 2219 | writes: false, |
| 2225 | 2220 | async run(ctx, user) { |
| @@ -2230,7 +2225,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 2230 | 2225 | { |
| 2231 | 2226 | name: "thought", |
| 2232 | 2227 | description: |
| 2233 | "Where one of your thoughts went: its id (from `tell` without a repo) answers with the planner's placement and reply.", | |
| 2228 | "Where one of your thoughts went: its id (from `tell` without a repo) answers with the placement and reply.", | |
| 2234 | 2229 | inputSchema: { |
| 2235 | 2230 | type: "object", |
| 2236 | 2231 | properties: { id: { type: "string", maxLength: 64 } }, |
| @@ -2260,7 +2255,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 2260 | 2255 | { |
| 2261 | 2256 | name: "asked", |
| 2262 | 2257 | description: |
| 2263 | "What people asked the crew for, in repositories you can write: by default what has nothing merged yet, oldest first, with closing pulls.", | |
| 2258 | "What people asked the crew for, in repositories you can write: by default what has nothing merged yet, oldest first.", | |
| 2264 | 2259 | inputSchema: { |
| 2265 | 2260 | type: "object", |
| 2266 | 2261 | properties: { |
| @@ -2290,7 +2285,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 2290 | 2285 | { |
| 2291 | 2286 | name: "app_members", |
| 2292 | 2287 | description: |
| 2293 | "The people a private app names: they may enter the app and its previews. Without `members`, the list; with it, plans.", | |
| 2288 | "The people a private app names, who may enter it and its previews. Without `members`, the list; with it, plans.", | |
| 2294 | 2289 | inputSchema: { |
| 2295 | 2290 | type: "object", |
| 2296 | 2291 | properties: { |
| @@ -2421,7 +2416,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 2421 | 2416 | { |
| 2422 | 2417 | name: "feed_chips", |
| 2423 | 2418 | description: |
| 2424 | "The feed chips you switched off, which `feed` and `asks` leave out. With `kind`, `value` and `hidden` it switches one off or on.", | |
| 2419 | "The feed chips you switched off, left out of `feed` and `asks`. With `kind`, `value` and `hidden` it sets one.", | |
| 2425 | 2420 | inputSchema: { |
| 2426 | 2421 | type: "object", |
| 2427 | 2422 | properties: { |
| @@ -2458,7 +2453,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 2458 | 2453 | { |
| 2459 | 2454 | name: "make_it_yours", |
| 2460 | 2455 | description: |
| 2461 | "Make an app you can see yours: a fork of its code and history, following the original; data, secrets, crew, domains are not copied.", | |
| 2456 | "Make an app you can see yours: a fork of its code and history, following the original; nothing else is copied.", | |
| 2462 | 2457 | inputSchema: { |
| 2463 | 2458 | type: "object", |
| 2464 | 2459 | properties: { |
| @@ -2508,7 +2503,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 2508 | 2503 | { |
| 2509 | 2504 | name: "front_page", |
| 2510 | 2505 | description: |
| 2511 | "The forge's front page as a stranger sees it. A site admin also gets the picks, and with `pinned`, `hidden`, `weights` sets them.", | |
| 2506 | "The forge's front page as a stranger sees it. A site admin also gets the picks and sets them with `pinned`, `hidden`, `weights`.", | |
| 2512 | 2507 | inputSchema: { |
| 2513 | 2508 | type: "object", |
| 2514 | 2509 | properties: { |
| @@ -2623,7 +2618,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 2623 | 2618 | { |
| 2624 | 2619 | name: "watch", |
| 2625 | 2620 | description: |
| 2626 | "Watch a milestone, or stop (`watch: false`): its progress shows as one feed item, and your phone is told once, when it lands.", | |
| 2621 | "Watch a milestone, or stop (`watch: false`): progress is one feed item; your phone is told once, when it lands.", | |
| 2627 | 2622 | inputSchema: { |
| 2628 | 2623 | type: "object", |
| 2629 | 2624 | properties: { |
| @@ -2701,7 +2696,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 2701 | 2696 | { |
| 2702 | 2697 | name: "run_log", |
| 2703 | 2698 | description: |
| 2704 | "A run's log, or its last `tail` lines: the same text and the same access as GET /api/v1/repos/:owner/:name/runs/:id/log.", | |
| 2699 | "A run's log, or its last `tail` lines, as GET /api/v1/repos/:owner/:name/runs/:id/log.", | |
| 2705 | 2700 | inputSchema: { |
| 2706 | 2701 | type: "object", |
| 2707 | 2702 | properties: { |
| @@ -2840,7 +2835,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 2840 | 2835 | { |
| 2841 | 2836 | name: "returns", |
| 2842 | 2837 | description: |
| 2843 | "What the crew's tokens bought over the last days (1–90, default 7): dollars, runs by state, changes landed, cost per landed change.", | |
| 2838 | "What the crew's tokens bought over the last days (1–90, default 7): dollars, runs, changes landed, cost per change.", | |
| 2844 | 2839 | inputSchema: { |
| 2845 | 2840 | type: "object", |
| 2846 | 2841 | properties: { |
| @@ -2865,7 +2860,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 2865 | 2860 | { |
| 2866 | 2861 | name: "review", |
| 2867 | 2862 | description: |
| 2868 | "Approve a pull, or request changes with a `reason` (required for changes); approving your own pull is refused as on the page.", | |
| 2863 | "Approve a pull, or request changes with a `reason` (required for changes); your own pull is refused.", | |
| 2869 | 2864 | inputSchema: { |
| 2870 | 2865 | type: "object", |
| 2871 | 2866 | properties: { |
| @@ -2921,7 +2916,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 2921 | 2916 | { |
| 2922 | 2917 | name: "spend", |
| 2923 | 2918 | description: |
| 2924 | "Report what your session spent on an app's work the forge did not run: who, model, tokens and/or dollars, the issue or pull.", | |
| 2919 | "Report what your session spent on an app's work the forge did not run: who, model, tokens and/or dollars, issue or pull.", | |
| 2925 | 2920 | inputSchema: { |
| 2926 | 2921 | type: "object", |
| 2927 | 2922 | properties: { |
| @@ -2950,7 +2945,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 2950 | 2945 | { |
| 2951 | 2946 | name: "usage", |
| 2952 | 2947 | description: |
| 2953 | "What the crew's runs on an app spent over the last days (1–90, default 7): tokens, dollars, time, by agent and issue. Writers only.", | |
| 2948 | "What the crew's runs on an app spent over the last days (1–90, default 7), by agent and issue. Writers only.", | |
| 2954 | 2949 | inputSchema: { |
| 2955 | 2950 | type: "object", |
| 2956 | 2951 | properties: { |
| @@ -2981,7 +2976,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 2981 | 2976 | { |
| 2982 | 2977 | name: "labels", |
| 2983 | 2978 | description: |
| 2984 | "Set the labels of an issue or a pull to exactly these (none clears them): only labels the repository has; writers only.", | |
| 2979 | "Set the labels of an issue or a pull to exactly these (none clears): only the repository's labels; writers only.", | |
| 2985 | 2980 | inputSchema: { |
| 2986 | 2981 | type: "object", |
| 2987 | 2982 | properties: { |
| @@ -3077,7 +3072,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 3077 | 3072 | { |
| 3078 | 3073 | name: "attach_look", |
| 3079 | 3074 | description: |
| 3080 | "Attach a look to an open pull: a PNG or JPEG (at most 5 MB, base64 in `image`) at `phone` or `desktop` width, with one line in `says`.", | |
| 3075 | "Attach a look to an open pull: PNG or JPEG (max 5 MB, base64 in `image`), `phone` or `desktop`, one line in `says`.", | |
| 3081 | 3076 | inputSchema: { |
| 3082 | 3077 | type: "object", |
| 3083 | 3078 | properties: { |
| @@ -3090,7 +3085,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 3090 | 3085 | image: { type: "string" }, |
| 3091 | 3086 | dryRun: { |
| 3092 | 3087 | type: "boolean", |
| 3093 | description: "false to apply (default plans).", | |
| 3088 | description: "false to apply", | |
| 3094 | 3089 | }, |
| 3095 | 3090 | }, |
| 3096 | 3091 | required: ["app", "pull", "width", "says", "image"], |
| @@ -3131,7 +3126,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 3131 | 3126 | { |
| 3132 | 3127 | name: "hold", |
| 3133 | 3128 | description: |
| 3134 | "Hold a pull, or let it go: while held, nothing reviews or lands it. App writers only. `why` holds; `release: true` lets go.", | |
| 3129 | "Hold a pull (`why`) or let it go (`release: true`): while held, nothing reviews or lands it. Writers only.", | |
| 3135 | 3130 | inputSchema: { |
| 3136 | 3131 | type: "object", |
| 3137 | 3132 | properties: { |
| @@ -3146,7 +3141,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 3146 | 3141 | }, |
| 3147 | 3142 | dryRun: { |
| 3148 | 3143 | type: "boolean", |
| 3149 | description: "false to apply (default plans).", | |
| 3144 | description: "false to apply", | |
| 3150 | 3145 | }, |
| 3151 | 3146 | }, |
| 3152 | 3147 | required: ["app", "pull"], |
| @@ -3205,7 +3200,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 3205 | 3200 | }, |
| 3206 | 3201 | { |
| 3207 | 3202 | name: "plan", |
| 3208 | description: `Open and link several small issues, all or none (max ${PLAN_MAX}). Items: key, title, body, optional blockedBy; with pillars, \`pillar\` or \`later: true\` with \`why\`.`, | |
| 3203 | description: `Open and link several small issues, all or none (max ${PLAN_MAX}). With pillars, each has \`pillar\` or \`later: true\` with \`why\`.`, | |
| 3209 | 3204 | inputSchema: { |
| 3210 | 3205 | type: "object", |
| 3211 | 3206 | properties: { |
| @@ -3283,7 +3278,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 3283 | 3278 | { |
| 3284 | 3279 | name: "access", |
| 3285 | 3280 | description: |
| 3286 | "What outside agents tried: the redacted log of non-browser requests to public paths, newest first, max 500. Forge admin, write-scope token.", | |
| 3281 | "What outside agents tried: the redacted log of non-browser requests to public paths, newest first, max 500. Forge admin.", | |
| 3287 | 3282 | inputSchema: { |
| 3288 | 3283 | type: "object", |
| 3289 | 3284 | properties: { |
| @@ -3311,7 +3306,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 3311 | 3306 | { |
| 3312 | 3307 | name: "capacity", |
| 3313 | 3308 | description: |
| 3314 | "The forge's capacity and guards, live. With `key` and `value` (\"\" restores default), plans; dryRun false makes it.", | |
| 3309 | "The forge's capacity and guards, live. With `key` and `value` (\"\" restores default), plans.", | |
| 3315 | 3310 | inputSchema: { |
| 3316 | 3311 | type: "object", |
| 3317 | 3312 | properties: { |
| @@ -3320,7 +3315,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 3320 | 3315 | enum: ["crew.concurrency", "checks.concurrency", "checks.shards", "cells.egress", "guard_new_accounts", "signin.edge"], |
| 3321 | 3316 | }, |
| 3322 | 3317 | value: { type: "string", maxLength: 16 }, |
| 3323 | dryRun: { type: "boolean", description: "false to apply (default plans)." }, | |
| 3318 | dryRun: { type: "boolean", description: "false to apply" }, | |
| 3324 | 3319 | }, |
| 3325 | 3320 | }, |
| 3326 | 3321 | writes: true, |
| @@ -3350,7 +3345,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 3350 | 3345 | { |
| 3351 | 3346 | name: "scorecard", |
| 3352 | 3347 | description: |
| 3353 | "Crew scorecard (forge admin): per agent, all time and 30 days (landed, review rounds, red rate, reverts), by model and prompt.", | |
| 3348 | "Crew scorecard (forge admin): per agent, all time and 30 days (landed, review rounds, red rate, reverts).", | |
| 3354 | 3349 | inputSchema: { type: "object", properties: {} }, |
| 3355 | 3350 | writes: false, |
| 3356 | 3351 | adminOnly: true, |
| @@ -3362,7 +3357,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 3362 | 3357 | { |
| 3363 | 3358 | name: "flow", |
| 3364 | 3359 | description: |
| 3365 | "The forge's pipeline for a forge admin: per stage counts, `oldestWaiting`, `capacity`, `says` naming the bottleneck, merge `queue`.", | |
| 3360 | "The forge's pipeline (forge admin): per stage counts, `oldestWaiting`, `capacity`, the bottleneck, merge `queue`.", | |
| 3366 | 3361 | inputSchema: { type: "object", properties: {} }, |
| 3367 | 3362 | writes: false, |
| 3368 | 3363 | run(ctx, user) { |
| @@ -3390,7 +3385,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 3390 | 3385 | { |
| 3391 | 3386 | name: "contribute", |
| 3392 | 3387 | description: |
| 3393 | "For any agent that arrives: what this forge is, its bottleneck, open “help wanted” issues in public repositories, and how to propose.", | |
| 3388 | "For any arriving agent: what this forge is, its bottleneck, open “help wanted” issues, how to propose.", | |
| 3394 | 3389 | inputSchema: { type: "object", properties: {} }, |
| 3395 | 3390 | writes: false, |
| 3396 | 3391 | run: (ctx) => good(welcome(ctx.app)), |
| @@ -3398,13 +3393,13 @@ const TOOLS: readonly Tool[] = [ | ||
| 3398 | 3393 | { |
| 3399 | 3394 | name: "limits", |
| 3400 | 3395 | description: |
| 3401 | "Every limit the forge's owner can hit, with value, bounds and reason. With `key` and `value` (\"\" restores default), plans.", | |
| 3396 | "Every limit the forge's owner can hit, with value, bounds. With `key` and `value` (\"\" restores default), plans.", | |
| 3402 | 3397 | inputSchema: { |
| 3403 | 3398 | type: "object", |
| 3404 | 3399 | properties: { |
| 3405 | 3400 | key: { type: "string", enum: [...LIMIT_KEYS] }, |
| 3406 | 3401 | value: { type: "string", maxLength: 16 }, |
| 3407 | dryRun: { type: "boolean", description: "false to apply (default plans)." }, | |
| 3402 | dryRun: { type: "boolean", description: "false to apply" }, | |
| 3408 | 3403 | }, |
| 3409 | 3404 | }, |
| 3410 | 3405 | writes: true, |
| @@ -3442,7 +3437,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 3442 | 3437 | charter: { type: "string", maxLength: 2000 }, |
| 3443 | 3438 | dial: { type: "integer", minimum: 0, maximum: 100 }, |
| 3444 | 3439 | members: { type: "array", maxItems: 500, items: { type: "string", maxLength: 64 } }, |
| 3445 | dryRun: { type: "boolean", description: "false to apply (default plans)." }, | |
| 3440 | dryRun: { type: "boolean", description: "false to apply" }, | |
| 3446 | 3441 | }, |
| 3447 | 3442 | }, |
| 3448 | 3443 | writes: true, |
| @@ -3484,7 +3479,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 3484 | 3479 | { |
| 3485 | 3480 | name: "cloud_accounts", |
| 3486 | 3481 | description: |
| 3487 | "Cloud accounts for a forge admin: each attached provider token with use, verification, write permission and today's vendor calls.", | |
| 3482 | "Cloud accounts (forge admin): each attached provider token with use, verification, write permission, today's calls.", | |
| 3488 | 3483 | inputSchema: { type: "object", properties: {} }, |
| 3489 | 3484 | // A read, but marked a write so a `ro` token never lists the accounts; it |
| 3490 | 3485 | // is a forge admin's and the audit rows name every vendor call. |
| @@ -3500,7 +3495,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 3500 | 3495 | { |
| 3501 | 3496 | name: "cloud_account", |
| 3502 | 3497 | description: |
| 3503 | "Change a cloud account (forge admin, admin-scope token). `verb`: attach, verify, rotate, rename, remove, allow_writes or audit.", | |
| 3498 | "Change a cloud account (admin-scope token). `verb`: attach, verify, rotate, rename, remove, allow_writes, audit.", | |
| 3504 | 3499 | inputSchema: { |
| 3505 | 3500 | type: "object", |
| 3506 | 3501 | properties: { |
| @@ -3555,13 +3550,13 @@ const TOOLS: readonly Tool[] = [ | ||
| 3555 | 3550 | { |
| 3556 | 3551 | name: "quotas", |
| 3557 | 3552 | description: |
| 3558 | "Per-account repository and app quotas (number or null; not enforced yet). With `key` and `value` (\"\" clears), plans; dryRun false makes it.", | |
| 3553 | "Per-account repository and app quotas (number or null; not enforced yet). With `key` and `value` (\"\" clears), plans.", | |
| 3559 | 3554 | inputSchema: { |
| 3560 | 3555 | type: "object", |
| 3561 | 3556 | properties: { |
| 3562 | 3557 | key: { type: "string", enum: [...QUOTA_KEYS] }, |
| 3563 | 3558 | value: { type: "string", maxLength: 16 }, |
| 3564 | dryRun: { type: "boolean", description: "false to apply (default plans)." }, | |
| 3559 | dryRun: { type: "boolean", description: "false to apply" }, | |
| 3565 | 3560 | }, |
| 3566 | 3561 | }, |
| 3567 | 3562 | writes: true, |
| @@ -3598,7 +3593,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 3598 | 3593 | type: "object", |
| 3599 | 3594 | properties: { |
| 3600 | 3595 | mode: { type: "string", enum: [...SIGNUP_MODES] }, |
| 3601 | dryRun: { type: "boolean", description: "false to apply (default plans)." }, | |
| 3596 | dryRun: { type: "boolean", description: "false to apply" }, | |
| 3602 | 3597 | }, |
| 3603 | 3598 | }, |
| 3604 | 3599 | writes: true, |
| @@ -3668,7 +3663,7 @@ const TOOLS: readonly Tool[] = [ | ||
| 3668 | 3663 | { |
| 3669 | 3664 | name: "board_write", |
| 3670 | 3665 | description: |
| 3671 | "Write a whole board under a slug (made or replaced). `board` is {title, range, refresh, panels: [{title, chart, query, w, h}]}.", | |
| 3666 | "Write a whole board under a slug (made or replaced): {title, range, refresh, panels: [{title, chart, query, w, h}]}.", | |
| 3672 | 3667 | inputSchema: { |
| 3673 | 3668 | type: "object", |
| 3674 | 3669 | properties: { |
test/mcp-size.test.ts +7 −1
| @@ -13,6 +13,8 @@ import { createUser } from "../src/core/users.ts"; | ||
| 13 | 13 | import { serve, type Servers } from "../src/http/server.ts"; |
| 14 | 14 | |
| 15 | 15 | const CEILING = 40_000; |
| 16 | // Headroom: a new tool should fit without another round of cuts. | |
| 17 | const HEADROOM_CEILING = 37_000; | |
| 16 | 18 | |
| 17 | 19 | let dataDir: string; |
| 18 | 20 | let app: App; |
| @@ -42,7 +44,7 @@ afterAll(async () => { | ||
| 42 | 44 | await rm(dataDir, { recursive: true, force: true }); |
| 43 | 45 | }); |
| 44 | 46 | |
| 45 | test("tools/list stays under 40 KB", async () => { | |
| 47 | test("tools/list stays under 40 KB, with 3 KB of headroom (37,000 bytes)", async () => { | |
| 46 | 48 | const res = await fetch(`${servers.url}/mcp`, { |
| 47 | 49 | method: "POST", |
| 48 | 50 | headers: { |
| @@ -69,4 +71,8 @@ test("tools/list stays under 40 KB", async () => { | ||
| 69 | 71 | bytes, |
| 70 | 72 | `tools/list is ${bytes} bytes, over ${CEILING}; the five longest descriptions: ${longest.join(", ")}`, |
| 71 | 73 | ).toBeLessThanOrEqual(CEILING); |
| 74 | expect( | |
| 75 | bytes, | |
| 76 | `tools/list is ${bytes} bytes, over the ${HEADROOM_CEILING} headroom; the five longest descriptions: ${longest.join(", ")}`, | |
| 77 | ).toBeLessThanOrEqual(HEADROOM_CEILING); | |
| 72 | 78 | }); |
new above
offline
Non-blocking: with the description gone, an agent sees only
{type:"string"}forrepoand learns the form from a not_found round-trip. If the next pull needs bytes back, a three-character pattern hint is cheaper than a wasted call. Something likepattern: "^[^/]+/[^/]+$"ordescription: "o/n"would do. Fine as is for this issue.