Building and Securing MCP Servers

This guide explains how MCP hosts, clients, and servers work together, how to implement a simple server with Python and FastMCP, and how to protect production deployments with OAuth, secret management, gateways, policy enforcement, validation, isolation, and human approval.

AI Agents and MCP Servers: An Overview

AI agents become commercially useful when they can do more than generate text. A support agent may need to retrieve an account record, a developer agent may inspect a repository, and an operations agent may query monitoring data or create an incident ticket. Each capability traditionally requires a custom integration, authentication flow, request format, and error-handling layer.

The Model Context Protocol, or MCP, standardizes this connection. It gives an AI application a consistent client-server interface for discovering and using external tools, applications, and data sources. Instead of building a proprietary connector for every model and service combination, a team can expose capabilities through an MCP server and connect them to compatible AI hosts.

For startups, the main advantage is modularity. A product team can keep model selection, agent orchestration, and business-system integrations loosely coupled. A database connector, ticketing integration, or internal search service can be developed and secured independently, then made available to multiple AI applications.

Direct answer: An MCP server is an integration boundary that allows an AI agent to discover approved capabilities and invoke them through a standardized protocol. It reduces integration duplication, but it must be treated as a security-sensitive application interface because the connected agent may be able to read data or perform real actions.

A useful architectural principle is to treat every MCP capability as if it were being exposed through a conventional production API. The fact that the caller is an AI agent does not reduce the need for identity, authorization, validation, rate limits, monitoring, and safe failure behavior. In many cases, the unpredictable nature of model-driven tool selection makes those controls even more important.

What Are MCP Servers?

An MCP server is a program or network service that exposes context and capabilities to an MCP-compatible client. The server does not contain the language model. It provides controlled interfaces that the model-enabled host can discover and use.

  • Tools: Callable operations such as searching a catalog, creating a ticket, calculating a price, or checking service status.
  • Resources: Contextual data that clients can read, including documents, files, schemas, and application records.
  • Prompts: Reusable templates or interaction patterns for performing defined tasks consistently.

The architecture separates three roles. The MCP host is the AI application that manages the user experience and model interaction. An MCP client runs within that host and maintains a connection to a server. The MCP server publishes its available capabilities and handles approved requests.

This separation matters because a single host may connect to several MCP servers, each with a different owner and risk profile. A coding assistant might connect to a repository server, an issue-tracking server, and an internal documentation server. Security policies should therefore be applied per server and per capability rather than assuming that every connected tool deserves the same level of trust.

Deployment pattern Typical use Primary security focus
Local stdio server Desktop clients, development, individual workflows Process isolation, package trust, filesystem permissions, safe environment variables
Remote HTTP server Shared services, SaaS integrations, multi-user agents TLS, OAuth, token validation, tenant isolation, rate limiting, audit logging

Key Standards and Specifications Governing MCP Servers

MCP implementations are shaped by the protocol specification and by established web standards. MCP uses JSON-RPC 2.0 messages for communication among hosts, clients, and servers. JSON-RPC defines structured requests, responses, notifications, method names, parameters, results, and errors without forcing every integration team to invent its own message format.

Supported transports determine how those messages move. A local process may communicate through stdio, while a remote service uses an HTTP-based transport. Transport selection changes the threat model.

For protected remote HTTP deployments, MCP authorization is based on OAuth 2.1 concepts. A protected MCP server acts as an OAuth resource server. The MCP client presents an access token, and an authorization server authenticates the resource owner when required and issues a token intended for the MCP server.

  • Validate the token signature or introspection response.
  • Verify the expected issuer and intended audience.
  • Reject expired, malformed, or otherwise invalid tokens.
  • Enforce scopes and capability-specific authorization.
  • Support revocation or rapid expiry for compromised credentials.

Important distinction: OAuth requirements primarily protect remote HTTP-based MCP servers. Local stdio servers still require strong operating-system, dependency, process, and secret controls.

Production implementations should also apply established web-security controls: HTTPS, exact redirect URI validation, PKCE for authorization-code flows, secure token storage, request size limits, input validation, rate limiting, safe error handling, dependency management, and protection against server-side request forgery.

A Simple MCP Server Implementation in Python

