Documentation Index Fetch the complete documentation index at: https://docs.sedata-ai.tech/llms.txt
Use this file to discover all available pages before exploring further.
Most tools that accept user prose are good candidates for safetyCheck. This
example shows the wrapper in isolation — same shape as the
weather server’s summarizer tool.
summarizer.ts
import { z } from 'zod'
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
import { instrumentServer , safetyCheck } from '@sedata-ai/mcp'
import type { TelemetryConfig } from '@sedata-ai/mcp'
const NAME = 'summarizer-mcp'
const VERSION = '0.1.0'
const server = new McpServer ({ name: NAME , version: VERSION })
const telemetryConfig : TelemetryConfig = {
serverName: NAME ,
serverVersion: VERSION ,
exporterEndpoint: 'https://otel.sedata-ai.tech/v1' ,
exporterAuth: { type: 'bearer' , token: process . env . SEDATA_TOKEN ! },
}
const telemetry = instrumentServer ( server , telemetryConfig )
server . registerTool (
'text-summarizer' ,
{
title: 'Text Summarizer' ,
description: 'Summarize text content' ,
inputSchema: { text: z . string () },
outputSchema: { summary: z . string () },
},
safetyCheck (
async ({ text }) => {
// toy summarizer — replace with your real implementation
const summary = text . length > 120 ? text . slice ( 0 , 120 ) + '...' : text
return {
content: [{ type: 'text' , text: JSON . stringify ({ summary }) }],
structuredContent: { summary },
}
},
{
parameterName: 'text' , // which input field to check
output_screen: true , // log a 🚨 line if flagged
},
),
)
const stop = async ( code = 0 ) => { await telemetry . shutdown (); process . exit ( code ) }
process . on ( 'SIGINT' , () => stop ( 0 ))
process . on ( 'SIGTERM' , () => stop ( 0 ))
server . connect ( new StdioServerTransport ())
If the safety API flags the text parameter:
The wrapper doesn’t call your handler.
It returns a structured blocked response:
{
"content" : [
{ "type" : "text" , "text" : "{ \" summary \" : \" 🚫 CONTENT BLOCKED: ... \" , \" blocked \" : true, \" reason \" : \" Content flagged by safety check \" , \" timestamp \" : \" ... \" }" }
],
"structuredContent" : { "summary" : "🚫 CONTENT BLOCKED: ..." }
}
With output_screen: true, your terminal also prints:
🚨 Safety Check Alert: Content "..." was flagged as malicious (API latency: 42ms)
The active span gets mcp.safety_check.flagged = true plus latency and
content attributes.
The wrapper writes safety attributes (flagged: false, latency, success) to
the span, then calls your handler with the original params unchanged.
Customizing the blocked response
The blocked response uses structuredContent.summary as the summary key. If
your tool’s outputSchema uses a different key, you’ll either:
match the wrapper’s expectation (call your output field summary), or
fork the wrapper for that tool.
// shape your outputSchema to match
outputSchema : { summary : z . string () }
The wrapper adds one round-trip to api.sedata-ai.tech per call. Typical
latency: tens of milliseconds. The wrapper records this latency on the span
as mcp.safety_check.latency_ms so you can monitor it.
If the safety API is unreachable, the wrapper fails open — your handler
runs and the span attribute mcp.safety_check.success is false. Set up an
alert on mcp.safety_check.success = false rate to catch outages.
See also
Safety checks concept Detailed flow and failure modes.
safetyCheck reference Full function signature.