Correct the MCP skill against what the server actually serves - #9
Merged
Conversation
Testing the skill end to end turned up four things it gets wrong. The tool list was already stale a week after merging: the server exposes twelve tools, this file documented ten. Missing were `export_dependencies_csv` and `get_server_instructions`, whose own description says to always call it first — which this file contradicted by telling the agent to open with a `list_*` call. Rather than restate the inventory and watch it drift again, the section now names the tools by area and sends the reader to `tools/list` and the schemas their client already holds. That is the same reasoning that slimmed `corgea-scan`. The filter shape was wrong. Only `scan_id`, `project`, `repo`, `page` and `page_size` are top-level; severity, status, branch and the rest go in a nested `filters` object, and passing them flat is the easy mistake to make. The Cursor guidance implied the bridge was optional. It is not: Cursor's native `url` transport connects and then tries to open a GET SSE stream, which this server refuses, and the connection dies with `Failed to open SSE stream: Not Acceptable`. The `--transport http-only` bridge is the only shape that works, and the direct-HTTP section now says to test before trusting it. Finally, keeping the token out of the config file does not keep it off the machine — the client expands it before spawning the bridge, so it lands in `mcp-remote`'s command line where `ps` can read it. Worth saying, since the previous wording implied otherwise. Co-authored-by: Cursor <cursoragent@cursor.com>
The tool describes itself as "Always call first", so an agent reading `tools/list` will open every session with it. On production it returns an empty string, making that a wasted round trip on a rate-limited API. This is worth a line precisely because it contradicts what the schema says: the tool description is the one thing an agent cannot second-guess on its own. If the server ever starts returning text there, that text describes the server as deployed and outranks this file. Co-authored-by: Cursor <cursoragent@cursor.com>
Testing this against production showed the agent filtering SCA findings by reachability and ranking them sensibly with the skill absent. That is not surprising once you read what the server sends: each tool description carries its filters, valid values and sort keys in full, including every reachability state. A skill restating them earns nothing and goes stale, which is the same failure as the tool list this PR already cut. What is left is what the schemas cannot say: that filters nest inside a `filters` object, that empty results usually mean a missed filter rather than a clean account, that rate limits punish a loop of `get_*`, and that `export_dependencies_csv` hands back a URL instead of rows. Also sharpens the SSE note. The failure is not limited to SSE-only clients — a client that merely opens a stream after connecting fails too, and Cursor's built-in HTTP client does exactly that. Co-authored-by: Cursor <cursoragent@cursor.com>
`${env:CORGEA_TOKEN}` is the only route the token has into Cursor here, and the
only setup instruction was `launchctl setenv`. A Cursor started from a Windows
shortcut or a Linux desktop entry got nothing and sent an empty header.
Now says why a shell `export` cannot reach a desktop-launched editor, and gives
the persistent form for each platform. Launching Cursor from a shell that
already exports the variable is the portable check, since it settles the cause
in one step.
Same correction as Corgea/docs#327, raised there by review.
Co-authored-by: Cursor <cursoragent@cursor.com>
juangaitanv
reviewed
Aug 18, 2026
The `ps` warning was written as though every client behaves like Cursor. Only
Cursor expands `${env:...}` before spawning the bridge and puts the token in
`mcp-remote`'s argv, where any user on the machine can read it. Claude Desktop
does not interpolate at all — it passes `${CORGEA_TOKEN}` through and the
bridge substitutes it from its own environment, so the token stays out of the
command line and is visible only to processes running as the same user.
Both still argue for a machine-scoped token that gets rotated; neither argues
for putting the literal back in the config.
Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
We tested the skill end to end for the first time — hosted server, Cursor, real token — and it was wrong in several places. Some of it would stop someone connecting at all; the rest was content that earns nothing because the server already provides it.
Things that were wrong
Cursor cannot connect using the direct-HTTP form. Its native
urltransport connects, then opens a GET SSE stream, which this server refuses; the connection dies withFailed to open SSE stream: Not Acceptableand no tools appear. The skill impliedmcp-remotewas a convenience. This cost an hour to diagnose.The tool list had already drifted, a week after merging.
tools/liston production returns twelve tools; the skill documented ten. Missing wereexport_dependencies_csvandget_server_instructions.get_server_instructionsis a trap. Its own description says "Always call first", so an agent readingtools/listwill open every session with it. It returns an empty string. That contradiction is exactly the kind of thing a skill can say and a schema cannot.The filter shape was wrong. Only
scan_id,project,repo,pageandpage_sizeare top-level; everything else nests inside afiltersobject.The token isn't as private as implied. Cursor expands
${env:CORGEA_TOKEN}before spawning the bridge, so it lands inmcp-remote's command line wherepscan read it.Things that were redundant
Asked a test project "are any dependencies actually exploitable?" with the skill absent, and the agent filtered on reachability and ranked sensibly anyway. Reading what the server sends explains why: each tool description carries its filters, valid values and sort keys in full, including every reachability state. So the skill's prioritisation advice, its reachability value list and its list-before-get guidance were all restating the schema — earning nothing, and drifting the moment the server changes.
Those are gone. The tool section is now a map of what exists by area, plus the handful of things the schemas genuinely do not say.
What changed
tools/list.get_server_instructionsdocumented as safe to skip while it returns empty.filters, empty-results-means-missed-filter, rate limits favouringlist_*over loopedget_*, andexport_dependencies_csvreturning a URL rather than rows.--transport http-only, the 406 symptom, and why the bridge is mandatory. Direct-HTTP section names Cursor as a client that fails.mcp-remoteby hand.psexposure caveat under token handling.Net effect is two lines shorter than
maindespite adding the transport troubleshooting.Test plan
tools/listagainst production returns exactly the twelve tools listedget_server_instructionson production returns""urlform, and a working connection with thehttp-onlybridgescripts/validate.mjspassesRelated: Corgea/docs#327 carries the same transport fix into the public docs.