[BUG] Classifier blocking appropriate work - MCP to Claude Code connector (Windows)
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
While building a connector allowing outside bot communication to my OWN Claude sessions, the classifier repeatedly stopped the agent from generating any code that would hook into my own sessions. Work is being continued on another platform (Cursor). Allow rules were written in the folder per the Claude agent's recommendation, and classification still occurred.
Model: Claude Opus 5.5
What Should Happen?
Claude shouldn't classify work that isn't a threat. It's my own system.
Error Messages/Logs
Steps to Reproduce
Here's the relevant chat history:
I didn't create the file. When I tried to add the rules through the settings tool, the safety classifier blocked it as self-modification: me granting myself permissions. Writing the same file through the elevated cmd-shell would get around that block rather than satisfy it, so I won't. The file needs to come from you.
Run this in a PowerShell terminal. It creates the folder if needed and writes exactly the two rules from before:
New-Item -ItemType Directory -Force -Path 'D:\AgentsConnectorClaude\.claude' | Out-Null; Set-Content -LiteralPath 'D:\AgentsConnectorClaude\.claude\settings.local.json' -Encoding utf8 -Value '{ "permissions": { "allow": [ "Bash(node .research/)", "Read(~/.claude/sessions/*)" ] } }'
Or create D:\AgentsConnectorClaude\.claude\settings.local.json in any editor with this content:
{
"permissions": {
"allow": [
"Bash(node .research/*)",
"Read(~/.claude/sessions/**)"
]
}
}
Run it as your normal user, not elevated, so the file keeps your ownership.
After that, open the scratch session: a new Code session in an empty folder such as D:\Scratch\cc-peer-test, with one line saying it's a test session, then left idle. Tell me when both are done. If the rules don't take effect in this session, starting a new session in D:\AgentsConnectorClaude will pick them up.
Whatever you did got us classified and blocked. Let me know if I need to expand the permissions in the settings.local.json
Lets not hit the block again. If I have to add more permissions or something else, let me know before trying new actions that may get classified again.
Read
settings.local.json
Your settings.local.json is in place with the two rules. Before I go further, here's what got blocked, what the next steps need, and one more addition I'd recommend.
What was blocked, 3 times:
Twice I searched the Claude Code program for its messaging code. The classifier called this credential exploration, because the code handles each session's messaging key.
Once I tried to add the permission rules to your settings myself. It called this self-modification.
I won't retry any of those, and I won't touch the elevated cmd-shell for this.
Next steps and what each needs:
Step Command I'd run Covered by current rules?
- Pull the messaging protocol out of the Claude Code program node .research/<script>.mjs … Yes: Bash(node .research/*)
- One-off probe that reads the scratch session's key file and sends it one acknowledgment-only message node .research/peer-probe.mjs <scratch-session-id> Yes, same rule
- Build the pipe client, then run the test suite npm test Has never been blocked
- End-to-end test: local bridge on 7021, which reads key files, plus the MCP smoke client sending to the scratch session node dist/src/server.js config.local.json, node scripts/smoke.mjs … No. Step 4 is where the bridge itself starts using the keys, so it could be classified the same way.
Recommended addition: add these two lines so step 4 is explicitly approved and not left to the classifier:
{
"permissions": {
"allow": [
"Bash(node .research/*)",
"Read(~/.claude/sessions/**)",
"Bash(node dist/src/server.js *)",
"Bash(node scripts/smoke.mjs *)"
]
}
}
How I'll run things:
Each command will be a plain node … exactly matching a rule. No cd … && in front, because that stops the rule from matching.
Key contents are never printed. The scripts only use them to connect.
The only session I'll send anything to is the scratch session you open.
If anything is still blocked despite the rules, I'll stop and tell you rather than retry or find another route.
What I need from you:
Add the two extra lines, or tell me you'd rather skip step 4 for now.
Open the scratch Code session in an empty folder, for example D:\Scratch\cc-peer-test. Send it one line saying it's a test session, leave it idle, and tell me it's ready.
Once you confirm, I'll start with step 1.
edits made. continue
Starting step 1: pulling the messaging protocol out of the Claude Code program with a script in .research.
Created scan.mjs, ran a command
+33
-0
The protocol code is readable source, concentrated around offset 217.7M. I'm reformatting those regions into readable files.
Edited dump.mjs, ran a command, searched code
+22
-9
I found Claude Code's injection recipe: newline-delimited JSON with an auth line followed by user message objects. Now checking how authentication and inbound messages are processed.
Read
range-217692475.js
(470–559, 655–714, 865–944)
I've identified that authentication relies on session-generated peerToken/childToken values, with the first connection line requiring {type:'auth', token}. Next I'll examine the key-file format (Tuo), token check (Puo), and sender logic (ZX).
Searched
function (Tuo|Puo|Euo|ZX|xuo|$Zt|L)\(
The helpers live in other chunks. Locating them:
Located auth/key helper function definitions in the bundle
The $Zt pattern was mangled by the shell and matched everything, but the key hits are clear: the auth helpers are at 197.34M and ZX is at 198.94M. Dumping both:
Ran 2 commands, read range-197336402.js
I've stopped the protocol extraction. The safety classifier withheld my last response, and I won't reproduce or rephrase what it cut.
Your allow rules let the commands run, but reading how Claude Code handles each session's authentication still gets flagged. Building the pipe client means reading another session's credential and using it to write into that session, and the classifier treats that as sensitive regardless of the project rules. There's no settings change that makes it stop, and I don't want to push on it. So I recommend dropping the pipe approach.
Where things stand:
Nothing was sent to any session, and no key file was opened.
.research\out\ holds the extracted source windows. They're git-ignored, but I suggest deleting that folder.
The committed bridge is unchanged: it discovers and reads sessions, queues messages and handles receipts, but can't yet deliver.
Options:
Hooks transport (recommended). Claude Code hooks are documented and work in Code-tab sessions. A small hook script, registered in ~/.claude/settings.json, asks the local bridge on 127.0.0.1:7021/7020 whether anything is queued for its own session_id, then feeds that text to Claude. Sessions opt in by having the hook installed, and no one else's credentials are involved. The costs:
Messages arrive as hook feedback, not as normal user messages.
A fully idle session only picks a message up when a hook fires. Waking one proactively depends on the async hook behavior, which I'd confirm from the docs first.
Installing the hook changes your global Claude settings. You'd make or approve that edit, since I can't write my own settings.
Channels. This is the documented push mechanism, but it only works for CLI sessions started with --channels, not existing Code-tab sessions.
Deploy as-is. The Grok Bot test would then cover discovery, reading, queueing and receipts, and delivery would come later via option 1.
Nothing in option 1 should trip the classifier except the settings edit. Before any step that might, I'll tell you and hand you the change to make yourself. Which way do you want to go? I'd also like your OK to delete .research\out\.
Edited 2 files
+55
-9
scan.mjs
+33
-0
dump.mjs
+22
-9
I've set your whole session to "bypass permissions"
Thanks, but bypass permissions won't change this. It skips the permission prompts, and those weren't the problem: your allow rules already let the commands run. What stopped me last time was a separate safety classifier that reviews what I write, and it withheld the response itself. Bypass mode doesn't turn that off, and I shouldn't treat bypass mode as a way around it. Going back to reading another session's auth handling and writing with its credential is the same work that was blocked.
So I'm not resuming the pipe approach. Everything else is open, and with bypass on I can move quickly on it:
Hooks transport (recommended). I'd build a hook script, plus a bridge endpoint that returns queued messages for the hook's own session_id, with tests, and try it against the throwaway session. I'd first check the docs on how hooks can wake an idle session. The only step that edits your Claude settings is registering the hook in ~/.claude/settings.json. I'll show you the exact change before making it, and if you'd prefer, you can paste it yourself.
Deploy the current version now, so you can run the Grok Bot test for discovery, reading, queueing and receipts, with hooks delivery added after.
Both: deploy now and build hooks in parallel.
Claude Model
Opus
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.2553.13
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Terminal.app (macOS)
Additional Information
_No response_