1. as many have harped about, the LLM writing is so fluffed up it's borderline unreadable. Please just write in your own voice. It's more interesting and would probably be easier to grok
2. that repo is obviously vibe-coded, but I suppose it gets the point across. It doesn't give me much confidence in the code itself, however.
And a big thing:
Unless I'm misunderstanding, I feel like you are re-inventing the wheel when it comes to Authorization via MCP, as well as trying to get away with not having extra logic at the app layer, which is impossible here.
MCP servers can use OIDC to connect to your auth server right now: https://modelcontextprotocol.io/docs/tutorials/security/auth...
You give the following abstractions, which I think are interesting thought experiments but unconventional and won't work at all:
Ring 0 (Constitutional): System-level constraints. Never overridable.
Example: "Never self-replicate" "Never exfiltrate credentials"
Ring 1 (Organizational): Policy-level constraints. Requires admin authority to change.
Example: "No PII in outputs" "Read-only database access"
Ring 2 (Session): User preferences. Freely changeable by user.
Example: "Explain like I'm five" "Focus on Python examples"
In Ring 0 and 1 you're still asking for the LLM to determine if the security is blocked, which opens it up to jailbreaking. Literally what your whole article is about. This won't work: # Generate (Pass filtered tools to LLM)
response_text, security_blocked = self._call_llm(
query, history, system_prompt, allowed_tools, tools
)
Ring 0 and 1 MUST be done via Authorization and logic at the application layer. MCP Authorization helps with that, somewhat. Ring 2 can simply be part of your system prompt. Standard RBAC acts as a firewall: it catches the model’s illegal action after the model attempts it.
That's the point. It's the same reason you will have mirroring implementations of RBAC on a client and server: you can't trust the client. LLM can't do RBAC. It can pretend it does, but it can't.The best you can do is inject the user's roles and permissions in the prompt to help with this, if you'd like. But it's kind of a waste of time -- just feed the response back into the LLM so it sees "401 Unauthorized" and either tries something else or lets the user know they aren't allowed.
I'm sorry, but as a resident of Ontario and a developer this whole posting just enrages me. I don't want to discourage OP but you should know there's a lot just incorrect here. I'd be much more relaxed about that if it all wasn't just one-shotted by AI.