Skip to content

MCP Server ​

The Model Context Protocol (MCP) server bridges AI assistants like Claude to your indexed codebase, enabling intelligent code search, pattern recognition, and Wikit-aware development.

Overview ​

The MCP server provides:

  • Semantic Code Search: Find code by meaning across all projects
  • WordPress Pattern Recognition: Understand hook registrations, invocations, and ACF fields
  • Wikit Block Discovery: Search indexed Gutenberg blocks and their schemas
  • Project Management: Inspect project indexing status and manifests
  • Saved Searches & History: Persist common queries and review past searches

Architecture ​

%%{init: {'theme':'neutral'}}%%
graph TB
    subgraph "AI Layer"
        Claude[Claude Desktop]
        Cursor[Cursor IDE]
        Other[Other AI Tools]
    end

    subgraph "MCP Server"
        Server[MCP Server<br/>Host port 6765<br/>SSE transport]
        Tools[MCP Tools]
    end

    subgraph "Data Layer"
        Qdrant[(Vector DB<br/>Qdrant)]
        Git[Git Repositories]
        Projects[WordPress Projects]
    end

    Claude -->|MCP Protocol| Server
    Cursor -->|MCP Protocol| Server
    Other -->|MCP Protocol| Server

    Server --> Tools
    Tools --> Qdrant
    Tools --> Git
    Tools --> Projects

Available Tools ​

Code Search Tools ​

search_codebase ​

Semantic search across all indexed repositories.

python
# Example usage in Claude
search_codebase(
    query="custom post type registration",
    project="my-site",
    file_types="php",
    exclude_patterns=["tests/"],
    include_context=True,
    limit=10
)

Parameters:

  • query (string): Search query
  • project (string, optional): Project name to scope search ("platform", "framework", or a project name). When omitted, searches all collections.
  • file_types (string | list, optional): Filter by file extensions. Accepts a comma-separated string (e.g. "php,js") or a list.
  • component_type (string, optional): Filter by function, class, hook, etc.
  • exclude_patterns (list, optional): Path substrings to exclude (e.g. ["vendor/", "tests/"])
  • include_context (bool, optional): Include surrounding code lines (default: false)
  • context_lines (int, optional): Number of context lines before/after, 1-20 (default: 5)
  • limit (int): Maximum results (default: 20)

Returns: A result object with status, count, collection, query, search_type, execution_time_ms, and a results array. Each result entry:

json
{
  "file_path": "wp-content/themes/custom/functions.php",
  "component_type": "function",
  "name": "register_portfolio_post_type",
  "line_number": 45,
  "language": "php",
  "content": "function register_portfolio_post_type() {...}",
  "repository": "my-site",
  "score": 0.89
}

search_all_collections ​

Search across ALL indexed collections at once (framework, platform, and every project). Useful when you don't know which collection holds the code.

python
search_all_collections(
    query="user authentication flow",
    file_types="php"
)

search_functions ​

Find specific functions by name. Supports fuzzy matching across naming conventions (e.g. getUser finds get_user).

python
search_functions(
    function_name="get_user",
    project="my-site",
    language="php",
    fuzzy_match=True
)

search_classes ​

Find class definitions by name. Supports fuzzy matching across naming conventions.

python
search_classes(
    class_name="CustomPostType",
    project="my-site",
    fuzzy_match=True
)

Parameters: class_name, project (optional), fuzzy_match (default true). There is no language parameter.

search_code_patterns ​

Find code by structural relationship: class inheritance, interface implementation, or function calls.

python
search_code_patterns(
    pattern_type="extends",   # "extends" | "implements" | "calls_function"
    pattern_value="WP_Widget"
)

search_function_callers ​

Find what functions call a given function (reads the indexed calls metadata).

python
search_function_callers(function_name="render_block", project="my-site")

search_function_calls ​

Find what functions a given function calls.

python
search_function_calls(function_name="render_block", project="my-site")

WordPress-Specific Tools ​

search_wordpress_hooks ​

Find WordPress hook registrations — add_action() and add_filter() calls.

python
search_wordpress_hooks(
    hook_name="init",
    hook_type="action",   # "action" | "filter"
    project="my-site"
)

To find where hooks are invoked (do_action() / apply_filters()), use search_hook_invocations instead.

search_hook_invocations ​

Find where WordPress hooks are invoked — do_action() and apply_filters() calls (not registrations).

python
search_hook_invocations(
    hook_name="save_post",
    invocation_type="action",   # "action" for do_action, "filter" for apply_filters
    project="my-site"
)

search_acf_fields ​

Find Advanced Custom Fields (ACF) field and field-group definitions.

python
search_acf_fields(
    field_name="hero_image",
    field_type="image",
    project="my-site"
)

search_acf_field_usages ​

Find where ACF fields are used in code — get_field(), get_sub_field(), the_field(), have_rows() calls.

python
search_acf_field_usages(
    field_name="hero_image",
    project="my-site"
)

wordpress_docs ​

Search WordPress core documentation.

python
wordpress_docs(
    query="register_post_type",
    type="function",
    get_details=True
)

Wikit-Specific Tools ​

search_wikit_blocks ​

