Pro

What an MCP consent screen needs

Articles ·

An MCP server that does anything useful needs to know whose bookings, inbox or payments it's touching, so remote servers sign people in with OAuth. The person clicks Connect in their agent, a browser tab opens on your server, and your server asks: may this agent have access?

That page gets less attention than any other screen in the product. It's usually the OAuth library's default: a logo, "Authorize application", the scopes as the request spelled them, one button. For MCP that's not enough, for one reason: most MCP clients introduce themselves. They register with your server the first time they connect, so the name on the request is whatever the client said it was. Your server has never seen most of them before, and can't check the name. The consent screen is where a person decides whether to trust it.

Here's a working one. Allow it, cancel it, or untick everything it could change and watch the button.

Copper connecting to Acme’s MCP server

Copper wants to access Acme

  • See your bookings (always included)
  • See menus and recipes (always included)

You’ll return to localhost:33418

The first Allow fails on purpose, so you can see the error and retry.

An app the server doesn’t know, read-only

pantry-sync wants to access Acme

  • See your bookings (always included)
  • See menus and recipes (always included)

Acme hasn’t verified pantry-sync. Only allow it if you started this yourself.

You’ll return to pantry-sync.example.net

1. Name both sides in the heading

"Copper wants to access Acme" says who's asking and for what in five words. "Authorize application" says neither. Put the two logos above it with a few dots between them: it's the one picture everyone already reads as "connect these two".

2. Show who's signed in

People have work and personal accounts, and a shared laptop has someone else's. Show the email of the account the agent will act as, with a way to switch right there. Connecting the wrong account is the most common mistake on this screen, and the hardest to notice later.

3. Say where they'll go back to

After Allow, your server sends the browser to the client's redirect address with a code that becomes the agent's access. That address is the part of the request an attacker controls. Show its host exactly as it is, localhost:33418 included, port and all:

Afterwards you'll go back to localhost:33418.

A person who started from Copper on their own laptop expects localhost. A person who clicked a link in an email doesn't, and this line is the only place they'd find out.

4. Warn about clients you don't know

Unless your server has a reason to vouch for the client (it's your own app, or one you've reviewed), say so, in one sentence, in the warning color:

Acme hasn't verified pantry-sync. Only allow it if you just started this from pantry-sync yourself.

Not a wall of red, and not a scary checkbox. The instruction has to be something a person can actually check: did I just do this?

5. Write permissions as things a person would say

The request says bookings:read lists:write messages:write. A person needs to know what the agent can see and what it can change, and the verb says both: "See your bookings", "Change shopping lists", "Message your guests". One list, reads first, no headings and no scope names. Add a line of detail only when the phrase isn't enough.

6. Make the risky ones optional, and off

Some permissions the agent needs to work at all; mark those required and don't make people tick them. Everything else is a checkbox. Anything that moves money, deletes things or speaks for the person in public starts unticked: Refunds, in the example. The client can ask for it again later, when it actually needs it.

When every change is unticked, the button says so: Allow read-only. The label is the last thing anyone reads before they press it, so it's the right place for the consequence.

7. Errors that say nothing happened

If issuing the grant fails, the important news is that nothing was shared. Say that, say what failed, and offer the same button again:

Acme didn't answer within 10 seconds. Nothing was shared; try again.

8. End with a result, not a redirect

After Allow, the browser leaves for the client. Before it does, or when the client is a desktop app that doesn't take the tab back, the page should say what just happened in one line: connected to Acme, and you can go back to Copper. After Cancel: not connected, nothing shared.

Move focus to that heading. The buttons it came from are gone, and a screen reader user otherwise lands nowhere.

The short version

  • Heading: "Agent wants to access Server".
  • The signed-in account, with Switch.
  • The return host, exactly.
  • A one-line warning for clients you don't know.
  • Permissions as verb phrases in one list.
  • Risky permissions optional and unticked; "Allow read-only".
  • Errors that say nothing was shared.
  • A result that says what happened.

The Authorize component is all of the above in one small card, with the motion and accessibility worked out, ready for your agent to drop into your server's authorization page. Its counterpart on the agent's side is Connections, the list where people see and manage the servers they've connected.