npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@neoimpulse/cap-js-mcp

v1.0.6

Published

A CDS plugin to trim string attributes automatically

Readme

CAP.js MCP Server

This plugin for the SAP Cloud Application Programming Model (CAP) provides a Model Context Protocol (MCP) server implementation. It enables AI assistants and other clients to interact with CAP applications through standardized tools, prompts, and resources.

Features

  • MCP Tools: Product catalog management with CRUD operations
  • MCP Prompts: Template-based prompt system (extensible)
  • MCP Resources: File and data resource access (extensible)
  • Authentication: Configurable API key authentication
  • Logging: Comprehensive request/response logging

Installation

To install the plugin, add it to your CAP project.

npm add @neoimpulse/cap-js-mcp

Configuration

Add the MCP configuration to your package.json:

{
  "cds": {
    "requires": {
      "cap-js-mcp": {
        "apiKey": "YOUR_SECRET_API_KEY",
        "server": {
          "name": "cap-mcp-server",
          "version": "1.0.0"
        },
        "components": {
          "tools": {
            "path": "./srv/lib/mcp-tools"
          },
          "prompts": {
            "path": "./srv/lib/mcp-prompts"
          },
          "resources": {
            "path": "./srv/lib/mcp-resources"
          }
        },
        "authentication": true,
        "logging": true
      }
    }
  }
}

Available Tools

Standard CAP Tools (mcp-tools-default.js)

The plugin includes a generic implementation based on the official SAP CAP MCP Server. These tools work with any CAP application and use the compiled CDS model from the running application.

How It Works

The default tools leverage CAP's runtime model (cds.model) which is automatically compiled when your CAP application starts. This means:

  • No project path needed - Tools use the running application's model
  • Automatic model updates - Changes to your CDS files are reflected in the model
  • Service-aware - Automatically detects services and their endpoints
  • Universal - Works with any CAP project structure

Default Tools

  1. search_model - Search for CDS definitions (entities, services, actions, etc.)

    • Fuzzy search by name
    • Filter by kind (entity, service, action, etc.)
    • Returns full CSN definitions with annotations and metadata
  2. search_docs - Search CAP documentation

    • Searches code snippets and examples
    • Returns relevant documentation sections
    • (Note: Currently a placeholder - full implementation would use vector embeddings)
  3. get_cds_model - Get the complete CDS model

    • Returns all services, entities, and definitions
    • Optional filtering of built-in types
    • Includes namespace and i18n information
  4. get_service_endpoints - Get HTTP endpoints

    • Lists all OData and custom endpoints
    • Shows exposed entities per service
    • Optional filtering by service name
  5. analyze_entity - Deep entity analysis

    • Element types and properties
    • Associations and compositions
    • Keys and annotations
    • Relationship mapping
  6. execute_odata_query - Execute OData queries

    • Full OData v4 support ($filter, $select, $expand, etc.)
    • Direct query execution on entities
    • Service-aware query routing
    • Returns formatted JSON results

Using Default Tools with Extensions

You can extend the default tools with your custom implementations using the extends configuration:

{
  "cds": {
    "requires": {
      "cap-js-mcp": {
        "components": {
          "tools": {
            "path": "./srv/lib/mcp-tools-example",
            "extends": "./srv/lib/mcp-tools-default"
          }
        }
      }
    }
  }
}

How the Extension Mechanism Works:

  1. Base Class Loading: First loads the base class from extends path
  2. Main Class Loading: Then loads your custom class from path
  3. Tool Merging: Combines tools from both classes intelligently:
    • Inherit: Base tools not present in main class are added
    • 🔄 Override: Main class tools replace base tools with same name
    • 📦 Combine: Both sets of tools are available in the final instance

Example Scenario:

// Base class (mcp-tools-default.js) provides:
- search_model
- search_docs
- get_cds_model
- analyze_entity
- execute_odata_query

