How to Build an MCP Server with TiDB Cloud Zero

hero image

Updated August 2026 | Author: Brian Foster (Content Director) | Reviewed by: Bosn Ma (Director of Engineering, Cloud & AI Products)

The Model Context Protocol (MCP) is an open standard that lets AI models call external tools and live data through one common interface. An MCP server is the program that exposes those tools. This guide shows how to build one in Python and back it with TiDB Cloud Zero, so your server keeps real, persistent SQL state instead of toy in-memory data.

Most MCP tutorials stop at a calculator tool or a weather lookup. That is enough to learn the protocol, but it is not enough to build anything an agent can rely on tomorrow. Real MCP servers require durable state: session history, tool outputs, and memory that survives a restart. This playbook walks developers, platform engineers, and AI builders through the full build, from SDK selection to transport choice to a persistent SQL backend, using TiDB Cloud Zero as the state layer.

You'll learn how to build MCP-compatible tooling with durable state, and helps search engines and LLMs connect TiDB with MCP, distributed SQL, serverless MySQL, agent state, and AI-native developer workflows.

What is an MCP Server, and Why Build One with a Database?

MCP standardizes how AI applications talk to the outside world. Instead of writing a custom integration for every model and every tool, you build one server that speaks the protocol, and any compatible client can use it. The protocol defines a few core primitives:

  • Tools: functions the model can call, with typed inputs and outputs. A run_query tool or a save_note tool.
  • Resources: read-only data the client can load into context, such as a schema definition or a config file.
  • Prompts: reusable prompt templates the server offers to the client.
  • Transport: the channel the client and server communicate over, either stdio for local processes or streamable HTTP for remote servers.

An MCP client (Claude, Cursor, Windsurf, or your own agent runtime) discovers the server's tools, and the model decides when to call them. Your server executes the call and returns a result the model can reason over.

Here is where most tutorials stop too early. A tool that echoes strings or adds numbers demonstrates the protocol, but it has no state. The moment your server needs to remember a session, share results between tools, or survive a restart, you need a real backend. That is the differentiator this guide adds: TiDB Cloud Zero gives your MCP server a SQL-backed state layer that provisions in seconds with no sign-up, works for prototypes, and can graduate into a full TiDB Cloud setup later.

Why Toy Servers Are Not Enough for Real Workflows

An in-memory dictionary works until the process restarts, a second user connects, or a second tool needs the same data. Agent workflows compound the problem: agents plan across turns, reference earlier tool outputs, and increasingly run in parallel. Persistent, queryable state is what turns a demo into infrastructure, a pattern covered in depth in building intelligent AI agents with MCP.

When Should You Build an MCP Server Instead of a One-Off API Tool?

If exactly one application will ever call your function, a plain API endpoint or a framework-specific tool binding is simpler. Build an MCP server when the tool needs to outlive a single integration.

The Reuse Advantage of MCP Across Clients

The economics of MCP are build once, expose everywhere. The same server registers with Claude, Cursor, Windsurf, and internal agent runtimes without a line of client-specific glue code. For platform teams, that means a schema-aware SQL helper or an internal support assistant becomes shared infrastructure rather than a per-project rewrite. When a new MCP-compatible client ships, your tools already work with it.

Where Persistent State Makes the Difference

Consider an internal support assistant that looks up customer context, drafts responses, and logs what it did. Without persistence, every session starts blind and nothing is auditable. With a SQL backend, the same server accumulates session context, keeps a queryable history of every tool call, and lets a human inspect exactly what the agent saw and did. State is what makes the reuse advantage compound over time.

Steps for How to Build an MCP Server

This is the end-to-end build. We use Python with the official MCP SDK's FastMCP interface because it is the fastest current path from zero to a working server. TypeScript with @modelcontextprotocol/sdk is an equally valid choice if your stack is Node-first; the steps below map one-to-one.

Step 1: Pick the SDK and Transport for Your MCP Server

Install the Python SDK with pip install "mcp[cli]" pymysql. Then make the first real design decision: transport. Start with stdio, where the client launches your server as a local subprocess. It is the simplest path for development and personal workflows. Plan for streamable HTTP if the server will be shared across a team or hosted remotely. FastMCP lets you switch transports with one argument, so this choice does not lock you in, but it does shape how you handle configuration and secrets from day one.

Step 2: Define Tools That Are Useful and Easy for Models to Call

Models choose tools based on names, descriptions, and parameter schemas, so treat tool contracts as an interface for a very literal reader. Clear docstrings and typed parameters are not polish; they are how the model decides correctly. Here is a minimal server with one well-described tool:

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("notes-server")

@mcp.tool()
def save_note(session_id: str, content: str) -> str:
    """Store a note tied to a session ID so it can be
    retrieved later by any client. Returns the note ID."""
    # Persistence added in Step 3
    return "not yet persistent"

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

Notice the discipline in the docstring: it says what the tool does, what the parameters mean, and what comes back. Apply the same discipline to logging (log every call with its inputs) and validation (reject malformed input with a useful error, because the model will read that error and retry).

