Tutorials

How to Build Your First MCP Server in 2026: The Complete Stateless HTTP Guide

Master the Model Context Protocol with the new July 2026 stateless HTTP spec. Build production-ready AI tools for Claude Code and Cursor.

How to Build Your First MCP Server in 2026: The Complete Stateless HTTP Guide

How to Build Your First MCP Server in 2026: The Complete Stateless HTTP Guide

Welcome to the absolute most definitive, comprehensive guide on the internet on how to build mcp server 2026! If you have been working with AI agents, large language models (LLMs), or advanced coding assistants over the last couple of years, you know that connecting them to external data sources has historically been a highly fragmented, painful, and tedious process.

Enter the Model Context Protocol (MCP). By August 2026, MCP has truly become the "USB-C for AI." Just as USB-C standardized how we plug physical devices together—eliminating the need for a drawer full of proprietary charging cables—MCP standardizes how AI models plug into our datasets, internal APIs, and developer tools. This mcp tutorial will walk you through everything you need to know to get started, scale up, and deploy your tools to production.

Whether you're looking for an mcp server typescript boilerplate, an mcp server python example, or want to fundamentally understand the monumental July 2026 spec changes regarding mcp stateless HTTP, this massive model context protocol guide has you absolutely covered. Grab a coffee, because we are diving deep into the code, architecture, and production practices that will define AI engineering for years to come.

---

1. Why MCP Matters in August 2026 (The "USB-C for AI")

To understand why MCP is so revolutionary, we have to look back at the dark ages of AI integrations—circa 2023 and 2024. In those days, if you wanted your AI assistant to read your GitHub pull requests, you had to build a custom GitHub plugin specifically formatted for that one assistant. If you then wanted Cursor to query your internal production database, you had to write a completely different, custom database connector using Cursor's proprietary extension APIs. Every new tool, every new LLM, and every new editor required its own bespoke integration.

It was an N-by-M problem of massive proportions. You had N data sources and M AI assistants, meaning the community had to write N×M integrations just to get basic functionality working everywhere.

MCP changed everything by introducing a universal, standardized architecture. It established a common language for AI models to request context and perform actions. The architecture is brilliantly simple yet powerful:

  • Host: The application where the user interacts with the AI. This could be Cursor, Windsurf, Claude Code, or even a custom internal chatbot you built for your company.
  • Client: The component within the Host that manages the MCP connections, handling the transport layer and protocol negotiations.
  • Server: Your application—the code you write—that exposes tools, resources, and prompts via the standard MCP interface.

Real-World Examples of MCP in Action

Because it is standardized, a single MCP server you build today can instantly be used by Claude Code, Cursor, Windsurf, and dozens of other AI interfaces without changing a single line of code. It is the ultimate write-once, run-anywhere paradigm for AI context.

Consider these powerful real-world scenarios:

    • The Ultimate DevOps Assistant: You build an MCP server that connects to your AWS account and DataDog. Without writing any custom plugins for your IDE, you can open Cursor and say, "Check the recent error logs for the billing microservice and see if it correlates with our last ECS deployment." Cursor's AI seamlessly uses the MCP server to query AWS and DataDog simultaneously, giving you an immediate, context-rich answer.
    • Customer Support Triage: You build an MCP server that interfaces with Zendesk, Stripe, and your internal PostgreSQL database. Using Claude Code, a support engineer can prompt: "Refund the last charge for the user associated with Zendesk ticket #4912 and update their database status to 'churned'." The AI plans the steps, calls the Zendesk tool to find the email, calls the Stripe tool to issue the refund, and calls the SQL tool to update the database—all through one unified interface.
    • Automated Threat Modeling: A security engineer creates an MCP server that wraps Semgrep and internal threat intelligence feeds. In Windsurf, they can highlight a block of code and ask, "Does this implementation violate any of our internal security policies?" The AI reads the local file, sends it to the MCP server's Semgrep tool, and provides actionable remediation steps.
