Test MCP Server
Click on "Deploy 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.
Related MCP server: mcp-connect
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 REMOTE_DEPLOYMENT.md for complete deployment guide.
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 deployed
Maintenance
Related MCP Connectors
- QuallaaOAuthcom.quallaa
Talk to your public-facing AI from any MCP client — Claude, ChatGPT, Cursor, Cline, Windsurf.
MCP server for progressive tool usage at any scale (see https://klavis.ai)
Nifty's MCP server — exposes tasks, projects, messages, and files as tools for AI agents.
An MCP server that provides an API to LLMs to manage their JumpCloud resources.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceAn MCP server that publishes CLI tools on your machine for discoverability by LLMs5 npm1MIT
- AlicenseNot gradedqualityBmaintenanceA dead simple MCP server for exposing your app functions to AI agents like Claude Desktop.6 npm6MIT
- FlicenseNot gradedqualityDmaintenanceA standalone MCP server that exposes API endpoints as tools for AI assistants, using SSE transport.-
- FlicenseNot gradedqualityDmaintenanceLocal MCP server that exposes fixed tools for GPT, Claude, and Gemini while routing to any OpenAI-compatible chat completions backend with independent configuration per target.1-