Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Test MCP Serversearch for recent API documentation with a limit of 5 results"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Test MCP Server
A dual-transport Model Context Protocol (MCP) server that exposes your API as tools to LLM clients.
Supports two transports:
Stdio (local): For Claude Desktop, Cursor, Windsurf
HTTP/SSE (remote): For OpenAI Responses API and web clients
What is MCP?
The Model Context Protocol (MCP) is a standard that connects AI systems with external tools and data sources. MCP servers expose tools (functions), resources (data), and prompts that LLMs can use via a JSON-RPC interface over stdio.
Architecture
This is a proper MCP server that:
✅ Supports dual transports: stdio (local) and HTTP/SSE (remote)
✅ Uses the official MCP Python SDK (
mcppackage) for stdio✅ Uses FastAPI for HTTP/SSE transport
✅ Can be launched by MCP clients (Claude Desktop, Cursor, Windsurf)
✅ Can be called remotely by OpenAI Responses API
✅ Exposes tools with strict JSON schemas for deterministic behavior
✅ Includes authentication, rate limiting, and security best practices
✅ Follows SOLID principles with clean separation of concerns
Project Structure
windsurf-project/
├── main.py # Entry point for stdio transport (local)
├── main_http.py # Entry point for HTTP/SSE transport (remote)
├── requirements.txt # Python dependencies
├── mcp_config.json # Configuration for local MCP clients
├── .env.example # Environment variables template
├── README.md # This file
├── REMOTE_DEPLOYMENT.md # Guide for deploying as remote server
├── ThingsIveLearned.md # Project patterns and insights
└── test_mcp/ # Main package
├── __init__.py # Package initialization
├── server.py # MCP server (stdio transport)
├── http_server.py # MCP server (HTTP/SSE transport)
├── tools.py # Tool implementations (shared)
├── config.py # Configuration settings
└── handlers.py # Legacy handlers (can be removed)Installation
Install dependencies:
pip install -r requirements.txtConfigure environment (optional):
cp .env.example .env
# Edit .env with your API credentials if neededAvailable Tools
1. search_items
Search for items with pagination support.
Input Schema:
{
"query": "search term", // required
"limit": 10, // optional, 1-50, default 10
"cursor": "pagination_token" // optional
}Output:
{
"items": [
{
"id": "item_001",
"title": "Item Title",
"summary": "Brief description",
"score": 0.95
}
],
"nextCursor": "next_page_token",
"total": 42
}2. get_item
Retrieve detailed information about a single item.
Input Schema:
{
"id": "item_001" // required
}Output:
{
"id": "item_001",
"title": "Item Title",
"body": "Full content...",
"createdAt": "2025-10-08T08:00:00Z",
"url": "https://example.com/items/item_001",
"metadata": {
"author": "Author Name",
"tags": ["tag1", "tag2"]
}
}3. health
Check server health status.
Input Schema: {} (no parameters)
Output:
{
"status": "healthy",
"server": "test-mcp-server",
"version": "0.1.0",
"timestamp": "2025-10-08T08:43:00Z"
}Usage
Local Usage (Stdio Transport)
Testing Manually
Run the stdio server:
python main.pyThen send a JSON-RPC request via stdin:
{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}Connecting to Claude Desktop
Open your Claude Desktop config file:
macOS:
~/Library/Application Support/Claude/claude_desktop_config.jsonWindows:
%APPDATA%\Claude\claude_desktop_config.json
Add this server configuration:
{
"mcpServers": {
"test-mcp-server": {
"command": "python",
"args": [
"/Users/mokes/CascadeProjects/windsurf-project/main.py"
],
"env": {
"API_BASE_URL": "http://localhost:8000/api/v1",
"API_KEY": ""
}
}
}
}Restart Claude Desktop
The tools will appear in Claude's tool palette
Connecting to Cursor/Windsurf
Add the server to your MCP configuration (similar process to Claude Desktop).
Remote Usage (HTTP/SSE Transport)
Quick Start
Start the HTTP server:
python main_http.pyServer runs at http://localhost:8000
Test with curl:
# List tools
curl -X POST http://localhost:8000/mcp \
-H "Content-Type: application/json" \
-d '{"action": "list_tools"}'
# Call a tool
curl -X POST http://localhost:8000/mcp \
-H "Content-Type: application/json" \
-d '{
"action": "call_tool",
"name": "search_items",
"arguments": {"query": "test", "limit": 5}
}'Using with OpenAI Responses API
Once deployed to a public URL:
from openai import OpenAI
client = OpenAI()
resp = client.responses.create(
model="gpt-5",
tools=[{
"type": "mcp",
"server_label": "my-api",
"server_url": "https://api.yourdomain.com/mcp",
"authorization": "Bearer your_token",
"require_approval": "never"
}],
input="Search for items about AI"
)
print(resp.output_text)See
Customizing for Your API
Option 1: Replace Mock Data with Real API Calls
Edit test_mcp/tools.py and uncomment the real API call examples:
async def search_items_tool(arguments: Dict[str, Any]) -> Dict[str, Any]:
query = arguments.get("query", "")
limit = arguments.get("limit", 10)
cursor = arguments.get("cursor")
# Call your actual API
params = {"q": query, "limit": limit}
if cursor:
params["cursor"] = cursor
data = await call_api("GET", "/search", params=params)
return {
"items": data.get("items", []),
"nextCursor": data.get("nextCursor"),
"total": data.get("total", 0)
}Option 2: Add New Tools
Define the tool schema in
test_mcp/server.py:
Tool(
name="create_item",
description="Create a new item",
inputSchema={
"type": "object",
"properties": {
"title": {"type": "string", "minLength": 1},
"body": {"type": "string"}
},
"required": ["title"]
}
)Implement the tool in
test_mcp/tools.py:
async def create_item_tool(arguments: Dict[str, Any]) -> Dict[str, Any]:
title = arguments.get("title")
body = arguments.get("body", "")
# Your implementation
data = await call_api("POST", "/items", json={"title": title, "body": body})
return dataWire it up in the
call_toolhandler:
elif name == "create_item":
result = await create_item_tool(arguments)
return [TextContent(type="text", text=json.dumps(result, indent=2))]Best Practices
✅ DO:
Keep tool outputs compact and stable - LLMs rely on predictable shapes
Use opaque cursors for pagination (not page numbers)
Validate inputs strictly with JSON schemas (min/max, enums, defaults)
Return clear error messages - avoid HTML or stack traces
Add timeouts and retries for external API calls
Never expose secrets in tool outputs
❌ DON'T:
Don't return huge blobs of data - summarize or paginate
Don't use page numbers - use cursors for deterministic pagination
Don't hardcode API keys - use environment variables
Don't expose internal IDs or PII unless required
Don't make tools that have side effects without idempotency keys
Key Patterns
Separation of Concerns:
server.py: MCP protocol handling (stdio, JSON-RPC)tools.py: Business logic and API callsconfig.py: Configuration management
Type Safety:
Pydantic models for validation
Python type hints throughout
Strict JSON schemas for tool inputs
Error Handling:
Graceful degradation
Clear error messages
Timeout handling
Determinism:
Stable output formats
Predictable pagination
Consistent error codes
Troubleshooting
Server won't start
Check Python version (3.10+)
Verify all dependencies installed:
pip install -r requirements.txtCheck for syntax errors:
python -m py_compile main.py
Tools not appearing in Claude Desktop
Verify the path in
claude_desktop_config.jsonis absoluteCheck Claude Desktop logs for errors
Restart Claude Desktop after config changes
API calls failing
Verify
API_BASE_URLandAPI_KEYin environmentCheck network connectivity
Add logging to
tools.pyto debug
Environment Variables
API_BASE_URL: Base URL for your API (default:http://localhost:8000/api/v1)API_KEY: API authentication key (optional)ENVIRONMENT: Environment name (default:development)DEBUG: Enable debug logging (default:true)
License
MIT
Contributing
Follow SOLID principles
Add type hints to all functions
Update
ThingsIveLearned.mdwith new patternsTest with Claude Desktop before committing
This server cannot be installed
Resources
Looking for Admin?
Admins can modify the Dockerfile, update the server description, and track usage metrics. If you are the server author, to authenticate as an admin.