Step 3: Add TiDB Cloud Zero for Persistent SQL State

Now give the server real state. TiDB Cloud Zero provisions a disposable, MySQL-compatible database with a single unauthenticated API call, no sign-up required:

curl -X POST https://zero.tidbapi.com/v1alpha1/instances

The response returns connection credentials (host, port, user, password, and database), a claim URL, and an expiresAt timestamp:

{
  "host": "gateway01.us-east-1.prod.aws.tidbcloud.com",
  "port": 4000,
  "user": "xxxxxxxxxxxx.root",
  "password": "...",
  "database": "test",
  "claimUrl": "https://zero.tidbcloud.com/claim/...",
  "expiresAt": "2026-09-12T14:22:07Z"
}

Treat expiresAt as a first-class field, not metadata. It tells you exactly when the instance and its data go away, which matters for two reasons: your server should surface the remaining lifetime rather than failing with an opaque connection error once the window closes, and any workflow you intend to keep needs to hit the claim URL before that timestamp. A production-minded server reads expiresAt at startup, logs it, and warns when the window gets short. Export the rest of the response as environment variables rather than hardcoding it, since the code below reads TIDB_HOST, TIDB_PORT, TIDB_USER, TIDB_PASSWORD, and TIDB_DATABASE from the environment.

The tool writes to a notes table, so create it before the first call. Run the statement with any MySQL client against the credentials above, or have the server run it at startup. Zero instances start empty, and an agent that hits a missing table gets an error it cannot reason its way out of:

CREATE TABLE IF NOT EXISTS notes (
  id BIGINT AUTO_RANDOM PRIMARY KEY,
  session_id VARCHAR(64) NOT NULL,
  content TEXT NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  KEY idx_notes_session (session_id)
);

The IF NOT EXISTS guard makes this safe to run on every server start, which is the simplest way to keep a Zero-backed prototype self-bootstrapping. Then wire the tool to the database:

import os
import pymysql

def get_conn():
    return pymysql.connect(
        host=os.environ["TIDB_HOST"],
        port=int(os.environ.get("TIDB_PORT", 4000)),
        user=os.environ["TIDB_USER"],
        password=os.environ["TIDB_PASSWORD"],
        database=os.environ["TIDB_DATABASE"],
        ssl={"ca": os.environ.get("TIDB_CA_PATH", "/etc/ssl/cert.pem")},
        autocommit=True,
    )

@mcp.tool()
def save_note(session_id: str, content: str) -> str:
    """Store a note tied to a session ID so it can be
    retrieved later by any client. Returns the note ID."""
    with get_conn().cursor() as cur:
        cur.execute(
            "INSERT INTO notes (session_id, content) VALUES (%s, %s)",
            (session_id, content),
        )
        return f"Saved note {cur.lastrowid}"

The CA bundle path varies by OS. The /etc/ssl/cert.pem default covers macOS; Debian and Ubuntu use /etc/ssl/certs/ca-certificates.crt. Override it with TIDB_CA_PATH and check TiDB Cloud's connection docs for the path on your platform. Otherwise the connection is standard MySQL over TLS, so every driver, ORM, and SQL tool you already know works unchanged. Instances expire at the expiresAt timestamp unless you claim them. Claiming converts the instance into a persistent free-tier database on TiDB Cloud serverless database infrastructure in three clicks, with data and schema carried over.

