-
Notifications
You must be signed in to change notification settings - Fork 0
Examples
This page contains practical, real-world usage examples for the matlab-mcp-server. Each example progresses from simple to advanced scenarios, with complete runnable code blocks.
Understanding how code flows through the system helps you use it effectively:
graph LR
A["AI Agent<br/>(Claude, etc)"] -->|MCP Protocol| B["FastMCP Server"]
B -->|Routes Tool Call| C["Job Executor"]
C -->|Acquire Engine| D["Engine Pool<br/>(elastic scaling)"]
D -->|Execute Code| E["MATLAB Engine"]
E -->|Results| D
D -->|Release| C
C -->|Format Output| F["Result Formatter"]
F -->|Plotly Conversion| G["Interactive Plots"]
F -->|Text/Files| H["Inline Response"]
G -->|MCP Response| A
H -->|MCP Response| A
Key observations:
- Session isolation: Each connection gets its own MATLAB workspace
- Automatic promotion: Fast code (< 30s) returns inline; slow code becomes async jobs
- Interactive plots: MATLAB figures are auto-converted to Plotly JSON
- File management: Upload, execute, retrieve results within session temp directory
What it demonstrates: Basic arithmetic, MATLAB output capture
Prerequisites: None — this runs in any MATLAB environment
% Calculate the sum of squares from 1 to 100
n = 100;
result = sum(1:n).^2;
fprintf('Sum of 1²+2²+...+%d² = %d\n', n, result);Agent prompt: "Calculate the sum of squares from 1 to 100"
Expected output:
Sum of 1²+2²+...+100² = 338350
What it demonstrates: Linear algebra, eigenvalue decomposition
Prerequisites: Core MATLAB (no toolboxes required)
% Find eigenvalues and eigenvectors of a magic square
A = magic(4);
[V, D] = eig(A);
disp('Magic 4x4 Matrix:');
disp(A);
disp('Eigenvalues:');
disp(diag(D));Agent prompt: "Create a 4x4 magic square and compute its eigenvalues"
Expected output:
Magic 4x4 Matrix:
16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1
Eigenvalues:
34.0000
8.9443
0.0000
-8.9443
What it demonstrates: Linear system solving, formatted output
Prerequisites: None
% Solve Ax = b where A is 3x3 and b is [1; 2; 3]
A = [3 1 -1; 2 -2 1; 1 1 2];
b = [1; 2; 3];
x = A \ b;
fprintf('Solution vector x:\n');
disp(x);
% Verify: compute residual
residual = norm(A*x - b);
fprintf('Residual (should be ~0): %.2e\n', residual);Agent prompt: "Solve the linear system Ax=b where A is 3 1 -1]; [2 -2 1]; [1 1 2 and b is [1; 2; 3]"
Expected output:
Solution vector x:
0.6667
0.3333
0.6667
Residual (should be ~0): 1.11e-16
What it demonstrates: Text manipulation, cell arrays
Prerequisites: None
% Work with strings and cells
names = {'Alice', 'Bob', 'Charlie'};
scores = [95, 87, 92];
for i = 1:length(names)
fprintf('%s scored %d%%\n', names{i}, scores(i));
end
% String operations
msg = "MATLAB is powerful";
fprintf('Uppercase: %s\n', upper(msg));
fprintf('Reversed: %s\n', msg(end:-1:1));Agent prompt: "Show me how to work with names and scores in MATLAB"
Expected output:
Alice scored 95%
Bob scored 87%
Charlie scored 92%
Uppercase: MATLAB IS POWERFUL
Reversed: lufecop si LBATAM
What it demonstrates: Tabular data, table arrays
Prerequisites: None
% Create and manipulate a table
T = table({'Alice'; 'Bob'; 'Charlie'}, [25; 30; 28], ...
'VariableNames', {'Name', 'Age'});
disp(T);
fprintf('\nAverage age: %.1f\n', mean(T.Age));
fprintf('Oldest person: %s (age %d)\n', ...
T.Name{T.Age == max(T.Age)}, max(T.Age));Agent prompt: "Create a table with names and ages, then find the oldest person"
Expected output:
Name Age
____ ___
Alice 25
Bob 30
Charlie 28
Average age: 27.7
Oldest person: Bob (age 30)
What it demonstrates: 2D line plots, axis labels, legend, interactive Plotly conversion
Prerequisites: None
% Plot three sine waves with different frequencies
x = linspace(0, 2*pi, 300);
f1 = sin(x);
f2 = sin(2*x);
f3 = sin(0.5*x);
plot(x, f1, 'b-', 'LineWidth', 2, 'DisplayName', 'sin(x)');
hold on;
plot(x, f2, 'r--', 'LineWidth', 2, 'DisplayName', 'sin(2x)');
plot(x, f3, 'g:', 'LineWidth', 2.5, 'DisplayName', 'sin(0.5x)');
hold off;
xlabel('Angle (radians)');
ylabel('Amplitude');
title('Sine Waves at Different Frequencies');
legend('Location', 'northeast');
grid on;Agent prompt: "Plot three sine waves: sin(x), sin(2x), and sin(0.5x) from 0 to 2π with different colors and line styles"
Expected output: Interactive Plotly chart with:
- Three colored lines (blue solid, red dashed, green dotted)
- Interactive legend (click to toggle traces)
- Hover tooltips showing (x, y) coordinates
- Zoom and pan controls
What it demonstrates: 3D visualization, color mapping, Plotly conversion
Prerequisites: None
% Create and plot a 3D surface
[X, Y] = meshgrid(-5:0.2:5, -5:0.2:5);
Z = sin(sqrt(X.^2 + Y.^2)) ./ (sqrt(X.^2 + Y.^2) + 0.1);
surf(X, Y, Z, 'EdgeColor', 'none');
colormap('cool');
colorbar;
xlabel('X');
ylabel('Y');
zlabel('Z');
title('3D Surface: sin(r)/r');Agent prompt: "Create a 3D surface plot of sin(r)/r where r = sqrt(x² + y²)"
Expected output: Interactive 3D Plotly surface with:
- Color-mapped surface (cool colormap)
- Colorbar legend
- Rotatable 3D view
- Hover values at each point
What it demonstrates: Multiple subplot layout, different plot types
Prerequisites: None
x = linspace(0, 10, 100);
% Subplot 1: Line plot
subplot(2, 2, 1);
plot(x, sin(x), 'b-', 'LineWidth', 2);
title('Sine Wave');
xlabel('x'); ylabel('sin(x)');
grid on;
% Subplot 2: Bar chart
subplot(2, 2, 2);
categories = {'A', 'B', 'C', 'D'};
values = [10, 24, 36, 18];
bar(categories, values, 'FaceColor', [0.2 0.6 0.8]);
title('Bar Chart');
ylabel('Values');
% Subplot 3: Scatter plot
subplot(2, 2, 3);
scatter(randn(100,1), randn(100,1), 50, 'r', 'filled');
title('Scatter Plot');
xlabel('X'); ylabel('Y');
grid on;
% Subplot 4: Histogram
subplot(2, 2, 4);
data = randn(1000, 1);
histogram(data, 30, 'EdgeColor', 'k');
title('Histogram');
xlabel('Value'); ylabel('Frequency');Agent prompt: "Create a 2×2 subplot grid with a line plot, bar chart, scatter plot, and histogram"
Expected output: Four-panel Plotly figure with proper axis domains and shared container
What it demonstrates: Statistical visualization, customized appearance
Prerequisites: Statistics & Machine Learning Toolbox (optional for mean/std)
% Generate random data and plot histogram
rng(42); % Reproducible results
data = normrnd(100, 15, 1000, 1);
histogram(data, 50, 'Normalization', 'pdf', ...
'EdgeColor', 'black', 'FaceColor', [0.7 0.7 0.9]);
hold on;
% Overlay normal distribution
mu = mean(data);
sigma = std(data);
x = linspace(mu - 4*sigma, mu + 4*sigma, 200);
y = normpdf(x, mu, sigma);
plot(x, y, 'r-', 'LineWidth', 2.5);
hold off;
xlabel('Value');
ylabel('Probability Density');
title(sprintf('Histogram with Normal Distribution (μ=%.1f, σ=%.1f)', mu, sigma));
legend('Data', 'Normal Fit');
grid on;Agent prompt: "Create a histogram of 1000 random values from a normal distribution with mean 100 and std 15, overlaid with the theoretical normal curve"
Expected output: Histogram with overlaid normal distribution curve, statistics in title
What it demonstrates: Signal processing, FFT, frequency domain, multi-panel plotting
Prerequisites: Signal Processing Toolbox (optional; core functions work without it)
% Generate a signal with multiple frequency components
fs = 1000; % Sampling rate (Hz)
t = 0:1/fs:1; % 1 second of data
f1 = 50; % 50 Hz component
f2 = 120; % 120 Hz component
signal = sin(2*pi*f1*t) + 0.5*sin(2*pi*f2*t) + 0.1*randn(size(t));
% Compute FFT
N = length(signal);
Y = fft(signal);
freqs = (0:N-1) * fs / N;
% Plot time and frequency domains
subplot(2, 1, 1);
plot(t, signal, 'b-', 'LineWidth', 1);
xlabel('Time (s)');
ylabel('Amplitude');
title('Time Domain Signal');
grid on;
subplot(2, 1, 2);
plot(freqs(1:N/2), abs(Y(1:N/2))/N, 'r-', 'LineWidth', 2);
xlabel('Frequency (Hz)');
ylabel('Magnitude');
title('Frequency Domain (FFT)');
xlim([0 300]);
grid on;Agent prompt: "Create a signal with 50 Hz and 120 Hz components, then show both time and frequency domain plots"
Expected output: Two-panel figure showing:
- Time domain: oscillating waveform
- Frequency domain: two peaks at 50 Hz and 120 Hz
What it demonstrates: Signal filtering, frequency response, before/after comparison
Prerequisites: Signal Processing Toolbox
% Design a low-pass Butterworth filter
fs = 1000;
cutoff_freq = 100; % Hz
[b, a] = butter(4, cutoff_freq/(fs/2));
% Generate noisy signal
t = 0:1/fs:2;
clean_signal = sin(2*pi*50*t);
noise = 0.5*randn(size(t));
noisy_signal = clean_signal + noise;
% Apply filter
filtered_signal = filtfilt(b, a, noisy_signal);
% Plot results
subplot(3, 1, 1);
plot(t(1:500), noisy_signal(1:500), 'b-', 'LineWidth', 1);
title('Noisy Signal (50 Hz + noise)');
ylabel('Amplitude');
grid on;
subplot(3, 1, 2);
plot(t(1:500), filtered_signal(1:500), 'g-', 'LineWidth', 2);
title('Filtered Signal (Low-Pass, 100 Hz cutoff)');
ylabel('Amplitude');
grid on;
subplot(3, 1, 3);
plot(t(1:500), clean_signal(1:500), 'r--', 'LineWidth', 2);
title('Original Clean Signal (reference)');
ylabel('Amplitude');
xlabel('Time (s)');
grid on;Agent prompt: "Design a 4th-order Butterworth low-pass filter with 100 Hz cutoff, apply it to a noisy 50 Hz signal, and show before/after/original"
Expected output: Three-panel figure with noisy, filtered, and clean signals
Jobs exceeding sync_timeout (default 30s) are automatically promoted to async execution. Report progress with the built-in mcp_progress() helper.
What it demonstrates: Long-running async job, progress reporting, random sampling
Prerequisites: None
% Estimate π using Monte Carlo method
% This will auto-promote to async if it takes > 30 seconds
rng(42); % Reproducible results
n_trials = 5e6; % 5 million trials
inside_circle = 0;
% Update progress every 500k trials
for i = 1:n_trials
x = rand();
y = rand();
if x^2 + y^2 <= 1
inside_circle = inside_circle + 1;
end
% Report progress every 500k iterations
if mod(i, 5e5) == 0
progress_pct = (i / n_trials) * 100;
msg = sprintf('Trial %d / %d (%.1f%%)', i, n_trials, progress_pct);
mcp_progress(__mcp_job_id__, progress_pct, msg);
end
end
% Final result
pi_estimate = 4 * inside_circle / n_trials;
fprintf('Estimated π: %.6f (actual: %.6f, error: %.6f%%)\n', ...
pi_estimate, pi, abs(pi_estimate - pi)/pi * 100);Agent prompt: "Estimate π using a Monte Carlo simulation with 5 million random points and report progress every 500,000 trials"
Agent experience:
- Agent calls
execute_codewith the above code - Server returns immediately with
job_id: "job-xyz123"and statusrunning - Agent polls
get_job_status("job-xyz123")periodically:- After 10s:
progress: 10%, message: "Trial 500000/5000000" - After 20s:
progress: 20%, message: "Trial 1000000/5000000" - ...
- After 10s:
- After ~60s:
status: "completed", full result returned
Expected final output:
Estimated π: 3.141627 (actual: 3.141593, error: 0.001%)
What it demonstrates: Heavy computation, timeout handling, decomposition
Prerequisites: None
% Compute SVD of a large random matrix
fprintf('Creating 5000x5000 random matrix...\n');
A = randn(5000, 5000);
fprintf('Computing SVD (this may take 30+ seconds)...\n');
[U, S, V] = svd(A);
% Get singular values
singular_vals = diag(S);
fprintf('SVD complete.\n');
fprintf('Matrix size: %d x %d\n', size(A, 1), size(A, 2));
fprintf('Rank estimate (singular values > 1e-10): %d\n', sum(singular_vals > 1e-10));
fprintf('Condition number: %.2e\n', singular_vals(1) / singular_vals(end));
% Plot singular value decay
loglog(1:min(100, length(singular_vals)), singular_vals(1:min(100, length(singular_vals))), 'b.-');
xlabel('Index');
ylabel('Singular Value (log scale)');
title('Singular Value Spectrum (first 100)');
grid on;Agent prompt: "Compute the SVD of a 5000×5000 random matrix and show the singular value spectrum"
Expected behavior:
- Code takes ~40 seconds
- Auto-promotes to async after ~30 seconds
- Returns job ID immediately
- Agent polls for completion
- Final result includes SVD computation stats and plot
What it demonstrates: Iterative algorithm, intermediate progress updates
Prerequisites: None
% Solve Ax = b using conjugate gradient-like iteration (simplified)
n = 1000;
A = diag(100:100+n-1); % Diagonal matrix with eigenvalues 100..1099
b = randn(n, 1);
x = zeros(n, 1); % Initial guess
r = b - A*x;
p = r;
rsold = r' * r;
max_iter = 500;
tolerance = 1e-6;
for i = 1:max_iter
Ap = A * p;
alpha = rsold / (p' * Ap);
x = x + alpha * p;
r = r - alpha * Ap;
rsnew = r' * r;
% Report progress
if mod(i, 50) == 0 || i == 1
residual = sqrt(rsnew);
progress_pct = (i / max_iter) * 100;
msg = sprintf('Iteration %d: residual = %.2e', i, residual);
mcp_progress(__mcp_job_id__, progress_pct, msg);
end
if rsnew < tolerance^2
fprintf('Converged in %d iterations\n', i);
break;
end
beta = rsnew / rsold;
p = r + beta * p;
rsold = rsnew;
end
fprintf('Final residual: %.2e\n', sqrt(rsnew));
fprintf('Solution norm: %.2f\n', norm(x));Agent prompt: "Solve a large system of linear equations using an iterative solver, reporting progress every 50 iterations"
Expected output:
Iteration 50: residual = 1.23e-04
Iteration 100: residual = 2.45e-06
...
Converged in 147 iterations
Final residual: 9.87e-07
Solution norm: 3.45
What it demonstrates: File upload, data reading, processing
Prerequisites: None
% Assume agent uploaded a CSV file named 'data.csv'
% Read it back from the session temp directory
data_file = fullfile(__mcp_temp_dir__, 'data.csv');
fprintf('Reading data from: %s\n', data_file);
% Read CSV (simple tab/comma-separated)
data = readmatrix(data_file);
fprintf('Data shape: %d rows × %d columns\n', size(data, 1), size(data, 2));
% Compute statistics
fprintf('Column means: %s\n', mat2str(mean(data), 3));
fprintf('Column stds: %s\n', mat2str(std(data), 3));
fprintf('Min values: %s\n', mat2str(min(data), 3));
fprintf('Max values: %s\n', mat2str(max(data), 3));
% Generate a plot
boxplot(data);
xlabel('Column');
ylabel('Value');
title('Data Distribution by Column');Agent workflow:
- Upload CSV file:
upload_data("data.csv", base64_content) - Execute the MATLAB code above
- Read output stats and generated plot
- Agent can retrieve saved images with
read_image()
What it demonstrates: Writing files, saving figures, data retrieval
Prerequisites: None
% Generate results and save to session temp directory
results_dir = __mcp_temp_dir__;
% Create synthetic data
x = linspace(0, 10, 100);
y = sin(x) + 0.1*randn(size(x));
% Save as CSV
csv_file = fullfile(results_dir, 'analysis_results.csv');
writematrix([x' y'], csv_file);
fprintf('Saved CSV: %s\n', csv_file);
% Save as MAT file
mat_file = fullfile(results_dir, 'analysis_results.mat');
save(mat_file, 'x', 'y');
fprintf('Saved MAT: %s\n', mat_file);
% Create and save a figure
plot(x, y, 'b.', 'MarkerSize', 8);
hold on;
plot(x, sin(x), 'r-', 'LineWidth', 2);
hold off;
xlabel('x'); ylabel('y');
title('Data vs Fit');
legend('Noisy Data', 'True Curve');
grid on;
fig_file = fullfile(results_dir, 'analysis_plot.png');
saveas(gcf, fig_file);
fprintf('Saved figure: %s\n', fig_file);
% List all files in temp directory
files = dir(results_dir);
fprintf('\nFiles in temp directory:\n');
for i = 1:length(files)
if ~files(i).isdir
fprintf(' - %s (%d bytes)\n', files(i).name, files(i).bytes);
end
endAgent workflow:
- Execute code above
- Server returns list of files created
- Agent retrieves CSV:
read_data("analysis_results.csv") - Agent retrieves plot:
read_image("analysis_plot.png") - Agent retrieves MAT summary:
read_data("analysis_results.mat", format="summary")
What it demonstrates: Script generation, syntax, readability
Prerequisites: None
% Generate a reusable MATLAB script dynamically
script_dir = __mcp_temp_dir__;
script_file = fullfile(script_dir, 'auto_generated_analysis.m');
% Build script content
script_content = [
"% Auto-generated analysis script\n"
"% Generated by MATLAB MCP Server\n\n"
"function results = auto_generated_analysis(input_data)\n"
" %% Compute statistics\n"
" results.mean = mean(input_data);\n"
" results.std = std(input_data);\n"
" results.median = median(input_data);\n"
" results.iqr = iqr(input_data);\n"
" \n"
" %% Create visualization\n"
" figure('Visible', 'off');\n"
" histogram(input_data, 30);\n"
" title('Distribution of Input Data');\n"
" xlabel('Value');\n"
" ylabel('Frequency');\n"
" \n"
" print(gcf, '-dpng', 'distribution.png');\n"
" close(gcf);\n"
"end\n"
];
% Write script
fid = fopen(script_file, 'w');
fprintf(fid, script_content);
fclose(fid);
fprintf('Generated script: %s\n', script_file);
fprintf('Script size: %d bytes\n', numel(script_content));Agent can then retrieve: read_script("auto_generated_analysis.m")
File: config.yaml
server:
transport: "stdio"
log_level: "info"
pool:
min_engines: 1
max_engines: 2
execution:
sync_timeout: 30
max_execution_time: 600
sessions:
max_sessions: 1
security:
blocked_functions_enabled: trueUse case: Local agent testing, single MATLAB license
File: config.yaml
server:
transport: "sse"
host: "127.0.0.1" # Bind to localhost only; expose via reverse proxy
port: 8765
log_level: "info"
pool:
min_engines: 4
max_engines: 16
scale_down_idle_timeout: 600
health_check_interval: 30
execution:
sync_timeout: 30
max_execution_time: 3600
temp_dir: "/var/matlab-mcp/temp"
sessions:
max_sessions: 50
session_timeout: 3600
job_retention_seconds: 86400
security:
blocked_functions_enabled: true
require_proxy_auth: true
max_upload_size_mb: 500
output:
plotly_conversion: true
thumbnail_enabled: true
monitoring:
enabled: true
sample_interval: 10
dashboard_enabled: true
http_port: 8766Use case: Shared server serving multiple concurrent AI agents behind reverse proxy (nginx)
File: config.yaml
pool:
min_engines: 8
max_engines: 32
scale_down_idle_timeout: 300
health_check_interval: 15
proactive_warmup_threshold: 0.7
queue_max_size: 200
execution:
sync_timeout: 60
max_execution_time: 7200
workspace_isolation: true
engine_affinity: true
sessions:
max_sessions: 200
monitoring:
enabled: true
sample_interval: 5
retention_days: 14Use case: High-throughput production workloads
sequenceDiagram
participant A as AI Agent
participant S as Server
participant J as Job Executor
participant P as Engine Pool
participant E as MATLAB Engine
A->>S: execute_code(code)
activate S
S->>S: Validate security
S->>J: Create job
J->>P: Acquire engine
activate P
P->>E: (get or start)
activate E
P-->>J: Engine handle
deactivate P
J->>E: eval(code, stdout)
E-->>J: Results
deactivate E
J->>J: Format output
deactivate S
J-->>S: Result dict
S-->>A: MCP response
P->>E: Release engine
Note over P: Engine returns to IDLE pool
| Tool | Input | Output | Notes |
|---|---|---|---|
execute_code(code) |
MATLAB string | Job ID or inline result | Auto-async if > 30s |
check_code(code) |
MATLAB string | Linting issues | Static analysis |
get_workspace() |
— | Variable list | Current session only |
get_job_status(job_id) |
Job ID | Status, progress | Poll for updates |
upload_data(filename, content_base64) |
File + data | Path, size | Max 100 MB default |
read_data(filename, format) |
Filename | Content or summary |
.mat, .csv, .xlsx
|
read_image(filename) |
Image file | Image content |
.png, .jpg, .gif
|
list_files() |
— | Directory contents | Session temp dir |
get_pool_status() |
— | Pool metrics | Engines, utilization |
get_server_health() |
— | Health status | Healthy / degraded / unhealthy |
% This will be REJECTED with BlockedFunctionError:
system('ls -la')Agent message: "Blocked function: system() is not allowed. Use MATLAB alternatives like dir() for directory listing."
Workaround:
% Use MATLAB functions instead
files = dir('.');
disp({files.name}')% This will auto-promote to async (takes ~45 seconds):
tic
pause(45)
tocAgent experience:
- Receives
job_id: "job-abc"with statusrunning - Polls
get_job_status("job-abc")until completion - Once done, calls
get_job_result("job-abc")for full output
% Generate very large output (won't all be returned inline)
big_data = randn(10000, 10000);
disp(big_data); % Would be huge!Server behavior:
- Captures output
- Detects truncation needed (> 50KB)
- Saves to file in temp directory
- Returns
output_saved: "output_large.txt"in response - Agent can retrieve with
read_data("output_large.txt")
This Examples page provides progressions from basic to advanced scenarios. For more help, refer to the Configuration Guide, Async Jobs, and Custom Tools sections.