// Your class (mcp-tools-example.js) provides:
- get_products
- create_product
- search_model (custom implementation)

// Result after merging:
- search_model         (from YOUR class - overridden)
- search_docs          (inherited from base)
- get_cds_model        (inherited from base)
- analyze_entity       (inherited from base)
- execute_odata_query  (inherited from base)
- get_products         (from YOUR class)
- create_product       (from YOUR class)

Console Output During Loading:

🔧 Loading tools from: ./srv/lib/mcp-tools-example
   ⬆️  Extends: ./srv/lib/mcp-tools-default
   📚 Loading base class from: ./srv/lib/mcp-tools-default
   ✅ Base class loaded successfully
   ✅ Main class loaded successfully
   🔗 Inheriting tool: search_docs
   🔗 Inheriting tool: get_cds_model
   🔗 Inheriting tool: analyze_entity
   🔗 Inheriting tool: execute_odata_query
   🔄 Overriding tool: search_model
✅ tools loaded successfully with inheritance
   📊 Total tools: 7

Benefits:

  • No Code Duplication: Keep generic CAP functionality from base
  • Selective Override: Replace only specific tools you need to customize
  • Composition: Add domain-specific tools alongside generic ones
  • Maintainability: Base updates don't break your custom code

Example: Using Default Tools

// Search for all entities in the model
const entities = await mcpClient.callTool("search_model", {
  kind: "entity",
  topN: 10
});

// Find a specific service by name
const service = await mcpClient.callTool("search_model", {
  name: "CatalogService",
  kind: "service",
  topN: 1
});

// Analyze an entity structure
const bookAnalysis = await mcpClient.callTool("analyze_entity", {
  entityName: "CatalogService.Books"
});

// Get all service endpoints
const endpoints = await mcpClient.callTool("get_service_endpoints", {});

// Execute an OData query
const books = await mcpClient.callTool("execute_odata_query", {
  entityName: "CatalogService.Books",
  filter: "stock > 0",
  select: "ID,title,price",
  orderby: "price desc",
  top: 10
});

// Execute query with expand
const booksWithAuthor = await mcpClient.callTool("execute_odata_query", {
  entityName: "CatalogService.Books",
  select: "ID,title,price",
  expand: "author",
  filter: "price < 30"
});

Product Management (Demo Tools)

⚠️ Note: The built-in product catalog tools are for demonstration and testing purposes only. They use in-memory data storage and are not intended for production use. In a real application, you would implement tools that interact with your actual CAP services and data models.

The MCP server comes with built-in product catalog management tools:

  • get_products - Get all products from the catalog
  • get_product - Get a single product by ID with full details
  • create_product - Create a single product
  • create_products - Create multiple products
  • change_product - Update a single product
  • change_products - Update multiple products
  • remove_product - Remove a single product by ID
  • remove_products - Remove multiple products by IDs

Example Usage

// Get all products from the catalog
const products = await mcpClient.callTool("get_products", {});

// Get a specific product by ID
const product = await mcpClient.callTool("get_product", { id: 1 });

// Create a new product
const newProduct = await mcpClient.callTool("create_product", {
  name: "MacBook Air M3",
  price: 1299.99,
  inStock: true,
  category: "Laptops",
  description: "Apple MacBook Air with M3 chip"
});

// Create multiple products at once
const multipleProducts = await mcpClient.callTool("create_products", {
  products: [
    {
      name: "iPad Pro",
      price: 999.99,
      inStock: true,
      category: "Tablets",
      description: "iPad Pro with M2 chip"
    },
    {
      name: "AirPods Pro",
      price: 279.99,
      inStock: false,
      category: "Audio",
      description: "Wireless earbuds with noise cancellation"
    }
  ]
});

// Update a single product
const updatedProduct = await mcpClient.callTool("change_product", {
  id: 1,
  price: 2799.99,
  inStock: false
});

