# MCP Features Guide
**Purpose:** Learn how Model Context Protocol (MCP) features work through this BIG-IP server implementation.
This guide is designed for developers learning MCP. Each section explains a feature, shows the code, and demonstrates how it works in practice.
---
## Table of Contents
1. [What is MCP?](#what-is-mcp)
2. [Feature 1: Tools](#feature-1-tools) (You already know this)
3. [Feature 2: Resources](#feature-2-resources) β NEW
4. [Feature 3: Prompts](#feature-3-prompts) β NEW
5. [Feature 4: Context State](#feature-4-context-state) β NEW
6. [Feature 5: Cross-Server Integration](#feature-5-cross-server-integration) β NEW
7. [Complete Workflow Diagram](#complete-workflow-diagram)
8. [Code Location Reference](#code-location-reference)
9. [Learning Path](#learning-path)
---
## What is MCP?
**Model Context Protocol (MCP)** is a standardized way for AI assistants (like Claude) to interact with external systems. Think of it as an API specifically designed for AI.
### Core Concept
```
βββββββββββββββ MCP Protocol ββββββββββββββββββββ
β β ββββββββββββββββββββββββββΊ β β
β Claude β (JSON-RPC over stdio) β MCP Server β
β (AI Agent) β β (Your Code) β
β β ββββββββββββββββββββββββββΊ β β
βββββββββββββββ ββββββββββββββββββββ
β
β Connects to
βΌ
ββββββββββββββββββββ
β BIG-IP Device β
β (Target System)β
ββββββββββββββββββββ
```
### Why MCP?
- **Standardized**: One protocol for all integrations
- **Secure**: Credentials stay in your MCP server, not with Claude
- **Composable**: Multiple MCP servers work together
- **Stateful**: Session-based interactions with caching
---
## Feature 1: Tools
**What:** Functions that Claude can call to perform actions.
**When to use:** Any operation that changes state or retrieves dynamic data.
### Example from our codebase
```python
@mcp.tool
async def list_virtual_servers(
device_name: str,
ctx: Context = None
) -> str:
"""List all virtual servers from a BIG-IP device"""
# Implementation...
```
**Location in code:** `server.py:937-1067`
### How Claude uses it:
**User:** "Show me virtual servers on lab-bigip"
**Claude calls:**
```python
list_virtual_servers(device_name="lab-bigip")
```
**Result:** Returns formatted table of virtual servers
### All Tools in This Server
| Tool Name | Purpose | Line |
|-----------|---------|------|
| `list_virtual_servers` | Query BIG-IP virtual servers | 937 |
| `list_bigip_devices` | Show configured devices | 1069 |
| `manage_as3` | Install/upgrade AS3 | 1107 |
| `create_as3_app` | Deploy AS3 applications | 1417 |
---
## Feature 2: Resources
**What:** Static or semi-static data that Claude can read (like files in a filesystem).
**When to use:** Configuration data, templates, catalogs, documentation.
**Key difference from Tools:** Resources are **read-only data access**, Tools are **actions**.
### Architecture
```
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Resource URIs β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β config://server ββΊ Server metadata β
β templates://available ββΊ List of all templates β
β templates://marketing ββΊ Specific template content β
β templates://engineering ββΊ Specific template content β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
β Claude reads these like files
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β "Show me available templates" β
β "What variables does the marketing template use?" β
β "Let me see the server configuration" β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
```
### Resource 1: Server Configuration
**URI:** `config://server`
**Purpose:** Server metadata and capabilities
**Code:** `server.py:1684-1697`
```python
@mcp.resource("config://server")
def get_server_config() -> str:
"""Get server configuration information"""
config = {
"name": "BIG-IP MCP Server",
"version": "1.0.0",
"description": "MCP server for F5 BIG-IP management",
"capabilities": [
"List virtual servers",
"Token-based authentication",
"Credential caching"
]
}
return json.dumps(config, indent=2)
```
**How to use:**
```
User: "What can this BIG-IP server do?"
Claude: [Reads config://server resource]
"This server can list virtual servers, uses token authentication, and caches credentials..."
```
### Resource 2: Template Catalog
**URI:** `templates://available`
**Purpose:** List all AS3 templates with their variables
**Code:** `server.py:1700-1743`
```python
@mcp.resource("templates://available")
def list_available_templates() -> str:
"""List all available AS3 application templates"""
templates_dir = Path(__file__).parent / "templates"
# Scan directory for .json files
template_files = list(templates_dir.glob("*.json"))
templates = []
for template_file in template_files:
# Extract variables like {{VIRTUAL_IP}}, {{POOL_MEMBER_1}}
variables = re.findall(r'\{\{([A-Z_]+)\}\}', template_str)
templates.append({
"name": template_name,
"file": template_file.name,
"variables": unique_vars,
"description": f"AS3 template for {template_name} applications"
})
return json.dumps({"count": len(templates), "templates": templates}, indent=2)
```
**Example output:**
```json
{
"count": 1,
"templates": [
{
"name": "marketing",
"file": "marketing.json",
"variables": ["TENANT_NAME", "APP_NAME", "VIRTUAL_IP", "POOL_MEMBER_1", "POOL_MEMBER_2"],
"description": "AS3 template for marketing applications"
}
]
}
```
**How to use:**
```
User: "What templates are available?"
Claude: [Reads templates://available]
"I found 1 template:
- marketing: Requires TENANT_NAME, APP_NAME, VIRTUAL_IP, POOL_MEMBER_1, POOL_MEMBER_2"
```
### Resource 3: Specific Template Content
**URI Pattern:** `templates://{template_name}`
**Purpose:** Get the full content of a specific template
**Code:** `server.py:1746-1768`
```python
@mcp.resource("templates://{template_name}")
def get_template_content(template_name: str) -> str:
"""Get the content of a specific AS3 template"""
template = load_as3_template(template_name)
# Extract variables from template
template_str = json.dumps(template)
variables = re.findall(r'\{\{([A-Z_]+)\}\}', template_str)
result = {
"name": template_name,
"variables": list(set(variables)),
"template": template # Full JSON template
}
return json.dumps(result, indent=2)
```
**How to use:**
```
User: "Show me the marketing template"
Claude: [Reads templates://marketing]
"Here's the marketing template. It creates an HTTP virtual server with a pool..."
[Shows full template JSON]
```
### Resources vs Tools: When to Use Each
| Scenario | Use Resource | Use Tool |
|----------|--------------|----------|
| List available templates | β
`templates://available` | β |
| View template content | β
`templates://marketing` | β |
| Deploy AS3 app | β | β
`create_as3_app` tool |
| Server capabilities | β
`config://server` | β |
| List virtual servers | β | β
`list_virtual_servers` tool |
| Check AS3 status | β | β
`manage_as3` tool |
**Rule of thumb:**
- **Resource** = "Show me what exists" (read-only catalog)
- **Tool** = "Do something" (action or dynamic query)
---
## Feature 3: Prompts
**What:** Pre-written guidance that Claude can load for contextual help.
**When to use:** Complex workflows, onboarding, multi-step processes.
**Think of it as:** Built-in documentation that Claude can reference to help users.
### Architecture
```
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Prompt System β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β User asks: "How do I create an AS3 app?" β
β β β
β βΌ β
β Claude loads: create_app_workflow prompt β
β β β
β βΌ β
β Claude reads comprehensive workflow guide β
β - Step-by-step instructions β
β - Example interaction β
β - Prerequisites β
β - MCP features explained β
β β β
β βΌ β
β Claude guides user through workflow β
β β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
```
### Prompt 1: Help Prompt
**Name:** `help_prompt`
**Purpose:** General server capabilities and usage
**Code:** `server.py:1775-1798`
```python
@mcp.prompt
def help_prompt() -> str:
"""Get help about available BIG-IP server capabilities"""
return """
This BIG-IP MCP server provides tools to manage F5 BIG-IP devices:
**Available Tools:**
- `list_virtual_servers`: Query all virtual servers from a BIG-IP device
- Requires: IP address, username, and password
- Caches authentication token for subsequent requests
- Returns detailed status of each virtual server
**Usage:**
Ask Claude to "list virtual servers on my BIG-IP" and provide:
- BIG-IP IP address or hostname
- Username
- Password
**Security:**
- Authentication tokens are cached per-device
- Tokens automatically expire after 19 minutes
- SSL verification can be enabled for production
"""
```
**How Claude uses it:**
```
User: "How do I use this BIG-IP server?"
Claude: [Loads help_prompt]
"This server provides tools to manage F5 BIG-IP devices.
You can list virtual servers by providing IP, username, and password.
Authentication tokens are cached..."
```
### Prompt 2: Workflow Guide
**Name:** `create_app_workflow`
**Purpose:** Complete guide for AS3 application creation with cross-MCP integration
**Code:** `server.py:1801-1875`
```python
@mcp.prompt
def create_app_workflow() -> str:
"""Guide for creating AS3 applications with phpIPAM integration"""
return """
# AS3 Application Creation Workflow
This workflow demonstrates cross-MCP-server integration.
## Prerequisites
- Both phpIPAM and BIG-IP MCP servers connected
- AS3 installed on BIG-IP
- phpIPAM configured with sections/subnets
## Step-by-Step Process
### 1. List Available Sections (phpIPAM)
Ask Claude: "List all sections from phpIPAM"
### 2. Select Your Section
Choose section (e.g., "marketing", "engineering")
### 3. Reserve Virtual IP (phpIPAM)
Workflow will reserve first available IP
### 4. Get Pool Member IPs (phpIPAM)
Ask Claude: "Show me web servers in marketing"
### 5. Create Application (BIG-IP)
Claude generates AS3 declaration and deploys
## Example Interaction
[Full conversation example with tool calls]
## MCP Features Demonstrated
- Cross-Server Orchestration
- Resources (templates)
- Prompts (this guide)
- Context State (cached tokens)
- Human-in-the-Loop
"""
```
**How Claude uses it:**
```
User: "I want to create a load balancer application"
Claude: [Loads create_app_workflow prompt]
"Let me guide you through the AS3 application creation workflow.
First, we need to list available sections from phpIPAM..."
[Follows step-by-step guide]
```
### Why Prompts Are Powerful
**Without prompts:**
```
User: "Help me create an AS3 app"
Claude: "I can help with that. What device do you want to use?"
[Generic conversation, Claude has to figure it out]
```
**With prompts:**
```
User: "Help me create an AS3 app"
Claude: [Loads create_app_workflow]
"I'll guide you through the workflow. This involves:
1. Selecting a section from phpIPAM
2. Reserving a virtual IP
3. Choosing pool members
4. Deploying the AS3 configuration
Let's start - let me list your available sections..."
[Structured, consistent experience]
```
### Prompts vs Documentation Files
| Feature | Prompt | README.md |
|---------|--------|-----------|
| Claude can load automatically | β
| β |
| Contextual guidance | β
| Limited |
| Always up-to-date | β
| Requires maintenance |
| Searchable by Claude | β
| β |
| Human-readable | β
| β
|
**Best practice:** Use **both**
- Prompts for Claude's guidance
- Markdown docs for human reference
---
## Feature 4: Context State
**What:** Session-based caching that persists across multiple tool calls.
**When to use:** Authentication tokens, user selections, workflow state.
**Key benefit:** Avoid re-authenticating or re-querying data within the same session.
### Context State Operations
```python
from fastmcp import Context
# SET state
ctx.set_state(key: str, value: dict)
# GET state
cached_data = ctx.get_state(key: str) -> dict | None
# State persists for the entire conversation session
```
### Use Case 1: Authentication Token Caching
**Problem:** Re-authenticating to BIG-IP on every tool call is slow and wasteful.
**Solution:** Cache tokens with expiration tracking.
#### Flow Diagram
```
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Token Caching with Context State β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β First Call: list_virtual_servers(device="lab-bigip") β
β β β
β βββΊ Check: ctx.get_state("bigip_token_lab-bigip") β
β β Result: None (no cached token) β
β β β
β βββΊ Authenticate to BIG-IP β
β β POST /mgmt/shared/authn/login β
β β Response: { token: "XYSABC...", timeout: 1200 } β
β β β
β βββΊ Cache token: β
β β ctx.set_state("bigip_token_lab-bigip", { β
β β "token": "XYSABC...", β
β β "expires_at": "2025-10-24T10:30:00" β
β β }) β
β β β
β βββΊ Query virtual servers using token β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β Second Call: manage_as3(device="lab-bigip", action="status") β
β β β
β βββΊ Check: ctx.get_state("bigip_token_lab-bigip") β
β β Result: Found! { token: "XYSABC...", β
β β expires_at: "2025-10-24T10:30" }β
β β β
β βββΊ Check expiration: Still valid β β
β β β
β βββΊ Reuse cached token (no re-authentication!) β
β β β
β βββΊ Check AS3 status using cached token β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
```
#### Code Implementation
**Setting state:** `server.py:997`
```python
# After successful authentication
token_obj = await authenticate_bigip(credentials)
# Cache token with device-specific key
ctx.set_state(f"bigip_token_{device_name}", token_obj.model_dump())
await ctx.info("Successfully authenticated to BIG-IP")
```
**Getting state:** `server.py:974`
```python
# Check for cached token
cached_token = ctx.get_state(f"bigip_token_{device_name}")
if cached_token:
token_obj = AuthToken(**cached_token)
# Check if expired
if token_obj.expires_at <= datetime.now():
token_obj = None # Expired, need to re-auth
await ctx.info("Cached token expired, will re-authenticate")
else:
await ctx.info("Using cached authentication token")
```
#### Token Structure
```python
class AuthToken(BaseModel):
token: str # "XYSABC123..."
expires_at: datetime # "2025-10-24T10:30:00"
```
**State key pattern:** `bigip_token_{device_name}`
- `bigip_token_lab-bigip`
- `bigip_token_prod-lb-01`
- `bigip_token_bos-dmz-lb-01`
### Use Case 2: VIP Reservation Caching
**Problem:** In guided workflow, user reserves a VIP, then later needs to select pool members. The VIP needs to be remembered.
**Solution:** Cache the reserved VIP in context state.
#### Flow Diagram
```
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β VIP Caching in Multi-Step Workflow β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β Step 1: Reserve VIP β
β User: "Create marketing app" β
β Claude β phpIPAM: reserve_ip_address(subnet_id=8) β
β Result: "192.168.50.3" β
β β β
β βββΊ ctx.set_state("as3_app_marketing", { β
β "virtual_ip": "192.168.50.3" β
β }) β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β Step 2: Select Pool Members (later in conversation) β
β User: "Use servers 1 and 2" β
β Claude β create_as3_app(pool_member_selection="1 and 2") β
β β β
β βββΊ ctx.get_state("as3_app_marketing") β
β β Result: { "virtual_ip": "192.168.50.3" } β
β β β
β βββΊ Use cached VIP + selected pool members β
β Deploy AS3 app with both! β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β Step 3: Clear State After Deployment β
β ctx.set_state("as3_app_marketing", None) β
β (Clean up for next app creation) β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
```
#### Code Implementation
**Setting state:** `server.py:1490-1495` (would be set by phpIPAM interaction)
```python
state_key = f"as3_app_{section_name}"
app_state = ctx.get_state(state_key) if ctx else None
if app_state and app_state.get("virtual_ip"):
virtual_ip = app_state["virtual_ip"]
await ctx.info(f"Using cached VIP: {virtual_ip}")
```
**Clearing state after deployment:** `server.py:1659`
```python
# Clear cached state after successful deployment
if ctx:
ctx.set_state(state_key, None)
```
**State key pattern:** `as3_app_{section_name}`
- `as3_app_marketing`
- `as3_app_engineering`
- `as3_app_finance`
### Context State Best Practices
1. **Use descriptive keys**: `bigip_token_{device_name}` not `token1`
2. **Include expiration**: Don't cache indefinitely
3. **Clear after use**: Clean up state when workflow completes
4. **Namespace by entity**: Device tokens, app state, user selections
5. **Handle missing state**: Always check if `get_state()` returns `None`
### State Lifecycle
```
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Context State Lifecycle β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β Session Start β
β β β
β βΌ β
β ββββββββββββββββββ β
β β Empty Context β ctx.get_state() β None β
β ββββββββββββββββββ β
β β β
β β First tool call β
β βΌ β
β ββββββββββββββββββ β
β β Set State β ctx.set_state("key", data) β
β ββββββββββββββββββ β
β β β
β β Multiple subsequent calls β
β βΌ β
β ββββββββββββββββββ β
β β Get State β ctx.get_state("key") β data β
β β (Reuse cached) β (No re-computation!) β
β ββββββββββββββββββ β
β β β
β β Workflow completes β
β βΌ β
β ββββββββββββββββββ β
β β Clear State β ctx.set_state("key", None) β
β ββββββββββββββββββ β
β β β
β β Session ends β
β βΌ β
β ββββββββββββββββββ β
β β State Destroyedβ All context cleared β
β ββββββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
```
### Performance Impact
**Without Context State:**
```
Call 1: list_virtual_servers() β Authenticate (2s) + Query (0.5s) = 2.5s
Call 2: manage_as3() β Authenticate (2s) + Query (0.5s) = 2.5s
Call 3: create_as3_app() β Authenticate (2s) + Deploy (3s) = 5s
Total: 10 seconds
```
**With Context State:**
```
Call 1: list_virtual_servers() β Authenticate (2s) + Query (0.5s) = 2.5s [Cache token]
Call 2: manage_as3() β Reuse token (0s) + Query (0.5s) = 0.5s
Call 3: create_as3_app() β Reuse token (0s) + Deploy (3s) = 3s
Total: 6 seconds (40% faster!)
```
---
## Feature 5: Cross-Server Integration
**What:** Multiple MCP servers working together, coordinated by Claude.
**When to use:** Workflows that span multiple systems (e.g., phpIPAM + BIG-IP).
**Key insight:** Claude acts as the orchestrator between servers.
### Architecture
```
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Cross-Server Orchestration β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β ββββββββββββββββ β
β β β β
β β Claude β β
β β (Orchestrator)β β
β β β β
β βββββββββ¬βββββββ β
β β β
β βββββββββββββββ΄ββββββββββββββ β
β β β β
β βΌ βΌ β
β βββββββββββββββββββ βββββββββββββββββββ β
β β phpIPAM Server β β BIG-IP Server β β
β βββββββββββββββββββ€ βββββββββββββββββββ€ β
β β Tools: β β Tools: β β
β β β’ list_sections β β β’ list_vs β β
β β β’ reserve_ip β β β’ create_as3_appβ β
β β β’ get_subnets β β β’ manage_as3 β β
β ββββββββββ¬βββββββββ ββββββββββ¬βββββββββ β
β β β β
β βΌ βΌ β
β βββββββββββββββββββ βββββββββββββββββββ β
β β phpIPAM DB β β BIG-IP Device β β
β βββββββββββββββββββ βββββββββββββββββββ β
β β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
```
### Complete Workflow: Creating an AS3 Application
This demonstrates all 5 MCP features working together.
```
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Complete AS3 Application Creation Workflow β
β (All 5 MCP Features in Action) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β USER: "Create a load balancer for the marketing department" β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β STEP 1: Claude loads guidance β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β [Feature: PROMPTS] β
β Claude loads: create_app_workflow prompt β
β β Understands: Need to coordinate phpIPAM + BIG-IP β
β β Knows: 5-step process to follow β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β STEP 2: List sections (phpIPAM Server) β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β [Feature: CROSS-SERVER] β
β Claude β phpIPAM: list_sections() β
β Result: [ β
β {id: 1, name: "marketing"}, β
β {id: 2, name: "engineering"} β
β ] β
β β
β Claude: "Found sections: marketing, engineering. Which one?" β
β User: "Marketing" β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β STEP 3: Reserve Virtual IP (phpIPAM Server) β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β [Feature: CROSS-SERVER] β
β Claude β phpIPAM: reserve_ip_address( β
β subnet_id="8", β
β hostname="marketing-vip" β
β ) β
β Result: "192.168.50.3" β
β β
β [Feature: CONTEXT STATE] β
β BIG-IP ctx.set_state("as3_app_marketing", { β
β "virtual_ip": "192.168.50.3" β
β }) β
β β
β Claude: "Reserved VIP: 192.168.50.3 β" β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β STEP 4: Get pool member options (phpIPAM Server) β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β [Feature: CROSS-SERVER] β
β Claude β phpIPAM: get_subnet_details( β
β subnet_id="7", β
β include_addresses=true β
β ) β
β Result: [ β
β {ip: "172.16.100.3", hostname: "web-mkt-3"}, β
β {ip: "172.16.100.4", hostname: "web-mkt-4"}, β
β {ip: "172.16.100.5", hostname: "web-mkt-5"} β
β ] β
β β
β Claude: "Available servers: β
β 1. 172.16.100.3 (web-mkt-3) β
β 2. 172.16.100.4 (web-mkt-4) β
β 3. 172.16.100.5 (web-mkt-5) β
β Which ones do you want?" β
β β
β User: "Use 1 and 2" β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β STEP 5: Check available templates (BIG-IP Server) β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β [Feature: RESOURCES] β
β Claude reads: templates://available β
β Result: Found "marketing" template β
β β
β Claude reads: templates://marketing β
β Result: Template requires VIRTUAL_IP, POOL_MEMBER_1, POOL_MEMBER_2 β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β STEP 6: Create AS3 application (BIG-IP Server) β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β [Feature: CONTEXT STATE] β
β Retrieve cached VIP: ctx.get_state("as3_app_marketing") β
β β virtual_ip = "192.168.50.3" β
β β
β [Feature: TOOLS] β
β Claude β BIG-IP: create_as3_app( β
β device_name="lab-bigip", β
β section_name="marketing", β
β virtual_ip="192.168.50.3", β From cached state β
β pool_members=["172.16.100.3", "172.16.100.4"], β
β auto_deploy=False β Preview first β
β ) β
β β
β Tool internally: β
β 1. [CONTEXT STATE] Check for cached BIG-IP token β
β ctx.get_state("bigip_token_lab-bigip") β
β β
β 2. [RESOURCES] Load template: templates/marketing.json β
β β
β 3. Render template with variables: β
β TENANT_NAME β "Marketing" β
β APP_NAME β "marketing_app" β
β VIRTUAL_IP β "192.168.50.3" β
β POOL_MEMBER_1 β "172.16.100.3" β
β POOL_MEMBER_2 β "172.16.100.4" β
β β
β 4. Return preview β
β β
β Claude: "Preview: β
β Tenant: Marketing β
β VIP: 192.168.50.3:80 β
β Pool: 172.16.100.3:80, 172.16.100.4:80 β
β Ready to deploy?" β
β β
β User: "Yes, deploy it" β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β STEP 7: Deploy application (BIG-IP Server) β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β [Feature: TOOLS] β
β Claude β BIG-IP: create_as3_app( β
β ... same parameters ... β
β auto_deploy=True β Deploy now! β
β ) β
β β
β Tool internally: β
β 1. [CONTEXT STATE] Reuse cached token (no re-auth!) β
β 2. POST AS3 declaration to BIG-IP β
β 3. Poll deployment status β
β 4. [CONTEXT STATE] Clear cached VIP state β
β ctx.set_state("as3_app_marketing", None) β
β β
β Result: "β
Application deployed successfully!" β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β FINAL RESULT: β
β Marketing load balancer is live! β
β VIP: 192.168.50.3 β
β Pool: web-mkt-3, web-mkt-4 β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
```
### Feature Interactions Summary
| Step | Tools | Resources | Prompts | Context State | Cross-Server |
|------|-------|-----------|---------|---------------|--------------|
| 1. Load guidance | | | β
| | |
| 2. List sections | β
| | | | β
|
| 3. Reserve VIP | β
| | | β
Set | β
|
| 4. Get pool IPs | β
| | | | β
|
| 5. Check templates | | β
| | | |
| 6. Preview app | β
| β
| | β
Get | |
| 7. Deploy app | β
| | | β
Get/Clear | |
**Every feature is used at least once!**
### Cross-Server Communication Pattern
**Key concept:** MCP servers cannot directly call each other. Claude is the orchestrator.
#### Anti-Pattern (Won't Work)
```python
# In BIG-IP server.py - WRONG!
@mcp.tool
def create_as3_app(...):
# Trying to call phpIPAM directly - NOT POSSIBLE
vip = phpipam_server.reserve_ip(subnet_id) # β No direct access
```
#### Correct Pattern
```python
# In BIG-IP server.py - CORRECT
@mcp.tool
def create_as3_app(...):
if not virtual_ip:
# Return instructions for Claude
return """
To proceed, please use the phpIPAM MCP server to reserve a VIP:
Call phpIPAM's reserve_ip_address tool with:
- subnet_id: "8"
- hostname: "marketing-vip"
Then call this tool again with the reserved IP.
"""
```
**Claude sees this and:**
1. Calls phpIPAM server's `reserve_ip_address` tool
2. Gets result: "192.168.50.3"
3. Calls BIG-IP server's `create_as3_app` tool with `virtual_ip="192.168.50.3"`
### Direct Mode vs Guided Mode
This server supports **both** patterns:
**Guided Mode** (Claude orchestrates)
```python
# Step 1
create_as3_app(device="lab-bigip", section="marketing")
β "Please reserve VIP from phpIPAM subnet 8"
# Claude calls phpIPAM, gets "192.168.50.3"
# Step 2
create_as3_app(device="lab-bigip", section="marketing",
pool_member_selection="1 and 2")
β "Preview: VIP 192.168.50.3, Pool: ..."
```
**Direct Mode** (User provides IPs)
```python
# Single call
create_as3_app(
device="lab-bigip",
section="marketing",
virtual_ip="192.168.50.3",
pool_members=["172.16.100.3", "172.16.100.4"],
auto_deploy=True
)
β "β
Deployed!"
```
---
## Complete Workflow Diagram
This diagram shows how all 5 features work together in the AS3 application creation workflow.
```
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Complete MCP Feature Workflow β
β (Creating AS3 App with Cross-Server Integration) β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β USER starts conversation β
β β β
β βΌ β
β βββββββββββββββββββββββββββββββββββ β
β β Feature 3: PROMPTS β β
β β Claude loads workflow guide β β
β ββββββββββββββ¬βββββββββββββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Feature 5: CROSS-SERVER (phpIPAM) β β
β β Tool: list_sections() β ["marketing", ...] β β
β ββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ β
β β β
β β User selects: "marketing" β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Feature 5: CROSS-SERVER (phpIPAM) β β
β β Tool: reserve_ip_address(subnet=8) β β
β β Result: "192.168.50.3" β β
β ββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Feature 4: CONTEXT STATE (BIG-IP) β β
β β ctx.set_state("as3_app_marketing", β β
β β {"virtual_ip": "192.168.50.3"}) β β
β ββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Feature 5: CROSS-SERVER (phpIPAM) β β
β β Tool: get_subnet_details(subnet=7) β β
β β Shows: Available web servers β β
β ββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ β
β β β
β β User selects: "1 and 2" β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Feature 2: RESOURCES (BIG-IP) β β
β β Read: templates://available β β
β β Read: templates://marketing β β
β ββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Feature 1: TOOLS (BIG-IP) β β
β β Call: create_as3_app( β β
β β device="lab-bigip", β β
β β section="marketing", β β
β β pool_member_selection="1 and 2" β β
β β ) β β
β ββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ β
β β β
β β Tool internally does: β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Feature 4: CONTEXT STATE (BIG-IP) β β
β β ctx.get_state("as3_app_marketing") β β
β β β Retrieves VIP: "192.168.50.3" β β
β β β β
β β ctx.get_state("bigip_token_lab-bigip") β β
β β β Retrieves cached auth token β β
β ββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Load template, render, generate preview β β
β β Show preview to user β β
β ββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ β
β β β
β β User: "Deploy it" β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Feature 1: TOOLS (BIG-IP) β β
β β Call: create_as3_app(..., auto_deploy=True) β β
β β β POST AS3 declaration to BIG-IP β β
β β β Poll deployment status β β
β ββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Feature 4: CONTEXT STATE (BIG-IP) β β
β β ctx.set_state("as3_app_marketing", None) β β
β β β Clear cached VIP after deployment β β
β ββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β β
SUCCESS! β
β Application deployed to BIG-IP β
β β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
FEATURE USAGE COUNT:
ββββββββββββββββββββ¬ββββββββ
β Tools β 3Γ β
β Resources β 2Γ β
β Prompts β 1Γ β
β Context State β 4Γ β
β Cross-Server β 3Γ β
ββββββββββββββββββββ΄ββββββββ
```
---
## Code Location Reference
Quick reference for finding each MCP feature in the codebase.
### Tools (4 total)
| Tool Name | Line | Description |
|-----------|------|-------------|
| `list_virtual_servers` | 937-1067 | Query BIG-IP virtual servers |
| `list_bigip_devices` | 1069-1105 | List configured devices |
| `manage_as3` | 1107-1415 | Install/upgrade AS3 |
| `create_as3_app` | 1417-1682 | Create AS3 applications |
**Declaration pattern:**
```python
@mcp.tool
async def tool_name(param: type, ctx: Context = None) -> str:
"""Tool description"""
```
### Resources (3 total)
| Resource URI | Line | Description |
|--------------|------|-------------|
| `config://server` | 1684-1697 | Server metadata |
| `templates://available` | 1700-1743 | List all templates |
| `templates://{template_name}` | 1746-1768 | Specific template content |
**Declaration pattern:**
```python
@mcp.resource("resource://uri")
def resource_name() -> str:
"""Resource description"""
return json.dumps(data, indent=2)
```
### Prompts (2 total)
| Prompt Name | Line | Description |
|-------------|------|-------------|
| `help_prompt` | 1775-1798 | General server help |
| `create_app_workflow` | 1801-1875 | AS3 workflow guide |
**Declaration pattern:**
```python
@mcp.prompt
def prompt_name() -> str:
"""Prompt description"""
return """
Multi-line prompt content...
"""
```
### Context State (Usage locations)
| Operation | Lines | Description |
|-----------|-------|-------------|
| Set token | 997, 1174, 1589 | Cache BIG-IP auth token |
| Get token | 974, 1151, 1577 | Retrieve cached token |
| Set VIP | 1490-1495 | Cache reserved VIP (intended) |
| Get VIP | 1490-1495 | Retrieve cached VIP |
| Clear state | 1659 | Clean up after deployment |
**Usage pattern:**
```python
# Set
ctx.set_state(key: str, value: dict)
# Get
data = ctx.get_state(key: str) # Returns dict or None
# Clear
ctx.set_state(key: str, None)
```
### Helper Functions
| Function | Line | Purpose |
|----------|------|---------|
| `load_as3_template` | 697-716 | Load JSON template from file |
| `render_as3_template` | 719-740 | Replace {{VARIABLES}} in template |
| `validate_as3_declaration` | 743-760 | Validate AS3 JSON structure |
| `deploy_as3_declaration` | 800-851 | POST declaration to BIG-IP |
| `authenticate_bigip` | 177-215 | Get auth token from BIG-IP |
---
## Learning Path
Recommended order to study and understand MCP features:
### Level 1: Fundamentals
1. **Start with Tools** (You already know this!)
- Read: `list_virtual_servers` (server.py:937-1067)
- Understand: Tool declaration, parameters, return values
- Practice: Call the tool via Claude
### Level 2: Data Access
2. **Study Resources**
- Read: `list_available_templates` (server.py:1700-1743)
- Read: `get_template_content` (server.py:1746-1768)
- Understand: Read-only data access pattern
- Practice: "Show me available templates"
- Compare: When to use Resource vs Tool
### Level 3: User Guidance
3. **Explore Prompts**
- Read: `create_app_workflow` (server.py:1801-1875)
- Understand: How Claude uses prompts for guidance
- Practice: Ask Claude "How do I create an AS3 app?"
- Experiment: Try different phrasings to trigger the prompt
### Level 4: State Management
4. **Master Context State**
- Read: Token caching logic (server.py:974-998)
- Read: VIP caching logic (server.py:1490-1495)
- Understand: State lifecycle (set β get β clear)
- Practice: Make multiple tool calls, observe caching
- Experiment: Time tool calls with/without caching
### Level 5: Advanced Integration
5. **Understand Cross-Server**
- Read: `create_as3_app` tool (server.py:1417-1682)
- Read: phpIPAM helper functions (server.py:763-930)
- Understand: How Claude orchestrates between servers
- Practice: Full workflow (guided mode)
- Experiment: Try direct mode vs guided mode
### Level 6: Synthesis
6. **Complete Workflow**
- Run the full AS3 application creation workflow
- Observe all 5 features working together
- Trace the execution through this guide
- Identify each feature usage in the flow
---
## Additional Resources
### Official Documentation
- **MCP Specification**: https://modelcontextprotocol.io/docs/specification
- **FastMCP 2.0 Docs**: https://gofastmcp.com/
### This Codebase
- **README.md**: Project overview and setup
- **TEMPLATES.md**: Template system documentation
- **CONFIGURATION.md**: Device configuration guide
- **CLAUDE.md**: Usage examples
### Experimentation Tips
1. **Enable verbose logging**: See exactly what MCP calls Claude makes
2. **Use Claude Desktop devtools**: Monitor MCP communication
3. **Modify prompts**: See how it changes Claude's behavior
4. **Add new resources**: Practice exposing data
5. **Track state**: Add logging to see cache hits/misses
---
## Summary
This BIG-IP MCP server demonstrates **all major MCP features**:
| Feature | What It Does | Why It Matters |
|---------|--------------|----------------|
| **Tools** | Execute actions | Core functionality |
| **Resources** | Expose data catalogs | Efficient data access |
| **Prompts** | Guide Claude | Consistent UX |
| **Context State** | Cache session data | Performance + UX |
| **Cross-Server** | Coordinate systems | Complex workflows |
**Key Takeaway:** MCP is more than just tools. It's a complete protocol for building AI-powered integrations with performance, usability, and composability built in.
**Next Steps:**
1. Follow the [Learning Path](#learning-path) above
2. Experiment with each feature
3. Build your own MCP server using these patterns
4. Combine multiple MCP servers for complex workflows
Happy learning! π