An MCP server is not merely a convenient adapter around a function. It becomes a policy boundary between an agent runtime and a business capability. Start by listing every tool, resource, and prompt the server exposes, then record the business consequence of each call. Reading a contact record, sending a message, changing a pipeline stage, and issuing a refund should not share one generic permission. A useful inventory names the data owner, allowed caller, required evidence, and recovery action for every operation.
Separate identity, authorization, and tenant scope
Authentication answers which principal is calling; authorization answers what that principal may do; tenant scope answers whose data may be touched. Keep those decisions separate in code and logs. Pass an immutable tenant identifier from the authenticated session, not from model-generated arguments. Resolve the actor, tenant, role, and environment before tool selection. If any value is missing or contradictory, fail closed and return a structured reason that an operator can investigate.
Design narrow tools instead of generic passthroughs
Avoid an execute-sql tool, arbitrary HTTP proxy, or unrestricted CRM update method. Expose business verbs with typed inputs such as find_available_slots, create_draft_message, or request_stage_change. Validate enum values, length limits, identifiers, and allowed field transitions at the server boundary. A narrow tool makes the permission review concrete and gives the evaluator a smaller surface to test. It also prevents prompt text from becoming an accidental programming language for privileged actions.
Put approval gates on consequential side effects
Reading information and changing the world need different control paths. A draft message can be generated automatically, while sending it may require a consent check, an allowed template, and a human approval for unusual recipients. Treat approvals as expiring capabilities tied to one exact proposed action, tenant, and payload hash. Never let an approval for one booking or message be reused for a modified request. Store the approver, timestamp, reason, and resulting tool call together.
Make audit records useful during an incident
Log the authenticated principal, tenant, tool name, input hash, policy decision, approval reference, upstream request ID, result class, and latency. Do not log secrets or unnecessary personal data. Correlate model turns, tool calls, and downstream provider requests with one trace identifier. The goal is not an impressive stream of events; it is the ability to answer which actor attempted which action, what policy allowed it, and whether the external system actually committed the change.
Plan revocation, expiry, and degraded modes
Credentials, tool grants, and approval tokens need explicit expiry and revocation paths. Test a disabled user, removed tenant, rotated secret, expired approval, unavailable policy service, and downstream timeout. When the policy dependency is unavailable, preserve read-only diagnostics only if the risk is understood; otherwise stop the action. Queueing a mutating request for later is not automatically safer because the business context may change before replay.
Verify the boundary with adversarial tests
Build a test matrix for cross-tenant identifiers, role confusion, prompt-injected tool arguments, replayed approvals, oversized payloads, hidden fields, and partial downstream success. Assert that denied calls create an audit event without reaching the provider. Add contract tests for every tool schema and integration tests for the real authorization headers. Review the results with the system owner before granting production access. The release criterion is explainable refusal, not only successful completion.
Roll out in a constrained pilot
Begin with one tenant, one read-only tool family, and one named operational owner. Capture the intended call patterns before enabling mutations. A pilot should include a denied request, a malformed argument, a revoked credential, and a downstream timeout so the team sees the boundary under pressure. When the read path is stable, introduce one reversible write with a small approval cohort. Compare the audit trail with the provider’s own records and confirm that identifiers line up. Review the permission inventory after every new tool rather than waiting for a quarterly security exercise. The server should also expose health and policy diagnostics that do not disclose customer data. During incident response, operators need to know whether a failure came from identity, tenant scope, policy, approval, provider authorization, or provider execution. This classification makes a safe pause possible without disabling unrelated workflows. Only expand the tool surface after the owner can demonstrate refusal, expiry, replay protection, and recovery in a recorded test run.



