Build Your Own Channel.
Every Arbitex channel is a lightweight adapter that calls one API endpoint. The Security API gives you the full 3-tier DLP pipeline, policy engine, and tamper-proof audit trail in a single HTTP call.
One endpoint. Full inspection.
Every channel module — AI Gateway, Email Relay, File Inspector, AppGuard, MCP Security — calls the same Security API. Your custom channel does too.
POSThttps://api.arbitex.ai/v1Send content, get a decision. The platform engine runs DLP detection across all 3 tiers, evaluates policy rules, records a tamper-proof audit event, and returns allow, block, or redact with findings. Your channel handles the transport; the engine handles everything else.
MCP Security: minimal code, full channel.
MCP Security is the newest Arbitex channel — and the smallest. Here is how it works, section by section.
Authenticate
Validate the incoming JWT. Extract the tenant ID, user identity, and scopes. Every request is tied to a principal before any content is inspected.
# JWT validation — extract tenant + identity
token = request.headers.get("Authorization")
claims = verify_jwt(token, jwks_url=JWKS_ENDPOINT)
tenant_id = claims["tenant_id"]
user_id = claims["sub"]Build Policy Context
Construct the context object the Security API needs: the channel name, the server or source identifier, and the direction (input or output).
# Policy context — tells the engine where this content came from
context = {
"channel": "mcp",
"server_id": request.json["server_id"],
"tool_name": request.json["tool_name"],
"direction": request.json.get("direction", "input"),
"tenant_id": tenant_id,
"user_id": user_id,
}Call the Intake Pipeline
Send the content payload to the Security API. The engine runs all 3 DLP tiers, evaluates policy rules, and returns a decision — all in one call.
# One call — full DLP + policy + audit
result = security_api.evaluate(
payload=request.json["payload"],
context=context,
)
# result.decision: "allow" | "block" | "redact"
# result.findings: [{ "type": "PCI", "entity": "card_number", ... }]Handle the Decision
Act on the engine's decision. Allow passes content through. Block returns an error to the caller. Redact strips sensitive entities and forwards the cleaned content.
# Enforce — your channel's only branching logic
if result.decision == "allow":
return forward(request.json["payload"])
elif result.decision == "block":
return error_response(403, result.findings)
elif result.decision == "redact":
return forward(result.redacted_payload)Audit Event Logged Automatically
You do not need to write audit code. The Security API records every evaluation — content hash, policy decision, findings, and tamper-proof audit trail link — automatically. Your channel gets full audit trail coverage for free.
Self-service client registration.
Register your application as a named client identity. Every client gets its own API key, per-client policy, rate limits, and usage dashboard — without opening a support ticket.
Client Registration
Name your client, describe what it does, and select a transport type — API, MCP, or sidecar. The portal generates an API key and an SDK snippet scoped to that client. The platform ties every request to a named identity, not just an IP or tenant.
Sandbox Environment
New clients start in sandbox mode. Sandbox requests flow through the same DLP pipeline and policy engine but production enforcement is not applied — findings are recorded without blocking. Test your integration before it matters.
Production Promotion
Sandbox-to-production promotion requires admin approval by default. Admins can configure three self-service modes: Off (always requires approval), Approval Flow (60-day default sandbox lifespan, then approval), or Auto (admin-set lifespan, fully auditable). Every promotion is logged.
Per-Client Dashboard
Each registered client gets its own usage dashboard — request volume, DLP findings by policy, rate limit headroom, and webhook delivery status. Inline documentation is attached to the client record so the integration context never gets lost.
Call the Security API from any language.
The integration is a single HTTP POST. Here are minimal working examples in six languages.
Python
import httpx
import os
API_KEY = os.environ["ARBITEX_API_KEY"]
def evaluate(text: str, server: str,
direction: str = "input") -> dict:
resp = httpx.post(
"https://api.arbitex.ai/v1/mcp/evaluate",
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"server_id": server,
"tool_name": "custom",
"payload": text,
"direction": direction,
},
)
return resp.json()
# {"decision": "allow"|"block"|"redact",
# "findings": [...]}JavaScript
const API_KEY = process.env.ARBITEX_API_KEY;
async function evaluate(text, server,
direction = "input") {
const res = await fetch(
"https://api.arbitex.ai/v1/mcp/evaluate",
{
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
server_id: server,
tool_name: "custom",
payload: text,
direction,
}),
}
);
return res.json();
}Go
func evaluate(text, server,
dir string) (Result, error) {
body, _ := json.Marshal(map[string]string{
"server_id": server,
"tool_name": "custom",
"payload": text,
"direction": dir,
})
req, _ := http.NewRequest("POST",
"https://api.arbitex.ai/v1/mcp/evaluate",
bytes.NewReader(body))
req.Header.Set("Authorization",
"Bearer "+os.Getenv("ARBITEX_API_KEY"))
req.Header.Set("Content-Type",
"application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil { return Result{}, err }
defer resp.Body.Close()
var result Result
json.NewDecoder(resp.Body).Decode(&result)
return result, nil
}Java
HttpClient client = HttpClient.newHttpClient();
String evaluate(String text, String server,
String direction) throws Exception {
String json = String.format(
"{\"server_id\":\"%s\","
+ "\"tool_name\":\"custom\","
+ "\"payload\":\"%s\","
+ "\"direction\":\"%s\"}",
server, text, direction);
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create(
"https://api.arbitex.ai/v1/mcp/evaluate"))
.header("Authorization",
"Bearer " + System.getenv("ARBITEX_API_KEY"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers
.ofString(json))
.build();
return client.send(req,
HttpResponse.BodyHandlers.ofString())
.body();
}Rust
async fn evaluate(
text: &str, server: &str, direction: &str,
) -> Result<Value, reqwest::Error> {
let client = reqwest::Client::new();
let resp = client
.post("https://api.arbitex.ai/v1/mcp/evaluate")
.bearer_auth(std::env::var("ARBITEX_API_KEY")
.unwrap())
.json(&serde_json::json!({
"server_id": server,
"tool_name": "custom",
"payload": text,
"direction": direction,
}))
.send()
.await?;
resp.json().await
}C++
std::string evaluate(
const std::string& text,
const std::string& server,
const std::string& direction) {
httplib::Client cli(
"https://api.arbitex.ai");
httplib::Headers headers = {
{"Authorization",
"Bearer " + std::string(
std::getenv("ARBITEX_API_KEY"))},
{"Content-Type", "application/json"}
};
std::string body =
R"({"server_id":")" + server +
R"(","tool_name":"custom","payload":")" +
text + R"(","direction":")" +
direction + R"("})";
auto res = cli.Post(
"/v1/mcp/evaluate", headers,
body, "application/json");
return res->body;
}Your content source. Our inspection engine.
See the channel size table on the Platform page to understand just how lightweight each adapter is.