B4.6Bloom · ANot started

Auth at transport, not in tool input

Reading depth

What you'll learn

Auth happens when the client connects to the server, not in the parameters of each tool call. Don't put api_key fields in tool schemas.

  • Auth lives at the transport layer (Streamable HTTP: OAuth/headers; stdio: parent process).
  • Tool inputs carry operation parameters only, never identity/credentials.
  • Credentials in tool inputs leak into the model's context — log/trace/cache risk.

Authentication and identity in MCP belong at the **transport layer**, not in tool input schemas. For Streamable HTTP, that means OAuth-style flows, bearer tokens, mTLS, or transport headers handled by the MCP client/server framework. For stdio, the parent process owns identity (the user who started the client). Putting credentials into tool inputs (an `api_key` parameter on every tool, a `user_token` field) is structurally wrong — it leaks credentials into the model's context, makes tool descriptions encode secrets, and breaks the abstraction MCP is built on.

Why this matters: the model sees tool inputs. Anything you put in a tool's input schema is something the model is reading, reasoning about, and potentially generating. Credentials in that surface become part of the prompt; they may end up in logs, traces, model-side caches, or — in the worst case — emitted back to the user. Even if the integration would 'work,' the security shape is wrong.

The correct pattern: the client authenticates to the server at connection time (Streamable HTTP) or by virtue of being the parent process (stdio). The server uses the established identity to scope all subsequent calls. Tool inputs carry only the *operation parameters* (what to do), never the *identity* (who is doing it).

Detection signature: tool schemas contain fields named `api_key`, `auth_token`, `user_id`, `session_token`, `bearer`. Each is a smell — sometimes legitimate (passing through a downstream system's parameter), but usually a sign that auth has leaked into the wrong layer. Refactor to handle identity at the transport handshake instead.

Key points

  • Auth lives at the transport layer (Streamable HTTP: OAuth/headers; stdio: parent process).
  • Tool inputs carry operation parameters only, never identity/credentials.
  • Credentials in tool inputs leak into the model's context — log/trace/cache risk.
  • Schema fields named api_key / auth_token / bearer in tool inputs are smells.

Examples

Wrong: auth in tool input

tool: send_email(api_key, to, subject, body) The model reads api_key on every call; it lands in conversation history, logs, traces.

Right: auth at transport

Client establishes auth at HTTP connection (OAuth flow). Server scopes to the authenticated user. tool: send_email(to, subject, body) No credential surface in the tool schema; the model never sees the key.

Pitfalls

  • Treating tool inputs as a convenient place to pass per-call auth. Convenient ≠ correct.
  • Multi-tenant servers that use a `tenant_id` tool input as if it were auth. Use real identity at the transport.
  • Forgetting that the model literally reads tool input descriptions and values during selection — secrets there become prompt content.

Source notes: 00-academy-basics/notes/05-mcp-intro.md

Ask Claude

Build a prompt with this lesson + your question, copy it, and open the Claude Project in a new tab.