test-mcp-functions.jsā¢9.14 kB
// Test script for TradeStation MCP Server functions
// This script tests all endpoints to verify they work correctly
import axios from 'axios';
import dotenv from 'dotenv';
dotenv.config();
const TS_TOKEN_URL = 'https://signin.tradestation.com/oauth/token';
const TS_API_BASE = 'https://sim-api.tradestation.com/v3';
// Get fresh access token
async function getAccessToken() {
const TS_CLIENT_ID = process.env.TRADESTATION_CLIENT_ID;
const TS_CLIENT_SECRET = process.env.TRADESTATION_CLIENT_SECRET;
const TS_REFRESH_TOKEN = process.env.TRADESTATION_REFRESH_TOKEN;
if (!TS_CLIENT_ID || !TS_CLIENT_SECRET || !TS_REFRESH_TOKEN) {
console.error('ā Missing required environment variables');
process.exit(1);
}
try {
console.log('š Obtaining access token...');
const response = await axios.post(TS_TOKEN_URL, new URLSearchParams({
grant_type: 'refresh_token',
client_id: TS_CLIENT_ID,
client_secret: TS_CLIENT_SECRET,
refresh_token: TS_REFRESH_TOKEN
}), {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
console.log('ā
Access token obtained\n');
return response.data.access_token;
} catch (error) {
console.error('ā Failed to obtain access token:', error.response?.data || error.message);
process.exit(1);
}
}
// Test helper function
async function testEndpoint(name, method, endpoint, token, data = null) {
console.log(`\nš” Testing: ${name}`);
console.log(` Endpoint: ${method} ${endpoint}`);
try {
const config = {
method,
url: `${TS_API_BASE}${endpoint}`,
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
'Accept': 'application/json'
},
timeout: 30000
};
if (data && (method === 'POST' || method === 'PUT')) {
config.data = data;
}
const response = await axios(config);
console.log(` ā
SUCCESS (${response.status})`);
console.log(` Response preview:`, JSON.stringify(response.data, null, 2).substring(0, 300) + '...');
return { success: true, data: response.data };
} catch (error) {
const status = error.response?.status || 'ERROR';
const errorMsg = error.response?.data?.Message || error.response?.data?.message || error.message;
console.log(` ā FAILED (${status}): ${errorMsg}`);
return { success: false, error: errorMsg, status };
}
}
// Main test function
async function runTests() {
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
console.log(' TradeStation MCP Server Function Tests');
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
const token = await getAccessToken();
const results = [];
// Phase 1: Market Data Functions
console.log('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
console.log('ā PHASE 1: Market Data Functions ā');
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
results.push(await testEndpoint(
'marketData (quotes)',
'GET',
'/marketdata/quotes/SPY,QQQ,AAPL',
token
));
results.push(await testEndpoint(
'barChart',
'GET',
'/marketdata/barcharts/SPY?interval=5&unit=Minute&barsback=10',
token
));
results.push(await testEndpoint(
'searchSymbols',
'GET',
'/marketdata/symbollookup?criteria=Apple',
token
));
results.push(await testEndpoint(
'optionChain',
'GET',
'/marketdata/options/chains/SPXW?expiration=2025-10-21',
token
));
results.push(await testEndpoint(
'getSymbolDetails',
'GET',
'/marketdata/symbols/SPY,QQQ',
token
));
// Phase 2: Account Functions
console.log('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
console.log('ā PHASE 2: Account Functions ā');
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
// First get accounts to use a valid account ID
const accountsResult = await testEndpoint(
'getAccounts',
'GET',
'/brokerage/accounts',
token
);
results.push(accountsResult);
// If we got accounts, use the first one for subsequent tests
let accountId = null;
if (accountsResult.success && accountsResult.data?.Accounts?.length > 0) {
accountId = accountsResult.data.Accounts[0].AccountID;
console.log(`\n ā¹ļø Using Account ID: ${accountId} for remaining tests`);
results.push(await testEndpoint(
'getBalances',
'GET',
`/brokerage/accounts/${accountId}/balances`,
token
));
results.push(await testEndpoint(
'getPositions',
'GET',
`/brokerage/accounts/${accountId}/positions`,
token
));
results.push(await testEndpoint(
'getOrders (All)',
'GET',
`/brokerage/accounts/${accountId}/orders`,
token
));
results.push(await testEndpoint(
'getOrders (Open only)',
'GET',
`/brokerage/accounts/${accountId}/orders?status=Open`,
token
));
// Note: These require valid order IDs, which may not exist
console.log('\n ā¹ļø Skipping getOrderDetails and getExecutions (require valid order IDs)');
} else {
console.log('\n ā ļø No accounts found - skipping account-specific tests');
}
// Phase 3: Order Preview (Safe - READ ONLY)
console.log('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
console.log('ā PHASE 3: Order Preview (READ-ONLY) ā');
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
if (accountId) {
const confirmOrderData = {
AccountID: accountId,
Symbol: 'SPY',
Quantity: 1,
OrderType: 'Limit',
TradeAction: 'BUY',
LimitPrice: 500.00,
TimeInForce: {
Duration: 'DAY'
}
};
results.push(await testEndpoint(
'confirmOrder (preview)',
'POST',
'/orderexecution/orderconfirm',
token,
confirmOrderData
));
} else {
console.log(' ā ļø Skipping confirmOrder (no account ID available)');
}
// Summary
console.log('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
console.log(' TEST SUMMARY');
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
const successful = results.filter(r => r.success).length;
const failed = results.filter(r => !r.success).length;
const total = results.length;
console.log(`\n Total Tests: ${total}`);
console.log(` ā
Passed: ${successful}`);
console.log(` ā Failed: ${failed}`);
console.log(` Success Rate: ${((successful/total)*100).toFixed(1)}%\n`);
if (failed > 0) {
console.log(' Failed Tests:');
results.forEach((r, i) => {
if (!r.success) {
console.log(` ${i + 1}. ${r.error} (Status: ${r.status})`);
}
});
}
console.log('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
if (successful === total) {
console.log('š All tests passed! Your MCP server is ready to use.\n');
} else {
console.log('ā ļø Some tests failed. Review the errors above.\n');
}
}
// Run tests
runTests().catch(console.error);