Search indexed Wikit Gutenberg blocks. Can filter by attribute, supported feature, or category.

python
search_wikit_blocks(
    block_name="hero",        # Optional
    has_attribute="backgroundType",  # Optional
    supports="align",         # Optional
    category="wdg-layout"     # Optional
)

Returns: A result object with status, query, filters, count, and a results array of indexed block components.

get_block_schema ​

Get the full parsed block.json schema for a Wikit block — attributes, supports, parent, keywords, and category.

python
get_block_schema(
    block_name="wdg/hero",   # full or partial block name
    project="my-site"        # Optional
)

Project Management Tools ​

get_project_info ​

Get project details and indexing status.

python
get_project_info(
    project_name="my-site"
)

Returns: Indexing status from the vector database, plus the project manifest (project.yml) when present.

json
{
  "status": "success",
  "project": "my-site",
  "indexed": true,
  "collection": "project_my_site",
  "vectors_count": 1450,
  "languages": ["php", "javascript"],
  "component_types": ["function", "class", "wikit_block"],
  "repositories": ["my-site"],
  "manifest": { "jira_project_key": "MS", "hosting": "pantheon" }
}

list_collections ​

List all vector database collections.

python
list_collections()

Recent Changes Tools ​

search_recent_changes ​

Get recently indexed code.

python
search_recent_changes(
    project="my-site",
    limit=10
)

batch_search ​

Run multiple searches in a single call (parallel by default). Each entry is a search config dict.

python
batch_search(
    searches=[
        {"id": "hooks", "query": "add_action", "file_types": "php"},
        {"id": "blocks", "query": "registerBlockType", "file_types": "js"}
    ],
    parallel=True,
    fail_fast=False
)

Parameters: searches (list of dicts — each may include id, query, project, file_types, component_type, exclude_patterns, limit), parallel (default true), fail_fast (default false). Maximum 10 concurrent searches per call.

Saved Searches & History ​

Save a search with a label for quick recall.

python
save_search(label="auth-hooks", query="authenticate", filters={"file_types": "php"})

Retrieve a saved search by label; optionally execute it.

python
get_saved_search(label="auth-hooks", execute=True)

list_saved_searches ​

List saved searches, sorted by last_used, use_count, label, or created_at.

python
list_saved_searches(sort_by="last_used", limit=20)

Delete a saved search by label.

python
delete_saved_search(label="auth-hooks")

get_search_history ​

Retrieve recent search history with result counts and timing.

python
get_search_history(limit=50, query_filter="payment")

MCP Auth Proxy (OAuth-Protected Services) ​

A separate MCP Auth Proxy (mcp-server/proxy_server.py) runs on host port 6766 and brokers authenticated access to external MCP services. Proxied tools appear at runtime with the mcp__mcp-auth-proxy__<service>_* prefix.

  • SSE endpoint: http://localhost:6766/sse
  • Health check: curl http://localhost:6766/health

Configured services (in mcp-server/registry.json):

ServiceTool prefixTransportDescription
Atlassianatlassian_*HTTP (proxied)Jira issues, Confluence pages, search
Figmafigma_*HTTP (proxied)Design files, variables, screenshots
Read.airead-ai_*HTTP (proxied)Meeting transcripts and summaries
Slackslack_*HTTP (proxied)Messages, channels, search, canvases

Authenticate a service with wdg mcp auth <service> (opens a browser for OAuth) and check token validity with wdg mcp status.

Configuration ​

Server Configuration ​

The MCP server is reachable from the host at port 6765 (set by MCP_SERVER_PORT in .env.defaults) over the SSE transport. The host port maps to the container's internal port 8765 — 8765 is container-internal only and should never appear in host or client configuration.

yaml
# docker-compose.yml (illustrative)
mcp-server:
  ports:
    - "6765:8765"   # host 6765 -> container 8765
  environment:
    - MCP_PORT=8765         # container-internal listen port
    - QDRANT_HOST=qdrant
    - QDRANT_PORT=6333

Host-facing endpoint: http://localhost:6765/sse

Client Configuration ​

Claude Desktop ​

Add to Claude Desktop config (~/Library/Application Support/Claude/claude_desktop_config.json on macOS):

json
{
  "mcpServers": {
    "wdg-local": {
      "url": "http://localhost:6765/sse"
    }
  }
}

Cursor IDE ​

Add to Cursor settings (.cursor/mcp.json):

json
{
  "servers": {
    "wdg-local": {
      "url": "http://localhost:6765/sse",
      "name": "WDG AI Dev Environment"
    }
  }
}

Usage Examples ​

Example 1: Finding Similar Code ​

User prompt to AI:

"Find all places where we validate email addresses"

AI uses MCP:

python
search_codebase(
    query="email validation",
    file_types=["php", "js"]
)

Result:

  • is_valid_email() in utils.php
  • validateEmailAddress() in forms.js
  • Email regex patterns
  • WordPress sanitize_email() usage

Example 2: Understanding Wikit Blocks ​

User prompt:

"What Wikit blocks are available for layout?"

AI uses MCP:

python
search_wikit_blocks()