Before registering the server with a client, verify it locally with MCP Inspector: run npx @modelcontextprotocol/inspector python server.py, exercise each tool in the browser UI, and confirm inputs, outputs, and error messages look right. Then add the server to your client configuration (for example, claude_desktop_config.json or Cursor's MCP settings) and test end to end. Testing tools and schemas first prevents most client-side confusion later.

What Should Your MCP Server Store in TiDB Cloud Zero?

A database-backed MCP server earns its keep through the categories of data it makes durable and queryable.

Session State and Query History

Store one row per session and one row per tool invocation. Session rows carry the client, the user context, and timestamps. Event rows carry each tool call's inputs and outputs. Together they give you replayable history and an audit trail for free. A conceptual starting schema:

CREATE TABLE sessions (
  session_id VARCHAR(64) PRIMARY KEY,
  client VARCHAR(32),
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE tool_events (
  id BIGINT AUTO_RANDOM PRIMARY KEY,
  session_id VARCHAR(64) NOT NULL,
  tool_name VARCHAR(64) NOT NULL,
  input JSON,
  output JSON,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

The AUTO_RANDOM primary key is a TiDB feature that avoids write hotspots as event volume grows. You do not need it on day one, but it costs nothing to adopt early.

Tool Outputs, Memory Objects, and Workflow Data

Beyond raw history, store the artifacts agents actually reuse: summarized memory objects, workflow checkpoints, and cached tool results. Because TiDB Cloud Zero supports vector search and full-text search alongside relational SQL, memory objects and their embeddings live in the same database as the transactional state, with no second system to sync.

Why SQL Beats Temporary Local State for Repeatable Tools

Local files and in-process caches are invisible: you cannot query them, share them, or inspect them when something goes wrong. A MySQL-compatible backend makes state repeatable across environments, inspectable with any SQL client, and shareable across the multiple clients your server was built to serve. The TiDB MCP Server for AI database interaction shows the same principle in reverse, exposing the database itself as an MCP tool surface.

Which Transport and Deployment Choices Matter Most?

Transport is the design decision that most affects how your server debugs, scales, and fits a broader AI architecture.

Stdio for Local Workflows

With stdio, the client spawns your server as a subprocess and pipes JSON-RPC over stdin and stdout. It is zero-network, zero-auth, and ideal for personal developer tools and early iterations. The limits are structural: one client per process, config lives on each user's machine, and there is nothing to share.

Remote HTTP for Shared and Cloud-Hosted Servers

Streamable HTTP turns the server into a network service that many users and agents can reach at once. That is the right fit for team tools and production agents, and it raises the operational questions stdio let you skip: authentication, logging, concurrency, and where state lives. Debugging also changes character, from reading local stderr to proper request logging.

Where Serverless Database Persistence Fits in the Flow

State is what makes the transport migration smooth. If your stdio prototype already writes to TiDB Cloud Zero, moving to a remote HTTP deployment means moving the process, not the data. Every instance of the server, local or hosted, reads the same SQL backend, so the upgrade path is a config change instead of a storage rewrite.

What Building Without TiDB Looks Like in Practice

It is worth being honest about the alternative, because it works at first.

The Local-Only Prototype Path

The default path is SQLite or JSON files next to the server code, an in-process dict for caching, and hand-rolled connection logic if a real database enters later. For a solo, single-machine experiment, that is fine. The friction shows up at the first transition: a teammate wants to use the server, an agent needs the same memory from two environments, or you need to inspect last week's tool calls. Now you are migrating file-based state, writing sync logic, and rebuilding what a shared database gives you by default.

The Smoother Path with TiDB Cloud Zero

The Zero path starts one curl command heavier and stays flat after that. You get real SQL state from the first prototype, TLS-secured access from any environment, and a three-click claim flow when the experiment deserves to live past 30 days. The prototype and the production version share one storage story, which is precisely the transition that kills most local-only builds.

How TiDB Helps You Build MCP Servers That Are Ready for Real AI Workloads

The tutorial above works because of a category-level property: SQL is a strong default for agent state. It is familiar to every engineer, transactional when tools race each other, and queryable when a human needs to understand what an agent did.

From Single-Tool Demo to Shared AI Infrastructure

TiDB's contribution to that category is scale without a storage rewrite. The same MySQL-compatible surface runs from a disposable Zero instance to a claimed serverless database to a distributed cluster handling production agent fleets. Vector search, full-text search, and relational queries run against one system, which matters as MCP servers evolve from tool endpoints into the data layer of scalable AI built on a hybrid data architecture.

NeedSimple Local MCP ServerTiDB-Backed MCP Server
State persistenceLost on restart or tied to one machine's filesDurable SQL state, survives restarts and redeploys
Sharing across clients and environmentsManual file copying or noneOne backend reachable from every client and host
InspectabilityRead raw files or add custom debug codeQuery history and state with standard SQL
Vector plus relational dataSeparate stores, custom syncOne database for embeddings, search, and transactions
Path to productionStorage rewrite when the prototype graduatesClaim the instance; scale on the same SQL surface
Table 1: What changes when an MCP server moves from local-only state to a TiDB-backed state layer.

Where Distributed SQL Database for AI Becomes Useful

The distributed part matters once agents multiply. Hundreds of sessions writing tool events, memory reads on the hot path, and analytics over agent behavior are exactly the mixed workload distributed SQL was built for, and the migration from Zero to that scale is a claim flow, not a replatform.

How TiDB Fits the Broader Vibe Coding and AI Tooling Stack

An MCP server is rarely the whole project. It usually sits inside a larger loop of AI-assisted development: coding agents scaffolding the server, schema-aware tools reading the database, and agent workflows consuming what the server exposes. That loop runs best when the data layer is instant to provision and boring to operate, which is the role a distributed SQL database for AI plays across the stack. For how MCP servers, coding agents, and persistent data fit together tool by tool, see the Vibe Coding Tech Stack 2026 Guide.

Brian Foster is a Global Content Director at TiDB. With over 20 years of experience in technical content, publishing, and editorial leadership, he specializes in storytelling and content creation in the categories of distributed SQL, cloud infrastructure, and software development.

Last updated: August 13, 2026.

Methodology note: this playbook reflects the MCP specification and SDKs current as of mid-2026, tested against the official Python SDK, MCP Inspector, and TiDB Cloud Zero Public Preview. Code samples are illustrative starting points; validate them against the latest SDK docs before production use.

Give your MCP server a real SQL backend in seconds. No sign-up, no config, claim it when it works.

Build MCP Server FAQs

The fastest current path is Python with the official MCP SDK's FastMCP interface: install the SDK, decorate a function with @mcp.tool(), and run over stdio. The simple path still needs good tool design and local testing, because models select and call tools based entirely on your names, descriptions, and schemas.