Skip to main content

MCP Server Governance

FieldValue
Document IDASCEND-SDK-003
Version1.0.0
Last UpdatedDecember 19, 2025
AuthorAscend Engineering Team
PublisherOW-KAI Technologies Inc.
ClassificationEnterprise Client Documentation
ComplianceSOC 2 CC6.1/CC6.2, PCI-DSS 7.1/8.3, HIPAA 164.312, NIST 800-53 AC-2/SI-4

Reading Time: 10 minutes | Skill Level: Intermediate

Overview

ASCEND provides governance for Model Context Protocol (MCP) servers, enabling control over AI tool execution. Every MCP tool invocation can be evaluated against governance policies before execution.

What is MCP?

The Model Context Protocol (MCP) allows AI models like Claude to interact with external tools and data sources. ASCEND governance ensures these interactions are:

  • Evaluated against risk policies
  • Approved or denied based on rules
  • Audited for compliance

Architecture

┌─────────────────────────────────────────────────────────────────────┐
│ MCP GOVERNANCE FLOW │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Claude │ │ MCP Server │ │ External │ │
│ │ AI │───────▶│ + ASCEND │───────▶│ Service │ │
│ │ │ │ Middleware │ │ │ │
│ └─────────┘ └──────┬──────┘ └─────────────┘ │
│ │ │
│ Tool Call │ ASCEND Governance │
│ "execute_sql" │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ ASCEND │ │
│ │ Platform │ │
│ │ │ │
│ │ ✓ Evaluate │ │
│ │ ✓ Approve │ │
│ │ ✓ Audit │ │
│ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘

Installation

Node.js/TypeScript

npm install @ascend/sdk

Python

pip install ascend-sdk

Quick Start

TypeScript MCP Server

// Source: sdk/nodejs/src/mcp.ts
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { AscendClient, mcpGovernance, requireGovernance } from '@ascend/sdk';

// Initialize ASCEND client
const ascend = new AscendClient({
apiKey: process.env.ASCEND_API_KEY!,
agentId: 'mcp-database-server',
agentName: 'MCP Database Server'
});

// Create MCP server
const server = new Server({
name: "database-server",
version: "1.0.0"
});

// Define tools with governance
server.setRequestHandler("tools/list", async () => ({
tools: [
{
name: "execute_sql",
description: "Execute SQL query",
inputSchema: {
type: "object",
properties: {
query: { type: "string" }
}
}
}
]
}));

// Governed tool handler
server.setRequestHandler("tools/call", async (request) => {
const { name, arguments: args } = request.params;

// Apply governance
const decision = await ascend.evaluateAction({
actionType: `mcp.${name}`,
resource: "database",
parameters: args
});

if (!decision.executionAllowed) {
return {
content: [{
type: "text",
text: `Tool execution denied: ${decision.reason}`
}],
isError: true
};
}

// Execute tool
const result = await executeSql(args.query);

// Log completion
await ascend.logActionCompleted(decision.actionId, { success: true });

return {
content: [{ type: "text", text: JSON.stringify(result) }]
};
});

Governance Middleware

Using mcpGovernance Wrapper

Wrap individual tools with governance:

// Source: sdk/nodejs/src/mcp.ts
import { mcpGovernance, requireGovernance, highRiskAction } from '@ascend/sdk';

// Wrap a tool with governance
const governedTool = mcpGovernance({
actionType: 'database.query',
resource: 'production_db',
riskLevel: 'medium'
})(originalToolHandler);

// Mark as requiring governance
const protectedTool = requireGovernance({
actionType: 'database.delete',
riskLevel: 'high'
})(deleteHandler);

// High-risk action helper
const dangerousTool = highRiskAction(async (params) => {
return await performDangerousOperation(params);
});

Governance Options

interface GovernanceOptions {
actionType: string; // Action category
resource: string; // Resource being accessed
riskLevel?: 'low' | 'medium' | 'high' | 'critical';
requireApproval?: boolean; // Always require human approval
timeout?: number; // Decision timeout (ms)
context?: Record<string, any>; // Additional context
}

Python MCP Server

from mcp import Server
from ascend import AscendClient

# Initialize ASCEND
client = AscendClient(
api_key=os.environ["ASCEND_API_KEY"],
agent_id="mcp-python-server"
)

server = Server("python-server")

@server.tool("execute_sql")
async def execute_sql(query: str):
# Evaluate governance
from ascend import AgentAction

action = AgentAction(
agent_id="mcp-python-server",
agent_name="MCP Python Server",
action_type="mcp.execute_sql",
resource=f"Execute: {query[:50]}",
tool_name="postgresql",
action_details={"query": query}
)

result = client.submit_action(action)

if not result.is_approved():
raise PermissionError(f"Query denied: {result.reason}")

# Execute query
data = await run_query(query)

return {"result": data}

Tool Risk Classification