By adopting MCP, you aren't just building a plugin for one tool; you are extending the cognitive capabilities of every AI assistant that supports the protocol.
For more deep dives on architectural patterns for AI, check out our Vibe Coding Codex Academy for interactive video lessons.

---

2. The MAJOR July 28, 2026 Spec Changes: The Era of Stateless HTTP

If you built MCP servers in 2025, you probably used Server-Sent Events (SSE) or stdio transports with persistent, sticky sessions. While these were powerful for local development and simple scripts, they posed massive challenges for enterprise deployment. Managing stateful SSE connections in modern serverless environments (like AWS Lambda, Cloudflare Workers, or Vercel) was notoriously difficult, often leading to connection drops, memory leaks, and scaling bottlenecks.

On July 28, 2026, Anthropic and the MCP working group released a monumental update to the specification: Native Stateless HTTP.

Key Changes in the July 2026 Spec:

    • Stateless HTTP Model: You can now deploy MCP servers as pure stateless REST endpoints. Every request contains all necessary context for the server to process it. There are no websockets to keep alive.
    • Header-Based Routing: The protocol now uses specific HTTP headers for routing, namely Mcp-Method (e.g., tools/call) and Mcp-Name (e.g., get_weather). This bypasses the need to parse the JSON body just to route the request.
    • Cacheable Tools/List: Requests to tools/list, resources/list, and prompts/list can now be aggressively cached via standard HTTP Cache-Control headers. This dramatically speeds up initialization in editors like Cursor.
    • Removal of Sticky Sessions: No more keeping WebSockets or SSE streams open. The client sends an HTTP POST request, the server responds, and the connection closes immediately.

Before and After Code Comparisons

To truly appreciate this update, let's look at how we used to deploy an MCP server via SSE in 2025, compared to the new stateless HTTP method.

Before (2025 Stateful SSE Transport):

javascript
// 2025: Managing complex SSE connections
import express from 'express';
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';

const app = express();
const server = new McpServer({ name: "legacy-server", version: "1.0" });
let transport; // Stateful variable!

app.get('/sse', async (req, res) => {
  transport = new SSEServerTransport("/messages", res);
  await server.connect(transport);
  // Connection stays open indefinitely. Hard to load balance!
});

app.post('/messages', async (req, res) => {
  // Must route messages to the specific stateful transport instance
  await transport.handlePostMessage(req, res); 
});

After (2026 Stateless HTTP Transport):

javascript
// 2026: Clean, stateless HTTP
import express from 'express';
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StatelessHttpTransport } from '@modelcontextprotocol/sdk/server/http.js';

const app = express();
app.use(express.json());

const server = new McpServer({ name: "modern-server", version: "2.0" });
const transport = new StatelessHttpTransport(); // Stateless!

app.post('/mcp', async (req, res) => {
  // One endpoint, stateless processing, easy to deploy on Vercel/Lambda
  await transport.handleExpressRequest(req, res, server);
});

This shift means you can now deploy an MCP server anywhere you can deploy an Express or FastAPI app, with zero WebSocket headaches.

---

3. Architecture Diagram: The Stateless MCP Lifecycle

Here is a look at the modern MCP architecture in 2026. This diagram shows exactly how a Host interacts with your new Stateless HTTP server.

mermaid
sequenceDiagram
    participant User
    participant Host as Host (Cursor / Claude Code)
    participant Client as MCP Client
    participant Server as Stateless MCP Server
    participant System as External API / DB

    User->>Host: "Summarize recent Jira tickets"
    Host->>Client: Request available tools
    Client->>Server: HTTP GET /mcp (Mcp-Method: tools/list)
    Server-->>Client: Returns [get_jira_tickets] (Cached)
    Client-->>Host: Tool list updated
    Host->>Host: LLM decides to call get_jira_tickets
    Host->>Client: Execute tool
    Client->>Server: HTTP POST /mcp (Mcp-Method: tools/call, Mcp-Name: get_jira_tickets)
    Server->>System: Fetch data
    System-->>Server: Data returned
    Server-->>Client: HTTP 200 OK (Tool Result JSON)
    Client-->>Host: Pass result to LLM
    Host-->>User: "Here is the summary of your Jira tickets..."

