A bridge between OData v2 services and the Model Context Protocol (MCP), dynamically generating MCP tools based on OData metadata.
The OData MCP Wrapper enables seamless integration between OData v2 services and the MCP (MCP). It automatically analyzes OData service metadata and generates corresponding MCP tools, allowing AI agents to interact with OData services through a standardized interface.
- Modular Architecture: Split into focused modules for maintainability
- Enhanced Error Handling: Comprehensive OData error parsing and propagation
- Smart Tool Naming: Service-aware tool naming preserving original names
- Automatic Tool Generation: Creates MCP tools from OData metadata
- Full CRUD Support: Create, Read, Update, Delete operations for entity sets
- Query Capabilities: Standard OData query parameters (filter, select, expand, orderby, etc.)
- Function Import Support: Handles OData function imports
- Authentication: Basic auth and cookie-based auth with CSRF token management
- GUID Optimization: Automatic base64 ↔ standard GUID conversion
- Response Optimization: Size limiting and selective field retrieval
- Legacy Date Support: Automatic conversion between SAP /Date(milliseconds)/ and ISO 8601
- Decimal Field Handling: Automatic numeric to string conversion for Edm.Decimal fields
- Pagination Hints: Suggested next call parameters for easy pagination
- Flexible Response Control: Options for metadata inclusion and error verbosity
- Multiple Transport Options: STDIO (default) and HTTP/SSE for web-based clients
- Read-Only Modes: Options to hide modifying operations for safer exploration
- Service-Specific Hints: Implementation guidance for known problematic services
- MCP Protocol Tracing: Debug logging for troubleshooting client issues
- Python 3.8+
- FastMCP package
-
Clone the repository:
git clone https://github.com/oisee/odata_mcp.git cd odata_mcp
-
Install dependencies:
pip install -r requirements.txt
Create a .env
file in the project directory:
# OData service URL (required)
ODATA_SERVICE_URL=https://your-odata-service.com/odata/
ODATA_URL=https://your-odata-service.com/odata/ # Alternative
# Basic Authentication (if required)
ODATA_USERNAME=your_username
ODATA_USER=your_username # Alternative
ODATA_PASSWORD=your_password
ODATA_PASS=your_password # Alternative
# Cookie Authentication (alternative to basic auth)
ODATA_COOKIE_FILE=/path/to/cookie.txt
ODATA_COOKIE_STRING="session=abc123; token=xyz789"
Option | Description | Default |
---|---|---|
--service |
OData service URL (overrides positional arg and env var) | - |
-u, --user |
Username for basic authentication | - |
-p, --password |
Password for basic authentication | - |
--cookie-file |
Path to cookie file (Netscape format) | - |
--cookie-string |
Cookie string (key1=val1; key2=val2) | - |
-v, --verbose, --debug |
Enable verbose output to stderr | False |
--tool-prefix |
Custom prefix for tool names | - |
--tool-postfix |
Custom postfix for tool names | _for_<service_id> |
--no-postfix |
Use prefix instead of postfix | False |
--tool-shrink |
Use shortened tool names | False |
--entities |
Comma-separated entities (supports wildcards with *) | All entities |
--functions |
Comma-separated functions (supports wildcards with *) | All functions |
--sort-tools |
Sort tools alphabetically | True |
--no-sort-tools |
Disable alphabetical sorting of tools | - |
--pagination-hints |
Add suggested_next_call in pagination responses | False |
--legacy-dates |
Convert /Date(ms)/ to/from ISO 8601 | True |
--no-legacy-dates |
Disable legacy date format conversion | - |
--verbose-errors |
Include detailed error messages | False |
--response-metadata |
Include __metadata blocks in responses | False |
--max-response-size |
Maximum response size in bytes | 5242880 (5MB) |
--max-items |
Maximum items per response | 100 |
--trace |
Print all tools and exit (debugging) | False |
--trace-mcp |
Enable detailed MCP protocol trace logging | False |
--read-only, -ro |
Hide all modifying operations (create, update, delete, functions) | False |
--read-only-but-functions, -robf |
Hide create, update, delete but allow functions | False |
--enable |
Enable only specific operation types (see Operation Type Filtering) | - |
--disable |
Disable specific operation types (see Operation Type Filtering) | - |
--hints-file |
Path to hints JSON file | hints.json |
--hint |
Direct hint JSON or text to inject | - |
--info-tool-name |
Custom name for the service info tool | odata_service_info |
--transport |
Transport type: 'stdio' or 'http' (SSE) | stdio |
--http-addr |
HTTP server address (with --transport http) | :8080 |
The wrapper automatically creates a service info tool that provides comprehensive metadata about the OData service:
- Default name:
odata_service_info
(with service-specific postfix) - Alias:
readme
(automatically created for better discoverability) - Custom name: Use
--info-tool-name
to specify a custom name
This tool is marked as the RECOMMENDED STARTING POINT and provides:
- Service URL and description
- Available entity sets and their operations
- Entity types with properties and relationships
- Function imports with parameters
- Implementation hints and known issues
- List of all registered MCP tools
Example:
# Default naming (creates both odata_service_info and readme aliases)
python odata_mcp.py --service https://example.com/odata/
# Custom naming (no readme alias)
python odata_mcp.py --service https://example.com/odata/ --info-tool-name get_started
The wrapper supports read-only modes for safer exploration of OData services:
--read-only
(-ro
): Hides all modifying operations (create, update, delete, and function imports)--read-only-but-functions
(-robf
): Hides create, update, and delete operations but still allows function imports
These modes are mutually exclusive and useful when:
- Exploring unfamiliar OData services
- Preventing accidental data modifications
- Creating read-only MCP endpoints for users
The wrapper supports fine-grained control over which operation types are generated using --enable
and --disable
flags. This helps reduce tool count for services with many entities.
- C: Create operations
- S: Search operations
- F: Filter operations (includes count)
- G: Get (retrieve single entity) operations
- U: Update operations
- D: Delete operations
- A: Actions/Function imports
- R: Read operations (expands to S, F, and G)
# Enable only read operations (search, filter, get)
python odata_mcp.py --service https://example.com/odata/ --enable "R"
# Enable only filter and get operations
python odata_mcp.py --service https://example.com/odata/ --enable "FG"
# Disable create, update, and delete operations
python odata_mcp.py --service https://example.com/odata/ --disable "CUD"
# Disable actions/function imports
python odata_mcp.py --service https://example.com/odata/ --disable "A"
Notes:
- Operation codes are case-insensitive
--enable
and--disable
are mutually exclusive- The special
R
code in--enable
expands to S, F, and G operations - This filtering is more flexible than
--read-only
modes as it allows specific operation combinations
The wrapper includes a flexible hint system to provide guidance for services with known issues or special requirements:
# Use default hints.json from script directory
python odata_mcp.py https://my-service.com/odata/
# Use custom hints file
python odata_mcp.py --hints-file /path/to/custom-hints.json https://my-service.com/odata/
# Inject hint directly from command line
python odata_mcp.py --hint "Remember to use \$expand for complex queries" https://my-service.com/odata/
# Combine file and CLI hints (CLI has higher priority)
python odata_mcp.py --hints-file custom.json --hint '{"notes":["Override note"]}' https://my-service.com/odata/
Hints are matched by URL patterns and appear in the odata_service_info
tool response under implementation_hints
.
Default hints are provided for:
- SAP OData Services: General SAP-specific issues and workarounds
- SAP PO Tracking Service (SRA020_PO_TRACKING_SRV): Specific guidance for purchase order tracking
- Northwind Demo Services: Identifies public demo services
The hints.json file follows this structure:
{
"version": "1.0",
"hints": [
{
"pattern": "*/sap/opu/odata/*",
"priority": 10,
"service_type": "SAP OData Service",
"known_issues": [...],
"workarounds": [...],
"field_hints": {
"FieldName": {
"type": "Edm.String",
"format": "Expected format",
"example": "12345"
}
},
"examples": [
{
"description": "Example description",
"query": "filter_EntitySet with $filter=...",
"note": "Additional note"
}
],
"notes": [...]
}
]
}
Patterns support wildcards (* and ?) and are matched against the service URL. Multiple hints can match; they are merged by priority (higher values override).
Use --trace-mcp
to enable detailed protocol debugging. This creates a log file with all MCP messages:
- Linux/WSL:
/tmp/mcp_trace_*.log
- Windows:
%TEMP%\mcp_trace_*.log
Useful for diagnosing client compatibility issues.
# Using environment variables
python odata_mcp.py
# Using command line arguments (basic auth)
python odata_mcp.py --service https://your-service.com/odata/ \
--user USERNAME \
--password PASSWORD \
--verbose
# Using cookie authentication
python odata_mcp.py --service https://your-service.com/odata/ \
--cookie-file cookie.txt \
--verbose
# Additional options
python odata_mcp.py --tool-prefix myprefix \
--tool-postfix myservice \
--no-postfix
# Generate tools only for specific entities
python odata_mcp.py --service https://your-service.com/odata/ \
--entities "Products,Categories,Orders" \
--verbose
# Use wildcards in entity filtering
python odata_mcp.py --service https://your-service.com/odata/ \
--entities "Product*,Order*,Customer" \
--verbose
# Control tool sorting (default is alphabetical)
python odata_mcp.py --service https://your-service.com/odata/ \
--no-sort-tools \
--verbose
# Enable pagination hints for easier navigation
python odata_mcp.py --service https://your-service.com/odata/ \
--pagination-hints \
--verbose
# SAP-specific options for legacy systems
python odata_mcp.py --service https://sap-service.com/odata/ \
--legacy-dates \
--response-metadata \
--verbose-errors
# Debug mode - show all tools without starting server
python odata_mcp.py --service https://your-service.com/odata/ \
--trace
# Run with HTTP/SSE transport for web clients
python odata_mcp.py --service https://your-service.com/odata/ \
--transport http \
--http-addr :8080
# HTTP transport on specific interface
python odata_mcp.py --service https://your-service.com/odata/ \
--transport http \
--http-addr 127.0.0.1:3000
# Read-only mode - hide all modifying operations
python odata_mcp.py --service https://your-service.com/odata/ \
--read-only \
--verbose
# Read-only but allow functions
python odata_mcp.py --service https://your-service.com/odata/ \
--read-only-but-functions \
--verbose
# Enable MCP protocol trace logging for debugging
python odata_mcp.py --service https://your-service.com/odata/ \
--trace-mcp \
--verbose
The wrapper dynamically generates MCP tools for each entity set. Use --entities
to limit tool generation to specific entities only (useful for large services):
- List/Filter:
filter_EntitySetName
- Query entities with filtering, sorting, pagination - Count:
count_EntitySetName
- Get entity count with optional filtering - Search:
search_EntitySetName
- Full-text search (if supported) - Get:
get_EntitySetName
- Retrieve single entity by key - Create:
create_EntitySetName
- Create new entity - Update:
update_EntitySetName
- Update existing entity - Delete:
delete_EntitySetName
- Delete entity
# List entities with filtering
await filter_ProductSet(
filter="Price gt 20",
orderby="Price desc",
top=10
)
# Get specific entity
await get_ProductSet(ID="12345")
# Create new entity
await create_ProductSet(
Name="New Product",
Price=99.99,
CategoryID="CAT001"
)
# Update entity
await update_ProductSet(
ID="12345",
Price=89.99
)
# Get service information
await odata_service_info()
The OData MCP bridge supports two transport mechanisms:
- Standard input/output communication
- Used by Claude Desktop and other MCP clients
- No additional configuration required
- HTTP server with Server-Sent Events
- Enables web-based clients to interact with OData services
- Endpoints:
GET /health
- Health checkGET /sse
- Server-Sent Events streamPOST /rpc
- JSON-RPC endpoint
# Start with default port 8080
python odata_mcp.py --transport http --service https://your-service.com/odata/
# Use custom port
python odata_mcp.py --transport http --http-addr :3000 --service https://your-service.com/odata/
# Bind to specific interface
python odata_mcp.py --transport http --http-addr 192.168.1.100:8080 --service https://your-service.com/odata/
-
Using the provided HTML client:
# Start the server python odata_mcp.py --transport http --service https://services.odata.org/V2/Northwind/Northwind.svc/ # Open examples/sse_client.html in a web browser
-
Using the test script:
./test_http_transport.sh
-
Using curl:
# Test health endpoint curl http://localhost:8080/health # Test RPC endpoint curl -X POST http://localhost:8080/rpc \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}'
⚠️ Security Warning: The HTTP/SSE transport does not include authentication. Only use it in secure, trusted environments or behind a reverse proxy with proper authentication.
The project uses a modular architecture for maintainability:
odata_mcp_lib/ # Core modular library
├── __init__.py # Clean API exports
├── constants.py # OData type mappings & namespaces
├── models.py # Pydantic data models
├── guid_handler.py # GUID conversion utilities
├── metadata_parser.py # OData metadata parsing
├── client.py # HTTP client with error handling
├── bridge.py # MCP bridge implementation
├── name_shortener.py # Tool name shortening logic
└── transport/ # Transport implementations
├── __init__.py # Transport base classes
├── stdio.py # STDIO transport
└── http_sse.py # HTTP/SSE transport
odata_mcp.py # Main executable
examples/
├── sse_client.html # Web-based SSE client
test_odata_mcp.py # Test suite
test_http_transport.sh # HTTP transport test script
- MetadataParser: Fetches and parses OData
$metadata
XML - ODataClient: Manages HTTP communication and CSRF tokens
- ODataMCPBridge: Generates MCP tools from metadata
- GUIDHandler: Converts between base64 and standard GUID formats
# Run unit tests
python test_odata_mcp.py
# Run with live service (requires valid OData service)
RUN_LIVE_TESTS=true python test_odata_mcp.py
from odata_mcp_lib import MetadataParser, ODataClient, ODataMCPBridge
from odata_mcp_compat import MetadataParser, ODataClient, ODataMCPBridge
- Enhanced testing suite with comprehensive coverage
- Module-specific unit tests leveraging new architecture
- CI/CD pipeline setup for automated testing
- Performance benchmarking and optimization
- OData v4 support
- Enhanced batch operations
- Cookie-based authentication (completed)
- OAuth 2.0 authentication
- Response caching for performance
- Input validation improvements
- Schema validation for input/output data
- Advanced query capabilities (complex filters, aggregations)
- Navigation property enhancements
- Custom tool generation templates
- GraphQL interface layer
- Cross-service federation
- Advanced security features (field-level security, data masking)
- Comprehensive monitoring and metrics
- Horizontal scaling support
- Modular Architecture: Split monolithic codebase into 7 focused modules
- Enhanced Error Handling: Comprehensive OData error parsing
- Smart Tool Naming: Service-aware naming preserving original names
- Backward Compatibility: Zero breaking changes maintained
- Code Cleanup: Removed redundant files and improved organization
- GUID Optimization: Automatic base64 ↔ standard format conversion
- Response Optimization: Size limiting and field selection
- Cookie Authentication: Support for SSO/MYSAPSSO2 tokens (see COOKIE_AUTH.md)
- Legacy Date Support: SAP /Date(milliseconds)/ format conversion
- Decimal Field Handling: Automatic conversion for Edm.Decimal types
- Pagination Hints: Suggested next call parameters for easy pagination
- Enhanced Trace Mode: Comprehensive debugging output
- Feature Parity: Matched Go implementation features
- HTTP/SSE Transport: Web-based client support via Server-Sent Events
- Transport Abstraction: Clean interface for multiple transport types
- Read-Only Modes: Options to hide modifying operations (--read-only, --read-only-but-functions)
- Service Hints: Implementation guidance for known problematic services
- MCP Trace Logging: Protocol debugging support with --trace-mcp
-
Connection Failures
- Verify OData service URL and network connectivity
- Check authentication credentials
- Use
--verbose
for detailed error information
-
Import Errors
- Use
from odata_mcp_lib import ...
for new imports - Use
from odata_mcp_compat import ...
for legacy compatibility
- Use
-
Tool Generation Issues
- Ensure service metadata is accessible
- Check for valid entity sets in the metadata
- Review verbose logs for parsing errors
-
GUID/Binary Field Issues
- GUID fields are automatically converted from base64
- Binary fields may be excluded by default for performance
- Use
$select
to limit returned fields - Apply
$top
for pagination - Use
$filter
to reduce result sets - Consider excluding binary fields for large datasets
- Architecture Guide - System design and module structure
- Implementation Guide - Development patterns and guidelines
- Cookie Authentication - Detailed cookie auth documentation
Copyright (c) 2025. All rights reserved.
Project Status: Production Ready ✅
Architecture: Modular and Maintainable ✅
Version: 1.3 (Refactored)