Limitations of Python MCP Servers — The Real-World Gap Between FastMCP and TypeScript

Maru

@maru

Python MCP 서버의 한계 — FastMCP와 TypeScript의 실운영 격차

Limitations of Python MCP Servers — The Real-World Gap Between FastMCP and TypeScript

The Model Context Protocol (MCP) ecosystem has surged by over 2,200%, emerging as the new standard for connecting AI agents and tools. However, looking at actual market statistics, 86% of publicly available MCP servers remain confined to developers' local environments.

The simplicity that allowed for easy, configuration-free operation in local environments often transforms into significant security attack surfaces and design hurdles when transitioning to production and multi-tenant environments. This contradictory phenomenon is called the 'MCP Paradox.' In this post, we will examine the design limitations of the popular Python-based FastMCP, and explore why TypeScript-based architectures or dedicated self-hosting platforms are becoming the preferred alternatives for real-world production environments.

The Rise of the Python Ecosystem: FastMCP and fastapi-mcp

FastMCP, released by Anthropic, perfectly eliminates the cumbersome boilerplate code that Python developers face when building MCP servers. Without the need to manually handle complex protocol specifications, you can easily connect local scripts or functions to AI agents using just a few lines of decorator patterns, as if you were developing in a FastAPI environment.

Additionally, the community library fastapi-mcp takes a clever approach by automatically converting existing FastAPI endpoints into MCP tools, complete with Pydantic validation. Thanks to these tools, developers can focus on core feature development instead of wasting time on complex infrastructure setup.

Comparing the tool registration methods of the two ecosystems through code highlights their underlying design differences more clearly.

python
# Python (FastMCP)
from fastmcp import FastMCP

mcp = FastMCP("My MCP Server")

@mcp.tool
def greet(name: str) -> str:
    """Greets a user by name."""
    return f"Hello, {name}!"

typescript
// TypeScript (SDK v1.0.0+ Modern API)
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";

const server = new McpServer({
  name: "my-mcp-server",
  version: "1.0.0"
});

server.registerTool(
  "greet",
  {
    description: "Greets a user by name.",
    inputSchema: {
      name: z.string()
    }
  },
  async ({ name }) => ({
    content: [{ type: "text", text: `Hello, ${name}!` }]
  })
);

Python's FastMCP boasts overwhelming convenience by automatically parsing Python type hints and docstrings from the functions themselves to construct schemas. On the other hand, TypeScript adopts a structure that explicitly combines Zod schemas under a modern McpServer class. This structural difference begins to create a critical gap in code stability and granular control when moving beyond prototyping into large-scale production environments.

Code Quality and the Trap of 'Script Wrapping'

Behind the advantage of easy and fast tool integration hides a gap in code quality and stability that must be addressed in production. According to an academic investigation report on agent interoperability protocols, the median number of code smells in MCP servers written in JavaScript or TypeScript was 2, whereas it was twice as high at 4 for Python implementations.

This gap stems from the 'script wrapping' practice, where many Python developers hastily wrap existing personal legacy scripts with FastMCP decorators to distribute them as tools. In this process, strict type validation or systematic error handling is often omitted, increasing the risk of AI agents falling into uncontrollable states or malfunctioning due to minor exceptions.

Supply chain security threats originating from loose dynamic execution environments cannot be ignored either. A prime example is the distribution of typosquatting packages like mcp-server-postgress, where Python MCP environments that dynamically load and execute unverified external libraries are easy targets for serious security incidents. This is the first barrier developers must clear when integrating MCP into real service systems beyond the local prototype stage.

Critical Architectural Barriers: Session State and OAuth Decoupling

When scaling MCP beyond local operation to multi-tenant or enterprise systems, the biggest hurdle is synchronizing session state and authentication information. According to an analysis from the Portal One engineering blog, Python MCP servers running as independent processes based on standard I/O (stdio) find it difficult to directly access the main web application's default user sessions or workspace permissions. Unless one resorts to temporary fixes like passing authentication tokens as arguments during every tool call, the structure makes it hard to guarantee granular permission control in distributed environments.

Conversely, the TypeScript MCP SDK provides structural primitives to handle such distributed security environments by default. It can immediately reference the authenticated context of the calling user through the authInfo field embedded in the tool execution context, and securely mediate external OAuth flows through the dedicated ProxyOAuthServer class. Unlike Python, where you would have to implement such complex session control frameworks from scratch within an asynchronous loop, TypeScript comes pre-equipped for large-scale production deployment.

Self-Hosting Platform Alternatives: Native MCP in Openship

If building an MCP server from scratch and managing authentication and permissions in production is too daunting, you might consider alternatives that have integrated MCP natively at the platform level. Unlike traditional tools like Coolify or Dokku, Openship—a self-hosting platform—has opted for a unique architecture that embeds an MCP server directly into the platform itself. Instead of developers taking security risks by deploying their own MCP servers for infrastructure control, it bypasses the issue by providing a verified, secure interface provided by the platform.

Openship utilizes a Bun-based CLI and OpenResty, aiming for a lightweight architecture that does not require a separate agent on the target server. It keeps target infrastructure simple by SSH-streaming immutable Docker containers generated in the build pipeline to the target server.

Openship's Bun-based CLI can be installed and executed with a single line of command, even without Node.js.

bash
# 오픈쉽 CLI 설치 및 개발 환경 실행
curl -fsSL https://get.openship.io | sh
openship up

When the service starts, a local API server and dashboard are activated, and the built-in MCP server securely mediates so that AI tools like Claude Code or Cursor can perform project deployments, cluster inspections, environment variable changes, and rollbacks to previous deployments directly after local API token authentication.

For reference, Openship recently transitioned to a source-available AGPL-3.0 and Commons Clause license. While unauthorized resale as a commercial SaaS is prohibited, it can be freely utilized for internal enterprise self-hosting infrastructure. Instead of struggling manually to overcome complex session security or OAuth decoupling barriers, adopting a native MCP platform that acts as a security gateway at the platform level is an efficient compromise for maintaining production security standards.

Practical Advice for Developers

The 'MCP Paradox,' where local simplicity turns into a production security threat, offers an important criterion for architectural choices. Python's FastMCP is an excellent starting point for local-centric rapid prototyping or quickly migrating existing scripts. However, if you are at the stage of building commercial services where session isolation, multi-user authentication, and strict third-party permission management are essential, adopting a TypeScript-based SDK or designing an infrastructure-level verified gateway could be the more stable choice.


Reference Links