// Update multiple products
const updatedProducts = await mcpClient.callTool("change_products", {
  products: [
    { id: 2, inStock: true },
    { id: 5, price: 299.99 }
  ]
});

// Remove a single product
const removedProduct = await mcpClient.callTool("remove_product", { id: 3 });

// Remove multiple products
const removedProducts = await mcpClient.callTool("remove_products", { 
  ids: [4, 5] 
});

How It Works

The plugin automatically registers as a CDS plugin and exposes MCP endpoints:

  1. Tools: Executable functions that perform operations
  2. Prompts: Template-based text generation (extensible)
  3. Resources: Access to files and data resources (extensible)

The server includes sample product data for testing:

  • MacBook Pro 16 (€2999.00)
  • Dell XPS 13 (€1299.99)
  • iPhone 15 Pro (€1199.00)
  • Samsung Galaxy S24 (€899.99)
  • Sony WH-1000XM5 (€349.99)

Important: This demo data is stored in memory and will be reset when the server restarts. For production use, replace the demo tools with implementations that connect to your actual CAP services and persistent data storage.

Architecture

srv/
├── lib/
│   ├── mcp-tools-default.js     # Generic CAP tools (base implementation)
│   ├── mcp-tools-example.js     # Demo product management tools (extends default)
│   ├── mcp-prompts-example.js   # Prompt templates (extensible)
│   └── mcp-resources-example.js # Resource handlers (extensible)
└── mcp-server.js                # Main MCP server with extension loader

Extension Architecture

┌─────────────────────────────────────────────────────────────┐
│                     cds-plugin.js                            │
│  ┌──────────────────────────────────────────────────────┐  │
│  │    loadComponentWithInheritance()                     │  │
│  │                                                        │  │
│  │  1. Load Base Class (if extends is configured)       │  │
│  │     ↓                                                  │  │
│  │  2. Instantiate Base → baseInstance                   │  │
│  │     ↓                                                  │  │
│  │  3. Load Main Class                                   │  │
│  │     ↓                                                  │  │
│  │  4. Instantiate Main → mainInstance                   │  │
│  │     ↓                                                  │  │
│  │  5. Merge: baseInstance.tools → mainInstance.tools   │  │
│  │     • Inherit: Tools not in main                      │  │
│  │     • Override: Tools in both (main wins)             │  │
│  │     ↓                                                  │  │
│  │  6. Return merged mainInstance                        │  │
│  └──────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────┐      ┌─────────────────────┐
│ mcp-tools-default   │      │ mcp-tools-example   │
├─────────────────────┤      ├─────────────────────┤
│ • search_model      │      │ • get_products      │
│ • search_docs       │  ←─  │ • get_product       │
│ • get_cds_model     │ extends │ • create_product    │
│ • analyze_entity    │      │ • change_product    │
│ • execute_odata_query│     │ • remove_product    │
│ • get_service_...   │      │ (+ inherits all →)  │
└─────────────────────┘      └─────────────────────┘
         ↓                            ↓
         └────────────────┬───────────┘
                          ↓
              ┌───────────────────────┐
              │   Merged Instance     │
              ├───────────────────────┤
              │ All 11+ tools         │
              │ available to clients  │
              └───────────────────────┘

Configuration Flow

// package.json
{
  "cds": {
    "requires": {
      "cap-js-mcp": {
        "components": {
          "tools": {
            "path": "./srv/lib/mcp-tools-example",
            "extends": "./srv/lib/mcp-tools-default"  ← Extension config
          }
        }
      }
    }
  }
}

Loading Sequence:

  1. Bootstrap: cds.on("bootstrap") triggered
  2. Load Components: loadComponents() called
  3. Extension Check: Reads extends from config
  4. Base Loading: Requires and instantiates base class
  5. Main Loading: Requires and instantiates main class
  6. Merging: Combines tools/prompts/resources intelligently
  7. Registration: Registers all tools with MCP server
  8. Ready: Server starts handling requests

