Repository navigation
Add hosted Sysdig Secure MCP - #101
Conversation
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
jamesgagan
left a comment
There was a problem hiding this comment.
Review: Sysdig Secure MCP proxy
Thanks for this. The proxy's overall design is good:
- It exposes tools only.
- It re-checks the policy on every call.
- Results go through
PiScrubber. - The OAuth callback binds to loopback and checks a 256-bit
statebefore reading anything else.
That makes it stricter than jarvis-mcp. Some things need fixing before merge, mainly the OAuth lifecycle, the read-only guarantee, and the compliance docs.
Summary: 9 required changes, 5 minor items, 2 pre-existing notes. Reviewed at 8609bb3e0c3e79c8f59794714fbd9aad2724858f, checked against the MCP SDK 1.32.0 source this PR locks.
Required changes
Bugs
- 1. Recover from token expiry (
oauth.ts,index.ts)- Implement
invalidateCredentials. - Add a
.catchto thewaitForCodepromise stored inredirectToAuthorization. - On
UnauthorizedError, drop the cachedconnectionand reconnect. If that is out of scope, fail fast with "restart to sign in" and don't open a tab.
- Implement
- 2. Don't block
tools/liston browser sign-in (server.ts:75-81)- Return the static allowlist until connected.
- Declare
tools: { listChanged: true }and sendnotifications/tools/list_changedonce connected. - Start OAuth only on the first
tools/call.
- 3. Harden the callback listener (
oauth.ts:78-84)- Wrap
new URL(request.url…)in try/catch and return 400 on failure. - Close the callback server once a code arrives.
- Close it in
shutdown()even whenconnectionis still undefined.
- Wrap
Security
- 4. Make the allowlist authoritative (
read-only.ts:20-24): admit a tool only if it is onDOCUMENTED_READ_ONLY_TOOLSand not annotatedreadOnlyHint: false. Update the tests and the README wording to match. - 5. Validate the authorization URL before opening it (
oauth.ts:187-216)- Require
authorizationUrl.protocol === "https:"and a host under*.sysdig.com. - Call
rundll32.exeby its absolute%SystemRoot%\System32path.
- Require
- 6. Scrub errors and
structuredContent(server.ts:83-94)- Catch upstream
callToolerrors and rethrow them withscrubText(message). - Scrub
structuredContentas one serialized string, not leaf by leaf.
- Catch upstream
Docs, compliance and release
- 7. Correct the docs this PR makes false
TOOL_INVENTORY.md:275still describes the earlier remote-URL design.SYSTEM_DESIGN_AND_ARCHITECTURE.md:85,:167and:783need to mention the loopback OAuth listener.SYSTEM_DESIGN_AND_ARCHITECTURE.md:681and.github/copilot-instructions.md:142must say Sysdig is a US-hosted third-party service.
- 8. Data residency
- Remove the built-in US East default so
SYSDIG_SECURE_MCP_URLis required. - Keep the server opt-in (out of the default
.mcp.json) until a STRA/PIA covers it. - Add a STRA/PIA note to the docs and to this PR's description.
- Remove the built-in US East default so
- 9. Revert the
validateCatalogchange (scripts/release/release-lib.mjs:199-221) toconst configuredIds = Object.keys(mcp.mcpServers ?? {});.
1. Token expiry is never recovered, and one path crashes the process
raven/packages/sysdig-mcp/src/oauth.ts
Lines 185 to 204 in 8609bb3
raven/packages/sysdig-mcp/src/index.ts
Lines 13 to 24 in 8609bb3
this.authorizationCode = this.callback.waitForCode(this.expectedState); // nothing awaits this after the first connectWhen the access token expires and there is no usable refresh token:
- The SDK's 401 handler (
client/streamableHttp.js→client/auth.jsauthInternal) callsredirectToAuthorizationagain and throwsUnauthorizedError. - Only the first-connect
catch(oauth.ts:236) ever callsfinishAuth. If the user signs in now, they see "sign-in complete", but no token is stored. The next call opens another tab. - If the user ignores the tab, the 5-minute timer rejects a promise that has no handler. On Node 24 that terminates the process.
- Without
invalidateCredentials, aninvalid_granterror is retried with the same dead refresh token on every call.
I understand tokens are deliberately in memory and a restart re-authenticates. The problem is that the user is never told to restart.
2. tools/list blocks on browser sign-in at every host start
raven/packages/sysdig-mcp/src/server.ts
Lines 74 to 81 in 8609bb3
- The
tools/listhandler awaitsgetClient(), which opens the browser and waits up to 5 minutes (oauth.ts:16). - Hosts list tools right after
initialize. - The server is in
.mcp.jsonand the release catalog, so every RAVEN user gets a sign-in tab whenever their IDE starts, including users who never use Sysdig. - The server declares no
listChanged. A host whose firsttools/listtimed out (the SDK client default is 60 s) has no signal to list again. - Client registration is in memory only, so every start also registers a new OAuth client with Sysdig.
- The README says sign-in happens "on first use", but it happens at host startup.
4. The read-only filter trusts Sysdig's own annotation
raven/packages/sysdig-mcp/src/read-only.ts
Lines 19 to 24 in 8609bb3
if (tool.annotations?.readOnlyHint === true) return true; // any tool name passes
return DOCUMENTED_READ_ONLY_TOOLS.has(tool.name); // only consulted when unannotated- The MCP spec says clients should not make tool-use decisions based on annotations from servers they don't control.
- With the current logic, any new upstream tool that labels itself read-only reaches the LLM without Raven review.
- The proxy relays
readOnlyHint: trueto clients, which may auto-approve those calls. - The README and
TOOL_INVENTORY.mdsay "only read-only tools are exposed". The code only guarantees "tools Sysdig labels read-only".
5. The authorization URL is opened with no scheme or host check
raven/packages/sysdig-mcp/src/oauth.ts
Lines 186 to 216 in 8609bb3
authorization_endpointcomes from discovered OAuth metadata, and the authorization server's host is not pinned.config.tsconstrains only the MCP URL.- The SDK's
SafeUrlSchemarejects onlyjavascript:,data:andvbscript:, so afile:,smb:or custom-protocol URL is passed torundll32 url.dll,FileProtocolHandler,openorxdg-open. - This is the same class as CVE-2025-6514 in
mcp-remote. - It needs hostile or compromised metadata to exploit. The fix is a one-line protocol and host check.
execFilewithout a shell is correct and rules out argument injection.
6. PI scrubbing misses errors and structuredContent
raven/packages/sysdig-mcp/src/server.ts
Lines 82 to 94 in 8609bb3
- Errors: an error thrown by
upstream.callToolreaches the client unscrubbed. The SDK sendserror.messageanderror.dataas-is, andStreamableHTTPErrorincludes the upstream response body. #93 fixed the same error-body gap (194f8eb). structuredContent:scrubStringValuesscrubs each leaf string on its own, so{"password":"hunter2"}callsscrubText("hunter2"). The key-based credential rule inpi-scrubber.tsnever fires.
3. A malformed request crashes the proxy, and the listener stays open
raven/packages/sysdig-mcp/src/oauth.ts
Lines 77 to 84 in 8609bb3
- A request target such as
//makesnew URL()throw inside the request listener. The exception is uncaught, so the process exits. - The listener stays bound until shutdown, so any local process can trigger this at any time, and so can a browser sending requests to the loopback port.
- Separately, a SIGTERM during a pending sign-in leaves the listener open, because
connectionis still undefined.
7. Docs made false by this PR
docs/TOOL_INVENTORY.md:275says Sysdig is "configured as a remote MCP server directly in.mcp.json". It is a local stdio command entry. https://github.com/bcgov/raven/blob/8609bb3e0c3e79c8f59794714fbd9aad2724858f/docs/TOOL_INVENTORY.md#L274-L276SYSTEM_DESIGN_AND_ARCHITECTURE.md:85(rewritten in this PR) says "no network listener".:167says "no exposed ports" and:783says "No network ports exposed". The OAuth callback listens on127.0.0.1for the whole process lifetime.raven/docs/SYSTEM_DESIGN_AND_ARCHITECTURE.md
Lines 84 to 86 in 8609bb3
SYSTEM_DESIGN_AND_ARCHITECTURE.md:681says "All enterprise data stays on BC Gov infrastructure". This row is used in security walkthroughs.raven/docs/SYSTEM_DESIGN_AND_ARCHITECTURE.md
Lines 680 to 682 in 8609bb3
.github/copilot-instructions.md:142says the servers "add no third-party data sinks".raven/.github/copilot-instructions.md
Lines 141 to 143 in 8609bb3
The same kind of compliance statement was raised in the #96 review.
8. US East default with no residency or STRA/PIA note
raven/packages/sysdig-mcp/src/config.ts
Lines 1 to 7 in 8609bb3
- The built-in default is
secure.sysdig.com, which is Sysdig US East. - The only residency text in the PR is "review … for FOIPPA and data-residency requirements".
- BC Gov standards require Canadian regions only, and a STRA/PIA for any product handling personal data.
- #90 removed Jarvis's built-in default endpoint so the destination is always explicit.
Can you confirm whether our Sysdig tenant has a Canadian region? I couldn't find one in Sysdig's region list.
9. validateCatalog dead branch weakens the release guard
raven/scripts/release/release-lib.mjs
Lines 198 to 229 in 8609bb3
- Any
.mcp.jsonentry without acommandnow skips the catalog-parity check. Any HTTPS host passes, andheadersare not inspected. - The branch was added for the earlier remote-URL design (first commit) and is unreachable with the final
.mcp.json. No test covers it. - Reverting to the original one-liner restores the guard.
Minor (non-blocking)
- Lockfile.
package-lock.jsondrops 14 unrelatedlibcfields. This is an npm 10 rewrite artifact. Start from main's lockfile and re-add only thesysdig-mcphunks. - Docs and tests.
- Add JSDoc to the exported functions and classes.
- Add a
SYSDIG_SECURE_MCP_URLrow to the env-var table inTOOL_INVENTORY.md. - Add tests for
oauth.ts(state mismatch, a single pending callback, timeout).
- OAuth client metadata.
clientMetadatasets noscope, so every advertised scope is requested while the consent screen says "Read-only".- Client registration is in memory only, so each start creates a new registration.
- PR hygiene.
- Use the title format
TICKET-### - Description. - Add a description with an acceptance checklist.
- Drop the stray blank-line change in
scripts/setup-credentials.ps1.
- Use the title format
- Package count.
SYSTEM_DESIGN_AND_ARCHITECTURE.md:178says "20 packages"; there are 22.
Pre-existing (not blocking, for awareness)
- Prompt injection, as a class. Sysdig event text (process command lines, image names) can be attacker-influenced. It now reaches the same LLM session as the write-capable Jira, Confluence, Bitbucket and GitHub servers. Server logs already do this today; this PR adds another feed.
jarvis-mcphas the same gaps as items 4 and 6.- It forwards results and errors with no PI scrubbing (
packages/jarvis-mcp/src/index.ts:86-93). - Its catalog entry says
"access": "read-only", but it forwards a write tool (release/server-catalog.json:98-104).
- It forwards results and errors with no PI scrubbing (
setup-credentials.ps1 -Verify(:43-48) prints the first and last two characters of each secret, and the asterisk count reveals its length.
12607b3 to
2a2db43
Compare
32b157e to
d4215c9
Compare
|
@jamesgagan thanks for the thorough review. I've changed direction: the local Why: in testing, the proxy didn't work reliably. The first tool call blocked on browser OAuth (up to 5 min) while the client timed out at 60 s, and the proxy-driven sign-in page rendered blank. Client-managed OAuth works, and it removes the listener, token-handling and registration issues you raised. Below is each item and its status (latest: Required changes
Minor
Pre-existing
Validation: |
There was a problem hiding this comment.
🟡 Changes recommended
The release gate accepts array-valued URLs because new URL() coerces its input, allowing malformed remote configuration that MCP clients cannot use.
1 open issue
What changed in this PR
Adds Sysdig Secure to RAVEN’s MCP registry as a hosted service with client-managed OAuth, without a local proxy or RAVEN-managed credentials.
Changes:
- Registers the remote Sysdig endpoint and excludes it from bundled releases.
- Adds remote-entry validation and tests for approved, credential-free HTTPS endpoints.
- Updates documentation and generated inventory for Sysdig’s dynamic tools, permissions, and data handling.
| File | Description |
|---|---|
scripts/release/release.test.mjs |
Tests Sysdig configuration, bundle exclusion, and rejected remote entries. |
scripts/release/release-lib.mjs |
Validates approved remote entries separately from bundled servers. |
scripts/gen-inventory.lib.mjs |
Adds hosted Sysdig documentation and excludes dynamic tools from totals. |
README.md |
Explains OAuth setup, permissions, and data-residency considerations. |
docs/TOOL_INVENTORY.md |
Regenerates inventory with the hosted Sysdig integration. |
docs/SYSTEM_DESIGN_AND_ARCHITECTURE.md |
Documents Sysdig’s remote architecture and security boundaries. |
.mcp.json |
Registers the hosted Sysdig Secure HTTP endpoint. |
.github/copilot-instructions.md |
Adds Sysdig hosting and assessment context. |
Review effort: Balanced
There was a problem hiding this comment.
🟡 Changes recommended
A critical validation bypass lets mixed-transport catalog entries retain a command while adding a foreign URL and credential-bearing headers, evading remote allowlist and credential checks.
1 open issue
1 resolved since last review
Review effort: Balanced
| const configuredIds = Object.keys(mcp.mcpServers ?? {}); | ||
| const configuredIds = Object.entries(mcp.mcpServers ?? {}) | ||
| .filter(([id, configured]) => { | ||
| if (configured?.command !== undefined) return true; |
There was a problem hiding this comment.
Fixed in 6e35b38: validateCatalog now treats an entry as local only when it has exactly command and args; anything else, including entries that keep a command but add type, url or headers, goes through validateRemoteMcpEntry and fails unless it is the approved Sysdig endpoint. validateCatalog also accepts an optional .mcp.json object, so the new regression test runs tampered jira entries (command + http URL + headers, command + headers, and type: "stdio") through it, and all are rejected.
jamesgagan
left a comment
There was a problem hiding this comment.
Review: Hosted Sysdig Secure MCP (round 2)
Thanks for the rework. Moving OAuth into the MCP client removes every round-1 listener, token and browser-launch issue, and RAVEN no longer holds any Sysdig code or credentials. The release gate also holds up well. It fails closed on every bypass I tried:
- mixed-transport entries
null, array and string entries__proto__andconstructorIDs- look-alike hosts
- userinfo, query, fragment and port
It also runs on every PR through npm test, not only at release.
Summary: 2 required doc changes, 5 minor items and 2 pre-existing notes. Round-1 item 8 is accepted as is. Reviewed at 6e35b386c2c104c535b1ffba6b9b57e3dfc682c6.
Required changes
Docs, compliance and release
-
1. Scope the PI-scrubbing claims to Raven-owned servers. These still say all output is scrubbed:
README.md:3,:849SYSTEM_DESIGN_AND_ARCHITECTURE.md:43,:169,:376,:400,:620,:677
Name the exception in each one: hosted Sysdig, and
jarvis-mcptoo. -
2. Scope the local-stdio and fixed-tool claims, and list Sysdig as an endpoint.
SYSTEM_DESIGN_AND_ARCHITECTURE.md:85,:221and:652: say "Raven-owned servers".:255: add Sysdig to the §4.2 endpoint list.
1. PI-scrubbing claims made false by this PR
The PR says it plainly at README.md:39 and SYSTEM_DESIGN:632: Sysdig responses do not pass through PiScrubber. The blanket claims around them were left as they were:
- ("personal information scrubbed by default before anything reaches the model")
Lines 2 to 4 in 6e35b38
- ("One setting controls all servers.")
Lines 848 to 850 in 6e35b38
- ("Personal information is scrubbed before it reaches the AI.")
raven/docs/SYSTEM_DESIGN_AND_ARCHITECTURE.md
Lines 42 to 44 in 6e35b38
- (two rows below the row this PR edited)
raven/docs/SYSTEM_DESIGN_AND_ARCHITECTURE.md
Lines 168 to 170 in 6e35b38
- ("applied to all data before it is returned to the AI")
raven/docs/SYSTEM_DESIGN_AND_ARCHITECTURE.md
Lines 375 to 377 in 6e35b38
- ("Every MCP server instantiates a
raven/docs/SYSTEM_DESIGN_AND_ARCHITECTURE.md
Lines 399 to 401 in 6e35b38
PiScrubber") - ("Tool output passes through the PI scrubber before the AI sees it." This is 12 lines above the new Sysdig bullet.)
raven/docs/SYSTEM_DESIGN_AND_ARCHITECTURE.md
Lines 619 to 621 in 6e35b38
- (the FOIPPA s.30 row: "
raven/docs/SYSTEM_DESIGN_AND_ARCHITECTURE.md
Lines 676 to 678 in 6e35b38
RAVEN_SCRUB_PI=truecontrols this globally". The PR edited the row directly below it.)
The §13 compliance table and the executive summary are the parts used in security walkthroughs. The same class was raised in the #96 review.
jarvis-mcp already had this gap before this PR, since it has no PiScrubber, so :400, :677 and README :849 were already loose. Sysdig turns them from loose into false: it is a US-hosted third party. Name both exceptions in one pass.
Suggested wording for SYSTEM_DESIGN:43: "Personal information returned by Raven-owned servers is scrubbed before it reaches the AI. Hosted Sysdig and the Jarvis proxy return responses unscrubbed (see §11.3)."
2. Local-stdio, fixed-tool and endpoint-list claims
- ("Transport is local stdio … no remote access")
raven/docs/SYSTEM_DESIGN_AND_ARCHITECTURE.md
Lines 84 to 86 in 6e35b38
- ("Tool registration is static … cannot be modified at runtime by … any external input")
raven/docs/SYSTEM_DESIGN_AND_ARCHITECTURE.md
Lines 220 to 222 in 6e35b38
- (§4.2 "Access other systems: No". The endpoint list omits Sysdig, even though the PR updated the matching list in §11.3.)
raven/docs/SYSTEM_DESIGN_AND_ARCHITECTURE.md
Lines 254 to 256 in 6e35b38
- ("The tool manifest is fixed at server startup")
raven/docs/SYSTEM_DESIGN_AND_ARCHITECTURE.md
Lines 651 to 653 in 6e35b38
Sysdig's tool list is defined by Sysdig at runtime and, per Sysdig's docs, changes between releases. The §11.6 "Can the AI be tricked?" answer relies on a fixed manifest.
Round-1 follow-up
- Item 8 (data residency and default-on): accepted as is. No change needed to the STRA wording or to the default-on entry.
- Optional: Sysdig stays default-on, its output is unscrubbed, monitored workloads can influence that output, and it shares the session with Raven's write tools. Two cheap mitigations:
- Add a short Sysdig section to
.github/copilot-instructions.md: treat Sysdig output as untrusted, confirm before any Sysdig tool that changes state, and don't paste raw Sysdig output into Jira, Confluence or PR text. - Revisit the "Prompt injection via tool output: Low/Low" row at SYSTEM_DESIGN:667.
- Add a short Sysdig section to
Minor (non-blocking)
${VAR}URLs pass the gate.validateRemoteMcpEntrychecks the parsed URL, not the raw string.https://${X}.sysdig.com/mcp/secureparses to host${x}.sysdig.comand passes every check.- Claude Code expands
${VAR}in.mcp.jsonurlfields, so the host actually contacted would come from the environment. - Fix: add
/^[a-z0-9.-]+$/.test(hostname)andurl.href === configured.url. raven/scripts/release/release-lib.mjs
Lines 246 to 263 in 6e35b38
- The host allowlist is wider than the assessment.
hostSuffix: "sysdig.com"accepts the apex and any subdomain, and the test asserts thateu1.app.sysdig.comis accepted.- The README tells users to switch regions, but the stated STRA covers US East.
- Fix: pin
secure.sysdig.com(or an explicit host list), and say in the docs that another region needs its own assessment. raven/scripts/release/release.test.mjs
Lines 49 to 51 in 6e35b38
- No
validateCatalogtest tampers with the approved entry itself.- The mixed-transport test only tampers with
jira, which fails the allowlist first. If the wiring skipped validation for approved IDs, every test would stay green. - Fix: add
validateCatalog(undefined, …)cases forsysdig-secure-mcpwithheaders, and with a foreignurl. raven/scripts/release/release.test.mjs
Lines 71 to 83 in 6e35b38
- The mixed-transport test only tampers with
- Misleading error for local entries.
- A local entry with
env,cwdor the valid"type": "stdio"now fails with "Remote MCP entry 'jira' is not an approved remote server." - Fix: give catalog IDs their own message, for example "Local MCP entry 'jira' may contain only command and args".
raven/scripts/release/release-lib.mjs
Lines 201 to 208 in 6e35b38
- A local entry with
- Inventory count is hard-coded.
data.length + 2and the Sysdig rows are hard-coded, andgen-inventory --checknever reads.mcp.json. TOOL_INVENTORY.md:10 ("CI-enforced") and :27 ("map 1:1 to the keys in .mcp.json") are therefore not enforced for remote entries.- Fix: derive the remote rows from
APPROVED_REMOTE_MCP_SERVERS, or add a test that asserts the count matches.mcp.json. raven/scripts/gen-inventory.lib.mjs
Lines 55 to 57 in 6e35b38
Pre-existing (not blocking, for awareness)
- Launcher text is built from unvalidated entrypoint segments.
writeLaunchersinterpolates the 3rd and later path segments ofentrypointinto double-quoted sh and cmd launchers without escaping, andvalidateCatalognever constrains those segments.- An entrypoint like
packages/jira-mcp/dist/$(id).js, mirrored in.mcp.json, would run duringvalidateLauncherin the release build. - It needs a merged catalog change. A charset check on
entrypointcloses it. raven/scripts/release/release-lib.mjs
Lines 363 to 387 in 6e35b38
- Scrubbing default is documented wrong. SYSTEM_DESIGN:419 says scrubbing is bypassed when
RAVEN_SCRUB_PIis unset. The code enables it unless the value isfalseor0(pi-scrubber.ts:12-14and:267-270).raven/docs/SYSTEM_DESIGN_AND_ARCHITECTURE.md
Lines 418 to 420 in 6e35b38
|
Addressed in I’m leaving the two URL-policy suggestions unchanged in this PR. The default remains |
jamesgagan
left a comment
There was a problem hiding this comment.
PR-review: #101 (no ticket)
Head SHA: 358d84d
Scope: Only what changed since round 2 (6e35b38..358d84d, one commit, 8 files), plus a check that each round-2 finding is resolved.
Tier: Deep, set by scripts/release/release-lib.mjs · Round: 3 · Decoy: rejected 5/5
TL;DR
8 findings: 0 Important, 3 Nit, 5 Pre-existing. Nothing to fix before merge. Both round-2 required changes are done. The release gate accepts exactly the same entries as before, and CI passes.
Required changes
None. It's ready to ship.
Still open from earlier rounds
- Host allowlist breadth and ${VAR} URLs: the author declined both on purpose, so users outside BC Gov can use other regions. The docs now say the STRA covers the US East deployment only.
- Optional mitigations (a Sysdig section in copilot-instructions.md, and the SYSTEM_DESIGN:667 row): not adopted. They were optional.
- Launcher injection (round-2 item I, pre-existing): unchanged.
Resolved this round:
- Round-2 required items 1 and 2.
- The local-entry error message.
- Tests that tamper with the Sysdig entry.
- The inventory server count, now derived from .mcp.json.
- The pre-existing RAVEN_SCRUB_PI default in §7.5.
Things that look scary but I verified are fine
- Moving the "is it local?" test to catalog membership: the security lens traced 14 entry shapes, including proto, null, two-element args and an approved ID in local shape. All still fail closed. Only the error messages changed.
- gen-inventory.lib.mjs now importing release-lib.mjs: release-lib.mjs does no I/O when imported, so the "pure" header still holds.
- The server count of 18: 16 local servers + Jarvis + Sysdig. That matches the committed TOOL_INVENTORY, and gen-inventory --check runs in CI.
- main has moved 6 commits: all are dependency bumps, and none touch PR files.
Lower-priority observations
Nits (3), all verified 5/5:
- C. Connection direction reversed. SYSTEM_DESIGN:85 () says "hosted Sysdig … connects directly to the MCP client". It's the other way round:
raven/docs/SYSTEM_DESIGN_AND_ARCHITECTURE.md
Lines 84 to 86 in 358d84d
the client connects to Sysdig. - A. New error is misleading for uncatalogued local entries. Such an entry now gets "Remote MCP entry … not an approved remote server", the mirror image of the round-2 error-message nit. The parity check at :215-221 is now unreachable. release-lib.mjs#L200-L223
()raven/scripts/release/release-lib.mjs
Lines 200 to 223 in 358d84d
- G. New inventory key check is hard to diagnose. Its error names no key and is thrown outside the try/catch. The new-package checklist doesn't mention SERVERS. gen-inventory.lib.mjs#L33-L39
()raven/scripts/gen-inventory.lib.mjs
Lines 33 to 39 in 358d84d
Pre-existing (5), all verified 5/5:
- B. Appendix C.7 (:923, :929): says PI is "already removed" with no exception. Same class as round-2 item 1. My round-2 miss. It's the one I'd ask the author to fix, and it takes a one-line qualifier. SYSTEM_DESIGN#L922-L930
()raven/docs/SYSTEM_DESIGN_AND_ARCHITECTURE.md
Lines 922 to 930 in 358d84d
- F. TOOL_INVENTORY:173: RAVEN_SCRUB_PI is still listed as used by "all" servers. The matching SYSTEM_DESIGN row was fixed.
- I. README:847: "All data stays local / no Atlassian data to external LLM providers" is false with Copilot as the client.
- H. SharePoint inline images: they're unscrubbed, but SYSTEM_DESIGN never mentions SharePoint, and :83 says responses contain "no binary data".
- D. release-lib.mjs:195: \ to / normalisation lets ".\packages\…" pass. On POSIX that runs a different file, which only exists if the PR also commits it. Low severity.
Needs a human look
None. Every finding got 5/5.
Findings I considered and dropped
- JSDoc on validateInventoryMcpServers and render: the repo convention is one-line JSDoc, the same call as in round 2.
- Stale test name; the Sysdig tamper regex also matches "not approved": the test that runs against the real .mcp.json catches that case.
- copilot-instructions:142 STRA sentence not narrowed: item 8 is accepted, and the sentence isn't false.
- "Sysdig subdomains" also matching the apex domain; :636 omitting Sysdig; where OAuth tokens live: all fall inside the allowlist breadth the author already declined.
- Commit subject not imperative: the PR will be squash-merged. Stale tool counts were already noted in round 2.
Net recommendation
Approve. The 3 Nits and the C.7 qualifier take about 10 minutes and can go in a fixup or a follow-up PR, whichever the author prefers.


Summary
Adds Sysdig Secure to RAVEN's MCP registry as a hosted remote MCP server. The MCP client (VS Code / Copilot) connects directly to Sysdig's
/mcp/secureendpoint and handles the OAuth sign-in itself. RAVEN runs no Sysdig code and stores no Sysdig credentials.This PR previously contained a local read-only stdio proxy (
packages/sysdig-mcp). That proxy has been removed; see "Why not a local proxy" below.Changes
.mcp.jsonsysdig-secure-mcpentry (type: "http").scripts/release/release-lib.mjsvalidateCatalogaccepts a.mcp.jsonentry withoutcommandonly if it is on a reviewed allowlist (APPROVED_REMOTE_MCP_SERVERS), contains onlytype: "http"andurl, and the URL is HTTPS on an approved Sysdig host and path with no credentials, port, query or fragment. Anything else fails the release. Remote entries are excluded from the bundled release catalog.scripts/release/release.test.mjs__proto__,headers, non-httptype, invalid URL,http:, foreign host, look-alike host (sysdig.com.attacker.example), embedded credentials, query string, wrong path.scripts/gen-inventory.lib.mjs,docs/TOOL_INVENTORY.mdnpm run gen-inventory.README.md,docs/SYSTEM_DESIGN_AND_ARCHITECTURE.md,.github/copilot-instructions.mdPiScrubber; tool permissions governed by the user's Sysdig role.Compared with
main, this PR touches only the 8 Sysdig-related files above. No other MCP server, package, lockfile entry or setup script is changed.Why not a local proxy
The proxy version was tested and did not work in practice:
MCP request timed out after 60000 ms).Client-managed OAuth worked reliably, keeps tokens in the client's secure storage, and needs no RAVEN code.
Security and compliance
Testing
npm run buildpasses.npm run gen-inventory:check:TOOL_INVENTORY.md is up to date.npx vitest run --root . scripts/release: 10 passed.sysdig-secure-mcpconnects in VS Code, signs in through the MCP servers panel, and lists and calls Sysdig tools.Acceptance checklist
sysdig-secure-mcpappears in the MCP client and signs in via browser OAuth.npm run build,npm run gen-inventory:checkand the release tests pass.