Default Risk Levels

Tool PatternRisk LevelApproval
*_read, *_list, *_getLOWAuto
*_create, *_updateMEDIUMAuto/Single
*_delete, *_dropHIGHMulti
*_execute, *_adminCRITICALEscalation

Custom Classification

const tools = {
// Low risk - auto-approve
read_file: mcpGovernance({
actionType: 'file.read',
riskLevel: 'low'
})(readFileHandler),

// High risk - requires approval
delete_all: mcpGovernance({
actionType: 'database.delete_all',
riskLevel: 'critical',
requireApproval: true
})(deleteAllHandler)
};

MCP Server Registry

Register your MCP server with ASCEND for centralized management:

// Register MCP server
await ascend.registerMcpServer({
serverId: 'database-server-001',
serverName: 'Production Database Server',
serverType: 'database',
tools: [
{ name: 'execute_sql', riskLevel: 'high' },
{ name: 'list_tables', riskLevel: 'low' }
],
environment: 'production'
});

Error Handling

import { AscendClient, AuthorizationError, TimeoutError } from '@ascend/sdk';

server.setRequestHandler("tools/call", async (request) => {
try {
const decision = await ascend.evaluateAction({
actionType: `mcp.${request.params.name}`,
resource: "database"
});

if (!decision.executionAllowed) {
return {
content: [{
type: "text",
text: `Denied: ${decision.reason}`
}],
isError: true
};
}

// Execute tool...

} catch (error) {
if (error instanceof TimeoutError) {
return {
content: [{
type: "text",
text: "Governance timeout - please retry"
}],
isError: true
};
}

// Fail secure - deny on unknown errors
return {
content: [{
type: "text",
text: "Governance error - operation blocked"
}],
isError: true
};
}
});

Best Practices

1. Classify All Tools

// Map every tool to an action type
const toolActionTypes = {
'execute_sql': 'database.query',
'read_file': 'file.read',
'write_file': 'file.write',
'send_email': 'communication.email',
'make_payment': 'financial.payment'
};

2. Include Context

const decision = await ascend.evaluateAction({
actionType: 'database.query',
resource: 'production_db',
parameters: { query: sql },
context: {
user_id: sessionUserId,
session_id: sessionId,
mcp_server: 'database-server',
claude_model: 'claude-3-opus'
}
});

3. Log Completions

// Always log action outcomes for audit
try {
const result = await executeAction();
await ascend.logActionCompleted(decision.actionId, {
result: { success: true, rows: result.length }
});
} catch (error) {
await ascend.logActionFailed(decision.actionId, {
error: { message: error.message }
});
throw error;
}

Complete Example

// mcp-server.ts - Complete governed MCP server
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { AscendClient, FailMode } from '@ascend/sdk';

const ascend = new AscendClient({
apiKey: process.env.ASCEND_API_KEY!,
agentId: 'mcp-database-server',
agentName: 'MCP Database Server',
failMode: FailMode.CLOSED
});

const server = new Server({
name: "governed-database-server",
version: "1.0.0"
}, {
capabilities: {
tools: {}
}
});

// Tool definitions
server.setRequestHandler("tools/list", async () => ({
tools: [
{
name: "query",
description: "Execute read-only SQL query",
inputSchema: {
type: "object",
properties: {
sql: { type: "string", description: "SQL SELECT query" }
},
required: ["sql"]
}
},
{
name: "execute",
description: "Execute SQL statement (requires approval)",
inputSchema: {
type: "object",
properties: {
sql: { type: "string", description: "SQL statement" }
},
required: ["sql"]
}
}
]
}));

// Governed tool handler
server.setRequestHandler("tools/call", async (request) => {
const { name, arguments: args } = request.params;

// Determine risk level
const isReadOnly = name === 'query' && /^SELECT/i.test(args.sql);
const riskLevel = isReadOnly ? 'low' : 'high';

// Evaluate governance
const decision = await ascend.evaluateAction({
actionType: `mcp.database.${name}`,
resource: 'production_db',
parameters: { sql: args.sql },
riskIndicators: {
risk_level: riskLevel,
data_access: !isReadOnly
}
});

if (!decision.executionAllowed) {
return {
content: [{
type: "text",
text: `Operation denied by ASCEND governance.\n` +
`Reason: ${decision.reason}\n` +
`Risk Level: ${decision.riskLevel}`
}],
isError: true
};
}

// Execute the query
try {
const result = await executeQuery(args.sql);
await ascend.logActionCompleted(decision.actionId, {
result: { rowCount: result.length }
});
return {
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
};
} catch (error) {
await ascend.logActionFailed(decision.actionId, {
error: { message: error.message }
});
throw error;
}
});

// Start server
const transport = new StdioServerTransport();
await server.connect(transport);

Next Steps


Document Version: 1.0.0 | Last Updated: December 2025