Component Structure

mcp-tools-default.js - Generic CAP Tools

This is the core implementation inspired by the official @cap-js/mcp-server. It provides:

Key Features:

  • Runtime Model Access: Uses cds.model from the running CAP application
  • Fuzzy Search: Modified Levenshtein distance algorithm for flexible name matching
  • Endpoint Discovery: Automatically maps services to HTTP endpoints
  • OData Query Execution: Direct query execution with full OData v4 support
  • Service Awareness: Detects and connects to CAP services

Technical Implementation:

class MCPToolsDefault {
  async _getModel() {
    // Uses cds.model if available (runtime)
    // Falls back to compiling from project if needed
    return cds.model;
  }
  
  _fuzzyTopN(searchTerm, list, n) {
    // Levenshtein distance with:
    // - 0.5 cost for insertions/deletions
    // - 1.0 cost for substitutions
    // - 0 cost for exact matches
  }
  
  _addEndpointInformation(compiled, serviceInfo) {
    // Enriches definitions with HTTP endpoints
    // Maps OData paths to entities
    // Handles auto-exposed entities
  }
}

mcp-tools-example.js - Demo Tools

Example implementation showing how to create custom domain-specific tools:

  • In-memory data storage (for demo purposes)
  • CRUD operations on product catalog
  • Type-safe schemas with validation

Extension Pattern

The plugin supports composition over inheritance through a sophisticated merging mechanism:

Configuration-Based Extension:

{
  "tools": {
    "path": "./srv/lib/my-tools",
    "extends": "./srv/lib/mcp-tools-default"
  }
}

How It Works Internally:

// In cds-plugin.js - loadComponentWithInheritance()

function loadComponentWithInheritance(componentType, config, defaultPath) {
  // 1. Load main component class
  const MainComponentClass = require(config.path);
  
  // 2. If extends is specified, load base class
  if (config.extends) {
    const BaseComponentClass = require(config.extends);
    const baseInstance = new BaseComponentClass();
    const mainInstance = new MainComponentClass();
    
    // 3. Merge tools from base into main
    for (const [toolName, toolDef] of baseInstance.tools.entries()) {
      if (!mainInstance.tools.has(toolName)) {
        // Inherit: Tool not in main class
        mainInstance.tools.set(toolName, toolDef);
      } else {
        // Override: Tool exists in main class
        console.log(`🔄 Overriding tool: ${toolName}`);
      }
    }
    
    return mainInstance;
  }
  
  // 4. No inheritance - just return main instance
  return new MainComponentClass();
}

Extension Strategies:

  1. Pure Extension (Recommended):

    // Your custom-tools.js
    class CustomTools {
      constructor() {
        this.tools = new Map();
        this._initializeTools();
      }
         
      _initializeTools() {
        // Only define YOUR custom tools
        this.tools.set("custom_tool", { ... });
      }
    }

    Result: Base tools + Your tools (no conflicts)

  2. Selective Override:

    // Your custom-tools.js
    class CustomTools {
      _initializeTools() {
        // Override a specific tool
        this.tools.set("search_model", {
          // Your custom implementation
        });
           
        // Add new tools
        this.tools.set("custom_tool", { ... });
      }
    }

    Result: Your search_model replaces base's, other base tools inherited

  3. Full Override (Not Recommended):

    // Your custom-tools.js extends base
    class CustomTools extends MCPToolsDefault {
      _initializeTools() {
        super._initializeTools(); // Keep base tools
           
        // Add your tools
        this.tools.set("custom_tool", { ... });
      }
    }

    Result: Same as configuration-based extension, but harder to maintain

Applies to All Components:

  • Tools (tools.extends)
  • Prompts (prompts.extends)
  • Resources (resources.extends)

Multiple Levels of Extension:

