MCP Server Development
Server Requirements
To be listed in Testra's directory, MCP servers must meet these requirements:
Core Requirements
MCP v1.0+ Support
Implement all required MCP endpoints
Follow protocol specifications
Provide proper error handling
Documented API
Complete API documentation
Function descriptions and examples
Parameter and return type definitions
Security Audit Preferred
Optional but recommended security review
Vulnerability assessments
Best practices compliance
Open Source or Verifiable Builds
Public source code repository, OR
Verifiable build artifacts
Reproducible deployments
MCP Endpoint Reference
GET /health
– Health Check
Basic status check used to confirm that a server is operational.
Method: GET
URL: https://your-server.com/health
Response Example:
{
"status": "ok",
"uptime": 102934,
"timestamp": "2025-06-30T12:34:56Z"
}
status
: Should returnok
if the server is operationaluptime
: Time (in seconds) the server has been uptimestamp
: ISO 8601 timestamp of the check
GET /capabilities
– Function Discovery
Returns a list of callable functions exposed by the MCP server.
Method: GET
URL: https://your-server.com/capabilities
Response Example:
{
"functions": [
{
"name": "extract_entities",
"description": "Extracts named entities from a string",
"inputs": ["text"],
"outputs": ["entities"]
},
{
"name": "get_exchange_rate",
"description": "Returns current exchange rate between two currencies",
"inputs": ["from", "to"],
"outputs": ["rate"]
}
]
}
name
: Function identifier to be used with/execute
description
: Human-readable explanation of functioninputs
: List of expected input keysoutputs
: List of output keys
POST /execute
– Function Execution
Main execution endpoint for calling any available function listed in /capabilities
.
Method: POST
URL: https://your-server.com/execute
Headers:
Content-Type: application/json
Request Example:
{
"function": "get_exchange_rate",
"input": {
"from": "USD",
"to": "EUR"
}
}
Response Example:
{
"output": {
"rate": 0.9254
}
}
function
: Must match a name returned by/capabilities
input
: Object with named parameters expected by the functionoutput
: Object with named result keys as defined by the server
Development Templates
Node.js Template
const express = require('express');
const app = express();
// Middleware
app.use(express.json());
app.use(require('cors')());
// Server configuration
const SERVER_CONFIG = {
name: 'My MCP Server',
version: '1.0.0',
mcpVersion: '1.0.0',
description: 'Description of your server'
};
// Function registry
const functions = new Map();
// Register a function
function registerFunction(name, handler, schema) {
functions.set(name, { handler, schema });
}
// Health endpoint
app.get('/health', (req, res) => {
res.json({
status: 'healthy',
timestamp: new Date().toISOString(),
version: SERVER_CONFIG.version,
mcpVersion: SERVER_CONFIG.mcpVersion
});
});
// Capabilities endpoint
app.get('/capabilities', (req, res) => {
const functionList = Array.from(functions.entries()).map(([name, func]) => ({
name,
description: func.schema.description,
parameters: func.schema.parameters,
returns: func.schema.returns
}));
res.json({
mcpVersion: SERVER_CONFIG.mcpVersion,
server: {
name: SERVER_CONFIG.name,
version: SERVER_CONFIG.version,
description: SERVER_CONFIG.description
},
functions: functionList
});
});
// Execute endpoint
app.post('/execute', async (req, res) => {
const { function: functionName, parameters, requestId } = req.body;
try {
const func = functions.get(functionName);
if (!func) {
return res.status(400).json({
error: {
code: 'FUNCTION_NOT_FOUND',
message: `Function '${functionName}' not found`
},
requestId
});
}
const startTime = Date.now();
const result = await func.handler(parameters);
const executionTime = Date.now() - startTime;
res.json({
requestId,
result,
executionTime
});
} catch (error) {
res.status(500).json({
error: {
code: 'EXECUTION_ERROR',
message: error.message
},
requestId
});
}
});
// Example function registration
registerFunction('getPrice', async (params) => {
// Your function logic here
return {
price: 2345.67,
timestamp: new Date().toISOString(),
symbol: params.symbol
};
}, {
description: 'Get current price for a trading pair',
parameters: {
type: 'object',
properties: {
symbol: { type: 'string', description: 'Trading pair symbol' }
},
required: ['symbol']
},
returns: {
type: 'object',
properties: {
price: { type: 'number' },
timestamp: { type: 'string' },
symbol: { type: 'string' }
}
}
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`MCP Server running on port ${PORT}`);
});
Python Template
from flask import Flask, request, jsonify
from datetime import datetime
import time
app = Flask(__name__)
# Server configuration
SERVER_CONFIG = {
'name': 'My MCP Server',
'version': '1.0.0',
'mcpVersion': '1.0.0',
'description': 'Description of your server'
}
# Function registry
functions = {}
def register_function(name, handler, schema):
functions[name] = {'handler': handler, 'schema': schema}
@app.route('/health', methods=['GET'])
def health():
return jsonify({
'status': 'healthy',
'timestamp': datetime.utcnow().isoformat() + 'Z',
'version': SERVER_CONFIG['version'],
'mcpVersion': SERVER_CONFIG['mcpVersion']
})
@app.route('/capabilities', methods=['GET'])
def capabilities():
function_list = []
for name, func in functions.items():
function_list.append({
'name': name,
'description': func['schema']['description'],
'parameters': func['schema']['parameters'],
'returns': func['schema']['returns']
})
return jsonify({
'mcpVersion': SERVER_CONFIG['mcpVersion'],
'server': {
'name': SERVER_CONFIG['name'],
'version': SERVER_CONFIG['version'],
'description': SERVER_CONFIG['description']
},
'functions': function_list
})
@app.route('/execute', methods=['POST'])
def execute():
data = request.get_json()
function_name = data.get('function')
parameters = data.get('parameters', {})
request_id = data.get('requestId')
try:
if function_name not in functions:
return jsonify({
'error': {
'code': 'FUNCTION_NOT_FOUND',
'message': f"Function '{function_name}' not found"
},
'requestId': request_id
}), 400
start_time = time.time()
result = functions[function_name]['handler'](parameters)
execution_time = int((time.time() - start_time) * 1000)
return jsonify({
'requestId': request_id,
'result': result,
'executionTime': execution_time
})
except Exception as e:
return jsonify({
'error': {
'code': 'EXECUTION_ERROR',
'message': str(e)
},
'requestId': request_id
}), 500
# Example function
def get_price(params):
return {
'price': 2345.67,
'timestamp': datetime.utcnow().isoformat() + 'Z',
'symbol': params.get('symbol')
}
# Register the function
register_function('getPrice', get_price, {
'description': 'Get current price for a trading pair',
'parameters': {
'type': 'object',
'properties': {
'symbol': {'type': 'string', 'description': 'Trading pair symbol'}
},
'required': ['symbol']
},
'returns': {
'type': 'object',
'properties': {
'price': {'type': 'number'},
'timestamp': {'type': 'string'},
'symbol': {'type': 'string'}
}
}
})
if __name__ == '__main__':
app.run(debug=True, port=3000)
Testing Your Server
Before submitting to Testra, test your server locally:
# Install testing tools
npm install -g @testra/test-suite
# Test your server
testra-test http://localhost:3000 --comprehensive
# Example output:
# Health check endpoint
# Capabilities discovery
# Function execution
# Error handling
# Schema validation
# Rate limiting not implemented
# Security scan passed
Last updated