@sernixa/sdk
v0.6.4
Published
Sernixa TypeScript SDK — governed tool and agent execution with MCP call-gate support
Maintainers
Readme
@sernixa/sdk
TypeScript SDK for Sernixa — governed tool and agent execution with MCP call-gate support.
What This Does
The SDK gates local JavaScript/TypeScript function execution through Sernixa's
approval oracle. Your code runs only after Sernixa returns an approved-style
decision (approved, auto_approved, or executed).
The public SDK calls Sernixa's governed HTTP control API; it is not itself an MCP server. In strict gateway mode, the backend owns the native upstream MCP initialize/initialized/tools-call lifecycle. Compatibility mode leaves post-allow dispatch to the caller.
Before You Start
You need:
- A Sernixa workspace.
- A Sernixa API base URL, for example
https://api.sernixa.comfor hosted environments orhttp://localhost:8000for local development. - A browser-issued access token or an organization API key for automation.
- One function, tool, or MCP-style call to protect first.
Install
From npm:
npm install @sernixa/sdk@latest
export SERNIXA_BASE_URL=https://api.sernixa.com
export SERNIXA_API_KEY="<your-org-api-key>"For local development from this checkout:
npm install
npm -w packages/sdk run build
export SERNIXA_BASE_URL=http://localhost:8000Quick Start
import { Client } from '@sernixa/sdk'
const client = new Client({
baseUrl: process.env.SERNIXA_BASE_URL,
accessToken: process.env.SERNIXA_ACCESS_TOKEN,
// Or use apiKey: process.env.SERNIXA_API_KEY for automation.
})
const readFile = client.intercept(async (path: string) => `contents for ${path}`, {
intentId: 'mcp-read-file',
riskLevel: 'LOW',
operationClass: 'read',
dataSensitivity: 'internal',
systemsTouched: ['workspace'],
})
const result = await readFile('/workspace/report.md')The client also exposes typed control-plane methods for whoami(),
governanceTest(), browser-device login, current-plan and feature checks,
agent lifecycle evidence, Flight Recorder verification, and organization API-key
create/list/get/revoke operations.
Execution Passports
Capture a direct host request as a short-lived proof, then attach it to the exact plan. Verified human direction can authorize bounded work while unrequested scope and hard policy denials remain blocked:
const intent = await client.governanceIssueIntentProof({
provider: 'codex',
sessionId: 'session-123',
turnId: 'turn-123',
cwdDigest: sha256OfCwd,
prompt: directUserPrompt,
workspaceContext: {
repository: 'https://github.com/acme/project.git',
branch: 'main',
packages: [{ name: '@acme/sdk', registry: 'npm', version: '1.4.0' }],
},
})Declare a complete plan, then consume the exact signed proof immediately before your host dispatches each tool:
const passport = await client.governanceEvaluatePlan(
[
{
step_id: 'read-1',
tool_name: 'Read',
action: 'file.read',
arguments: { path: 'README.md' },
resource: 'README.md',
},
],
{ agentType: 'codex', intentProof: intent.intent_proof },
)
const authorization = await client.governanceAuthorizePlanStep({
toolName: 'Read',
action: 'file.read',
arguments: { path: 'README.md' },
resource: 'README.md',
provider: 'codex',
})The backend verifies the signed plan and exact hashes, enforces
organization/principal/expiry bindings, and atomically consumes each proof once.
Changed arguments, undeclared tools, and replay attempts throw
SernixaBlockedError. Authorization never executes the tool or overrides
native host permissions.
If the plan result is review, retain its plan_id and approval_id. After
the reviewer approves it, call governanceEvaluatePlan() again with the
identical plan plus both IDs. The approval is exact-plan and single-use; a
policy deny still wins.
Browser login and plan awareness
const pending = await client.startCliDeviceLogin('Developer workstation')
console.log(pending.verification_uri, pending.user_code)
let login = await client.pollCliDeviceLogin(pending.device_code)
// Poll at pending.interval_seconds until login.status === 'approved'.
const session = new Client({ accessToken: login.access_token })
const plan = await session.currentPlan()
const flight = await session.featureAvailability('flight_recorder')Browser sessions are revocable and carry backend-authoritative organization,
role, plan, and entitlement claims. logoutCliSession() revokes the current
browser session. API-key behavior is unchanged for service automation.
First Run Checklist
- Create or choose a Sernixa workspace.
- Use browser login for an interactive tool or create an organization API key for automation.
- Export
SERNIXA_BASE_URLand the selected credential. - Wrap one low-risk function with
client.intercept(...). - Run the function and confirm the decision appears in the Command Center.
- Move to higher-risk actions only after the low-risk path is working.
Rejected, blocked, expired, and timed-out decisions stop the protected function before the business action runs.
MCP Call Gate
Use mcpCallGate() to request approval for an MCP-style tool call through
Sernixa's governed HTTP call gate:
const response = await client.mcpCallGate({
mcpToolsetId: 'workspace-mcp',
toolName: 'read_file',
intentId: 'read-workspace-file',
arguments: { path: '/workspace/report.md' },
riskLevel: 'LOW',
operationClass: 'read',
dataSensitivity: 'internal',
})
if (response.status === 'accepted' && response.dispatch_mode === 'caller_owned_after_allowed') {
// Compatibility mode only: dispatch from the caller-owned host.
}
if (response.dispatch_mode === 'sernixa_gateway_proxy') {
console.log(response.gateway_enforcement?.protocol_version)
console.log(response.gateway_enforcement?.lifecycle_complete)
// Do not dispatch again: Sernixa already called the private upstream.
}native_mcp_transport remains false because this SDK endpoint is an HTTP
control API, not a public MCP server. dispatch_mode is the execution truth:
caller_owned_after_allowed in compatibility mode and
sernixa_gateway_proxy after strict Sernixa-owned upstream dispatch.
Gateway Wrapper
import { SernixaGateway } from '@sernixa/sdk'
const gateway = new SernixaGateway({
apiKey: process.env.SERNIXA_API_KEY,
mcpProfile: 'prod-tools',
enforceEbpf: true,
})
const result = await gateway.run(() => agent.run({ input: 'Summarize customer risk' }), {
intentId: 'agent-risk-summary',
riskLevel: 'MEDIUM',
operationClass: 'agent_run',
dataSensitivity: 'internal',
})enforceEbpf=true does not start an eBPF collector. It checks /ready and
requires Flight Recorder runtime support outside local_demo.
Delegation
import { Client } from '@sernixa/sdk'
const client = new Client()
const token = await client.createDelegationToken({
delegatorAgentId: 'orchestrator',
delegateeAgentId: 'worker',
scope: {
max_risk_level: 'low',
allowed_operation_classes: ['read'],
},
})
const governed = client.interceptWithDelegation(
async () => 'worker result',
{
intentId: 'delegated-read',
riskLevel: 'LOW',
operationClass: 'read',
dataSensitivity: 'internal',
systemsTouched: ['workspace'],
},
{
agentId: 'worker',
delegationTokenId: token.token_id as string,
signingSecret: process.env.SERNIXA_REQUEST_SIGNING_SECRET!,
},
)
const result = await governed()Error Handling
import {
SernixaBlockedError,
SernixaRejectedError,
SernixaTimeoutError,
SernixaSignatureError,
SernixaDelegationScopeError,
} from '@sernixa/sdk'
try {
await governed()
} catch (error) {
if (error instanceof SernixaBlockedError) {
console.error('Policy blocked:', error.reason)
} else if (error instanceof SernixaRejectedError) {
console.error('Reviewer rejected:', error.reason)
} else if (error instanceof SernixaDelegationScopeError) {
console.error('Delegation scope error:', error.reason)
} else if (error instanceof SernixaSignatureError) {
console.error('Signature error:', error.reason)
} else if (error instanceof SernixaTimeoutError) {
console.error('Approval pending:', error.approvalId)
}
}Environment Variables
| Variable | Default | Description |
| -------------------------------- | ----------------------- | ---------------------------------- |
| SERNIXA_BASE_URL | http://localhost:8000 | Sernixa API base URL |
| SERNIXA_ACCESS_TOKEN | (empty) | Revocable browser session token |
| SERNIXA_API_KEY | (empty) | Organization API key |
| SERNIXA_POLL_INTERVAL_SECONDS | 2 | Seconds between approval polls |
| SERNIXA_POLL_TIMEOUT_SECONDS | 600 | Max seconds to wait for approval |
| SERNIXA_TIMEOUT_MS | 10000 | Per-request HTTP timeout |
| SERNIXA_MAX_RETRIES | 2 | Retries for 429/5xx/network errors |
| SERNIXA_CAPTURE_ARGUMENTS | false | Submit function argument values |
| SERNIXA_REQUEST_SIGNING_KEY_ID | local-request-key-v1 | Key ID for delegation signing |
License
MIT
