Initial commit

This commit is contained in:
Zhongwei Li
2025-11-30 08:49:50 +08:00
commit adc4b2be25
147 changed files with 24716 additions and 0 deletions

View File

@@ -0,0 +1,58 @@
# Python Endpoints Demo
This example demonstrates how to create and use Python-based endpoints in MXCP.
## Features Demonstrated
### 1. Basic Python Functions
- `analyze_numbers` - Statistical analysis with various operations
- `create_sample_data` - Database operations from Python
### 2. Async Functions
- `process_time_series` - Demonstrates async Python endpoint
### 3. Database Access
- Using `mxcp.runtime.db` to execute SQL queries
- Parameter binding for safe SQL execution
## Running the Examples
In a terminal, test the endpoints:
```bash
# Create sample data
mxcp run tool create_sample_data --param table_name=test_data --param row_count=100
# Analyze numbers
mxcp run tool analyze_numbers --param numbers="[1, 2, 3, 4, 5]" --param operation=mean
# Process time series (async function)
mxcp run tool process_time_series --param table_name=test_data --param window_days=7
```
Or, if you prefer, you can also start the MXCP server and use any MCP client to call the tools:
```bash
mxcp serve
```
## Project Structure
```
python-demo/
├── mxcp-site.yml # Project configuration
├── python/ # Python modules
│ └── data_analysis.py # Python endpoint implementations
├── tools/ # Tool definitions
│ ├── analyze_numbers.yml
│ ├── create_sample_data.yml
│ └── process_time_series.yml
└── README.md
```
## Key Concepts
1. **Language Declaration**: Set `language: python` in the tool definition
2. **Function Names**: The function name must match the tool name
3. **Return Types**: Functions must return data matching the declared return type
4. **Database Access**: Use `db.execute()` for SQL queries
5. **Async Support**: Both sync and async functions are supported

View File

@@ -0,0 +1,3 @@
mxcp: 1
project: python-demo
profile: default

View File

@@ -0,0 +1,145 @@
"""
Example Python endpoints for data analysis.
"""
import statistics
from datetime import datetime, timedelta
from mxcp.runtime import config, db
def analyze_numbers(numbers: list, operation: str = "mean") -> dict:
"""
Analyze a list of numbers with various statistical operations.
"""
if not numbers:
return {"error": "No numbers provided"}
operations = {
"mean": statistics.mean,
"median": statistics.median,
"mode": statistics.mode,
"stdev": statistics.stdev if len(numbers) > 1 else lambda x: 0,
"sum": sum,
"min": min,
"max": max,
}
if operation not in operations:
return {"error": f"Unknown operation: {operation}"}
try:
result = operations[operation](numbers)
return {"operation": operation, "result": result, "count": len(numbers)}
except Exception as e:
return {"error": str(e)}
def create_sample_data(table_name: str, row_count: int) -> dict:
"""
Create a sample table with test data.
"""
try:
# Drop table if exists
db.execute(f"DROP TABLE IF EXISTS {table_name}")
# Create table
db.execute(
f"""
CREATE TABLE {table_name} (
id INTEGER PRIMARY KEY,
name VARCHAR,
value DOUBLE,
category VARCHAR,
created_at TIMESTAMP
)
"""
)
# Insert sample data
for i in range(row_count):
db.execute(
f"""
INSERT INTO {table_name} (id, name, value, category, created_at)
VALUES (
$id,
'Item ' || $item_num,
ROUND(RANDOM() * 1000, 2),
CASE
WHEN RANDOM() < 0.33 THEN 'A'
WHEN RANDOM() < 0.66 THEN 'B'
ELSE 'C'
END,
CURRENT_TIMESTAMP - INTERVAL ($days || ' days')
)
""",
{"id": i + 1, "item_num": i + 1, "days": i % 30},
)
return {"status": "success", "table": table_name, "rows_created": row_count}
except Exception as e:
return {"status": "error", "error": str(e)}
def aggregate_by_category(table_name: str) -> list:
"""
Aggregate data by category from a table.
"""
try:
results = db.execute(
f"""
SELECT
category,
COUNT(*) as count,
ROUND(AVG(value), 2) as avg_value,
ROUND(SUM(value), 2) as total_value,
MIN(value) as min_value,
MAX(value) as max_value
FROM {table_name}
GROUP BY category
ORDER BY category
"""
)
return results
except Exception as e:
return [{"error": str(e)}]
async def process_time_series(table_name: str, window_days: int = 7) -> list:
"""
Async function to process time series data with rolling windows.
"""
import asyncio
# Simulate some async processing
await asyncio.sleep(0.1)
results = db.execute(
f"""
WITH daily_data AS (
SELECT
DATE_TRUNC('day', created_at) as date,
category,
COUNT(*) as daily_count,
ROUND(AVG(value), 2) as daily_avg
FROM {table_name}
GROUP BY DATE_TRUNC('day', created_at), category
)
SELECT
date,
category,
daily_count,
daily_avg,
ROUND(AVG(daily_avg) OVER (
PARTITION BY category
ORDER BY date
ROWS BETWEEN {window_days - 1} PRECEDING AND CURRENT ROW
), 2) as rolling_avg
FROM daily_data
ORDER BY date DESC, category
LIMIT 50
"""
)
return results

View File

@@ -0,0 +1,16 @@
"""Example showing Python endpoints can return primitive arrays."""
def show_primitive_arrays() -> list:
"""Return Fibonacci sequence as array of numbers."""
return [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
def get_languages() -> list:
"""Return list of programming languages."""
return ["Python", "JavaScript", "Go", "Rust", "TypeScript"]
def get_pi_digits() -> list:
"""Return digits of pi."""
return [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9]

View File

@@ -0,0 +1,28 @@
mxcp: 1
tool:
name: aggregate_by_category
description: Aggregate data by category with statistics
language: python
source:
file: ../python/data_analysis.py
parameters:
- name: table_name
type: string
description: Name of the table to aggregate
return:
type: array
items:
type: object
properties:
category:
type: string
count:
type: integer
avg_value:
type: number
total_value:
type: number
min_value:
type: number
max_value:
type: number

View File

@@ -0,0 +1,27 @@
mxcp: 1
tool:
name: analyze_numbers
description: Analyze a list of numbers with statistical operations
language: python
source:
file: ../python/data_analysis.py
parameters:
- name: numbers
type: array
items:
type: number
description: List of numbers to analyze
- name: operation
type: string
enum: ["mean", "median", "mode", "stdev", "sum", "min", "max"]
default: "mean"
description: Statistical operation to perform
return:
type: object
properties:
operation:
type: string
result:
type: number
count:
type: integer

View File

@@ -0,0 +1,25 @@
mxcp: 1
tool:
name: create_sample_data
description: Create a sample table with test data
language: python
source:
file: ../python/data_analysis.py
parameters:
- name: table_name
type: string
description: Name of the table to create
- name: row_count
type: integer
description: Number of rows to generate
minimum: 1
maximum: 10000
return:
type: object
properties:
status:
type: string
table:
type: string
rows_created:
type: integer

View File

@@ -0,0 +1,21 @@
mxcp: 1
tool:
name: process_time_series
description: Process time series data with rolling window calculations (async)
language: python
source:
file: ../python/data_analysis.py
parameters:
- name: table_name
type: string
description: Name of the table containing time series data
- name: window_days
type: integer
default: 7
description: Size of the rolling window in days
minimum: 1
maximum: 365
return:
type: array
items:
type: object