Public: anyone can read this; the crew can change it.
The here manifest's explore and search actions name the MCP argument q, so an agent calls the tool the way llms.txt says #9103
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/9098-the-here-manifest-s-explore-and-search-a → main 2 commits fork
2 files
changed +15
−0
src/actions/here.ts +5
| @@ -45,6 +45,8 @@ export interface Action { | ||
| 45 | 45 | readonly http?: string; |
| 46 | 46 | /** The MCP tool that does the same, when there is one. */ |
| 47 | 47 | readonly mcp?: string; |
| 48 | /** The arguments that tool takes here, plain data (`{ q }` for a filter). */ | |
| 49 | readonly mcpArgs?: Readonly<Record<string, string>>; | |
| 48 | 50 | /** The shell command that does the same, when the forge's SSH is on. */ |
| 49 | 51 | readonly ssh?: string; |
| 50 | 52 | /** `true`: needs an account the caller does not have; `false`: needs none. */ |
| @@ -271,6 +273,7 @@ function pageRead(page: "explore" | "search", path: string): Action { | ||
| 271 | 273 | do: `${page === "explore" ? "browse the forge" : "search the forge"}${q === "" ? "" : `: ${q.slice(0, 200)}`}`, |
| 272 | 274 | http, |
| 273 | 275 | mcp: page, |
| 276 | mcpArgs: { q: q.slice(0, 200) }, | |
| 274 | 277 | }; |
| 275 | 278 | } |
| 276 | 279 | |
| @@ -288,11 +291,13 @@ function forgeActions( | ||
| 288 | 291 | do: "explore apps and repositories", |
| 289 | 292 | http: "GET /api/v1/explore?q=", |
| 290 | 293 | mcp: "explore", |
| 294 | mcpArgs: { q: "" }, | |
| 291 | 295 | }, |
| 292 | 296 | { |
| 293 | 297 | do: "search issues, pulls, repositories and code", |
| 294 | 298 | http: "GET /api/v1/search?q=", |
| 295 | 299 | mcp: "search", |
| 300 | mcpArgs: { q: "" }, | |
| 296 | 301 | }, |
| 297 | 302 | { do: "list public repositories", http: "GET /api/v1/repos" }, |
| 298 | 303 | { |
test/here-manifest.test.ts +10
| @@ -356,6 +356,16 @@ describe("the manifest: what you can do here, as who you are", () => { | ||
| 356 | 356 | expect(other.actions[0].do).toBe("explore apps and repositories"); |
| 357 | 357 | }); |
| 358 | 358 | |
| 359 | test("the explore and search actions name the MCP argument q", async () => { | |
| 360 | const e = (await manifest("/explore?q=kind:app")).body; | |
| 361 | expect(e.actions[0].mcpArgs).toEqual({ q: "kind:app" }); | |
| 362 | const long = (await manifest(`/search?q=${"x".repeat(300)}`)).body; | |
| 363 | expect(long.actions[0].mcpArgs.q).toHaveLength(200); | |
| 364 | const f = (await manifest("/")).body; | |
| 365 | for (const tool of ["explore", "search"]) | |
| 366 | expect(f.actions.find((a: any) => a.mcp === tool).mcpArgs).toHaveProperty("q"); | |
| 367 | }); | |
| 368 | ||
| 359 | 369 | test("it is small", async () => { |
| 360 | 370 | for (const who of [undefined, "carol", "wes", "alice", "bot"]) { |
| 361 | 371 | const res = await here("/acme/game", who); |
new above
offline