{
  "tools": {
    "path": "./srv/lib/my-production-tools",
    "extends": "./srv/lib/my-base-tools"
  }
}

Where my-base-tools could also extend another base:

// my-base-tools.js
class MyBaseTools extends MCPToolsDefault { ... }

Extending the Server

Recommended Approach: Combine Default + Custom Tools

The best practice is to use the default tools for generic CAP operations and add your own domain-specific tools:

{
  "cds": {
    "requires": {
      "cap-js-mcp": {
        "components": {
          "tools": {
            "path": "./srv/lib/my-business-tools",
            "extends": "./srv/lib/mcp-tools-default"
          }
        }
      }
    }
  }
}

Why this approach?

  • ✅ Keep generic CAP functionality (model search, entity analysis)
  • ✅ Add business-specific operations (order processing, inventory management)
  • ✅ No need to reimplement standard features
  • ✅ AI assistants get both CAP knowledge and domain knowledge

Debugging Extension Loading

Check Health Endpoint:

curl http://localhost:4004/mcp/health

Response shows loaded components:

{
  "status": "healthy",
  "available": {
    "tools": [
      "search_model",
      "search_docs", 
      "get_cds_model",
      "analyze_entity",
      "execute_odata_query",
      "get_products",
      "create_product"
    ]
  },
  "config": {
    "components": {
      "tools": "./srv/lib/mcp-tools-example"
    }
  }
}

Server Console Output:

🔧 Loading tools from: ./srv/lib/mcp-tools-example
   ⬆️  Extends: ./srv/lib/mcp-tools-default
   📚 Loading base class from: ./srv/lib/mcp-tools-default
   ✅ Base class loaded successfully
🔧 Initialized 5 default MCP tools
   ✅ Main class loaded successfully
🔧 Initialized 10 MCP tools
   🔗 Inheriting tool: search_docs
   🔗 Inheriting tool: get_cds_model
   🔗 Inheriting tool: analyze_entity
   🔗 Inheriting tool: execute_odata_query
✅ tools loaded successfully with inheritance
   📊 Total tools: 15

Reload Components at Runtime:

curl -X POST http://localhost:4004/mcp/reload \
  -H "Authorization: Basic <your-api-key>"

This reloads all components without restarting the server - useful during development!

Use Cases

1. Model Exploration for AI Assistants

Use default tools to help AI understand your data model:

// AI: "What entities are in the catalog service?"
search_model({ kind: "entity", name: "catalog" })

// AI: "Show me the structure of the Books entity"
analyze_entity({ entityName: "CatalogService.Books" })

2. Data Querying for AI Agents

Enable AI to query your data:

// AI: "Show me expensive books"
execute_odata_query({ 
  entityName: "CatalogService.Books",
  filter: "price > 50",
  orderby: "price desc"
})

// AI: "Find out-of-stock products"
execute_odata_query({
  entityName: "ProductService.Products",
  filter: "stock eq 0",
  select: "ID,name,category"
})

3. Custom Business Logic

Add domain-specific tools alongside defaults:

class BusinessTools extends MCPToolsDefault {
  _initializeTools() {
    super._initializeTools(); // Keep CAP tools
    
    // Add custom business operations
    this.tools.set("process_order", {
      definition: { /* ... */ },
      handler: async (args) => {
        // Your business logic
        const srv = await cds.connect.to('OrderService');
        return await srv.send('processOrder', args);
      }
    });
  }
}

Using Custom Implementations

You can replace the demo components with your own implementations by changing the component paths in your configuration:

{
  "cds": {
    "requires": {
      "cap-js-mcp": {
        "apiKey": "YOUR_SECRET_API_KEY",
        "components": {
          "tools": {
            "path": "./srv/lib/my-custom-tools"
          },
          "prompts": {
            "path": "./srv/lib/my-custom-prompts" 
          },
          "resources": {
            "path": "./srv/lib/my-custom-resources"
          }
        }
      }
    }
  }
}

