The financial benchmark service was stress-tested with real market data from the COVID-19 crash period (February-April 2020), when markets experienced:
Data was fetched live from FIS TimeSeries for 5 tickers (MSFT.O, AAPL.O, AMZN.O, JPM.N, JNJ.N), 62 trading days. The covariance matrix was computed from 61 daily log returns and annualized (×252).
| Test | Input | Result |
|---|---|---|
| Pandemic portfolio variance | 5 assets, real 2020 covariance | SUCCESS, portfolio vol=61.2%, 0 μs |
| Pandemic Monte Carlo 1M sims | vol=89.6%, return=-20% | SUCCESS, no Inf/NaN, 88K sims/sec |
| Extreme Monte Carlo 1M sims | vol=80%, return=-50% | SUCCESS, no Inf/NaN |
| 500-asset portfolio | 250K matrix operations | SUCCESS, 273 μs |
| 1000-asset portfolio | 1M operations, 8 MB payload | SUCCESS, 950 μs, 148 MB RSS |
| Zero volatility MC | vol=0.0 (deterministic) | SUCCESS |
| 200% volatility MC | vol=2.0 (extreme) | SUCCESS, no Inf/NaN |
| 1 simulation MC | Minimum input | SUCCESS |
| Malformed/empty JSON | Edge cases | Clean error messages, no crash |
| 20 concurrent requests | Parallel pandemic PV | All HTTP 200 |
| 500 sequential requests | Memory leak check | No RSS growth |
| Rapid-fire 100 requests | Sequential pandemic PV | All HTTP 200 |
| MCP stdio extreme | vol=80%, return=-50%, 100K sims | SUCCESS via stdio |
| Apache health post-stress | After all tests | Active, no crash |
Zero crashes. Zero Inf/NaN. Zero memory leaks. Tested on Ubuntu 22.04, Apache httpd with mod_axis2, HTTPS/HTTP2, 64 GB RAM.
The same test payloads can be run against Axis2/Java for identical financial results (different performance — see the performance comparison below).
Portfolio variance payloads grow as O(n²) — the covariance matrix dominates:
| Assets | Covariance elements | JSON payload | HTTP limit (50 MB) |
|---|---|---|---|
| 500 | 250,000 | ~6 MB | ✅ |
| 700 | 490,000 | ~11 MB | ✅ |
| 1000 | 1,000,000 | ~22 MB | ✅ |
| 1500 | 2,250,000 | ~50 MB | ✅ (borderline) |
| 2000 | 4,000,000 | ~89 MB | ❌ exceeds limit |
Monte Carlo and scenario analysis requests are always small (~200 bytes) regardless of simulation count — all computation happens server-side.
MCP stdio transport has no payload size limit (line-buffered I/O). The FINBENCH_MAX_ASSETS=2000 code cap is reachable via MCP but not via HTTP for portfolio variance due to the quadratic payload growth.
Summary: Apache Axis2/C serves financial calculations — portfolio variance, Monte Carlo VaR, scenario analysis — over HTTP/2 JSON and MCP (Model Context Protocol). An AI agent asks a question in natural language. The MCP server dispatches to native C computation. The answer comes back in microseconds, not seconds. This document shows what that looks like and why it matters.
A companion document (MCP_EXAMPLES.md in the Axis2/Java repo) runs the same demos against the Java implementation with head-to-head performance numbers. The financial results are identical — only performance differs.
Both Axis2/C and Axis2/Java support HTTPS/HTTP2. Axis2/C runs over Apache httpd with mod_h2; Axis2/Java runs over WildFly or Tomcat with ALPN-negotiated HTTP/2 on port 8443 (verified on WildFly 32, WildFly 39, and Tomcat 11).
All timings use the server-reported calc_time_us / calcTimeUs field — wall-clock time measured inside the service handler. Transport overhead (TLS, HTTP/2 framing) is excluded.
MCP lets an AI assistant (Claude, or any MCP client) call your financial services as tools. Instead of writing Python scripts, switching to terminals, or copy-pasting between spreadsheets and chat windows, the analyst says:
“What's the portfolio variance for my 500-asset book?”
The AI calls portfolioVariance via MCP, gets the answer in 269 microseconds, and explains the result in context. No code. No context-switching.
Three MCP methods handle everything:
initialize — handshake (protocol version, capabilities)tools/list — what calculations are available and their input schemastools/call — run a specific calculation with argumentsThe wire protocol is JSON-RPC 2.0 over stdio (subprocess-based MCP clients) or HTTP/SSE (persistent server). Axis2/C implements stdio today; HTTP/SSE is planned.
The same calculation that production portfolio management systems use for risk decomposition. For n assets, this is n^2 multiply-accumulate operations on the covariance matrix weighted by position sizes.
HTTP/2 JSON (curl):
curl -k --http2 -s \ -H "Content-Type: application/json" \ -d '{ "n_assets": 3, "weights": [0.4, 0.3, 0.3], "covariance_matrix": [ 0.04, 0.006, 0.002, 0.006, 0.09, 0.009, 0.002, 0.009, 0.01 ] }' \ https://10.10.10.10/services/FinancialBenchmarkService/portfolioVariance
Response:
{ "status": "SUCCESS", "portfolio_variance": 0.01894, "portfolio_volatility": 0.1376, "annualized_volatility": 2.1847, "calc_time_us": 0, "matrix_operations": 9, "ops_per_second": 929368029.7 }
(calc_time_us: 0 = sub-microsecond; ops_per_second is raw matrix multiply-accumulate throughput — the 929M figure comes from the 500-asset benchmark below, not this 3-asset example.)
MCP stdio (subprocess-based MCP client):
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"portfolioVariance","arguments":{"n_assets":3,"weights":[0.4,0.3,0.3],"covariance_matrix":[0.04,0.006,0.002,0.006,0.09,0.009,0.002,0.009,0.01]}}}' \ | /usr/local/axis2c/bin/financial-benchmark-mcp
MCP Response:
{ "jsonrpc": "2.0", "id": 1, "result": { "content": [{ "type": "text", "text": "{\"status\":\"SUCCESS\",\"portfolio_variance\":0.01894,\"portfolio_volatility\":0.1376, ...}" }] } }
(Response truncated for brevity — full response includes all fields from the HTTP/2 example above.)
At scale (500 assets = 250,000 matrix operations):
| Metric | Result |
|---|---|
| Calculation time | 269 microseconds |
| Operations per second | 929 million |
| Memory | 48 MB total process |
For context: a production portfolio system calculating correlations across 500 assets performs the same O(n^2) matrix multiplication. Enterprise Java runtimes typically require multi-GB heap allocations and several seconds of JVM startup. Axis2/C does it in 269 microseconds with 48 MB peak process memory (RSS under load).
Monte Carlo VaR is the standard approach for estimating portfolio loss at a given confidence level when closed-form solutions don't apply (fat tails, path-dependent instruments, non-linear positions). Each simulation traces a price path using:
S(t+dt) = S(t) * exp((mu - sigma^2/2)*dt + sigma*sqrt(dt)*Z)
where Z ~ N(0,1). Run 10,000 paths, sort the terminal values, read off the 5th percentile loss — that's your 95% VaR.
Production risk systems run this nightly for regulatory capital calculations. The constraint is always compute time: more simulations = tighter confidence intervals, but each simulation is a tight numerical loop.
HTTP/2 JSON:
curl -k --http2 -s \ -H "Content-Type: application/json" \ -d '{ "n_simulations": 10000, "n_periods": 252, "initial_value": 1000000, "expected_return": 0.08, "volatility": 0.20 }' \ https://10.10.10.10/services/FinancialBenchmarkService/monteCarlo
Response:
{ "status": "SUCCESS", "mean_final_value": 1084565.11, "median_final_value": 1062616.86, "std_dev_final_value": 218092.01, "var_95": 230403.21, "var_99": 323967.63, "cvar_95": 287680.36, "max_drawdown": 0.4899, "prob_profit": 0.62, "calc_time_us": 109617, "simulations_per_second": 91226.73, "percentile_vars": [ {"percentile": 0.01, "var": 323967.63}, {"percentile": 0.05, "var": 230403.21} ] }
MCP stdio:
echo '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"monteCarlo","arguments":{"n_simulations":10000,"n_periods":252,"initial_value":1000000,"expected_return":0.08,"volatility":0.20}}}' \ | /usr/local/axis2c/bin/financial-benchmark-mcp
Performance scaling:
| Simulations | Periods | Time | Throughput |
|---|---|---|---|
| 10,000 | 252 | 110 ms | 91K sims/sec |
| 100,000 | 252 | 1.08 sec | 92K sims/sec |
Linear scaling — the throughput stays constant as you add simulations. A nightly risk run that needs 1 million simulations across 10 portfolios finishes in about 2 minutes on a single core of modest hardware. The same calculation on an interpreted runtime would typically take significantly longer due to JIT warmup, garbage collection pauses, and floating-point overhead before the optimizer kicks in.
Monte Carlo is specifically identified as a future compute-intensive feature in production optimization roadmaps. The question is always: “where do we run it?” The answer with Axis2/C is: on the same hardware that already serves your API, in the same process, with no additional infrastructure.
Portfolio managers construct scenarios: bull case (price goes to X with probability P1), base case (Y, P2), bear case (Z, P3). The expected return is the probability-weighted sum. This is the daily workflow for fundamental analysts — every position has scenario prices and probabilities.
The interesting part is the lookup benchmark. Production systems with 500+ assets iterate over asset lists using O(n) linear search for every lookup. Replacing that with an O(1) hash table is the single most impactful algorithmic optimization available. This service measures both and shows the speedup.
HTTP/2 JSON:
curl -k --http2 -s \ -H "Content-Type: application/json" \ -d '{ "n_assets": 3, "assets": [ { "asset_id": 1, "current_price": 150.00, "position_size": 100, "scenario_prices": [165.0, 157.5, 150.0, 142.5, 135.0], "probabilities": [0.15, 0.25, 0.30, 0.20, 0.10] }, { "asset_id": 2, "current_price": 75.00, "position_size": 200, "scenario_prices": [82.5, 78.75, 75.0, 71.25, 67.5], "probabilities": [0.15, 0.25, 0.30, 0.20, 0.10] }, { "asset_id": 3, "current_price": 200.00, "position_size": 50, "scenario_prices": [220.0, 210.0, 200.0, 190.0, 180.0], "probabilities": [0.15, 0.25, 0.30, 0.20, 0.10] } ], "use_hash_lookup": true }' \ https://10.10.10.10/services/FinancialBenchmarkService/scenarioAnalysis
Response:
{ "status": "SUCCESS", "expected_return": 0.0, "weighted_value": 0.0, "upside_potential": 0.0, "downside_risk": 0.0, "calc_time_us": 1, "lookups_performed": 30, "lookups_per_second": 30000000.0, "lookup_benchmark": "linear_search_us=1 hash_lookup_us=4 ... n_assets=3 n_lookups=30" }
MCP stdio:
echo '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"scenarioAnalysis","arguments":{"n_assets":3,"assets":[{"asset_id":1,"current_price":150.0,"position_size":100,"scenario_prices":[165.0,157.5,150.0,142.5,135.0],"probabilities":[0.15,0.25,0.30,0.20,0.10]},{"asset_id":2,"current_price":75.0,"position_size":200,"scenario_prices":[82.5,78.75,75.0,71.25,67.5],"probabilities":[0.15,0.25,0.30,0.20,0.10]},{"asset_id":3,"current_price":200.0,"position_size":50,"scenario_prices":[220.0,210.0,200.0,190.0,180.0],"probabilities":[0.15,0.25,0.30,0.20,0.10]}],"use_hash_lookup":true}}}' \ | /usr/local/axis2c/bin/financial-benchmark-mcp
At 3 assets the O(n) vs O(1) difference is negligible. At 500+ assets with repeated lookups, hash tables dominate — the same optimization that turns 10-second page loads into sub-second responses in production.
curl -k --http2 -s \ -H "Content-Type: application/json" \ -d '{}' \ https://10.10.10.10/services/FinancialBenchmarkService/metadata
{ "service_name": "FinancialBenchmarkService", "version": "1.0.0", "operations": [ "portfolioVariance", "monteCarlo", "scenarioAnalysis", "metadata" ], "max_assets": 2000, "max_simulations": 1000000, "device_info": "Linux (RAM: 64301 MB, Axis2/C 2.0 HTTP/2 JSON)", "current_memory_kb": 15308 }
Creates a synthetic equal-weighted portfolio with a positive-semi-definite covariance matrix. The output is a ready-to-use portfolioVariance request.
curl -k --http2 -s \ -H "Content-Type: application/json" \ -d '{"n_assets": 500}' \ https://10.10.10.10/services/FinancialBenchmarkService/generateTestData \ -o /tmp/portfolio_500.json # Then benchmark it curl -k --http2 -s \ -H "Content-Type: application/json" \ -d @/tmp/portfolio_500.json \ https://10.10.10.10/services/FinancialBenchmarkService/portfolioVariance
The real power of MCP isn‘t “call a function via JSON.” Any REST API does that. The power is that **the AI discovers what’s available and constructs valid requests from natural language**, with no documentation, no SDK, no code generation step.
When Claude connects, it calls tools/list and receives this (abbreviated):
{ "tools": [ { "name": "portfolioVariance", "description": "Calculate portfolio variance using O(n^2) covariance matrix multiplication. Returns variance, volatility, annualized volatility, and microsecond timing. Target: 500 assets in ~5ms.", "inputSchema": { "type": "object", "required": ["n_assets", "weights", "covariance_matrix"], "properties": { "n_assets": { "type": "integer", "description": "Number of assets in the portfolio (max 2000)" }, "weights": { "type": "array", "items": {"type": "number"}, "description": "Portfolio weights. Must sum to 1.0 unless normalize_weights=true" }, "covariance_matrix": { "type": "array", "items": {"type": "number"}, "description": "Flattened n x n covariance matrix (row-major order)" }, "normalize_weights": { "type": "boolean", "description": "Rescale weights to sum to 1.0. Default: false" }, "n_periods_per_year": { "type": "integer", "description": "Trading periods for annualizing. Default 252 (equity). Use 12 (monthly), 365 (crypto)" } } } }, { "name": "monteCarlo", "description": "Monte Carlo VaR simulation using Geometric Brownian Motion. Returns VaR at caller-specified percentiles, CVaR, max drawdown, probability of profit, simulations-per-second throughput. Uses xorshift128+ PRNG + Box-Muller for high-throughput RNG.", "inputSchema": { "required": [], "description": "All fields have defaults — an empty {} request body is valid", "properties": { "n_simulations": {"type": "integer", "description": "Number of paths (max 1M). Default: 10,000"}, "n_periods": {"type": "integer", "description": "Steps per path (252 = 1 trading year). Default: 252"}, "initial_value": {"type": "number", "description": "Starting portfolio value. Default: 1,000,000"}, "expected_return": {"type": "number", "description": "Annualized expected return (0.08 = 8%). Default: 0.08"}, "volatility": {"type": "number", "description": "Annualized vol (0.20 = 20%). Default: 0.20"}, "random_seed": {"type": "integer", "description": "Seed for reproducibility. 0 = non-deterministic"}, "percentiles": {"type": "array", "items": {"type": "number"}, "description": "VaR percentiles, e.g. [0.01, 0.05] for 99% and 95%. Max 8"} } } } ] }
This is not documentation — this is machine-readable intent. Claude now knows:
{} is a valid Monte Carlo request (all defaults)No Python imports. No SDK. No reading API docs. The analyst says “run a Monte Carlo” and Claude already knows what to send.
Every example below was run live on April 8, 2026. The curl commands are real, the JSON responses are real, the timings are real. Each section frames the analyst question, shows what the MCP tool call looks like under the hood, and presents the actual response.
PM question: My 5-stock portfolio shows 19.8% vol. What happens if cross-asset correlations spike to 0.8 in a selloff?
Step 1 — Baseline (real market correlations):
curl -k --http2 -s \ -H "Content-Type: application/json" \ -d '{ "n_assets": 5, "weights": [0.25, 0.25, 0.20, 0.15, 0.15], "covariance_matrix": [ 0.0691, 0.0313, 0.0457, 0.0272, -0.0035, 0.0313, 0.0976, 0.0591, 0.0408, 0.0058, 0.0457, 0.0591, 0.1207, 0.0437, -0.0086, 0.0272, 0.0408, 0.0437, 0.0638, 0.0015, -0.0035, 0.0058,-0.0086, 0.0015, 0.0303 ], "normalize_weights": true }' \ https://10.10.10.10/services/FinancialBenchmarkService/portfolioVariance
{ "status": "SUCCESS", "portfolio_variance": 0.0392, "portfolio_volatility": 0.198, "annualized_volatility": 3.143, "calc_time_us": 0, "memory_used_kb": 37448, "matrix_operations": 25 }
MCP stdio equivalent:
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"portfolioVariance","arguments":{"n_assets":5,"weights":[0.25,0.25,0.20,0.15,0.15],"covariance_matrix":[0.0691,0.0313,0.0457,0.0272,-0.0035,0.0313,0.0976,0.0591,0.0408,0.0058,0.0457,0.0591,0.1207,0.0437,-0.0086,0.0272,0.0408,0.0437,0.0638,0.0015,-0.0035,0.0058,-0.0086,0.0015,0.0303],"normalize_weights":true}}}' \ | /usr/local/axis2c/bin/financial-benchmark-mcp
Step 2 — Stressed (all pairwise correlations → 0.8):
Same volatilities, but off-diagonal covariances recomputed as vol_i × vol_j × 0.8:
curl -k --http2 -s \ -H "Content-Type: application/json" \ -d '{ "n_assets": 5, "weights": [0.25, 0.25, 0.20, 0.15, 0.15], "covariance_matrix": [ 0.0691, 0.0656, 0.0730, 0.0530, 0.0366, 0.0656, 0.0974, 0.0866, 0.0629, 0.0434, 0.0730, 0.0866, 0.1204, 0.0699, 0.0483, 0.0530, 0.0629, 0.0699, 0.0635, 0.0351, 0.0366, 0.0434, 0.0483, 0.0351, 0.0303 ], "normalize_weights": true }' \ https://10.10.10.10/services/FinancialBenchmarkService/portfolioVariance
{ "status": "SUCCESS", "portfolio_variance": 0.0649, "portfolio_volatility": 0.2547, "annualized_volatility": 4.043, "calc_time_us": 0, "memory_used_kb": 39560, "matrix_operations": 25 }
MCP stdio equivalent:
echo '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"portfolioVariance","arguments":{"n_assets":5,"weights":[0.25,0.25,0.20,0.15,0.15],"covariance_matrix":[0.0691,0.0656,0.0730,0.0530,0.0366,0.0656,0.0974,0.0866,0.0629,0.0434,0.0730,0.0866,0.1204,0.0699,0.0483,0.0530,0.0629,0.0699,0.0635,0.0351,0.0366,0.0434,0.0483,0.0351,0.0303],"normalize_weights":true}}}' \ | /usr/local/axis2c/bin/financial-benchmark-mcp
Step 3 — Monte Carlo on the stressed portfolio (100K paths):
curl -k --http2 -s \ -H "Content-Type: application/json" \ -d '{ "n_simulations": 100000, "n_periods": 252, "initial_value": 1000000, "expected_return": 0.10, "volatility": 0.255, "random_seed": 42 }' \ https://10.10.10.10/services/FinancialBenchmarkService/monteCarlo
{ "status": "SUCCESS", "mean_final_value": 1104211.79, "var_95": 298687.71, "var_99": 410292.07, "cvar_95": 366609.94, "max_drawdown": 0.674, "prob_profit": 0.604, "calc_time_us": 726621, "simulations_per_second": 137623 }
MCP stdio equivalent:
echo '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"monteCarlo","arguments":{"n_simulations":100000,"n_periods":252,"initial_value":1000000,"expected_return":0.10,"volatility":0.255,"random_seed":42}}}' \ | /usr/local/axis2c/bin/financial-benchmark-mcp
What the assistant tells the PM:
| Metric | Normal correlations | Stressed (ρ = 0.8) | Change |
|---|---|---|---|
| Portfolio vol | 19.8% | 25.5% | +29% |
| 95% VaR (1yr, $1M) | $219K | $299K | +$80K |
| 99% VaR | $318K | $410K | +$92K |
| Prob of profit | 65.7% | 60.4% | -5.3pp |
| Max drawdown | 57% | 67% | +10pp |
The diversification benefit nearly disappears. Under normal correlations the portfolio achieves 19.8% vol vs a naive weighted average of 27.4% (28% diversification benefit). Under stress, vol jumps to 25.5% — the portfolio starts behaving like a single bet.
Three MCP calls. Two portfolioVariance (sub-microsecond each), one monteCarlo (0.73 seconds). Total wall time under 1 second.
Analyst question: I want to add a 3% position in a European semiconductor equipment name. 52-week range 542 to 1,313 (EUR). What does it do to my portfolio risk vs a Japanese alternative?
The assistant computes covariance from historical returns, then runs portfolioVariance on two candidate portfolios: the original 5 names scaled to 97% plus the new name at 3%.
Candidate A — European semi (vol 44%, correlation 0.68 to existing tech):
curl -k --http2 -s \ -H "Content-Type: application/json" \ -d '{ "n_assets": 6, "weights": [0.2425, 0.2425, 0.194, 0.1455, 0.1455, 0.03], "covariance_matrix": [ 0.0691, 0.0313, 0.0457, 0.0272,-0.0035, 0.0787, 0.0313, 0.0976, 0.0591, 0.0408, 0.0058, 0.0934, 0.0457, 0.0591, 0.1207, 0.0437,-0.0086, 0.1039, 0.0272, 0.0408, 0.0437, 0.0638, 0.0015, 0.0610, -0.0035, 0.0058,-0.0086, 0.0015, 0.0303, 0.0115, 0.0787, 0.0934, 0.1039, 0.0610, 0.0115, 0.1936 ], "normalize_weights": true }' \ https://10.10.10.10/services/FinancialBenchmarkService/portfolioVariance
{ "status": "SUCCESS", "portfolio_variance": 0.04141, "portfolio_volatility": 0.2035, "calc_time_us": 0, "matrix_operations": 36 }
MCP stdio equivalent:
echo '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"portfolioVariance","arguments":{"n_assets":6,"weights":[0.2425,0.2425,0.194,0.1455,0.1455,0.03],"covariance_matrix":[0.0691,0.0313,0.0457,0.0272,-0.0035,0.0787,0.0313,0.0976,0.0591,0.0408,0.0058,0.0934,0.0457,0.0591,0.1207,0.0437,-0.0086,0.1039,0.0272,0.0408,0.0437,0.0638,0.0015,0.0610,-0.0035,0.0058,-0.0086,0.0015,0.0303,0.0115,0.0787,0.0934,0.1039,0.0610,0.0115,0.1936],"normalize_weights":true}}}' \ | /usr/local/axis2c/bin/financial-benchmark-mcp
Candidate B — Japanese peer (vol 38%, correlation 0.31 to US tech):
curl -k --http2 -s \ -H "Content-Type: application/json" \ -d '{ "n_assets": 6, "weights": [0.2425, 0.2425, 0.194, 0.1455, 0.1455, 0.03], "covariance_matrix": [ 0.0691, 0.0313, 0.0457, 0.0272,-0.0035, 0.0310, 0.0313, 0.0976, 0.0591, 0.0408, 0.0058, 0.0368, 0.0457, 0.0591, 0.1207, 0.0437,-0.0086, 0.0409, 0.0272, 0.0408, 0.0437, 0.0638, 0.0015, 0.0239, -0.0035, 0.0058,-0.0086, 0.0015, 0.0303, 0.0066, 0.0310, 0.0368, 0.0409, 0.0239, 0.0066, 0.1444 ], "normalize_weights": true }' \ https://10.10.10.10/services/FinancialBenchmarkService/portfolioVariance
{ "status": "SUCCESS", "portfolio_variance": 0.03874, "portfolio_volatility": 0.1968, "calc_time_us": 0, "matrix_operations": 36 }
MCP stdio equivalent:
echo '{"jsonrpc":"2.0","id":5,"method":"tools/call","params":{"name":"portfolioVariance","arguments":{"n_assets":6,"weights":[0.2425,0.2425,0.194,0.1455,0.1455,0.03],"covariance_matrix":[0.0691,0.0313,0.0457,0.0272,-0.0035,0.0310,0.0313,0.0976,0.0591,0.0408,0.0058,0.0368,0.0457,0.0591,0.1207,0.0437,-0.0086,0.0409,0.0272,0.0408,0.0437,0.0638,0.0015,0.0239,-0.0035,0.0058,-0.0086,0.0015,0.0303,0.0066,0.0310,0.0368,0.0409,0.0239,0.0066,0.1444],"normalize_weights":true}}}' \ | /usr/local/axis2c/bin/financial-benchmark-mcp
Head-to-head Monte Carlo (100K paths each):
# European candidate (vol 20.35%) curl -k --http2 -s -H "Content-Type: application/json" \ -d '{"n_simulations":100000,"n_periods":252,"initial_value":1000000, "expected_return":0.10,"volatility":0.211,"random_seed":42}' \ https://10.10.10.10/services/FinancialBenchmarkService/monteCarlo # Japanese candidate (vol 19.68%) curl -k --http2 -s -H "Content-Type: application/json" \ -d '{"n_simulations":100000,"n_periods":252,"initial_value":1000000, "expected_return":0.10,"volatility":0.201,"random_seed":42}' \ https://10.10.10.10/services/FinancialBenchmarkService/monteCarlo
MCP stdio equivalents:
# European candidate echo '{"jsonrpc":"2.0","id":6,"method":"tools/call","params":{"name":"monteCarlo","arguments":{"n_simulations":100000,"n_periods":252,"initial_value":1000000,"expected_return":0.10,"volatility":0.211,"random_seed":42}}}' \ | /usr/local/axis2c/bin/financial-benchmark-mcp # Japanese candidate echo '{"jsonrpc":"2.0","id":7,"method":"tools/call","params":{"name":"monteCarlo","arguments":{"n_simulations":100000,"n_periods":252,"initial_value":1000000,"expected_return":0.10,"volatility":0.201,"random_seed":42}}}' \ | /usr/local/axis2c/bin/financial-benchmark-mcp
Results side by side (real output, 2026-04-08):
| Before (5 names) | + European semi | + Japanese peer | |
|---|---|---|---|
| Portfolio vol | 19.8% | 20.3% (+55bp) | 19.7% (-13bp) |
| 95% VaR ($1M) | $219K | $238K | $224K |
| 99% VaR | $318K | $340K | $323K |
| CVaR 95% | $279K | $300K | $284K |
| Prob of profit | 65.7% | 64.3% | 65.4% |
| Max drawdown | 57.1% | 59.7% | 57.7% |
portfolioVariance time | < 1 μs | < 1 μs | < 1 μs |
monteCarlo time | 0.68 sec | 0.72 sec | 0.67 sec |
The European name adds 55bp of vol because it's correlated 0.68 with the existing tech cluster. The Japanese alternative actually reduces vol by 13bp — the JPY exposure and lower tech correlation provide genuine diversification. The 99% VaR difference is $17K per $1M of notional.
Four portfolioVariance calls (sub-microsecond each) and two monteCarlo runs (0.67-0.72 seconds each). Total compute: ~1.4 seconds.
Quant question: I'm calibrating Monte Carlo for the nightly risk run. How many simulations for stable 99% VaR?
Run monteCarlo at 1K, 10K, 100K, and 1M paths with a fixed seed:
for N in 1000 10000 100000 1000000; do curl -k --http2 -s -H "Content-Type: application/json" \ -d "{\"n_simulations\":$N,\"n_periods\":252,\"initial_value\":1000000, \"expected_return\":0.10,\"volatility\":0.198,\"random_seed\":42}" \ https://10.10.10.10/services/FinancialBenchmarkService/monteCarlo done
MCP stdio equivalent (example for 100K):
echo '{"jsonrpc":"2.0","id":8,"method":"tools/call","params":{"name":"monteCarlo","arguments":{"n_simulations":100000,"n_periods":252,"initial_value":1000000,"expected_return":0.10,"volatility":0.198,"random_seed":42}}}' \ | /usr/local/axis2c/bin/financial-benchmark-mcp
Actual results (seed=42, vol=19.8%, 2026-04-08):
| Simulations | 95% VaR | 99% VaR | Calc time | Sims/sec |
|---|---|---|---|---|
| 1,000 | $244,132 | $338,909 | 6 ms | 164,295 |
| 10,000 | $221,010 | $326,476 | 66 ms | 152,423 |
| 100,000 | $219,248 | $317,559 | 716 ms | 139,650 |
| 1,000,000 | $217,666 | $316,045 | 6.6 sec | 150,773 |
The 95% VaR converges by 10K paths (< 1% change beyond that). The 99% VaR needs 100K — the 10K estimate is 2.8% higher than the converged value, which matters for regulatory reporting.
Production capacity math: at 716 ms per 100K-path run, a single core processes 83 funds per minute. A 500-fund universe completes in 6 minutes on one core, or 36 seconds on a 10-core node. That's regulatory-grade VaR without a compute cluster.
The examples above use synthetic data. This section shows a real end-to-end pipeline run on April 8, 2026: fetch 1 year of daily closing prices from a market data provider, compute the covariance matrix from historical returns, and run portfolio risk analysis on Axis2/C — all in under 2 seconds.
Pull 252 trading days of daily closes for a 5-stock portfolio: MSFT, AAPL, AMZN, JPM, JNJ.
# Fetch from your market data provider (any source that returns daily closes) # Example using a REST API with date range and field selection: curl -s -X POST "https://market-data-provider.example.com/api/v1/timeseries" \ -d "symbol=MSFT&fields=close,date&from=20250401&to=20260407" # Repeat for AAPL, AMZN, JPM, JNJ
import math, json # 254 daily log returns computed from 255 closing prices (April 2025 - April 2026) # Annualized covariance: cov(r_i, r_j) * 252 # Real annualized volatilities (from market data, as of 2026-04-07): # MSFT: 26.3% AAPL: 31.2% AMZN: 34.7% JPM: 25.2% JNJ: 17.4% # # Real correlation matrix: # MSFT AAPL AMZN JPM JNJ # MSFT 1.00 0.38 0.50 0.41 -0.08 # AAPL 0.38 1.00 0.54 0.52 0.11 # AMZN 0.50 0.54 1.00 0.50 -0.14 # JPM 0.41 0.52 0.50 1.00 0.03 # JNJ -0.08 0.11 -0.14 0.03 1.00 # # Note: JNJ is negatively correlated with tech — the diversification benefit is real.
curl -k --http2 -s \ -H "Content-Type: application/json" \ -d '{ "n_assets": 5, "weights": [0.25, 0.25, 0.20, 0.15, 0.15], "covariance_matrix": [ 0.0691, 0.0313, 0.0457, 0.0272, -0.0035, 0.0313, 0.0976, 0.0591, 0.0408, 0.0058, 0.0457, 0.0591, 0.1207, 0.0437, -0.0086, 0.0272, 0.0408, 0.0437, 0.0638, 0.0015, -0.0035, 0.0058,-0.0086, 0.0015, 0.0303 ], "normalize_weights": true }' \ https://10.10.10.10/services/FinancialBenchmarkService/portfolioVariance
Real result:
{ "status": "SUCCESS", "portfolio_variance": 0.0392, "portfolio_volatility": 0.198, "annualized_volatility": 3.14, "weight_sum": 1.0 }
MCP stdio equivalent:
echo '{"jsonrpc":"2.0","id":9,"method":"tools/call","params":{"name":"portfolioVariance","arguments":{"n_assets":5,"weights":[0.25,0.25,0.20,0.15,0.15],"covariance_matrix":[0.0691,0.0313,0.0457,0.0272,-0.0035,0.0313,0.0976,0.0591,0.0408,0.0058,0.0457,0.0591,0.1207,0.0437,-0.0086,0.0272,0.0408,0.0437,0.0638,0.0015,-0.0035,0.0058,-0.0086,0.0015,0.0303],"normalize_weights":true}}}' \ | /usr/local/axis2c/bin/financial-benchmark-mcp
Portfolio volatility: 19.8%. The individual stocks range from 17% (JNJ) to 35% (AMZN). The weighted-average vol would be 27.4%, but the portfolio achieves 19.8% — a 28% diversification benefit driven primarily by JNJ's negative correlation with the tech names.
curl -k --http2 -s \ -H "Content-Type: application/json" \ -d '{ "n_simulations": 100000, "n_periods": 252, "initial_value": 1000000, "expected_return": 0.10, "volatility": 0.198 }' \ https://10.10.10.10/services/FinancialBenchmarkService/monteCarlo
Real result (100K simulations, 1.08 seconds):
{ "status": "SUCCESS", "mean_final_value": 1106232.16, "var_95": 217878.47, "var_99": 317260.52, "cvar_95": 278149.14, "max_drawdown": 0.5524, "prob_profit": 0.659, "simulations_per_second": 92826.21 }
MCP stdio equivalent:
echo '{"jsonrpc":"2.0","id":10,"method":"tools/call","params":{"name":"monteCarlo","arguments":{"n_simulations":100000,"n_periods":252,"initial_value":1000000,"expected_return":0.10,"volatility":0.198}}}' \ | /usr/local/axis2c/bin/financial-benchmark-mcp
What this tells a portfolio manager:
This entire pipeline — real market data, real covariance matrix, real Monte Carlo VaR — ran end-to-end in under 2 seconds. The analyst‘s version of this workflow involves a Jupyter notebook, 15 minutes of setup, and a prayer that the dependencies haven’t broken since last quarter.
With MCP, Claude does it in one conversation turn.
monteCarlo via MCPThe financial calculations that matter — covariance matrices, Monte Carlo paths, scenario analysis — are tight numerical loops over floating-point arrays. This is exactly where C excels and where interpreted languages pay the highest overhead.
| Axis2/C (measured) | Interpreted runtimes (typical) | |
|---|---|---|
| 500-asset portfolio variance | 269 μs | Milliseconds to tens of milliseconds |
| 10K Monte Carlo paths | 110 ms | Seconds (varies with JIT warmup) |
| Peak memory for 500 assets | 48 MB RSS | Hundreds of MB (runtime + GC overhead) |
| Startup time | instant (shared lib) | 1-3 sec (interpreter/JVM startup) |
| MCP stdio startup | < 50 ms | 500 ms+ (module import / classloading) |
The MCP stdio startup matters because MCP clients launch MCP servers as subprocesses. Every time you open a conversation, the server starts. A 50ms C startup is invisible; a 3-second JVM startup is noticeable every time.
The examples above show a standalone MCP server called from a stdio-based MCP client. The real payoff is when the same MCP tools power an AI assistant embedded directly in a portfolio management application.
Picture a chat interface inside a web-based portfolio management platform. The portfolio manager is looking at their holdings and types:
“Which positions are most overweight relative to optimal?”
The assistant calls a rebalancing analysis tool via MCP, gets back the positions ranked by deviation from optimal sizing, and renders a chart inline — no page navigation, no separate tool, no waiting for the quant team to run a script.
“What's my downside risk if correlations spike to 0.8 in a selloff?”
The assistant calls portfolioVariance with stressed correlation assumptions, then calls monteCarlo with the stressed volatility to estimate the tail loss. Two MCP calls, one answer:
“Under stressed correlations, your portfolio vol increases from 14% to 22%. A 99% VaR Monte Carlo with 100K paths estimates a worst-case annual loss of $331K on your $1M book. The simulation took 1.08 seconds.”
The assistant generates an interactive visualization showing the distribution of terminal portfolio values — the PM drags a slider to adjust the confidence level and sees the VaR threshold move in real time.
This is not speculative. The building blocks exist today:
What Axis2/C adds to this picture is computation speed. An assistant that can run a 100K-path Monte Carlo in 1 second keeps the conversation interactive. An assistant that waits 30 seconds for a batch job to complete breaks the flow. The PM asks a follow-up, and the answer is already there.
The same MCP protocol works for both:
One protocol. One set of tool definitions. Multiple surfaces. The financial calculations don't change — only the interface does.
Monte Carlo VaR, portfolio correlation, and scenario analysis are the same calculations that run nightly in production risk engines. The question enterprise architects ask is: “Can we run these on modest hardware instead of dedicated compute clusters?”
At 92,000 simulations per second per core, a single 4-core server handles 1 million Monte Carlo paths in under 3 seconds. That's regulatory-grade VaR computation on hardware that costs less than a Bloomberg terminal.
To connect a stdio-based MCP client to the Axis2/C MCP server, add an entry to its configuration file. The path varies by client; Claude Desktop's ~/.config/claude/claude_desktop_config.json is shown as an example:
{ "mcpServers": { "axis2c-financial": { "command": "/usr/local/axis2c/bin/financial-benchmark-mcp" } } }
For remote servers accessible via SSH:
{ "mcpServers": { "axis2c-financial": { "command": "ssh", "args": ["user@your-server", "/usr/local/axis2c/bin/financial-benchmark-mcp"] } } }
The same Axis2/C deployment also hosts:
| Service | Operations | Purpose |
|---|---|---|
| LoginService | authenticate | JWT token generation, input validation, credential verification |
| TestwsService | testXSSProtection | XSS detection and input sanitization demonstration |
| BigDataH2Service | processBigDataSet, getServiceMetadata | HTTP/2 streaming for large JSON payloads |
These demonstrate that Axis2/C handles authentication, security validation, and large payload streaming alongside compute-intensive financial operations — all on the same Apache httpd instance, all over HTTP/2.
Note: The benchmark examples above omit authentication for clarity. Production deployments should require JWT tokens (via LoginService) for all financial calculation endpoints.
Measured on a lightly-loaded CI/CD VM (not dedicated compute hardware): Ubuntu 22.04, 4 vCPU AMD EPYC 7542 (single-threaded, no SMT), 64 GB RAM, Apache 2.4.52 with mod_http2 and mod_axis2. All numbers are wall-clock time including HTTP/2 framing, TLS negotiation, and JSON serialization — not micro-benchmark cherry-picks.
| Benchmark | Result |
|---|---|
| Portfolio variance (3 assets, 9 ops) | < 1 μs |
| Portfolio variance (500 assets, 250K ops) | 269 μs |
| Monte Carlo VaR (10K sims × 252 days) | 110 ms |
| Monte Carlo VaR (100K sims × 252 days) | 1.08 sec |
| Scenario analysis (3 assets, 30 lookups) | 1 μs |
| Hash lookup throughput | 30 million lookups/sec |
| Matrix operation throughput | 929 million ops/sec |
| Process memory under load | 48 MB |
| MCP stdio startup | < 50 ms |
docs/MCP.md — MCP architecture and implementation plandocs/HTTP2_JSON_DEBUG.md — Deployment troubleshooting guidedocs/HTTP2_SERVICES_DOT_XML.md — How services.xml configures message receiversdocs/HTTP2_ANDROID.md — Android deployment and signature differencesdocs/userguide/json-httpd-h2-userguide.md — Full HTTP/2 deployment guide