jev-agent-authorization
Health Uyari
- License — License: MIT
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Low visibility — Only 5 GitHub stars
Code Uyari
- process.env — Environment variable access in convex/_generated/server.js
Permissions Gecti
- Permissions — No dangerous permissions requested
Bu listing icin henuz AI raporu yok.
Jev agent authorization for MCP tool calls: Kinde identity and permissions plus Jev's typed, calibrated decisions, checked server-side before every call runs
Jev Gatehouse: Jev agent authorization with Kinde
A starter kit that checks every AI agent tool call before it runs. Kinde checks who the agent acts for and what that user can do. Jev, the System One model from TypeSafe AI, judges each call in about 200 ms. Policy code in the app decides: allow the call, ask the user to approve it, or stop it.
Live demo: jev-gatehouse.vercel.app

What it does
An agent calls a small workspace API through a Kinde MCP connection. The Kinde MCP server passes the user's access token to the API. The guard in front of the API runs these steps for each call:
- Verifies the Kinde access token (issuer, audience, signature).
- Reads the user's permissions and feature flags for the organization, from the token or from the Kinde Management API.
- Denies the call if a Kinde permission or flag is missing. Allows reads that have the permission.
- Sends every other call to Jev with the user's request, the tool call and the documents the agent read. Jev returns calibrated signals: does the call match the request, is it destructive, does it follow planted text, does it send data out, and how risky is it.
- Decides in code from the signals. A low-confidence call goes to an LLM judge.
- Writes the decision to a ledger before anything runs. If the write fails, the call does not run.
A call that needs approval is held for 10 minutes. The user approves it on a page that requires a fresh sign-in. The held call then runs once.
The app has five pages:
- Ledger (
/): a live stream of every decision, with the Kinde checks, the Jev signals and the cost. - Agent console (
/console): an in-app agent that uses the same Kinde MCP path as any external client. - Attack playground (
/playground): scripted attacks, such as planted instructions in a document, that go through the real guard. - Benchmark (
/benchmark): 300 labeled tool calls, three ways to decide, and the results. - Connect (
/connect): the Kinde MCP URL, the Cursor setup, and the tools that Kinde builds from the OpenAPI spec.
Who it is for and when to use it
Use this kit if your product has an API and your users want to reach it from an AI agent. For example:
- A SaaS team that ships an MCP server so customers can use the product from Cursor, Claude or their own agents.
- A platform team that puts internal APIs behind an agent.
- A developer who connects an agent to production data and wants a check before each write.
Add the guard when an agent can do something that is hard to undo: delete data, move money, change who has access, or send data out. Permissions alone do not stop these calls. An agent can follow text that it read in a document, and the user's permissions still allow the call. The guard asks a second question on every call: did the user ask for this?
Reads that the user has permission for skip Jev, so they add no cost.
How it works
flowchart LR
subgraph Clients
A1[Cursor or another MCP client]
A2[In-app agent]
end
subgraph Kinde
K1[Secure MCP connection]
K2[Sign-in, organizations, permissions, feature flags]
end
subgraph Convex
G[Guard]
L[(Decision ledger)]
W[Workspace API]
end
J[Jev on OpenRouter]
U[Approval page with fresh Kinde sign-in]
A1 --> K1
A2 --> K1
K1 -- "user token + X-Kinde-User-Id" --> G
G -- "verify token, read access" --> K2
G -- "state: call, request, what the agent read" --> J
J -- "typed signals" --> G
G --> L
G -- "allow" --> W
G -- "step-up: held call" --> U
U -- "approved once" --> W
For each call, the guard makes one decision:
sequenceDiagram
participant Agent
participant Kinde as Kinde MCP
participant Guard
participant Jev
participant Ledger
participant API as Workspace API
Agent->>Kinde: tools/call deleteProject
Kinde->>Guard: DELETE /api/v1/projects/acme-rebrand (user token)
Guard->>Guard: verify token, check permission and flag
Guard->>Jev: tool call, user request, content the agent read
Jev-->>Guard: matches 0.90, destructive 0.96, injected 0.06
Guard->>Ledger: step_up, high_impact_operation
Guard-->>Kinde: 403 with approval link
Kinde-->>Agent: held, give the user this link
Note over Guard,API: The user signs in again with Kinde and approves. The call runs once.
Screenshots
| The ledger | An attack, stopped |
|---|---|
![]() |
![]() |
| A destructive call, held for approval | Connect any agent through Kinde MCP |
![]() |
![]() |

