MCP server implementation in Clojure compiled to GraalVM native image
Retail MCP Server
A Model Context Protocol (MCP) server implementation in Clojure for integrating AI assistants with Retail APIs. This server provides tools, resources, and prompts that enable AI assistants to interact with e-commerce platforms for managing collections, orders, and inventory.
⚠️ Important Disclaimer
This repository is strictly for informational and educational purposes only.
- This project is NOT involved in any commercial activity
- All implementation is based solely on publicly available sources published on the internet
- This project does not infringe any copyrights or licenses
- The code is provided for learning and demonstration purposes
- Users are responsible for ensuring compliance with all applicable terms of service and licensing requirements when using this software
- This is an independent implementation and is not officially affiliated with or endorsed by any commercial entity
Features
- Native Compilation: Compiles to GraalVM native image for fast startup (<100ms) and low memory usage
- Complete API Coverage: All major Retail API endpoints (Collections, Orders, Inventory, Admin) - 14 MCP tools
- MCP Compliant: Full implementation of MCP 2024-11-05 specification (Tools, Resources, Prompts)
- Production Ready: Proper logging, error handling, timeout management (5s), and configuration
- Type-Safe: Clojure specs for validation with structured data
- Well-Tested: 88 tests with 1027 assertions, including property-based testing
- REPL-Driven Development: Full support for interactive development and testing
Table of Contents
- Getting Started
- Configuration
- Usage
- MCP Integration
- Development
- Architecture
- Testing
- Troubleshooting
Getting Started
Prerequisites
- GraalVM 23.1.0+ (or newer): For native image compilation with JDK 21+ support
- Clojure CLI 1.11+: For dependency management and running the application
- Retail API Key: Required - set via RETAIL_API_KEYenvironment variable
- clj-kondo (optional): For code linting during development
Installation
1. Install GraalVM
# Download from https://www.graalvm.org/downloads/
export GRAALVM_HOME=/path/to/graalvm
export PATH=$GRAALVM_HOME/bin:$PATH
# Install native-image component
gu install native-image
2. Install Clojure CLI
Follow the official Clojure installation guide.
3. Clone and Setup
git clone <repository-url>
cd clj-retail-mcp
# Install dependencies
clojure -P
Configuration
Environment Variables
Create a .env file or set environment variables:
export RETAIL_API_KEY="your-api-key-here"
export RETAIL_BASE_URL="https://api-test.kingpin.global"  # Optional, defaults to test environment
export LOG_LEVEL="INFO"  # Optional, defaults to INFO
Configuration File
Configuration is managed via resources/config.edn with environment variable support:
{:retail-api {:base-url #or [#env "RETAIL_BASE_URL" "https://api-test.kingpin.global"]
               :api-key #env "RETAIL_API_KEY"}
 
 :mcp-server {:name "retail-mcp-server"
              :version "1.0.0"
              :description "MCP Server for Retail API Integration"}
 
 :logging {:level #env ["LOG_LEVEL" :info]
           :pattern "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"}
 
 :graal {:initialize-at-build-time ["clojure" "retail"]
         :reflection-config ["reflect-config.json"]}}
Usage
Running the Server (Development)
The MCP server uses stdio transport (not HTTP/port-based):
# Start REPL with development profile
clojure -M:dev
# In REPL - development utilities (not actual MCP server):
(test-api-connection)    # Test Retail API connectivity
(list-tools)             # List available MCP tools
# Test individual client functions
(client/list-collections :limit 5)
# Test MCP tools directly
(let [tool (tools/tool-by-name "collections_get")]
  ((:handler tool) {:page 0 :limit 5}))
Note: The actual MCP server runs via stdio transport and is meant to be invoked by MCP clients (like Claude Desktop), not run standalone with ports.
Running the Server (Production)
The server uses stdio transport and should be invoked by MCP clients:
# Run directly with Clojure
clojure -M -m retail.mcp-server.core
# Or use the run script
./scripts/run-server.sh
# Or use the native binary (recommended)
./target/retail-mcp-server
Important: This is a stdio-based MCP server. It reads JSON-RPC requests from stdin and writes responses to stdout. It's designed to be invoked by MCP clients (like Claude Desktop), not run as a standalone HTTP server.
Building Native Image
# Build JAR
clojure -T:build uberjar
# Build optimized native image (recommended for production)
clojure -T:build native-image
# Build quick native image (faster, for development)
clojure -T:build quick-native
# Run native binary
./target/retail-mcp-server
Native Image Features:
- Fast startup (<100ms)
- Low memory footprint (~87MB binary)
- Serial GC (efficient for single-threaded workloads)
- CPU-optimized with -march=native
- HTTP/HTTPS protocol support enabled
- Full MCP protocol support (Tools, Resources, Prompts)
MCP Integration
Available Tools
The server provides 14 MCP tools for Retail API operations:
| Tool | Description | Required Parameters | Optional Parameters |
|------|-------------|---------------------|---------------------|
| collections_get | List all collections | - | page, limit |
| collections_get_by_id | Get collection by ID | collection_id | - |
| collections_create | Create new collection | collection_data | - |
| collections_update | Update collection | collection_id, collection_data | - |
| collections_products | Get products in collection | collection_id | page, limit |
| collections_add_products | Add products to collection | collection_id, products | - |
| collections_remove_products | Remove products from collection | collection_id, product_ids | - |
| collections_modify_product | Modify product in collection | product_id, product_data | - |
| collections_remove_all_products | Remove all products | collection_id | - |
| orders_list | List all orders | - | page, limit |
| orders_get | Get order by ID | order_id | - |
| orders_create | Create new order | collection_id, products, currency | requested_delivery_date |
| inventory_update | Update inventory quantities | products | - |
| admin_generate_api_key | Generate API key (admin) | entity_id | - |
Resources
- retail://api-status: Current API connection status and health check
Prompts
- retail-order-assistant: Interactive assistant for creating orders with validation and guidance
Client Integration
Claude Desktop Setup
Step 1: Build the native binary (if not already done)
clojure -T:build native-image
# Produces: target/retail-mcp-server (87MB)
Step 2: Locate Claude Desktop configuration file
- macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
- Linux: ~/.config/Claude/claude_desktop_config.json
- Windows: %APPDATA%\Claude\claude_desktop_config.json
Step 3: Add MCP server configuration
{
  "mcpServers": {
    "retail-mcp": {
      "command": "/absolute/path/to/clj-retail-mcp/target/retail-mcp-server",
      "env": {
        "RETAIL_API_KEY": "your-api-key-here",
        "RETAIL_BASE_URL": "https://api-test.kingpin.global",
        "LOG_LEVEL": "INFO"
      }
    }
  }
}
⚠️ Important: Use the absolute path to the binary! Relative paths will not work.
Step 4: Restart Claude Desktop
Quit and restart the Claude Desktop application for changes to take effect.
Step 5: Verify Integration
Check Claude Desktop logs if tools don't appear:
- macOS: ~/Library/Logs/Claude/mcp*.log
- Look for connection or startup errors
Using with Other MCP Clients
For other MCP clients supporting stdio transport:
{
  "mcpServers": {
    "retail-mcp": {
      "command": "/absolute/path/to/retail-mcp-server",
      "args": [],
      "env": {
        "RETAIL_API_KEY": "your-api-key-here",
        "LOG_LEVEL": "INFO"
      }
    }
  }
}
Note: This server uses stdio transport only (JSON-RPC over stdin/stdout), not HTTP.
Protocol Compliance
Implements the full MCP 2024-11-05 specification:
- Tools: All Retail API operations exposed as MCP tools
- Resources: API status monitoring and health checks
- Prompts: Interactive order creation assistance
- Transport: JSON-RPC over stdio for maximum compatibility
- Error Handling: Proper JSON-RPC error codes and structured responses
Example Usage with Claude
Once integrated with Claude Desktop, try these queries:
"Use the retail-mcp tools to list the first 5 collections"
"Show me the API status using the retail resource"
"Help me create an order using the retail-order-assistant prompt"
"Get collection details for ID 689b4145140f9871a93441bc"
"List all orders with a limit of 10"
Claude will automatically use the appropriate MCP tools to fulfill these requests.
Development
Project Structure
clj-retail-mcp/
├── deps.edn                 # Clojure dependencies
├── build.clj                # Build scripts for JAR and native image
├── README.md                # This file
├── LICENSE                  # Apache License 2.0
├── .gitignore               # Git ignore rules
├── scripts/
│   └── run-server.sh        # Server startup script
├── resources/
│   ├── config.edn           # Configuration with env var support
│   ├── logback.xml          # Logging configuration
│   └── META-INF/native-image/
│       └── reflect-config.json  # GraalVM reflection config
├── src/retail/mcp_server/
│   ├── core.clj             # Main MCP server & JSON-RPC protocol handlers
│   ├── retail_client.clj    # HTTP client for Retail API
│   └── tools.clj            # MCP tools implementation (14 tools)
├── test/retail/mcp_server/  # Comprehensive test suite (88 tests)
│   ├── protocol_test.clj         # MCP protocol compliance tests
│   ├── tools_test.clj            # Tool functionality tests
│   ├── tools_comprehensive_test.clj  # Comprehensive tool tests
│   ├── retail_client_test.clj    # API client tests
│   ├── integration_test.clj      # Integration tests
│   ├── reliability_test.clj      # Reliability and error tests
│   ├── performance_test.clj      # Performance tests
│   ├── validation_test.clj       # Validation tests
│   └── functional_test.clj       # Functional tests
└── dev/
    └── user.clj             # REPL development utilities
REPL Workflow
;; Start development
(require 'user)
(in-ns 'user)
;; Test API connection
(test-api-connection)
;; List available tools
(list-tools)
;; Test individual client functions
(client/list-collections :limit 5)
(client/get-collection "collection-id")
;; Test MCP tools directly
(let [tool (tools/tool-by-name "collections_get")]
  ((:handler tool) {:page 0 :limit 5}))
;; Reload code after changes
(refresh)
Note: For actual MCP server testing, use the test suite or run the binary with MCP client integration.
API Client Reference
The retail.mcp-server.retail-client namespace provides functions for all Retail API operations:
;; Collections
(list-collections :page 0 :limit 10)
(get-collection "collection-id")
(create-collection {:name "New Collection" :type "inStock" :description "..."})
(update-collection "collection-id" {:name "Updated"})
(delete-collection "collection-id")
(list-collection-products "collection-id" :page 0 :limit 10)
(add-products-to-collection "collection-id" {:products [...]})
(remove-products-from-collection "collection-id" ["product-id-1" "product-id-2"])
(modify-product-in-collection "product-id" {:price 99.99})
(remove-all-products-from-collection "collection-id")
;; Orders
(list-orders :page 0 :limit 10)
(get-order "order-id")
(create-order {:collection_id "..." :products [...] :currency "USD"})
;; Inventory
(update-inventory {:products [{:id "..." :quantity 100}]})
;; Admin
(generate-api-key {:entity_id "entity-id"})
;; Health Check
(check-api-connectivity)
Building
# Clean build artifacts
clojure -T:build clean
# Build JAR only
clojure -T:build uberjar
# Build optimized native image (production)
clojure -T:build native-image
# Build quick native image (development, faster compilation)
clojure -T:build quick-native
Architecture
Design Decisions
Why Custom HTTP Client Instead of Generated Code?
This project uses a custom HTTP client (retail.mcp-server.retail-client) instead of generated code from the OpenAPI specification for several reasons:
OpenAPI Specification Issues:
The target API's OpenAPI specification has incomplete schema definitions:
- #/components/schemas/Productis missing
- #/components/schemas/UpdateProductDtois missing
These missing schemas would cause OpenAPI generators to create references to non-existent classes, leading to compilation failures.
Advantages of Our Approach:
- Reliability: Works with the actual API regardless of spec completeness
- Type Safety: Uses Clojure specs for validation and proper data structures
- Error Handling: Custom error handling tailored to MCP server needs
- Performance: No unnecessary Java interop overhead
- Maintainability: Much easier to debug and extend than generated code
- GraalVM Compatibility: Fewer reflection issues than generated Java code
Implementation Stack
- Language: Clojure 1.12.0
- HTTP Client: http-kitv2.8.0 (performant, GraalVM-friendly, excellent timeout handling)
- JSON Processing: jsonistav0.3.8 with kebab-case key transformation
- Validation: Clojure specs (clojure.spec.alpha) for parameter validation
- Error Handling: Structured error responses with proper HTTP status codes
- Configuration: aerov1.1.6 for external configuration with environment variable support
- Logging: logbackv1.4.14 with SLF4J, optimized for stdio transport (logs to stderr)
- Build Tool: Clojure CLI tools with tools.buildv0.10.4
GraalVM Native Image Configuration
Optimization Levels
Production Build (native-image):
- -O3optimization (maximum performance)
- --gc=serialGC (efficient, works on all platforms - G1 only available on Linux)
- -march=native(CPU-specific optimizations)
- --enable-httpand- --enable-https(protocol support)
- --initialize-at-build-time=clojure(faster startup)
- Build time: ~4-5 minutes, produces ~87MB binary
Development Build (quick-native):
- -O1optimization (faster compilation)
- -Obquick build mode (significantly faster compilation)
- --gc=serialGC (minimal overhead, faster builds)
- --enable-httpand- --enable-https(protocol support)
Reflection Configuration
The reflect-config.json includes:
- Agent-Generated: Captured using java -agentlib:native-image-agent
- Clojure-Specific: Essential Clojure runtime patterns (RT, Var, Namespace)
- Application-Specific: All MCP handler functions and Retail API client methods
- I/O Operations: BufferedReader, InputStreamReader for stdio transport
- Logging: SLF4J and Logback reflection patterns
This ensures minimal reflection overhead while maintaining full functionality.
MCP Protocol Implementation
Transport: JSON-RPC over stdio (standard MCP transport)
Compatibility:
- Claude Desktop
- VS Code MCP extensions
- Other MCP-compliant clients supporting stdio transport
- Pure stdio transport (no HTTP server required)
Response Structure:
;; Success response
{:result {:content [{:type "text" :text "..."}]
          :isError false
          :structuredContent {:data ...}}}
;; Error response
{:result {:content [{:type "text" :text "Error: ..."}]
          :isError true
          :structuredContent {:error "..." :message "..." :status 500}}}
Testing
Test Suite Overview
Comprehensive testing with 88 tests and 1027 assertions covering:
- MCP protocol compliance
- All API endpoints
- Error handling scenarios
- Property-based testing
- Integration testing
- Performance testing
- Reliability testing
Testing Frameworks
- clojure.test - Standard Clojure testing framework
- test.check - Property-based testing for comprehensive coverage
- clojure.test.check.clojure-test - Integration between test.check and clojure.test
Test Categories
1. MCP Protocol Tests (protocol_test.clj)
- Initialize request handling
- Tool discovery and listing
- Resource management
- Prompt configuration
- Error handling for unknown methods
- JSON-RPC protocol compliance
2. Tools Tests (tools_test.clj, tools_comprehensive_test.clj)
- All 14 MCP tools validated
- Parameter validation (required vs optional)
- Tool lookup functionality
- Response structure validation
3. API Client Tests (retail_client_test.clj)
- HTTP request handling
- Response parsing
- Error handling (401, 404, 429, 500)
- Timeout management
- Connection failure scenarios
4. Integration Tests (integration_test.clj)
- Configuration loading
- End-to-end MCP protocol flow
- API integration with all endpoints
5. Reliability Tests (reliability_test.clj)
- Error recovery
- Timeout handling
- Graceful degradation
- API error scenarios
6. Performance Tests (performance_test.clj)
- Load testing
- Concurrent request handling
- Response time validation
7. Validation Tests (validation_test.clj)
- Parameter validation
- Data structure validation
- MongoDB ObjectId format validation
8. Functional Tests (functional_test.clj)
- Real-world usage scenarios
- Complete workflows
- Edge cases
Running Tests
# Run all tests
clojure -M:test
# Run specific test namespace
clojure -M:test -n retail.mcp-server.protocol-test
# Run with coverage
clojure -M:coverage
# Check linting
clj-kondo --lint src/ test/ dev/
Test Data
Sample IDs (from Postman collection):
- Test Collection ID: 689b4145140f9871a93441bc
- Test Order ID: 688cb1a4ec09249e669b42fe
- Test Product ID: 689b4d309af98b9bbc0791e0
- Test Entity ID: 68918a94d577736caa45c89b
Property-Based Test Generators:
- Page numbers: 0-100
- Limits: 1-100
- Valid currencies: USD, EUR, GBP, CAD, AUD
- Product items with SKU, quantity, price
- Order data with collection_id, products, currency
Test Coverage
API Endpoints:
- Collections API: /v1/integrations/collections/(GET, POST, PUT, DELETE)
- Orders API: /v1/integrations/orders/(GET, POST)
- Inventory API: /v1/integrations/inventory(PUT)
- Admin API: /admin/integrations/api-key(POST)
MCP Protocol:
- Tool discovery and execution
- Resource management
- Prompt management
- Error handling
- JSON-RPC compliance
Edge Cases:
- Invalid tool names
- Missing required parameters
- Rate limiting scenarios
- Network errors
- Response structure validation
Blackbox Testing Approach
Tests follow blackbox testing principles:
- No Internal Dependencies: Tests only public APIs and MCP interfaces
- Real-World Scenarios: Based on actual Postman collection examples
- Comprehensive Coverage: Happy path, edge cases, and error conditions
- Property-Based Testing: Generators test across input ranges
- Response Validation: Verifies response structure matches API specification
Troubleshooting
Common Issues
1. API Connection Failures
Problem: Tools return "connection-failed" or "timeout" errors
Solutions:
- Verify RETAIL_API_KEYis set correctly
- Check RETAIL_BASE_URLpoints to correct environment
- Verify network connectivity to Retail API
- Review API key permissions and validity
Debug:
# Start REPL and test API connectivity
clojure -M:dev
# In REPL:
(test-api-connection)
# Check configuration
(client/load-config)
2. Missing API Key Errors
Problem: "RETAIL_API_KEY environment variable is not set"
Solutions:
- Set environment variable: export RETAIL_API_KEY="your-key"
- Verify key is not set to placeholder "NOT_SET"
- Check .envfile is loaded properly
3. Native Image Build Failures
Problem: Build fails with reflection or missing class errors
Solutions:
- Ensure GRAALVM_HOMEorJAVA_HOMEis set correctly
- Use GraalVM 23.1.0+ for JDK 21+ support
- Review resources/META-INF/native-image/reflect-config.json
- Try quick-native build first to isolate issues
Debug:
# Verify GraalVM
echo $GRAALVM_HOME
$GRAALVM_HOME/bin/native-image --version
# Build with verbose output
clojure -T:build native-image
4. MCP Client Integration Issues
Problem: Claude Desktop or MCP client can't find or connect to server
Solutions:
- Use absolute path to binary in configuration (not relative path)
- Verify binary has execute permissions: chmod +x target/retail-mcp-server
- Check Claude Desktop logs for startup errors:
- macOS: ~/Library/Logs/Claude/mcp*.log
- Linux: ~/.config/Claude/logs/
- Windows: %APPDATA%\Claude\logs\
 
- macOS: 
- Ensure environment variables are in client config (not in shell)
- Restart Claude Desktop after configuration changes
Debug:
# Test server manually with stdio
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' | ./target/retail-mcp-server
# Expected output (JSON on stdout, logs on stderr):
# {"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2024-11-05",...}}
# Get absolute path for configuration
pwd
# Use: /absolute/path/shown/target/retail-mcp-server
5. Rate Limiting
Problem: 429 errors from API
Solutions:
- Implement exponential backoff in client code
- Review rate limit headers: x-ratelimit-limit,x-ratelimit-remaining,x-ratelimit-reset
- Reduce concurrent request volume
Debugging
Enable Debug Logging
# Development mode
LOG_LEVEL=DEBUG clojure -M -m retail.mcp-server.core
# Production binary
LOG_LEVEL=DEBUG ./target/retail-mcp-server
Check Logs
Logs are written to stderr to avoid interfering with MCP JSON-RPC communication on stdout.
Log Levels:
- ERROR: Critical errors requiring attention
- WARN: Warnings (missing API key, failed requests, etc.)
- INFO: General operational information
- DEBUG: Detailed request/response information
Health Check
Test server initialization:
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0.0"}}}' | ./target/retail-mcp-server
Expected response:
{"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2024-11-05","capabilities":{"resources":{},"tools":{},"prompts":{}},"serverInfo":{"name":"retail-mcp-server","version":"1.0.0",...}}}
Performance Tuning
Runtime Performance:
- Startup time: <100ms (native binary)
- Memory footprint: Low (~87MB binary, minimal runtime overhead)
- Request latency: <50ms for tool execution (excluding external API calls)
- API timeout: 5 seconds per HTTP request to Retail API
Timeout Configuration:
- Default HTTP timeout: 5000ms (5 seconds)
- Configured in retail-client.cljvia:timeoutoption
- Keep-alive: 30000ms (30 seconds) for connection reuse
- Adjust timeouts in code if API requires longer response times
Native Image Optimization:
- Production builds use -O3optimization and serial GC (--gc=serial)
- Development builds use -O1optimization and serial GC (--gc=serial) with-Obquick build
- Serial GC is used for cross-platform compatibility (G1 GC only available on Linux AMD64/AArch64)
- Build time: ~4-5 minutes for production binary
- Adjust optimization flags in build.cljbased on needs
Support
Resources
- MCP Specification: Model Context Protocol
- GraalVM Documentation: GraalVM Native Image
- Clojure Documentation: Clojure Guides
- http-kit Client: HTTP Client Documentation
Contributing
- Fork the repository
- Create a feature branch (git checkout -b feature/amazing-feature)
- Make your changes
- Run tests: clojure -M:test
- Run linting: clj-kondo --lint src/
- Commit your changes (git commit -m 'Add amazing feature')
- Push to the branch (git push origin feature/amazing-feature)
- Open a Pull Request
Code Quality Standards
All changes must:
- Pass all tests (88 tests, 1027 assertions)
- Have zero clj-kondo warnings/errors
- Maintain native image compilation compatibility
- Include appropriate tests for new functionality
- Follow existing code style and conventions
License
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
Copyright 2025
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License
Appendix
Environment Variable Reference
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| RETAIL_API_KEY | Yes | - | API authentication key |
| RETAIL_BASE_URL | No | https://api-test.kingpin.global | API base URL |
| LOG_LEVEL | No | INFO | Logging level (DEBUG, INFO, WARN, ERROR) |
Build Artifacts
| Artifact | Path | Purpose |
|----------|------|---------|
| JAR | target/mcp-server-0.1.0.jar | Standalone JAR |
| Native Binary | target/retail-mcp-server | GraalVM native executable |
| Classes | target/classes/ | Compiled Clojure classes |
HTTP Status Codes Handled
| Code | Error Type | Description |
|------|------------|-------------|
| 200-299 | Success | Request completed successfully |
| 401 | unauthorized | Invalid API key |
| 404 | not-found | Resource not found |
| 429 | rate-limit-exceeded | Too many requests |
| 500+ | api-error | Server error |
| Timeout | timeout | Request exceeded 5s timeout |
| Network | connection-failed | Cannot reach API |
Validation Rules
Collection IDs: 24-character MongoDB ObjectId (hex) Order IDs: 24-character MongoDB ObjectId (hex) Product IDs: 24-character MongoDB ObjectId (hex) Currencies: USD, EUR, GBP, CAD, AUD Pagination: page ≥ 0, limit 1-100
Last updated: 2025-10-29