MCP Server Governance
| Field | Value |
|---|---|
| Document ID | ASCEND-SDK-003 |
| Version | 1.0.0 |
| Last Updated | December 19, 2025 |
| Author | Ascend Engineering Team |
| Publisher | OW-KAI Technologies Inc. |
| Classification | Enterprise Client Documentation |
| Compliance | SOC 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 Pattern | Risk Level | Approval |
|---|---|---|
*_read, *_list, *_get | LOW | Auto |
*_create, *_update | MEDIUM | Auto/Single |
*_delete, *_drop | HIGH | Multi |
*_execute, *_admin | CRITICAL | Escalation |
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
- LangChain Integration — Govern LangChain tools
- Custom Agents — Build governed agents
- Smart Rules — Create MCP-specific rules
Document Version: 1.0.0 | Last Updated: December 2025