Benchmark results
The benchmark sends the same 300 tool calls, 3 times each, to three deciders. The false-allow rate is the share of calls that should not run but were allowed.
| Decider | False-allow | Accuracy | p50 latency | Cost per 1,000 calls |
|---|---|---|---|---|
| Jev signals with policy code (this kit) | 0.0% | 83.7% | 205 ms | $0.029 |
| Jev single verdict | 12.4% | 71.3% | 204 ms | $0.033 |
| LLM judge (Claude Sonnet 5) | 7.9% | 77.6% | 2,073 ms | $0.931 |
We wrote the cases and the labels. Run npm run bench to measure your own deployment. The benchmark page shows the limits of the method.
Development
Requirements
- Node.js 20.17 or later
- A Kinde business
- A Convex account
- An OpenRouter API key, for Jev, the LLM judge and the in-app agent
Initial set up
Clone the repository to your machine:
git clone https://github.com/kinde-starter-kits/jev-agent-authorization.gitGo into the project:
cd jev-agent-authorizationInstall the dependencies:
npm installCopy the environment file:
cp .env.local.sample .env.localStart Convex. This creates a deployment and writes
CONVEX_DEPLOYMENT,NEXT_PUBLIC_CONVEX_URLandNEXT_PUBLIC_CONVEX_SITE_URLto.env.local:npx convex dev
Set up Kinde
API. Create an API with the audience
https://gatehouse.api. Add these permissions:Permission Lets the user gatehouse:projects:readList and read projects gatehouse:projects:writeArchive projects gatehouse:projects:deleteDelete projects gatehouse:docs:readList and read documents gatehouse:docs:writeCreate and change documents gatehouse:invoices:readList invoices gatehouse:refunds:createRefund invoices gatehouse:members:readList members gatehouse:members:manageInvite and remove members gatehouse:customers:exportExport customer records Roles. Create
viewer(the read permissions),operator(the read permissions plusdocs:write,projects:writeandrefunds:create) andadmin(all permissions). Give your user a role in the organization the app uses.Feature flag. Create a boolean flag
bulk_exportat organization scope, default off. Exports need it.Web app. Create a back-end web application. Authorize it for the API. Set the callback URL to
http://localhost:3000/api/auth/kinde_callbackand the logout URL tohttp://localhost:3000. Put its values in theKINDE_*variables of.env.local.M2M app. Create a machine-to-machine application with the Management API scopes
read:organization_user_permissionsandread:organization_feature_flags. The guard uses it when a token has no organization, which is the case for most MCP clients.MCP connection. Create a Secure MCP connection:
- OpenAPI spec:
https://<your-deployment>.convex.site/api/openapi.json - Back-end URL: your Convex site URL
- Authentication: pass the user token through
- Extra header:
X-Kinde-User-Id: {{kinde.user.id}}
Do not turn on role-based access control for the MCP sign-in. MCP sign-ins have no organization, so Kinde refuses them. The guard checks organization permissions itself.
- OpenAPI spec:
Set Convex environment variables
Set these with npx convex env set NAME value:
| Variable | Value |
|---|---|
KINDE_ISSUER_URL |
https://<your_kinde_subdomain>.kinde.com |
GATEHOUSE_AUDIENCE |
https://gatehouse.api |
GATEHOUSE_ORG_CODE |
The organization code the app uses |
KINDE_M2M_CLIENT_ID, KINDE_M2M_CLIENT_SECRET |
From the M2M app |
KINDE_WEB_CLIENT_ID |
The web app client ID |
GATEHOUSE_APP_URL |
http://localhost:3000 |
GATEHOUSE_MCP_URL |
Your Kinde MCP connection URL |
OPENROUTER_API_KEY |
Your OpenRouter key |
JEV_MODEL |
Optional. Default typesafe/jev-1.13 |
LLM_JUDGE_MODEL |
The model for the LLM judge, for example anthropic/claude-sonnet-5 |
AGENT_MODEL |
Optional. The model for the in-app agent |
Run the app
Run Convex and Next.js in two terminals:
npx convex dev
npm run dev
Open http://localhost:3000 and sign in. The app creates your workspace on the first call. To put the workspace back to its first state:
npx convex run seed:resetWorkspace '{"ownerSub":"<your_kinde_user_id>"}'
Connect an MCP client
Add your Kinde MCP connection URL to an MCP client such as Cursor. The client signs you in through Kinde. Every tool call then goes through the guard and shows on the ledger.
Test
| Command | What it does |
|---|---|
npm test |
Unit and integration tests for the guard, the policy, Jev parsing, the agent and the benchmark |
npm run e2e |
A live check through Kinde MCP. Set E2E_MCP_URL and E2E_ACCESS_TOKEN first. See scripts/e2e.mjs |
npm run bench |
Runs the 300-case benchmark on your deployment. It makes about 2,000 model calls |
npm run lint |
ESLint |
npm run typecheck |
TypeScript |
A commit runs ESLint and Prettier on the staged files.
Project structure
convex/guard/: token checks, Kinde access, policy, the guard handler and the approval routesconvex/jev/: the Jev questions, the Jev client and the LLM judgeconvex/agent/: the in-app agent, its MCP client and the attack scenariosconvex/bench/: benchmark cases, runner and metricsconvex/workspace/: the workspace operations that the agent callssrc/app/: the Next.js pages
Documentation
- Kinde docs for sign-in, permissions, feature flags and MCP connections
- Introducing System One models and Jev for Jev
- Convex docs for the back end
Publishing
This is a starter kit, so there is no package to publish. A GitHub Action runs lint, typecheck, tests and a build on every push and pull request to main.
Contributing
Please refer to Kinde’s contributing guidelines.
License
By contributing to Kinde, you agree that your contributions will be licensed under its MIT License.
Yorumlar (0)
Yorum birakmak icin giris yap.
Yorum birakSonuc bulunamadi