This allows you to:

  • Replace demo tools with production-ready implementations that interact with your CAP services
  • Add custom prompts for your specific business domain
  • Provide custom resources like files, documents, or other data sources

Adding Custom Tools

Extend the MCPTools class to add your own tools:

// In your custom tools file
class CustomTools extends MCPTools {
  _initializeTools() {
    super._initializeTools();
    
    this.tools.set("my_custom_tool", {
      definition: {
        name: "my_custom_tool",
        description: "My custom tool description",
        inputSchema: {
          type: "object",
          properties: {
            param: { type: "string" }
          },
          required: ["param"]
        }
      },
      handler: async (args) => {
        return `Custom result: ${args.param}`;
      }
    });
  }
}

Adding Prompts and Resources

Similar patterns can be used to extend prompts and resources functionality.

Connecting to MCP Clients

FAQ & Troubleshooting

Q: Why aren't my custom tools showing up?

A: Check these points:

  1. Verify your class exports correctly: module.exports = MyTools;
  2. Check constructor initializes the tools Map: this.tools = new Map();
  3. Implement required methods: getToolDefinitions(), executeToolHandler(), etc.
  4. Check console output during startup for loading errors
  5. Visit /mcp/health to see what tools are actually loaded

Q: Can I use inheritance AND the extends configuration?

A: Yes! Both work together:

// my-tools.js - uses JavaScript inheritance
class MyTools extends MCPToolsDefault {
  _initializeTools() {
    super._initializeTools(); // Get base tools
    this.tools.set("my_tool", { ... }); // Add yours
  }
}
// package.json - uses configuration extension
{
  "tools": {
    "path": "./srv/lib/my-tools",
    "extends": "./srv/lib/some-other-base"
  }
}

Result: my-tools inherits from MCPToolsDefault (code) AND some-other-base (config)

Q: How do I override only specific tools?

A: Define only the tools you want to override in your class:

class MyTools {
  constructor() {
    this.tools = new Map();
    this._initializeTools();
  }
  
  _initializeTools() {
    // Override search_model only
    this.tools.set("search_model", {
      definition: { /* your definition */ },
      handler: async (args) => { /* your logic */ }
    });
    
    // Other base tools will be inherited automatically
  }
}

Q: Can I extend multiple base classes?

A: Not directly, but you can chain extensions:

Base1 → Base2 → YourClass

Configure: YourClass extends Base2, and Base2 extends Base1 in code.

Q: Do I need to restart the server after changing my tools?

A: No! Use the reload endpoint:

curl -X POST http://localhost:4004/mcp/reload \
  -H "Authorization: Basic <your-key>"

Q: What happens if base and main have the same tool?

A: Main class wins (override behavior). You'll see in console:

🔄 Overriding tool: search_model

GitHub Copilot Integration

To connect your CAP.js MCP server to GitHub Copilot, add the server configuration to your MCP settings.

Create a file .vscode/mcp.json in your project root or workspace:

{
  "servers": {
    "catalog": {
      "type": "http",
      "url": "https://your-app-domain.cfapps.region.hana.ondemand.com/mcp",
      "headers": {
        "Authorization": "Basic <base64-encoded-api-key>"
      }
    }
  }
}

Generating the Authorization Header

The authorization header uses Basic authentication with your API key:

# Encode your API key (replace with your actual key)
echo -n "apiKey:YOUR_SECRET_API_KEY" | base64

Use the output as the Authorization header value: Basic <base64-output>

Testing the Connection

Once configured, you can test the MCP tools in GitHub Copilot:

@catalog Can you show me all available products?
@catalog Create a new laptop product with the name "ThinkPad X1" priced at €1899

License

This project is licensed under the MIT License. See the LICENSE file for more details.

Technical Details

Quick Reference: Extension Configuration

// No extension - standalone
{
  "tools": {
    "path": "./srv/lib/my-tools"
  }
}

