মূল বিষয়বস্তুতে যান
Back to Blog
Engineering

Who is calling your MCP server? Actor context for APIs and MCP tools

How to separate client identity evidence, API credentials and authorization for APIs and MCP servers, and set tool-level policies by impact.

Toshendra Sharma

By Toshendra SharmaFounder & CEO, AgentCredia · Published November 12, 2026

Who is calling your MCP server? Actor context for APIs and MCP tools
November 12, 2026
11 min read
#MCP#API Security#AI Agents#Actor Intelligence

To identify who is calling your MCP server, answer three questions separately: which client is calling, which credential it used, and what that caller may do. Label client identity by its evidence basis (a validated request signature is verified, a client name is declared, a traffic pattern is inferred, and everything else is Unknown), keep authorization with your existing tokens and scopes, and set per-tool policies by impact.

That separation matters because MCP servers and agent-driven clients have widened the set of callers an API serves. A single tool on your MCP server might be called by a desktop assistant acting for one user, by a hosted agent platform acting for many, and by an automated workflow that nobody has looked at in weeks. Every one of those calls arrives with some kind of credential. Very few arrive with a clear answer to the question that matters for policy: who or what is actually making this call, and what evidence supports that?

This article is a practical guide to answering that question for APIs and MCP servers. If you want the short product view first, see MCP server caller identification.

What your MCP server can already see

Before adding anything new, look at what the protocol and the transport already hand you. As of November 2026 there are three sources of caller information on a typical deployment.

The client's self-description

In the 2025-11-25 revision of the specification and earlier, every session opens with an initialize request, and its clientInfo object carries the client's name and version, plus optional fields such as a display title, a description and a website URL (MCP lifecycle, 2025-11-25). The 2026-07-28 revision drops the handshake and makes the protocol stateless: clients send the same information as io.modelcontextprotocol/clientInfo in the _meta field of each request, and the specification says clients SHOULD include it on every request (MCP base protocol, 2026-07-28). Servers that support both eras can see either shape (MCP versioning and compatibility).

The specification is explicit about what this field is worth. It describes clientInfo as self-reported by the sender and not verified by the protocol, intended for display, logging and debugging, and says implementations should not rely on it for security decisions. Record it, group traffic by it, and label it as declared.

Transport headers

On the Streamable HTTP transport, every JSON-RPC message from the client is its own HTTP POST to the MCP endpoint (MCP Streamable HTTP transport). That means you get ordinary HTTP context on every call: the client address, TLS details, and the User-Agent header, which HTTP defines as information about the user agent originating the request (RFC 9110, section 10.1.5). The 2026-07-28 transport also requires headers that mirror the request body, including MCP-Protocol-Version, Mcp-Method and, for tool calls, Mcp-Name with the tool name, so a gateway can log which tool was called without parsing JSON.

Over the stdio transport there are no HTTP headers at all. The server runs as a local process launched by the client, so the caller is whatever started that process.

Authorization context

For HTTP transports, a protected MCP server acts as an OAuth 2.1 resource server. The client sends Authorization: Bearer <access-token> on every HTTP request, and the server must validate that the token was issued for it as the intended audience (MCP authorization, 2026-07-28). The token tells you which grant, user and scopes apply. For stdio, the specification says implementations should take credentials from the environment instead.

What that adds up to

Put together, these sources tell you which client says it is calling, which software stack the HTTP request came from as far as the header claims, and which grant the call runs under. None of them verifies which software actually produced the request. clientInfo and User-Agent are declarations, and a bearer token identifies an account and its scopes, not the program holding it. Verified client identity needs separate evidence, such as a request signature, which the rest of this article covers.

Three questions that are easy to merge

When a request reaches an API or an MCP tool, three distinct questions are in play.

1. Which client is this?

This is a question about the software making the call. Is it a known assistant from a specific operator? An internal workflow? A script running on a laptop? The evidence here can be strong, such as a request signature that validates against an operator's published key, or weak, such as a client name the caller chose for itself.

2. Which credential did it use?

This is a question about access. An API key, an OAuth access token or a session cookie tells you which account or grant the call is associated with. It says very little about the software holding the credential. A single API key can be shared between a person's terminal, a CI job and an agent framework, and the key looks identical in all three.

3. What is this caller allowed to do?

This is the authorization question. Scopes, roles and your own business rules decide whether a given action is permitted for a given account in a given context.

Many mistakes with automated callers come from merging these questions. A team sees a valid API key and assumes the caller is the developer who created it. Or it sees a known agent's name in a header and assumes the agent may do anything the account can do. Treating the three questions separately removes both mistakes.

Declarations, signatures and inferences

The evidence available about the client falls into a few kinds. Each has a place, and each has limits.

Declared identity

MCP clients identify themselves with clientInfo, as described above, and HTTP clients send a User-Agent string. Both are declarations: the caller states who it is. Declarations are valuable for analytics and for routing well-behaved clients to the right experience. They are also trivially easy to copy. A declaration should never, on its own, grant access to anything that matters.

Verified identity

Signed requests change the picture. With HTTP Message Signatures, standardized in RFC 9421, an automated client signs parts of each request with a private key, and the server verifies the signature with the matching public key. The IETF Web Bot Auth working group is chartered to standardize methods for cryptographically authenticating automated clients. As of November 2026, its protocol document, HTTP Message Signatures for automated traffic, is an Internet-Draft that defines a Signature-Agent header and a key directory served at a well-known URI under the operator's domain. Our guide on how to verify signed agent requests walks through the checks step by step.

When a signature validates, you have strong evidence that the request was produced by whoever holds that key. That is a meaningful step up from a declaration. It is still a statement about which client signed the request. It is not a statement about which person instructed it, whether that person delegated authority to it, or whether the action is safe.

Inferred identity

Where there is no signature and no trustworthy declaration, you can still infer something from context: request timing, the absence of browser context, the sequence of tool calls, consistency with earlier sessions. Inferences are useful for analytics and for low-impact decisions such as rate limits. They should be labeled as inferences everywhere they appear, so nobody mistakes them for verification.

Unknown

On many APIs, plenty of callers provide no meaningful identity evidence at all. That is normal. The right response is to record those calls as Unknown and decide, per route, what Unknown should mean. Our guide on handling unknown traffic covers how to choose those fallbacks.

Classify your tools by impact

Once identity evidence is separated from credentials and authorization, the next step is to decide how much evidence each operation needs. The most practical way to do that is to group tools and routes by impact.

Low impact

Read-only operations on public or non-sensitive data: searching documentation, listing a public catalog, fetching status information. Here the main goals are good service and fair use. Any authenticated caller can usually proceed. Verified agents might get a higher rate limit or a richer response. Unknown callers get the standard limit.

Medium impact

Reads of private data and reversible writes: fetching a user's records, creating drafts, updating non-critical settings. These require the normal credential and scope checks. Actor context helps you observe who is doing what, spot unusual automation on an account, and apply tighter limits to unidentified automated callers.

High impact

Irreversible or consequential actions: placing orders, deleting data, changing permissions, sending messages on a user's behalf, exporting large datasets. These deserve the strongest controls you have. Actor context becomes one input among several: a verified client from an operator you recognize, combined with a credential scoped for this action, might proceed; an inferred or unknown automated caller might be asked for a stronger credential, require explicit user confirmation, or be routed to review.

The point is not that agents are dangerous. It is that the evidence you require should scale with the consequences of getting it wrong.

A policy table you can actually maintain

A simple table keeps these decisions explicit and reviewable. For an MCP server it might look like this:

Tool Impact Verified agent Declared or inferred agent Unknown
search_docs Low Allow, higher limit Allow, standard limit Allow, standard limit
get_account_summary Medium Allow with valid scope Allow with valid scope, tighter limit Allow with valid scope, tighter limit
create_order High Allow with order scope Require user confirmation Require user confirmation
delete_project High Require user confirmation Deny for automated callers Require user confirmation

For more patterns like this, see AI agent access policies. Two details make tables like this work in practice. First, every cell still requires the normal credential and scope. Actor context adds conditions, it never replaces authorization. Second, the Unknown column is filled in deliberately. Leaving it blank invites a default that someone chose by accident.

Where the check lives in your code

The pattern is the same whether you run a REST API or an MCP server: evaluate the actor once per call, record the result, and let your own policy decide. In illustrative TypeScript-style code:

TS
async function handleToolCall(call: ToolCall, ctx: RequestContext) {
  // 1. Authorization you already have: credential and scope.
  const grant = await authorize(ctx.credential, call.tool);
  if (!grant.allowed) return deny("insufficient_scope");

  // 2. Actor context: class plus the basis behind it.
  const actor = await evaluateActor(ctx); // { actorClass, basis, evidenceSummary }
  log({ tool: call.tool, actor });         // always record, even in observe mode

  // 3. Your policy, per tool, with an explicit fallback.
  const rule = policyFor(call.tool, actor);
  if (rule === "confirm") return requireUserConfirmation(call);
  if (rule === "deny") return deny("policy");

  return runTool(call, grant);
}

Three habits in that sketch are worth copying:

  • Authorization runs first and runs always. Actor context never grants access that the credential does not.
  • Every call is logged with its actor result. That record is what lets you tune policies later with real data rather than intuition.
  • The fallback is explicit. When actor evaluation times out or returns Unknown, the policy function decides what happens. It never silently assumes the best case.

You also choose, per tool, whether the integration fails open or fails closed. For a low-impact search tool, failing open (proceed as if no actor check existed) is usually right. For a high-impact tool, failing closed (apply your stronger existing check) is the safer default.

Observe before you enforce

The most reliable way to introduce actor-aware policies is to start with none. Run actor evaluation in observation mode across all routes and tools for a meaningful period. Then look at the data:

  • Which clients call which tools, and with what evidence?
  • How much traffic is Unknown on each route, and does that change your fallback plans?
  • Which automated callers are clearly legitimate, such as assistants your customers use every day, and deserve a smoother path?
  • Where would a draft policy have challenged a caller you know was legitimate?

Only then turn on enforcement, one route at a time, starting with the highest-impact tools where the evidence is clearest. This sequence avoids the classic failure mode of breaking a customer's integration on day one because a rule looked reasonable on paper.

Communicating with agent operators

Actor-aware APIs work best when well-behaved clients know how to identify themselves. A few low-effort practices help:

  • Document how you treat signed requests and what operators gain by signing them, and point them to the current Web Bot Auth documents.
  • Publish your rate limits by actor class so operators can design around them.
  • Return clear, machine-readable errors when a call needs a stronger credential or user confirmation, so agents can ask their user instead of retrying blindly. The MCP authorization specification already defines one such signal: a 403 with error="insufficient_scope" and the required scopes in the WWW-Authenticate header, which lets a client run a step-up authorization flow.

Clear expectations turn identity evidence from an obstacle into an advantage for the clients you want.

How Proof of Actor fits

Proof of Actor gives APIs and MCP servers this actor context without building it from scratch. It detects the identity evidence available on each call and keeps verified signatures separate from declarations and inferences. It helps you understand which clients use which routes and tools, and how much traffic is Unknown. And it lets you route calls with your own per-tool policies, starting in observation mode. Every result is Human, Human + AI, Agent or Unknown, with its basis stated, and enforcement remains with you.

If you run an API or MCP server and want to know who is calling it, apply for early access. For more on how this applies to automated callers, see MCP Servers and APIs.

Sources

Key Takeaways

  • Client identity, the credential used and what the caller may do are three separate questions. Answer them separately.
  • A declared client name is a declaration. A verified signature is evidence about which client signed. Neither is authorization.
  • Classify tools and routes by impact, then decide what evidence each tier needs.
  • Unknown callers are normal on APIs. Give them an explicit, per-route fallback instead of a guess.
  • Observe first: record actor context for every call before any policy changes a response.