---

4. TypeScript Tutorial: Building a Production-Ready Server

Let's dive into our first mcp server typescript implementation. We are not building a simple "hello world" weather app here. We are going to build a comprehensive, production-ready server that includes a real database querying tool, a local file reading resource, and a prompt template. We will use the official @modelcontextprotocol/sdk (v2.0.0+).

Prerequisites

  • Node.js v22+
  • TypeScript
  • PostgreSQL (or any generic DB library, we'll use pg for demonstration)

Step 1: Initialize the Project

First, let's set up our project directory, install dependencies, and configure TypeScript.

bash
mkdir mcp-enterprise-server
cd mcp-enterprise-server
npm init -y
npm install @modelcontextprotocol/sdk express cors dotenv pg zod
npm install -D typescript @types/node @types/express @types/cors @types/pg ts-node-dev

Here is your package.json configuration:

json
{
  "name": "mcp-enterprise-server",
  "version": "1.0.0",
  "description": "Production ready MCP Server",
  "main": "dist/index.js",
  "type": "module",
  "scripts": {
    "build": "tsc",
    "start": "node dist/index.js",
    "dev": "ts-node-dev --esm --respawn src/index.ts"
  },
  "dependencies": {
    "@modelcontextprotocol/sdk": "^2.1.0",
    "cors": "^2.8.5",
    "dotenv": "^16.4.5",
    "express": "^4.19.2",
    "pg": "^8.12.0",
    "zod": "^3.23.8"
  },
  "devDependencies": {
    "@types/cors": "^2.8.17",
    "@types/express": "^4.17.21",
    "@types/node": "^20.14.9",
    "@types/pg": "^8.11.6",
    "ts-node-dev": "^2.0.0",
    "typescript": "^5.5.3"
  }
}

And your tsconfig.json:

json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"]
}

Step 2: Write the Server Code

Create src/index.ts. This file will contain our entire application logic, including database connections, file resources, and the stateless HTTP transport.

``typescript import express from 'express'; import cors from 'cors'; import dotenv from 'dotenv'; import { Pool } from 'pg'; import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { StatelessHttpTransport } from '@modelcontextprotocol/sdk/server/http.js'; import { z } from 'zod'; import fs from 'fs/promises'; import path from 'path';

dotenv.config();

const app = express(); app.use(cors()); app.use(express.json());

// Initialize PostgreSQL connection pool const pool = new Pool({ connectionString: process.env.DATABASE_URL || 'postgres://user:pass@localhost:5432/mydb' });

// 1. Initialize the MCP Server const server = new McpServer({ name: "enterprise-operations-server", version: "1.0.0" });

// 2. Define Tools (Actions the AI can take) // Tool: Query the Database safely server.tool( "query_users_db", "Run a SELECT query on the users database to retrieve customer data.", { sql: z.string().describe("The raw SQL SELECT statement to execute. Only SELECT is allowed."), }, async ({ sql }) => { // Basic safety check if (!sql.trim().toUpperCase().startsWith('SELECT')) { return { content: [{ type: "text", text: "Error: Only SELECT queries are permitted for safety." }], isError: true }; } try { const result = await pool.query(sql); return { content: [{ type: "text", text: JSON.stringify(result.rows, null, 2) }] }; } catch (error: any) { return { content: [{ type: "text", text: Database error: ${error.message} }], isError: true }; } } );