The safest way to learn MCP is to begin with a small server that performs a deterministic, non-sensitive operation. Avoid starting with production databases, payment systems, cloud-administration APIs, or credentials that can modify real environments.

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("pricing-tools")


@mcp.tool()
def calculate_discount(price: float, discount_percent: float) -> dict:
    """Calculate a discounted price for a non-sensitive pricing example."""

    if not 0 <= price <= 1_000_000:
        raise ValueError("price must be between 0 and 1,000,000")

    if not 0 <= discount_percent <= 100:
        raise ValueError("discount_percent must be between 0 and 100")

    discount = round(price * discount_percent / 100, 2)
    final_price = round(price - discount, 2)

    return {
        "original_price": price,
        "discount": discount,
        "final_price": final_price
    }


if __name__ == "__main__":
    mcp.run(transport="stdio")

Local validation workflow

  1. Pin and install a reviewed stable version of the official SDK.
  2. Run the server locally through stdio.
  3. Connect an MCP-compatible client or the MCP Inspector.
  4. Verify that only the intended tool is discoverable.
  5. Test valid, invalid, missing, oversized, and boundary-value arguments.
  6. Review logs to confirm that sensitive values are not recorded.
  7. Add external services only after local validation succeeds.

Only after these controls work should the server call an external API. When you add a network dependency, define timeouts, retry limits, destination allowlists, error mapping, response-size limits, and logging that excludes secrets and sensitive payloads.

Credential Storage and Token-Based Authentication

Credential rule: Never place credentials in source code, prompts, tool descriptions, model context, logs, or client-visible configuration.

Environment Recommended approach Avoid
Local development Environment variables, ignored local secret files, developer-specific credentials Committed .env files, shared production keys, secrets in command history
CI/CD Pipeline secret injection, short-lived workload identity, protected variables Secrets in build logs, images, test fixtures, or artifact metadata
Production Managed secret store, workload identity, automatic rotation, narrow access policy Static credentials embedded in containers or configuration repositories
  • Prefer short-lived access tokens.
  • Use narrow scopes and resource-specific permissions.
  • Validate issuer, audience, expiry, and authorization claims.
  • Rotate and revoke credentials through a documented lifecycle.
  • Separate development, staging, and production identities.
  • Keep user, agent, client, server, and downstream-service identities distinguishable.

For a protected remote MCP server, the client presents an access token issued by an authorization server. The server validates that token as a protected resource. Audience validation is essential: a token issued for an analytics API, source-code service, or another MCP endpoint must not be accepted merely because it is structurally valid.

Do not forward the client's MCP access token to downstream services by default. Token passthrough can expose a credential to a service for which it was not intended and can create confused-deputy behavior. A server that calls a downstream API should use an explicitly designed token-exchange, delegation, or server-side credential model with clear audience and scope boundaries.

Protecting MCP Servers with Gateways and Policy-Enforcement Layers

Do not rely on obfuscation. Use mediation and policy enforcement so that every MCP request is authenticated, authorized, constrained, and auditable.

An MCP gateway can sit between clients and servers. It can authenticate the human and agent, authorize individual tool calls, collect consent for delegated actions, apply tenant and environment policies, rate-limit requests, and create audit records.

Permit.io's MCP Gateway is one example of a proxy-based enforcement layer. Its documentation describes a drop-in proxy that adds authentication, authorization, consent, and audit around MCP traffic. This pattern can help teams apply deny-by-default access and associate each decision with both a human identity and the agent acting on that person's behalf.

Control pattern Primary value
MCP or API gateway Central authentication, per-tool authorization, quotas, consent, and audit
Identity-aware proxy User, device, and session-aware access to remote endpoints
Service mesh Workload identity, mutual TLS, service policy, and telemetry
Policy engine or middleware Domain-specific RBAC, ABAC, ReBAC, or policy-as-code decisions
Private MCP registry Approved server inventory, ownership, version, and provenance controls
Network segmentation Reduced exposure and restricted paths to sensitive systems
Container sandboxing Limited process, filesystem, kernel, and outbound-network access
Tool allowlisting Only required capabilities are visible and callable

If a gateway is intended to enforce policy, clients must not retain a direct connection that bypasses it. The control layer must also fail closed when authorization data is unavailable, preserve traceability across downstream calls, and avoid becoming a high-privilege universal credential broker.