AI responds with:

  • Hero block
  • Grid block
  • Columns block
  • Section block
  • Container block

User prompt:

"In the client-website project, show me how we handle custom post types"

AI uses MCP:

python
search_codebase(
    query="custom post type registration",
    project="client-website",
    component_type="function"
)

Advanced Features ​

Contextual Awareness ​

The MCP server understands:

  • Project context: Scopes searches to active project
  • File relationships: Knows which files depend on others
  • Git history: Can reference specific commits
  • WordPress conventions: Understands hooks, filters, CPTs

Search across multiple projects:

python
# Search in all projects
search_codebase(
    query="user authentication",
    project=None  # Searches all projects
)

# Compare implementations across projects
search_functions(
    function_name="get_user",
    project=None
)

Pattern Recognition ​

The MCP server identifies:

  • Wikit patterns: Recognizes WDG's standard implementations
  • WordPress best practices: Identifies secure coding patterns
  • Code reusability: Finds similar implementations

Performance ​

Response Times ​

OperationAverage TimeNotes
search_codebase50-100msDepends on collection size
search_functions20-50msDirect lookup
search_wikit_blocks10-20msSmall collection
get_project_info<10msCached
list_collections<10msDirect query

Caching ​

The MCP server implements caching for:

  • Project metadata (15 min TTL)
  • Collection lists (5 min TTL)
  • Wikit block catalog (1 hour TTL)

Optimization ​

python
# Limit result count for faster responses
search_codebase(query="...", limit=5)

# Use filters to reduce search space
search_codebase(
    query="...",
    project="my-site",
    file_types=["php"],
    component_type="function"
)

Security ​

Network Security ​

yaml
# Bind only to localhost (default)
MCP_HOST=127.0.0.1  # Local only

# Or bind to all interfaces (be careful!)
MCP_HOST=0.0.0.0  # Accessible on network

Authentication ​

Currently, the MCP server runs locally without authentication. For production deployments:

python
# Add API key authentication
MCP_API_KEY=your-secret-key

# Or use JWT tokens
MCP_JWT_SECRET=your-jwt-secret

Data Privacy ​

  • All queries stay local
  • No external API calls for search
  • Code never leaves your machine
  • Project data is isolated

Troubleshooting ​

Server Not Responding ​

bash
# Check if server is running (host-facing SSE server health endpoint)
curl http://localhost:6765/health

# View server logs
docker logs wdg-mcp-server

# Restart server
docker compose restart mcp-server

Connection Refused ​

bash
# Check port is not in use
lsof -i :6765

# Verify Docker network
docker network inspect wdg-network

# Check firewall settings
sudo ufw status

Slow Responses ​

bash
# Check Qdrant status
curl http://localhost:6333/collections

# Monitor server resources
docker stats wdg-mcp-server

# Reduce search limits
# Use more specific queries

Empty Results ​

bash
# Verify collections exist
curl http://localhost:6333/collections

# Check indexing status
wdg status

# Re-index if needed
wdg index my-site

API Reference ​

Health Check ​

The SSE app exposes a single plain-HTTP health endpoint. There are no REST /tools, /metrics, or WebSocket endpoints — tool discovery and invocation happen over the MCP/SSE protocol, not REST.

bash
curl http://localhost:6765/health

Response:

json
{
  "status": "ok",
  "version": "0.1.0"
}

The version field is read from the platform VERSION file (falls back to "unknown" if unreadable). For the full tool list and parameters, see the MCP API Reference.

Best Practices ​

1. Use Specific Queries ​

python
# Good: Specific and contextual
search_codebase(
    query="WordPress REST API endpoint registration",
    component_type="function"
)

# Bad: Too vague
search_codebase(query="api")

2. Scope to Project ​

python
# Good: Scoped search
search_codebase(
    query="user authentication",
    project="client-website"
)

# Bad: Unscoped (slower)
search_codebase(query="user authentication")

3. Use Appropriate Tools ​

python
# Good: Use specific tool
search_functions(function_name="get_user")

# Bad: Generic search
search_codebase(query="get_user")

4. Limit Results ​

python
# Good: Limited results
search_codebase(query="...", limit=5)

# Bad: Too many results
search_codebase(query="...", limit=100)

Integration Examples ​

Claude Desktop ​

Create a custom slash command:

json
// ~/Library/Application Support/Claude/commands/search-code.json
{
  "command": "/search-code",
  "description": "Search WDG codebase",
  "handler": {
    "tool": "search_codebase",
    "parameters": {
      "query": "$input"
    }
  }
}

Cursor IDE ​

Use in Cursor's chat:

User: "@wdg Find email validation in my-site project"

Cursor: [Uses MCP search_codebase tool]
Found 3 implementations:
1. is_valid_email() in utils.php
2. validateEmail() in forms.js
3. Email validation in checkout.php

Monitoring ​

View Real-Time Logs ​

bash
# Follow MCP server logs
docker logs -f wdg-mcp-server

# Filter for searches
docker logs wdg-mcp-server | grep "search_codebase"

Search History ​

The server records search activity internally. Review it through the get_search_history MCP tool rather than a REST endpoint:

python
get_search_history(limit=50)

Next Steps: