Before sending the Enterprise into battle, every system is tested on the holodeck. In MCP, that holodeck is the MCP Inspector โ an interactive development tool that lets you poke and prod your server without needing a full LLM client:
# Launch the Inspector โ your personal holodeck
mcp dev your_server.py
The Inspector opens a web UI where you can:
Think of it as running a Level 1 diagnostic from the bridge. You can validate every system before going to warp.
The mcp CLI provides additional commands for development workflow:
# Install your server in Claude Desktop for testing
mcp install your_server.py
# Install with a custom name
mcp install your_server.py --name "USS Enterprise"
# Install with environment variables (like ship access codes)
mcp install your_server.py -v STARFLEET_API_KEY=alpha-omega-7
# Run the interactive inspector
mcp dev your_server.py
The install command automatically configures Claude Desktop to connect to your server โ no manual JSON editing required. It's like docking at a starbase and having the maintenance crew handle the hookups.
The Kobayashi Maru is Starfleet's no-win scenario โ a stress test that pushes cadets to their limits. Your MCP server deserves the same treatment. Here's how to write programmatic tests:
import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
async def kobayashi_maru_test():
"""The no-win scenario: stress test all ship systems."""
params = StdioServerParameters(command='python', args=['warp_core.py'])
async with stdio_client(params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
# Test 1: Tool discovery โ can we see all weapons systems?
tools = await session.list_tools()
assert len(tools.tools) > 0, 'No tools found โ weapons offline!'
print(f"โ {len(tools.tools)} tools discovered")
# Test 2: Resource access โ are sensors operational?
resources = await session.list_resources()
print(f"โ {len(resources.resources)} resources available")
# Test 3: Tool execution โ fire at will!
result = await session.call_tool('engage_warp', {'factor': 9})
assert 'engaged' in result.content[0].text.lower(), \
'Warp drive failed to engage!'
print(f"โ Warp drive: {result.content[0].text}")
# Test 4: Error handling โ push past the limits
try:
result = await session.call_tool('engage_warp', {'factor': 15})
# Should have raised an error
if result.isError:
print("โ Warp factor limits enforced correctly")
except Exception as e:
print(f"โ Error properly raised: {e}")
print("\n๐ All systems nominal. Ship is ready for deployment.")
asyncio.run(kobayashi_maru_test())
This test spawns your server, connects to it, and exercises every capability โ just like Starfleet Academy's infamous test scenario. Run it in CI/CD to catch regressions before they reach production.
A single ship is powerful. A fleet is unstoppable. MCP clients can connect to multiple servers simultaneously, combining their capabilities into a single unified interface:
from langchain_mcp_adapters.client import MultiServerMCPClient
# Connect to an entire fleet of MCP servers
client = MultiServerMCPClient({
'enterprise': {
'command': 'python',
'args': ['enterprise_server.py'],
},
'defiant': {
'command': 'python',
'args': ['defiant_server.py'],
},
})
# The LLM now has access to ALL tools from ALL servers
# Enterprise tools: fire_phasers, raise_shields, sensor_scan
# Defiant tools: quantum_torpedo, ablative_armor, cloaking_device
Each server runs independently โ different processes, possibly different languages. The client aggregates all their tools into a single namespace. The model sees one unified set of capabilities, like an admiral commanding multiple ships from a flagship.
For production deployment, containerize your MCP server. It's like loading the ship into spacedock โ everything sealed, self-contained, ready for any environment:
# Dockerfile for your MCP server
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY warp_core.py .
# MCP servers communicate via stdio, so no ports to expose
CMD ["python", "warp_core.py"]
Since MCP uses stdio transport by default, there are no ports to expose โ the client spawns the container and pipes stdin/stdout. For remote deployments, MCP also supports SSE (Server-Sent Events) transport over HTTP.
To connect your server to Claude Desktop (Starfleet Command), add it to the configuration file. On macOS, edit ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"enterprise": {
"command": "python",
"args": ["/path/to/warp_core.py"],
"env": {
"STARFLEET_API_KEY": "your-api-key-here"
}
},
"defiant": {
"command": "python",
"args": ["/path/to/defiant_server.py"]
}
}
}
For Cursor, the configuration lives in .cursor/mcp.json at the project root:
{
"mcpServers": {
"enterprise": {
"command": "python",
"args": ["./warp_core.py"]
}
}
}
After saving, restart the client. Your server's tools will appear in the interface โ ready for the model to invoke at will.
When things go wrong (hull breach on Deck 7!), here's how to diagnose issues:
Claude Desktop writes MCP logs to:
# macOS
~/Library/Logs/Claude/mcp*.log
# Tail logs in real-time during development
tail -f ~/Library/Logs/Claude/mcp-server-enterprise.log
Since MCP uses stdout for protocol messages, print debug info to stderr:
import sys
@enterprise.tool()
def problematic_tool(x: int) -> str:
"""A tool that needs debugging."""
print(f"DEBUG: received x={x}", file=sys.stderr) # Goes to logs, not protocol
return f"Result: {x * 2}"
command in config doesn't resolve. Use absolute paths or ensure the binary is on PATH.Here's a complete, production-ready MCP server bringing all the concepts together โ resources, tools, prompts, error handling, and external API calls:
"""
USS Enterprise NCC-1701-D โ MCP Server
A complete Model Context Protocol server demonstrating all three primitives.
"""
from mcp.server.fastmcp import FastMCP
import httpx
enterprise = FastMCP("USS Enterprise NCC-1701-D")
# ============================================================
# RESOURCES โ Ship's Sensors (read-only, application-controlled)
# ============================================================
@enterprise.resource("enterprise://ship/status")
def ship_status() -> str:
"""Current ship status report."""
return (
"USS Enterprise NCC-1701-D Status Report\n"
"========================================\n"
"Hull Integrity: 98%\n"
"Shields: Online (standby)\n"
"Warp Core: Nominal\n"
"Life Support: Optimal\n"
"Crew Complement: 1,014\n"
"Current Position: Sector 001, Sol System"
)
@enterprise.resource("enterprise://crew/{department}")
def crew_manifest(department: str) -> str:
"""Crew manifest for a specific department."""
departments = {
"command": "Picard, J-L (Captain)\nRiker, W.T. (Commander)\nData (Lt. Cmdr)",
"engineering": "La Forge, G. (Lt. Cmdr)\nBarclay, R. (Lieutenant)",
"medical": "Crusher, B. (Cmdr)\nOgawa, A. (Nurse)",
"security": "Worf (Lt. Cmdr)\nDaniels (Lieutenant)",
}
return departments.get(department, f"Unknown department: {department}")
# ============================================================
# TOOLS โ Weapons & Systems (model-controlled, may have side effects)
# ============================================================
@enterprise.tool()
def fire_phasers(target: str, power_level: int = 50) -> str:
"""Fire phaser array at specified target. Power level 1-100."""
if power_level < 1 or power_level > 100:
raise ValueError("Power level must be between 1 and 100!")
if power_level > 80:
return f"Maximum phaser discharge at {target}. Direct hit!"
return f"Phaser burst at {target}, power level {power_level}%. Standing by."
@enterprise.tool()
def raise_shields(configuration: str = "standard") -> str:
"""Raise deflector shields. Configurations: standard, modulated, metaphasic."""
configs = {
"standard": "Standard shield configuration active. All frequencies rotating.",
"modulated": "Shields modulated to counter Borg cutting beam frequency.",
"metaphasic": "Metaphasic shields engaged. Safe for stellar corona entry.",
}
result = configs.get(configuration)
if not result:
raise ValueError(f"Unknown shield configuration: {configuration}")
return result
@enterprise.tool()
def engage_warp(factor: float) -> str:
"""Engage warp drive. Factor must be between 1 and 9.99."""
if factor < 1 or factor > 9.99:
raise ValueError(f"Warp factor {factor} outside safe parameters (1-9.99)!")
if factor > 9.9:
return f"WARNING: Warp {factor} engaged. Hull stress approaching critical!"
return f"Warp {factor} engaged. Smooth sailing through subspace."
@enterprise.tool()
async def hail_starbase(starbase_id: int) -> str:
"""Open hailing frequencies to a Federation starbase."""
async with httpx.AsyncClient() as client:
try:
response = await client.get(
f"https://api.example.com/starbase/{starbase_id}",
timeout=10.0
)
return response.json().get("message", "Channel open. No response.")
except httpx.RequestError:
return f"Unable to establish subspace link to Starbase {starbase_id}."
# ============================================================
# PROMPTS โ Tactical Patterns (user-controlled, selectable)
# ============================================================
@enterprise.prompt()
def tactical_analysis(threat: str, quadrant: str = "Alpha") -> str:
"""Request a tactical analysis of a threat."""
return (
f"You are Lt. Commander Worf, tactical officer aboard the USS Enterprise.\n\n"
f"Analyze the following threat: {threat} in the {quadrant} Quadrant.\n\n"
f"Provide:\n"
f"1) Threat assessment (scale 1-10)\n"
f"2) Recommended shield configuration\n"
f"3) Suggested evasive maneuvers\n"
f"4) Diplomatic options (if any โ you may note your skepticism)"
)
@enterprise.prompt()
def captains_log(stardate: str, summary: str) -> str:
"""Format a Captain's Log entry in the style of Jean-Luc Picard."""
return (
f"Captain's Log, Stardate {stardate}.\n\n"
f"Context: {summary}\n\n"
f"Write a formal Captain's Log entry. Reflect on the philosophical "
f"and ethical implications of the situation. Reference relevant literature "
f"or historical parallels where appropriate. Maintain the measured, "
f"contemplative tone characteristic of Captain Picard."
)
# ============================================================
# MAIN โ Launch the ship
# ============================================================
if __name__ == "__main__":
enterprise.run()
Save this as warp_core.py, run mcp dev warp_core.py to test, then mcp install warp_core.py to deploy to Claude Desktop. Your ship is now fully operational.
There are four lights. ๐