← All posts With user-facing MCP, you can let your users connect their AI agents to your app’s data in a governed, read-only way.
Your customers can use their agent app of choice – Claude, Codex, Cursor, or anything else that speaks MCP – and query their own data through your semantic layer.
Users authenticate through your own auth flow when connecting. Motley provides filtering mechanisms and safeguards so one user’s data never leaks to another. We support all major IdPs that speak OpenID Connect, such as Auth0, WorkOS, Okta, and Clerk, as well as your own solutions.
Configuring data access #
Defining what users can and cannot see happens on 2 levels: models and RLS (row-level security) filtering rules.
Your users’ agents only see the columns and measures that are in the models – no one can ever query a column in your DB that is not referenced in a model. Also, model columns can be marked as hidden – this keeps them out of everything the agents are shown (model listings, model inspection, sample rows) while they remain available to your named measures. The agents can see only non-hidden columns and the measures from your models.
Hiding a column is not a security boundary, though: it is left out of the catalog, not blocked at query time. If a column must be unreachable, leave it out of the model or scope it away with a filtering rule.
RLS filtering
A more interesting question you might have is how we isolate the users’ data from each other. The answer is RLS filtering rules. They are SQL-level, applied under the model layer, so our underlying database adapter behaves as if only this user’s rows exist.
Motley supports 2 types of RLS rulesets: column-based and join-based. Column-based is for cases where every table contains a column such as tenant_id
or similar that signals which user a row belongs to – this is usually the case if your application already uses RLS. Join-based works when the rows need to be filtered according to some property of another table, such as users.id
– that table carries the identifying column, and every other table reaches it through its own join path. Tables with no path are blocked unless you explicitly whitelist them as shared data. More technical details can be found in the SLayer RLS documentation.
The actual value of the filter (such as the tenant id) is typically supplied from a certain field in the JWT token returned by your identity provider, like {jwt.tenant_id}
– see below.
Authenticating your users #
You register an OAuth client for Motley in your IdP and paste its details in Motley dashboard.
When a user connects their agent to your MCP, Motley redirects them to your IdP’s login page. After completing the OAuth flow, Motley validates the ID token your IdP issued, asks the user once to approve the agent that is connecting, and then issues its own short-lived access token to that agent. That token carries the claims your filtering rules reference, so every query the agent makes is scoped to that user. Motley never sees the user’s credentials; the refresh token from your IdP is stored encrypted so that a long-lived session can be re-validated with you.
Testing the setup #
After you’ve configured your RLS filtering rules, you can test them by impersonating user identities. In Playground, you can paste the field values into the Variables block and run any query to check which data that user will see.
What users can do #
Once connected, a customer’s agent can:
- List the data models available to it, with their columns and measures
- Inspect a single model in detail – its columns, measures and joins, optionally with the underlying SQL and a few sample rows (the sample obeys the same RLS policy)
- Run queries with the columns and measures defined in the semantic layer, seeing only what they can according to the RLS policy
For more technical details and a setup walkthrough, see User-Facing MCP documentation.