Practical Security Controls for Startups

Prototype-to-production checklist

  • Expose only the tools required for the current workflow.
  • Apply deny-by-default authorization.
  • Validate every tool argument and enforce business-level constraints.
  • Isolate MCP server processes and minimize operating-system permissions.
  • Restrict outbound network access to approved destinations.
  • Pin dependencies and scan them for known vulnerabilities.
  • Review third-party servers, maintainers, packages, and updates.
  • Separate development, staging, and production credentials.
  • Log security-relevant activity with appropriate redaction.
  • Require human approval for destructive or high-impact operations.

Authentication alone is insufficient. An authenticated user can still supply malicious content, and a trusted MCP server can still be compromised. Teams must address prompt injection, tool poisoning, excessive permissions, untrusted packages, data leakage, command injection, unsafe outputs, and dangerous chaining between multiple tools.

Risk Practical control
Prompt injection Treat external content as untrusted data, preserve user intent, and reauthorize consequential actions
Tool poisoning Review tool descriptions and schemas, pin versions, and monitor unexpected metadata changes
Excessive permissions Narrow scopes, per-tool policy, tenant checks, and time-limited grants
Untrusted packages Provenance review, dependency scanning, signatures where available, and sandboxing
Data leakage Output filtering, field-level authorization, minimization, and redacted logs
Unsafe tool chaining Intent tracking, step limits, policy checks per call, and human approval for escalation

Consider an agent that reads an untrusted support ticket and then calls an administrative tool. The ticket may contain instructions intended to redirect the agent, extract secrets, or trigger an unauthorized action. Authentication confirms who connected; it does not prove that every instruction entering the model is safe. The system must preserve user intent, treat retrieved content as data rather than authority, and independently authorize every consequential tool call.

Conclusion

MCP simplifies the way AI applications connect to tools, resources, prompts, and external systems. For startups and scale-ups, that standardization can reduce integration work, improve portability, and make agent capabilities easier to develop as independent services.

It also creates a security boundary around systems that may read customer data, access internal knowledge, change application state, or trigger operational actions. A convenient tool interface is not automatically a safe one.

The strongest adoption path is incremental: begin with a minimal server, deterministic tools, synthetic or non-sensitive data, and local validation. Introduce short-lived credentials, narrow scopes, strict argument validation, process isolation, restricted network access, and auditable authorization before connecting production systems.

As agent autonomy increases, policy enforcement must become more specific—not less. High-impact actions should be authorized individually, linked to both human and agent identities, logged for investigation, and presented for human approval when the consequences cannot be safely reversed.

FAMRO helps startups and scale-ups design, build, integrate, and secure AI agent platforms, including MCP servers, API integrations, authorization layers, cloud deployment, observability, and production hardening. Our engineers can help you move from an experimental connector to a governed architecture that supports real business workflows without giving agents unnecessary access.

Build Secure MCP Foundations Before Expanding Agent Autonomy

FAMRO helps startups and scale-ups design MCP servers, integrate business systems, enforce least-privilege authorization, and deploy observable, production-ready AI agent platforms.

Frequently Asked Questions

An MCP server exposes tools, resources, and prompts to an MCP-compatible AI application. It provides a standardized interface through which an AI agent can discover approved capabilities, retrieve context, and perform controlled actions.

No. The MCP authorization specification primarily applies to protected HTTP-based servers. Local stdio servers generally use process-level trust and operating-system controls, although they still require secure secrets, dependency review, isolation, and restricted permissions.

A tool performs an operation, such as creating a ticket or calculating a value. A resource provides contextual information that a client can read, such as a document, schema, file, or application record.

No. Tool descriptions may be visible to models, clients, logs, and debugging interfaces. Credentials should be loaded at runtime from environment variables during controlled development or from managed secret stores and workload identities in production.

No. Teams must also enforce per-tool authorization, validate arguments, isolate processes, restrict network access, manage secrets, review dependencies, monitor activity, and address prompt injection, tool poisoning, data leakage, and unsafe tool chaining.

Human approval is appropriate for destructive, irreversible, financially significant, externally visible, or privilege-changing operations. The approval interface should clearly show the intended action, target, parameters, and expected effect.