The Node.js SDK (@ascend/sdk) is not yet published to npm. This documentation is a preview of the planned API. For production use, please use the Python SDK or the REST API.
MCP Integration for Node.js
Integrate ASCEND governance into your MCP (Model Context Protocol) server tools using higher-order functions and middleware patterns.
Overview
The ASCEND Node.js SDK provides seamless integration with MCP servers through the mcpGovernance wrapper function. This enables automatic authorization checks before any tool execution.
Installation
npm install @ascend/sdk
Quick Start
import { AscendClient, FailMode } from '@ascend/sdk';
import { mcpGovernance } from '@ascend/sdk/mcp';
// Initialize ASCEND client
const client = new AscendClient({
apiKey: 'owkai_your_api_key',
agentId: 'mcp-server-001',
agentName: 'My MCP Server',
failMode: FailMode.CLOSED
});
// Wrap MCP tool with governance
const queryDatabase = mcpGovernance(client, {
actionType: 'database.query',
resource: 'production_db'
})(async (sql: string): Promise<QueryResult> => {
return await db.execute(sql);
});
// Use the governed function
const result = await queryDatabase('SELECT * FROM users');
Function Reference
mcpGovernance()
The primary wrapper function for adding governance to MCP tools.
import { mcpGovernance } from '@ascend/sdk/mcp';
const governedFn = mcpGovernance(
client: AscendClient,
options: GovernanceOptions
)(originalFunction);
GovernanceOptions
interface GovernanceOptions {
/** Action type (required) */
actionType: string;
/** Resource identifier (required) */
resource: string;
/** Custom configuration */
config?: MCPGovernanceConfig;
/** Override risk level */
riskLevel?: 'low' | 'medium' | 'high' | 'critical';
/** Additional metadata */
metadata?: Record<string, unknown>;
/** Force human approval */
requireHumanApproval?: boolean;
}
Example
const processPayment = mcpGovernance(client, {
actionType: 'transaction.payment',
resource: 'payment_gateway',
riskLevel: 'high',
requireHumanApproval: true,
metadata: { category: 'financial' }
})(async (amount: number, currency: string) => {
return await gateway.process(amount, currency);
});
requireGovernance()
Simplified wrapper for common use cases.
import { requireGovernance } from '@ascend/sdk/mcp';
const readLogs = requireGovernance(
client,
'file.read',
'/var/log'
)(async (filename: string) => {
return await fs.readFile(`/var/log/${filename}`, 'utf-8');
});
highRiskAction()
Wrapper for actions requiring mandatory human approval.
import { highRiskAction } from '@ascend/sdk/mcp';
const dropTable = highRiskAction(
client,
'database.delete',
'production_db'
)(async (tableName: string) => {
return await db.execute(`DROP TABLE ${tableName}`);
});
MCPGovernanceConfig
Fine-tune governance behavior with configuration options.
interface MCPGovernanceConfig {
/** Wait for approval if pending (default: true) */
waitForApproval?: boolean;
/** Approval timeout in milliseconds (default: 300000) */
approvalTimeoutMs?: number;
/** Polling interval in milliseconds (default: 5000) */
approvalPollIntervalMs?: number;
/** Include tool name in context (default: true) */
includeToolName?: boolean;
/** Include arguments in context (default: true) */
includeArguments?: boolean;
/** Throw on denial (default: true) */
raiseOnDenial?: boolean;
/** Log all decisions (default: true) */
logAllDecisions?: boolean;
/** Approval required callback */
onApprovalRequired?: (decision: EvaluateActionResult, toolName: string) => void | Promise<void>;
/** Denial callback */
onDenied?: (decision: EvaluateActionResult, toolName: string) => void | Promise<void>;
/** Allowed callback */
onAllowed?: (decision: EvaluateActionResult, toolName: string) => void | Promise<void>;
/** Timeout callback */
onTimeout?: (decision: EvaluateActionResult, toolName: string) => void | Promise<void>;
}
Example with Config
const config: MCPGovernanceConfig = {
waitForApproval: true,
approvalTimeoutMs: 600000, // 10 minutes
approvalPollIntervalMs: 10000, // 10 seconds
onApprovalRequired: async (decision, toolName) => {
await sendSlackNotification(
`Action "${toolName}" requires approval`,
{ approvalId: decision.approvalRequestId }
);
},
onDenied: async (decision, toolName) => {
await logSecurityEvent({
event: 'action_denied',
tool: toolName,
reason: decision.reason,
riskScore: decision.riskScore
});
},
onAllowed: async (decision, toolName) => {
metrics.increment('actions_allowed', { tool: toolName });
}
};
const sensitiveOperation = mcpGovernance(client, {
actionType: 'system.admin',
resource: 'server-001',
config
})(async () => {
// Sensitive operation
});
MCPGovernanceMiddleware
Apply governance to multiple tools using a middleware pattern.
import { MCPGovernanceMiddleware } from '@ascend/sdk/mcp';
const middleware = new MCPGovernanceMiddleware(client, defaultConfig);
Methods
wrap()
Wrap a function with governance.
const governed = middleware.wrap(
actionType: string,
resource: string,
fn: Function,
config?: MCPGovernanceConfig
);
wrapHighRisk()
Wrap a function requiring human approval.
const governed = middleware.wrapHighRisk(
actionType: string,
resource: string,
fn: Function,
config?: MCPGovernanceConfig
);
governedTools
Get list of governed tool names.
const tools: string[] = middleware.governedTools;
Example
const middleware = new MCPGovernanceMiddleware(client);
// Standard governance
const queryFn = middleware.wrap(
'database.query',
'production_db',
async (sql: string) => db.execute(sql)
);
// High-risk governance
const deleteFn = middleware.wrapHighRisk(
'database.delete',
'production_db',
async (table: string, where: string) => db.execute(`DELETE FROM ${table} WHERE ${where}`)
);
console.log(`Governed: ${middleware.governedTools}`);
// Output: ['queryFn', 'deleteFn']
Complete MCP Server Example
/**
* Complete MCP server with ASCEND governance
*/
import { Server, Tool } from '@modelcontextprotocol/sdk';
import { AscendClient, FailMode, Decision } from '@ascend/sdk';
import {
mcpGovernance,
highRiskAction,
MCPGovernanceConfig,
MCPGovernanceMiddleware
} from '@ascend/sdk/mcp';
// Initialize ASCEND client
const ascend = new AscendClient({
apiKey: process.env.ASCEND_API_KEY!,
agentId: 'data-assistant-mcp',
agentName: 'Data Assistant MCP Server',
environment: 'production',
failMode: FailMode.CLOSED
});
// Register the MCP server
await ascend.register({
agentType: 'mcp_server',
capabilities: [
'database.query',
'database.write',
'file.read',
'file.write',
'api.call'
],
allowedResources: [
'production_db',
'analytics_db',
'/var/data',
'internal_api'
]
});
// Create MCP server
const server = new Server({ name: 'data-assistant' });
// Middleware for common config
const middleware = new MCPGovernanceMiddleware(ascend, {
waitForApproval: true,
approvalTimeoutMs: 600000,
onApprovalRequired: async (decision, tool) => {
console.log(`[MCP] Approval required for ${tool}`);
}
});
// Define tools with governance
// Tool 1: Low-risk analytics query
const analyzeData = middleware.wrap(
'database.query',
'analytics_db',
async function analyzeData(query: string): Promise<AnalyticsResult> {
if (!query.toUpperCase().startsWith('SELECT')) {
throw new Error('Only SELECT queries allowed');
}
const result = await db.execute(query);
return { rows: result, count: result.length };
}
);
// Tool 2: Medium-risk file operations
const readDataFile = mcpGovernance(ascend, {
actionType: 'file.read',
resource: '/var/data',
riskLevel: 'medium'
})(async function readDataFile(filename: string): Promise<string> {
const safePath = path.join('/var/data', path.basename(filename));
return await fs.readFile(safePath, 'utf-8');
});
// Tool 3: High-risk database write
const updateRecords = mcpGovernance(ascend, {
actionType: 'database.write',
resource: 'production_db',
riskLevel: 'high',
config: {
waitForApproval: true,
onApprovalRequired: async (decision) => {
await notifyOpsTeam(decision.approvalRequestId);
}
}
})(async function updateRecords(
table: string,
updates: Record<string, unknown>,
where: string
): Promise<UpdateResult> {
const setClause = Object.keys(updates)
.map(k => `${k} = ?`)
.join(', ');
const result = await db.execute(
`UPDATE ${table} SET ${setClause} WHERE ${where}`,
Object.values(updates)
);
return { affectedRows: result.rowCount };
});
// Tool 4: Critical-risk deletion (always requires approval)
const deleteRecords = highRiskAction(
ascend,
'database.delete',
'production_db'
)(async function deleteRecords(
table: string,
where: string
): Promise<DeleteResult> {
const result = await db.execute(`DELETE FROM ${table} WHERE ${where}`);
return { deletedRows: result.rowCount };
});
// Tool 5: External API call
const fetchUserData = mcpGovernance(ascend, {
actionType: 'api.call',
resource: 'internal_api',
metadata: { apiType: 'internal', requiresAuth: true }
})(async function fetchUserData(userId: string): Promise<User> {
const response = await fetch(`https://api.internal/users/${userId}`);
return response.json();
});
// Register tools with MCP server
server.addTool({
name: 'analyze_data',
description: 'Run analytics query',
handler: analyzeData
});
server.addTool({
name: 'read_data_file',
description: 'Read data file',
handler: readDataFile
});
server.addTool({
name: 'update_records',
description: 'Update database records',
handler: updateRecords
});
server.addTool({
name: 'delete_records',
description: 'Delete database records (requires approval)',
handler: deleteRecords
});
server.addTool({
name: 'fetch_user_data',
description: 'Fetch user from internal API',
handler: fetchUserData
});
// Start server
server.start();
console.log('MCP Server started with ASCEND governance');
console.log(`Governed tools: ${middleware.governedTools}`);
Error Handling
import {
AuthorizationError,
TimeoutError,
CircuitBreakerOpenError
} from '@ascend/sdk';
const safeQuery = mcpGovernance(ascend, {
actionType: 'database.query',
resource: 'production_db',
config: {
raiseOnDenial: false // Don't throw, return graceful error
}
})(async (sql: string) => {
try {
return await db.execute(sql);
} catch (error) {
if (error instanceof AuthorizationError) {
return {
error: 'Authorization denied',
reason: error.message,
policyViolations: error.policyViolations,
riskScore: error.riskScore
};
}
if (error instanceof TimeoutError) {
return {
error: 'Approval timeout',
timeoutMs: error.timeoutMs,
message: 'Action requires approval but timed out'
};
}
if (error instanceof CircuitBreakerOpenError) {
return {
error: 'Service unavailable',
recoveryTime: error.recoveryTimeSeconds,
message: 'Governance service temporarily unavailable'
};
}
throw error;
}
});
Best Practices
1. Use Specific Action Types
// Good: Specific action type
mcpGovernance(client, { actionType: 'database.query', resource: 'prod_db' })
// Bad: Generic action type
mcpGovernance(client, { actionType: 'action', resource: 'db' })
2. Include Meaningful Context
mcpGovernance(client, {
actionType: 'api.call',
resource: 'payment_api',
metadata: {
operation: 'refund',
category: 'financial',
requiresAudit: true
}
})
3. Configure Appropriate Risk Levels
// Read operations: default (low)
mcpGovernance(client, { actionType: 'database.query', resource: 'db' })
// Write operations: medium to high
mcpGovernance(client, {
actionType: 'database.write',
resource: 'db',
riskLevel: 'high'
})
// Destructive operations: high with approval
highRiskAction(client, 'database.delete', 'db')
4. Handle Approval Workflows
const config: MCPGovernanceConfig = {
waitForApproval: true,
approvalTimeoutMs: 300000,
onApprovalRequired: async (decision, tool) => {
// Notify user
await sendNotification(
`Your request requires approval. ID: ${decision.approvalRequestId}`
);
}
};
5. Use Middleware for Multiple Tools
const middleware = new MCPGovernanceMiddleware(client, defaultConfig);
// Consistent governance across all tools
const tool1 = middleware.wrap('type1', 'resource1', fn1);
const tool2 = middleware.wrap('type2', 'resource2', fn2);
const tool3 = middleware.wrapHighRisk('type3', 'resource3', fn3);