// 3. Define Resources (Data the AI can read) // Resource: Read local configuration files server.resource( "system/config", "file:///etc/app/config.json", { description: "Read the internal application configuration" }, async (uri) => { try { // For demonstration, reading a local mock file const configPath = path.resolve(process.cwd(), 'mock-config.json'); const data = await fs.readFile(configPath, 'utf-8'); return { contents: [{ uri: uri.href, text: data, mimeType: "application/json" }] }; } catch (e) { throw new Error("Configuration file not found."); } } );

// 4. Define Prompts (Pre-packaged context triggers) server.prompt( "analyze_customer_churn", "Analyze why a specific customer might be churning", { customerId: z.string().describe("The ID of the customer") }, ({ customerId }) => { return { messages: [ { role: "user", content: { type: "text", text: Please analyze the churn risk for customer ${customerId}. First, use the query_users_db tool to fetch their recent activity, then summarize the findings.`

} } ] }; } );

// 5. Mount the Stateless HTTP Transport const transport = new StatelessHttpTransport();

app.post('/mcp', async (req, res) => { try { // Optional: Add simple authentication here (see Security section) await transport.handleExpressRequest(req, res, server); } catch (error) { console.error("MCP Request Error:", error); res.status(500).json({ error: "Internal Server Error" }); } });

const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(✅ Enterprise MCP Server running on http://localhost:${PORT}/mcp); });

code
### Step 3: Run and Build

To run the server in development mode:
bash npm run dev
code
To build for production:
bash npm run build npm start
code
This server is now highly capable. It provides an LLM with the ability to safely query a PostgreSQL database, read internal configuration files, and provides a structured prompt for the user to initiate complex workflows.

---

## 5. Python Tutorial: Complete Working Server with FastMCP

If you prefer Python, **FastMCP** (the FastAPI-inspired framework for MCP) is the definitive go-to choice. It makes creating an **mcp server python** incredibly elegant, leveraging Pydantic for validation. We will build a similarly complex server in Python.

### Step 1: Install Dependencies
bash pip install fastmcp uvicorn pydantic requests
code
### Step 2: Write the Server Code

Create `server.py`:
python from fastmcp import FastMCP from pydantic import BaseModel, Field import requests import json import os

Initialize FastMCP in stateless HTTP mode

mcp = FastMCP("python-enterprise-tools", transport="http")

Tool 1: File Searcher

class FileSearchArgs(BaseModel): query: str = Field(..., description="The text to search for") directory: str = Field(default=".", description="The directory to search in")

@mcp.tool() def search_files(args: FileSearchArgs) -> str: """Search for text across files in a directory.""" results = [] for root, _, files in os.walk(args.directory): for file in files: if file.endswith(('.py', '.js', '.txt', '.md')): path = os.path.join(root, file) try: with open(path, 'r', encoding='utf-8') as f: if args.query.lower() in f.read().lower(): results.append(path) except Exception: pass if not results: return f"No files found containing '{args.query}'." return "Found matches in: " + " ".join(results)

Tool 2: External API Fetcher (e.g., GitHub issues)

class GithubIssueArgs(BaseModel): repo: str = Field(..., description="Repository name in format owner/repo") state: str = Field(default="open", description="State of the issues to fetch (open, closed, all)")

@mcp.tool() def fetch_github_issues(args: GithubIssueArgs) -> str: """Fetch issues from a public GitHub repository.""" url = f"https://api.github.com/repos/{args.repo}/issues?state={args.state}&per_page=5" response = requests.get(url, headers={"Accept": "application/vnd.github.v3+json"}) if response.status_code != 200: return f"Failed to fetch issues: {response.status_code} - {response.text}" issues = response.json() formatted_issues = [] for issue in issues: formatted_issues.append(f"- [#{issue['number']}] {issue['title']} (State: {issue['state']})") return f"Recent {args.state} issues for {args.repo}: " + " ".join(formatted_issues)

Resource 1: System Info

@mcp.resource("system://info") def get_system_info() -> str: """Get system architecture and OS info.""" import platform info = { "os": platform.system(), "release": platform.release(), "architecture": platform.machine(), "python_version": platform.python_version() } return json.dumps(info, indent=2)

Prompt 1: Code Review Helper

@mcp.prompt("review_python_code") def code_review_prompt(file_path: str) -> str: """Initiate a code review for a specific Python file.""" return f"Please review the Python code located at {file_path}. Focus on PEP8 compliance, security vulnerabilities, and potential performance optimizations. Start by using the search_files tool to locate it if you need to verify the path."

Run via Uvicorn for HTTP deployment

if __name__ == "__main__": import uvicorn # mcp.app returns a standard ASGI Starlette/FastAPI app uvicorn.run(mcp.app, host="0.0.0.0", port=8000)
code
### Step 3: Run the Server
bash python server.py
code
With just 60 lines of code, you have a highly functional Python MCP server that exposes tools, resources, and prompts, all delivered seamlessly over stateless HTTP.

---

## 6. Deploying to Production (Vercel, Railway, Docker)

The biggest advantage of the July 2026 spec is how incredibly easy it is to deploy. Because the architecture relies on simple HTTP POST requests, you can deploy your MCP server to virtually any modern cloud provider.

### Option A: Deploying to Vercel (Next.js API Route)

If you are using Next.js or Vercel, your MCP server is just an API handler.
typescript // pages/api/mcp.ts import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { StatelessHttpTransport } from '@modelcontextprotocol/sdk/server/http.js'; import type { NextApiRequest, NextApiResponse } from 'next';

const server = new McpServer({ name: "vercel-mcp", version: "1.0" }); // ... define tools here ...

const transport = new StatelessHttpTransport();

export default async function handler(req: NextApiRequest, res: NextApiResponse) { if (req.method !== 'POST') { return res.status(405).json({ error: 'Method Not Allowed' }); } // Security check: Validate Auth Header if (req.headers.authorization !== Bearer ${process.env.MCP_SECRET}) { return res.status(401).json({ error: 'Unauthorized' }); }

await transport.handleNextRequest(req, res, server); }

code
Set your `MCP_SECRET` in the Vercel dashboard, and your server is live and globally distributed!

### Option B: Deploying to Railway or Render (Docker)

For robust, long-running Node.js or Python applications, Docker is king. Here is a production-ready `Dockerfile` for our TypeScript server.
dockerfile

Dockerfile

FROM node:22-alpine AS builder WORKDIR /app COPY package.json ./ RUN npm ci COPY . . RUN npm run build

FROM node:22-alpine WORKDIR /app COPY --from=builder /app/package.json ./ COPY --from=builder /app/node_modules ./node_modules COPY --from=builder /app/dist ./dist

ENV NODE_ENV=production ENV PORT=3000 EXPOSE 3000

CMD ["npm", "start"]

code
Deploying this to Railway or Render is as simple as connecting your GitHub repository. They will detect the Dockerfile, build the image, and provide you with a public URL (e.g., `https://my-mcp-server.up.railway.app/mcp`).

---

## 7. Security Considerations and Code Examples

When you expose an MCP server to the internet via HTTP, you are exposing a powerful API that an autonomous LLM will interact with. Security is paramount. Do not skip this step!

### 1. Authentication (Middleware Example)
Always require an API key via the `Authorization` header. Do not expose public unauthenticated MCP servers unless the tools are purely informational and heavily rate-limited.
typescript // Express Auth Middleware const authenticateMcp = (req, res, next) => { const authHeader = req.headers.authorization; const expectedToken = Bearer ${process.env.MCP_API_KEY}; if (!authHeader || authHeader !== expectedToken) { console.warn([Auth Failed] Unauthorized access attempt from IP: ${req.ip}); return res.status(401).json({ error: "Unauthorized. Invalid MCP API Key." }); } next(); };

// Apply to route app.post('/mcp', authenticateMcp, async (req, res) => { await transport.handleExpressRequest(req, res, server); });

code
### 2. Rate Limiting
Implement standard HTTP rate limiting on your `/mcp` endpoint to prevent an LLM caught in a loop from running up your cloud bill or overloading your database.
typescript import rateLimit from 'express-rate-limit';

const mcpLimiter = rateLimit({ windowMs: 15 60 1000, // 15 minutes max: 100, // Limit each IP to 100 requests per windowMs message: "Too many requests to the MCP server. Please try again later." });

app.post('/mcp', mcpLimiter, authenticateMcp, async (req, res) => { ... });

code
### 3. Input Validation
Use strict schemas (like Zod in TS or Pydantic in Python). Never trust the input coming from the LLM. If an LLM is asked to run a SQL query, validate that it's a `SELECT` statement, not a `DROP TABLE`.

---

## 8. Debugging MCP Servers

Developing MCP servers can sometimes feel like a black box because you are building an API meant for an AI to consume, not a human. Here are common errors and how to fix them.

### Error: "No tools found" in the Host UI
**Cause:** The Host sent a `tools/list` request, but the server returned an empty array or threw an error.
**Solution:** Ensure your server logic registers tools *before* mounting the transport. If using HTTP, verify the Host is sending the `Mcp-Method: tools/list` header correctly, and check your server logs for routing errors.

### Error: "Tool execution failed: Unknown tool"
**Cause:** The LLM tried to call a tool by a name that doesn't exist, or you changed the name of a tool but the Host has a cached version of the tool list.
**Solution:** In Cursor, click the "Refresh MCP Servers" button. If deploying to a CDN like Cloudflare, ensure you are purging the cache for the `/mcp` endpoint when you deploy new tool definitions.

### Error: "Connection Refused"
**Cause:** The Host cannot reach your server URL.
**Solution:** If running locally, ensure your server is actually running (`npm start`). If running via Docker, ensure you exposed the correct port (e.g., `-p 3000:3000`). If using Claude Code, verify the URL in `~/.claude.json` is correct.

### Using Curl to Debug
Because it's just HTTP, you can easily debug your server using curl:
bash

List Tools

curl -X POST http://localhost:3000/mcp \ -H "Mcp-Method: tools/list" \ -H "Content-Type: application/json" \ -d '{}'

Call a Tool

curl -X POST http://localhost:3000/mcp \ -H "Mcp-Method: tools/call" \ -H "Mcp-Name: get_weather" \ -H "Content-Type: application/json" \ -d '{"params": {"city": "London"}}'
code
---

## 9. Building a Real-World MCP Server: Supabase Integration Case Study

To truly grasp the power of MCP, let's look at a case study. Imagine you are building a SaaS product using Supabase, and you want your Cursor AI assistant to be able to manage database rows directly from your IDE.

We can build a `supabase-mcp-server`.

1. **The Setup:** We initialize an Express HTTP MCP server and install the `@supabase/supabase-js` client.
2. **The Tools:** We define tools like `fetch_user_by_email`, `update_subscription_status`, and `list_recent_signups`.
3. **The Implementation:**
typescript import { createClient } from '@supabase/supabase-js'; import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { z } from 'zod';

const supabase = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_SERVICE_KEY!); const server = new McpServer({ name: "supabase-manager", version: "1.0" });

server.tool( "fetch_user_by_email", "Fetch user details from Supabase using their email address", { email: z.string().email() }, async ({ email }) => { const { data, error } = await supabase.from('users').select('').eq('email', email).single(); if (error) return { content: [{ type: "text", text: Error: ${error.message} }], isError: true }; return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] }; } );

code
4. **The Workflow:** A developer is writing a migration script in Cursor. They need to know the exact JSON structure of the `users` table. They ask the AI: "Use the Supabase tool to fetch the user record for test@example.com." The AI executes the tool, receives the real JSON data from production, and instantly writes the correct TypeScript interfaces in the migration script. **This saves hours of context switching!**

---

## 10. Configuring Your Server in Claude Code and Cursor

Now that we have production-ready servers running, let's connect them to our host applications.

### Configuration for Claude Code (claude_desktop_config.json)

Claude Code (and Claude Desktop) use a configuration file to manage MCP connections. The file is typically located at:
- **Mac:** `~/Library/Application Support/Claude/claude_desktop_config.json`
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`

Open the file and configure your HTTP transports:
json { "mcpServers": { "enterprise-tools": { "transport": "http", "url": "http://localhost:3000/mcp", "headers": { "Authorization": "Bearer my-secret-local-token" } }, "python-fastmcp": { "transport": "http", "url": "https://my-production-fastmcp.up.railway.app/mcp", "headers": { "Authorization": "Bearer prod-token-12345" } } } } ``

Restart Claude Desktop, and you will see a small plug icon indicating your MCP servers are connected. You can now prompt Claude to use your tools!

Configuration for Cursor IDE

Cursor has deep, native, visual support for MCP. Connecting a cursor mcp server is done entirely through the UI.

    • Open Cursor Settings (Cmd/Ctrl + ,)
    • Navigate to Features -> MCP Servers
    • Click + Add New MCP Server
    • Set the following fields in the modal:
- Name: EnterpriseDB - Type: HTTP
(Note: this stateless HTTP option was added in Cursor v0.45.0) - URL: http://localhost:3000/mcp - Auth Header (Optional): Bearer my-secret-local-token
    • Click Save & Connect.
Screenshot Description: The Cursor settings panel showing a green dot next to "EnterpriseDB", indicating a successful stateless HTTP connection, with a list of available tools (query_users_db) populated below it.

Cursor will immediately ping the /mcp endpoint with the Mcp-Method: tools/list header, discover your tools, and make them available in the Composer/Chat window!

Ready to master Vibe Coding in Cursor? Check out our Vibe Coding Missions to practice these skills in real-world scenarios.

---

11. Top 10 Official MCP Servers to Learn From

If you want to see how the pros do it, check out the modelcontextprotocol/servers repository. Here are the top 10 most useful servers as of August 2026:

    • github-mcp: Full read/write access to GitHub PRs, issues, and repos.
    • postgres-mcp: Connects to any PostgreSQL database and allows the LLM to inspect schema and run safe queries.
    • google-drive-mcp: Search and read documents across your Google Workspace.
    • slack-mcp: Read messages and post updates to Slack channels.
    • jira-mcp: Manage agile workflows directly from Cursor or Claude.
    • aws-s3-mcp: List buckets and read object contents.
    • playwright-mcp: Allows the LLM to spin up a headless browser, navigate pages, and scrape dynamic content.
    • linear-mcp: Issue tracking and project management integration.
    • notion-mcp: Search your knowledge base and append notes to pages.
    • docker-mcp: Inspect running containers and read logs locally.
Studying the source code for these servers is the best way to master mcp tools resources prompts.

---

12. Frequently Asked Questions (FAQ)

Here are the most common questions developers have when adopting the stateless HTTP MCP specification in 2026.

Q1: What is the exact difference between MCP Tools, Resources, and Prompts?

  • Tools: Actionable functions the LLM can decide to execute (e.g., fetch_url, create_ticket, execute_sql). Tools accept parameters and return data. The LLM chooses when and how to call them.
  • Resources: Read-only data that the host application can read and inject into the context window (e.g., file://logs/error.log, system://config). Resources are like files on a virtual file system. The LLM doesn't "execute" them; it just reads their contents.
  • Prompts: Pre-defined conversational templates that the user can trigger from the host UI to start a conversation with specific context. Prompts guide the LLM's initial behavior.

Q2: Does the new Stateless HTTP spec completely replace the old stdio transport?

Absolutely not.
stdio (Standard Input/Output) is still perfectly valid and is highly preferred for local, system-level tasks. For example, if you want an MCP server that reads your local .git folder or modifies files on your local hard drive, stdio is safer and faster because it runs as a local process. HTTP is the new standard for cloud-based tools, external APIs, shared databases, and SaaS integrations where a network connection is required.

Q3: Can I use both TypeScript and Python MCP servers at the exact same time?

Yes! This is the beauty of the protocol. Your host application (like Claude Code or Cursor) acts as a centralized client that manages multiple connections. You can have a local
stdio Python server handling data science tasks, and a remote HTTP TypeScript server connected to your database simultaneously. The LLM will see a unified, merged list of tools from all connected servers.

Q4: How do I debug an HTTP MCP Server when the LLM keeps hallucinating tool calls?

First, ensure your tool descriptions are incredibly precise. The LLM relies entirely on the
description string you provide in the tool definition to understand what the tool does. Second, use Postman or curl to manually send a tools/call HTTP POST request to your server. Verify the JSON payload the server returns is correctly formatted according to the MCP specification (an array of content` objects). If the server returns plain text instead of JSON, the client will fail to parse it.

Q5: Is the Model Context Protocol owned exclusively by Anthropic?

While Anthropic originally proposed and open-sourced the specification in late 2024, it is now an open standard governed by an independent working group. Widespread industry support is built into tools far beyond Anthropic's ecosystem. Companies behind Cursor, Windsurf, Zed, Sourcegraph, and dozens of others actively contribute to and support the specification.

Q6: How do I handle large file uploads or downloads via an MCP tool?

Because MCP uses JSON over HTTP (or JSON-RPC over stdio), it is not optimized for transferring massive binary files (like a 1GB video). If your tool needs to process a large file, the best practice is to pass a URL or a local file path to the tool, rather than passing the file's raw bytes through the MCP protocol. The MCP server can then independently download or read the file, process it, and return a text-based summary or the location of the output file.

Q7: Are MCP servers secure to expose on the public internet?

Inherently, exposing any API to the public internet carries risk. However, because stateless HTTP MCP servers are just standard REST endpoints, you can apply all standard web security practices. You must use HTTPS/TLS, require strong Authentication headers (like Bearer tokens or API keys), implement rate limiting, and carefully validate all input payload schemas using libraries like Zod or Pydantic. Never trust the input, even if it comes from a highly capable LLM.

Q8: Can an MCP server call another MCP server?

While technically possible (Server A could act as a Client and make an HTTP request to Server B), it is generally considered an anti-pattern. The Host application (Cursor, Claude) should be the orchestrator. If you have two separate toolsets, connect both of them to the Host. The LLM acts as the central brain and will seamlessly chain tool calls together, fetching data from Server A and passing it to a tool on Server B.

---

Conclusion

Building an mcp server 2026 is more powerful and developer-friendly than ever before thanks to the stateless HTTP specification. By mastering these architectural patterns, TypeScript implementations, and deployment strategies, you are fundamentally future-proofing your AI engineering career.

You can now build robust, secure, production-ready context engines that work across any compatible IDE, chatbot, or autonomous agent. The days of writing custom plugins are over. The era of universal AI context is here.

Get out there, start building, and vibe code your way to production!

Want to master building AI agents and MCP servers? Join the Vibe Coding Codex Academy today!*

🚀 VIBE CODING CODEX ACADEMY

Ready to Stop Typing Code & Start Directing AI Systems?

Join 5,000+ developers building real production software with AI. Learn the 7-Stage Vibe Coding OS, harness engineering, and earn your verified Build DNA Certificate.

#MCP#TypeScript#Python#Claude Code#Cursor#AI Agents

Related Posts

Tutorials

The Spec-First Protocol: How We Build SaaS MVPs in 6 Hours Using Cursor Composer

8 min read
How to Build Your First App and Actually Make Money From It
Tutorials

How to Build Your First App and Actually Make Money From It

5 min read