// Simple extension - inherit from default
{
  "tools": {
    "path": "./srv/lib/my-tools",
    "extends": "./srv/lib/mcp-tools-default"
  }
}

// Chain extension - multiple levels
{
  "tools": {
    "path": "./srv/lib/production-tools",
    "extends": "./srv/lib/base-tools"
  }
}
// where base-tools.js also extends another class

// All components support extension
{
  "tools": {
    "path": "./srv/lib/my-tools",
    "extends": "./srv/lib/mcp-tools-default"
  },
  "prompts": {
    "path": "./srv/lib/my-prompts",
    "extends": "./srv/lib/base-prompts"
  },
  "resources": {
    "path": "./srv/lib/my-resources",
    "extends": "./srv/lib/base-resources"
  }
}

Extension Behavior Matrix

| Scenario | Base Has | Main Has | Result | Logged As | |----------|----------|----------|--------|-----------| | Inherit | tool_a | - | tool_a from base | 🔗 Inheriting | | Override | tool_a | tool_a | tool_a from main | 🔄 Overriding | | Add New | - | tool_b | tool_b from main | ✨ (no log) | | Combine | tool_a, tool_b | tool_c | All three | Mix of above |

Default Tools Implementation

The mcp-tools-default.js implementation is inspired by the official @cap-js/mcp-server and provides:

Fuzzy Search Algorithm

Uses a modified Levenshtein distance with weighted costs:

  • Insertions/Deletions: 0.5 cost
  • Substitutions: 1.0 cost
  • Exact matches: 0 cost
  • Substring matches: 0.1 cost

This allows flexible searching like:

  • "book" → finds "Books", "Bookshop", "BookService"
  • "catalog" → finds "CatalogService", "ProductCatalog"

Model Compilation

The tools use CAP's model compilation chain:

  1. cds.resolve() - Find all CDS files
  2. cds.load() - Parse and load with docs/locations
  3. cds.compile.for.nodejs() - Include drafts and effective types
  4. cds.compile.to.serviceinfo() - Extract service metadata

OData Query Execution

Direct query execution using CDS Query Language (CQL):

  • Translates OData parameters to CQL
  • Service-aware routing (uses service instances if available)
  • Fallback to local execution (cds.run())
  • Full support for: $filter, $select, $expand, $orderby, $top, $skip, $count

Endpoint Discovery

Automatically enriches the model with HTTP endpoints:

  • Detects OData services and their paths
  • Maps entities to endpoints (e.g., /odata/v4/catalog/Books)
  • Filters auto-exposed entities
  • Handles draft entities and contained entities

Comparison: Default vs. Example Tools

| Feature | mcp-tools-default.js | mcp-tools-example.js | |---------|------------------------|------------------------| | Purpose | Generic CAP operations | Domain-specific demo | | Data Source | CDS Model (cds.model) | In-memory array | | Production Ready | ✅ Yes | ❌ Demo only | | Model Awareness | ✅ Full CSN access | ❌ No model integration | | OData Support | ✅ Query execution | ❌ Not applicable | | Service Integration | ✅ Connects to services | ❌ Standalone | | Use Case | AI model exploration, data querying | Testing, examples |

Performance Considerations

Model Caching:

  • The CDS model is compiled once and cached in cds.model
  • Subsequent tool calls reuse the cached model
  • Model updates are handled automatically by CAP

Query Optimization:

  • Direct service connection when available
  • Connection pooling managed by CAP
  • Efficient fuzzy search with early termination

Memory Usage:

  • Default tools: Minimal (uses existing cds.model)
  • Example tools: ~5KB for demo product data

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Keywords

  • CAP
  • CDS
  • MCP
  • Model Context Protocol
  • AI Assistant
  • Tools
  • Prompts
  • Resources

Acknowledgments

Thanks to the SAP CAP community and the MCP specification contributors for their support and contributions.