Terminal — ai coding agent — ~/project
~/project $ agent
ai-coding-agent v1.0.40
Model: a-random-sota-model via LLM Gateway
MCP Servers:
✓ notion (remote — OAuth)
✓ github (remote — OAuth)
● tavily (remote — OAuth) — Not authenticated
You: Use the tavily MCP to search "what is the model context protocol"
Agent: I'll run that search for you.
tool search
{
"query": "what is the model context protocol"
}
mcp tavily requires authentication
Server returned: 401 Unauthorized — Bearer token required
Agent: The tavily MCP server requires OAuth authentication.
Opening browser for SSO login...
◠ Waiting for OAuth callback on localhost:9876...
Terminal — ai coding agent — ~/project
... (OAuth flow completed in browser)
oauth ✓ Token received from Cognito
User: dev@example.com
Scopes: openid, tavily-mcp/search
Expires: 3600s
MCP Servers:
✓ notion (remote — OAuth)
✓ github (remote — OAuth)
✓ tavily (remote — OAuth) — Authenticated as dev
Agent: Great, I'm now authenticated. Let me run that search.
tool search
// params
{
"query": "what is the model context protocol"
}
// output
{
"answer": "The Model Context Protocol (MCP) is an open standard that lets AI models connect to external tools and data sources through a uniform interface.",
"results": [
{ "title": "What is the Model Context Protocol?",
"url": "https://www.databricks.com/blog/what-is-model-context-protocol" }
]
}
200 ✓ Returned for dev@example.com (JWT validated)
Agent: Here's what I found:
MCP is an open standard for connecting AI models to external tools and data through a uniform interface.
You: Now use tavily to extract the full text of that page
Agent: I'll try the extract tool.
tool extract
// params
{
"url": "https://www.databricks.com/blog/what-is-model-context-protocol"
}
// output
{
"error": "forbidden",
"message": "dev@example.com does not have scope 'tavily-mcp/extract'",
"required_scope": "tavily-mcp/extract",
"user_scopes": ["openid", "tavily-mcp/search"],
"status": 403
}
403 ✗ Forbidden — missing required scope
Agent: Access denied. Your token only grants tavily-mcp/search.
The extract tool requires tavily-mcp/extract, which your role doesn't include.
This is OAuth working as intended:
The AI agent can only call the tools your scopes allow. No more, no less.
⚠ Meanwhile, in the shared-API-key timeline...
💀 The "Old Way" — hardcoded credentials
✗Shared API key baked into every developer's mcp.json
✗Every call shares one identity — no per-user scope, no tool boundaries
✗Audit log says "api-key-prod" — who actually made the call?
✗Someone leaves? Rotate key → break everyone
✗Key leaked in a repo? Full access until someone notices
// .mcp.json — the nightmare version
{
"tavily": {
"type": "stdio",
"command": "npx",
"args": ["tavily-mcp"],
"env": {
"TAVILY_API_KEY": "tvly-SHARED-KEY-everyone-has-this" // 💀 on every laptop
}
}
}
✓ With OAuth MCP
// .mcp.json — the OAuth version
{
"tavily": {
"type": "http",
"url": "https://<your-api>.execute-api.us-east-1.amazonaws.com/mcp"
// That's it. No secrets. OAuth handles auth per-user.
}
}
✓ Per-user identity — audit says exactly who
✓ Scoped access — only what your role allows
✓ Revoke one user — everyone else keeps working
✓ No secrets in config — nothing to leak
✓ SSO integration — same login as everything else
"If you can't do it in the UI, the agent can't do it via MCP"