Skip to content

feat: add MCP client access policy#84

Open
Zhenyu98 wants to merge 1 commit into
Waishnav:mainfrom
Zhenyu98:security/chatgpt-client-access-policy
Open

feat: add MCP client access policy#84
Zhenyu98 wants to merge 1 commit into
Waishnav:mainfrom
Zhenyu98:security/chatgpt-client-access-policy

Conversation

@Zhenyu98

@Zhenyu98 Zhenyu98 commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add an opt-in MCP client denylist with off and enforce modes
  • inspect initialize.params.clientInfo before creating the MCP transport
  • reject matching clients with HTTP 403 and JSON-RPC error -32003
  • add structured client observation and denial logs
  • add regression coverage for Codex detection and clients without clientInfo

Motivation

ChatGPT and Codex currently share connected apps. DevSpace is intended to let ChatGPT control the local PC remotely, while Codex already runs locally and should use its native filesystem, shell, Git, and patch tools.

Without a server-side guard, Codex may accidentally invoke DevSpace instead of its native tools.

Behavior

Enable the guard with:

DEVSPACE_CLIENT_ACCESS_MODE=enforce
DEVSPACE_DENIED_CLIENTS=codex

Clients matching the denylist are rejected before an MCP transport or workspace session is created. Clients that omit clientInfo are allowed to preserve current ChatGPT compatibility.

Practical deployment testing confirmed:

  • ChatGPT open_workspace succeeded
  • Codex open_workspace returned HTTP 403, JSON-RPC -32003, and MCP client not allowed
  • Codex MCP App resource reads were also denied

clientInfo is self-declared, so this is a guard against accidental client use rather than cryptographic isolation.

Verification

  • npm test
  • npm run typecheck
  • npm run build
  • git diff upstream/main...HEAD --check
  • live ChatGPT connection test
  • live Codex denial test

Summary by CodeRabbit

  • New Features
    • Added optional client access controls for MCP initialize requests.
    • Supports enforcing a deny-list of client identities and returns a clear JSON-RPC access-denied response (HTTP 403) for blocked clients.
  • Configuration
    • Documented environment and config options for access mode and denied clients.
    • Defaults to disabled (off) unless enforcement is enabled.
  • Tests
    • Added unit and HTTP integration coverage for client extraction, access decisions, configuration parsing, and invalid settings.

@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2f203b8c-405f-48bd-8612-68ccbebf08d0

📥 Commits

Reviewing files that changed from the base of the PR and between e2e032a and 5a28200.

📒 Files selected for processing (9)
  • .env.example
  • package.json
  • src/client-access-http.test.ts
  • src/client-access.test.ts
  • src/client-access.ts
  • src/config.test.ts
  • src/config.ts
  • src/server.ts
  • src/user-config.ts
🚧 Files skipped from review as they are similar to previous changes (7)
  • .env.example
  • package.json
  • src/client-access.test.ts
  • src/config.test.ts
  • src/user-config.ts
  • src/client-access.ts
  • src/config.ts

📝 Walkthrough

Walkthrough

Adds configurable MCP client access control. Client declarations are extracted from initialize requests, normalized against a denylist, and enforced by the server. Configuration supports environment and persisted settings, with tests covering policy behavior and HTTP enforcement.

Changes

Client Access Guard

Layer / File(s) Summary
Client access configuration
src/user-config.ts, src/config.ts, src/config.test.ts, .env.example
Adds optional client-access settings, environment/file parsing, validation, persisted configuration coverage, and example variables.
Client declaration and policy evaluation
src/client-access.ts, src/client-access.test.ts
Extracts and sanitizes initialize.clientInfo, derives normalized identities, and evaluates denylist matches with focused tests.
Initialize request enforcement
src/server.ts, src/client-access-http.test.ts, package.json
Rejects denied clients with JSON-RPC 403 responses, logs decisions and startup settings, and runs unit and HTTP coverage through the test script.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Suggested reviewers: waishnav

Sequence Diagram(s)

sequenceDiagram
  participant MCPClient
  participant MCPServer
  participant ClientAccessPolicy
  MCPClient->>MCPServer: Send MCP initialize request
  MCPServer->>ClientAccessPolicy: Extract declared client
  ClientAccessPolicy-->>MCPServer: Return normalized client
  MCPServer->>ClientAccessPolicy: Evaluate configured access policy
  ClientAccessPolicy-->>MCPServer: Return allow or deny decision
  MCPServer-->>MCPClient: Continue or return JSON-RPC 403
Loading

Poem

A rabbit guards the client gate,
With codex marked to wait.
Names are cleaned and lists are read,
Safe decisions hop ahead.
Tests twinkle in the meadow bright—
The server knows wrong from right.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding an MCP client access policy.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Zhenyu98
Zhenyu98 force-pushed the security/chatgpt-client-access-policy branch 2 times, most recently from 8d925bc to e2e032a Compare July 18, 2026 11:55
@Zhenyu98
Zhenyu98 marked this pull request as ready for review July 18, 2026 12:08

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
package.json (1)

31-31: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Add an HTTP-level regression test for initialize denial.

The new command runs policy-unit tests only. Add a server test proving a denied initialize request returns HTTP 403/code -32003, while missing clientInfo proceeds, before any transport or session is created.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@package.json` at line 31, Add an HTTP-level regression test to the server
test suite, alongside the existing initialize/policy tests, covering both cases:
a denied initialize request returns HTTP 403 with code -32003, while an
initialize request without clientInfo proceeds before creating any transport or
session. Update the package.json test script’s test command to execute the new
server test.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/config.ts`:
- Around line 129-150: Update parseClientAccessMode to distinguish undefined
from an empty string: default to "off" only when value is undefined, while
treating "" as invalid and throwing the existing configuration error. Preserve
the "off" and "enforce" handling for their explicit values and keep
parseClientAccessConfig’s environment-variable precedence unchanged.

In `@src/server.ts`:
- Around line 1762-1765: Update the denial branch around sendJsonRpcError in the
initialize request handling to pass the validated initialize request’s JSON-RPC
ID, including 0, through the error-response helper. Extend or reuse
sendJsonRpcError so it emits that ID instead of always using null, while
retaining null only when the request ID cannot be established.

---

Nitpick comments:
In `@package.json`:
- Line 31: Add an HTTP-level regression test to the server test suite, alongside
the existing initialize/policy tests, covering both cases: a denied initialize
request returns HTTP 403 with code -32003, while an initialize request without
clientInfo proceeds before creating any transport or session. Update the
package.json test script’s test command to execute the new server test.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8da7000a-369f-4b92-a7f1-724333f28395

📥 Commits

Reviewing files that changed from the base of the PR and between 80423b5 and e2e032a.

📒 Files selected for processing (8)
  • .env.example
  • package.json
  • src/client-access.test.ts
  • src/client-access.ts
  • src/config.test.ts
  • src/config.ts
  • src/server.ts
  • src/user-config.ts

Comment thread src/config.ts
Comment thread src/server.ts
@Zhenyu98
Zhenyu98 force-pushed the security/chatgpt-client-access-policy branch from e2e032a to 5a28200 Compare July 18, 2026 12:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant