How to Keep a Shared Bob MCP Server From Acting Like One User
A practical guide to delegated access, session identity, and audit logs so your shared tools can still answer who did what.
Sooner or later every shared MCP rollout runs into the same boring question: who actually did this?
I do not mean which tool name showed up in the trace or which server handled the POST. I mean who approved the deployment, closed the ticket, queried the customer record, or changed the access policy.
If the honest answer is “Bob” or, worse, the name of one long-lived bearer token sitting behind a shared server, then the architecture is unfinished. You did not build user-aware automation. You built a service account funnel with better branding.
That sounds harsh, but the current IBM Bob guidance is blunt enough to justify it. The IBM Bob security guidelines say to use delegated access when needed, use time-limited tokens, monitor and audit all actions, and, for shared MCP servers, make sure actions are attributable to specific users or sessions. That is not a style preference. It is the difference between an automatable system and a future incident report full of shrugs.
I care about this part of enterprise MCP design because it hides inside something that looks efficient. A shared remote server is easy to centralize, easy to update, and easy to point every Bob user at through .bob/mcp.json. The Bob MCP docs explicitly support project-level .bob/mcp.json files that teams can share through version control, and remote MCP configuration supports custom HTTP headers such as Authorization. The convenience is real. So is the way teams quietly reinvent the service account model and call it agent infrastructure.
The cheap version is one credential for everyone
The bad design usually starts out looking responsible, which is part of why it survives design review.
There is one remote MCP server for a shared internal system such as deployments, tickets, or change requests. Bob talks to it over HTTP. The team does not want every user setting up their own credentials yet, so someone provisions one token for the server and distributes the config.
It often looks like this:
{
"mcpServers": {
"deploy-control": {
"url": "https://mcp.internal.example.com/mcp",
"headers": {
"Authorization": "Bearer ${SHARED_DEPLOY_MCP_TOKEN}"
}
}
}
}Using an environment variable instead of hardcoding the token is still better operational hygiene. It does not fix the architecture if everyone ends up using the same credential. Where the secret string lives is not the real issue. The issue is that the server sees one actor for every request.
That produces audit records like this:
{
"timestamp": "2026-05-23T10:14:09Z",
"tool": "approve_deployment",
"target": "checkout-service",
"actor": "shared-bob-mcp",
"result": "approved"
}This record answers almost nothing that matters after the fact. Which engineer asked for the action? Which Bob session was it tied to? Was the caller allowed to approve production or only staging? Was the token minted for five minutes or copied into a wiki six months ago? You can keep piling logs around this, but the identity hole stays put.
That is why I do not like hearing “we have auditing” when the audit trail only knows the server-side credential. You do not have auditing yet. You have a timestamped receipt from a shared robot account.
What attribution looks like in practice
For a shared MCP server, the minimum bar is simple even if the implementation takes work: the request that reaches the server must still be tied to a human user or a narrowly scoped session.
The MCP authorization spec frames HTTP-based authorization as the client accessing a protected MCP server on behalf of a resource owner. It also recommends short-lived access tokens. That lines up neatly with Bob’s own security guidance: delegated access, time-limited credentials, and auditable actions.
In practice, I want the remote server, or a gateway directly in front of it, to validate a user-bound token and emit a structured audit event that survives the entire request path. At minimum, keep these fields:
The human identity:
sub, and, if your IdP provides it safely, a stable username or emailThe issuing authority and target:
iss,aud, and the scopes or roles that justified the actionToken lifetime and replay clues:
exp, and a token or request identifier such asjtiwhen availableMCP request correlation: session identifier, request identifier, tool name, and target system
Decision outcome: allowed, denied, or failed, with the policy reason when possible
The useful shape is closer to this:
{
"timestamp": "2026-05-23T10:14:09Z",
"actor": {
"sub": "00u7x9b3...",
"email": "sam@example.com"
},
"client": {
"product": "IBM Bob",
"mcpSessionId": "1f3a4b5c-6d7e-8f9a-0b1c-2d3e4f5a6b7c",
"tool": "approve_deployment"
},
"policy": {
"scopes": ["deploy:approve"],
"delegated": true,
"tokenExpiresAt": "2026-05-23T10:19:09Z"
},
"target": "checkout-service",
"result": "approved"
}Now the record can answer a serious question. Sam approved the deployment. The call came through a specific Bob session. The server saw a delegated token with the deploy:approve scope, and that token expired five minutes later. That is the beginning of accountability, which is a lot more useful than another dashboard that can only tell you a tool fired.
Notice what I am not asking for here. I am not asking you to store full prompt transcripts as the only audit system, or to bury the truth in a blob store full of raw HTTP dumps. Good auditability is not maximal logging. It is the ability to answer who, what, when, which permission, and which target without needing a forensic hobby.
Useful MCP headers are not the same thing as identity
There is a subtle trap here because MCP over HTTP is getting better observability support. The current MCP transport spec defines Streamable HTTP as the standard remote transport, and SEP-2243 standardizes request headers such as Mcp-Method, Mcp-Name, and Mcp-Session-Id so proxies, gateways, and observability tools can reason about MCP traffic without tearing apart the JSON body.
I like that change. It helps routing, rate limiting, correlation, and troubleshooting. It does not solve attribution by itself.
Mcp-Session-Id tells you that several requests belong to the same logical MCP session. It does not tell you which human sat behind that session. Mcp-Method and Mcp-Name tell you what kind of MCP operation happened. They do not tell you whether the caller was allowed to do it.
So keep the headers. They are useful. Just do not confuse request metadata with identity. A beautiful trace that still collapses every actor into one shared token is just a more expensive blind spot.
Prompt warnings are not policy
There is another shortcut teams try after they notice the identity problem. They keep the shared credential and add instructions around it:
Only use this tool for the current user
Ask for confirmation before production actions
Never approve your own deployment
Those rules are fine as defense in depth. They are not a security boundary.
The server has to enforce the policy because the server is where the blast radius lives. If the remote MCP tool can approve a deployment, create a change request, or read customer data, the authorization decision needs to happen with server-side knowledge of the user, the session, the scopes, and the target resource. Prompt text can remind the model. It cannot carry your authorization model.
This is also why I prefer denial events in the audit log. A server that records who was refused, for which action, and why, is much easier to trust than one that only logs successful calls and leaves failures to chat history.
Shared remote infrastructure is not always the right answer
Bob’s own transport guidance is refreshingly practical here. The Bob transport docs describe STDIO as lower latency, simpler, and “inherently more secure with no network exposure,” and they recommend it for security-sensitive local operations. The MCP transport spec also says clients should support stdio whenever possible.
That matters because not every useful tool needs to be a shared service.
If the capability is mostly local to the developer machine, such as reading a repository, running a formatter, checking a build, or querying a local scratch database, a shared remote MCP server may add centralization without adding enough value. You take on network exposure, shared-service hardening, multi-user authorization, and attribution requirements just to avoid installing a local tool.
I would keep these workflows local by default:
Repository and filesystem helpers
Local build, test, and formatting tools
Developer-specific scratch data or local diagnostics
Anything where the useful authority already comes from the workstation user
I would consider a shared remote server when the target system is already centralized and the controls are worth centralizing too:
Deployment approvals
Ticketing or change-management workflows
Internal data systems with real access policy
Shared operational tooling that needs consistent server-side enforcement
That is the actual trade-off. Shared MCP infrastructure does not become “more enterprise” just because it is remote. It earns that label when the central server adds real policy, real auditability, and real operational control.
A short checklist before you roll this out
If you are about to stand up a shared MCP server for Bob, I would want these answers before the first broad rollout:
Can the server identify the human user behind each action, not just the Bob client or a shared token?
Are credentials delegated and time-limited, or did you quietly create a durable service account path?
Does the audit event capture actor, session, tool, target, permission, and outcome in structured form?
Are authorization decisions enforced server-side for every sensitive tool call?
Do denied actions get logged with enough context to review policy behavior later?
Did you keep local-only workflows on STDIO instead of centralizing them out of habit?
If someone asks “who approved this at 10:14 UTC on May 23, 2026,” can you answer without opening a chat transcript?
If the answer to the last question is no, stop there. The server is not ready yet.
Conclusion
The interesting failure mode in shared MCP is not tool power. That part is obvious. The failure shows up when the first working version looks good enough while quietly erasing the human actor from the record.
IBM Bob’s current security guidance does us a favor by saying the quiet part out loud: use delegated access, use time-limited tokens, audit actions, and make shared MCP activity attributable to specific users or sessions. Once you accept that, the architecture gets simpler. A shared MCP server is either identity-aware infrastructure, or it is a service account wearing an agent costume.


