> ## 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.

# Summarizer with safetyCheck

> A free-text tool wrapped with inline content validation.

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](/examples/weather-server) summarizer tool.

## `summarizer.ts`

```ts theme={null}
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())
```

## What happens on a flagged input

If the safety API flags the `text` parameter:

1. The wrapper **doesn't call** your handler.
2. It returns a structured blocked response:
   ```json theme={null}
   {
     "content": [
       { "type": "text", "text": "{ \"summary\": \"🚫 CONTENT BLOCKED: ...\", \"blocked\": true, \"reason\": \"Content flagged by safety check\", \"timestamp\": \"...\" }" }
     ],
     "structuredContent": { "summary": "🚫 CONTENT BLOCKED: ..." }
   }
   ```
3. With `output_screen: true`, your terminal also prints:
   ```text theme={null}
   🚨 Safety Check Alert: Content "..." was flagged as malicious (API latency: 42ms)
   ```
4. The active span gets `mcp.safety_check.flagged = true` plus latency and
   content attributes.

## What happens on a clean input

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.

```ts theme={null}
// shape your outputSchema to match
outputSchema: { summary: z.string() }
```

## Performance

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

<CardGroup cols={2}>
  <Card title="Safety checks concept" icon="shield" href="/concepts/safety-checks">
    Detailed flow and failure modes.
  </Card>

  <Card title="safetyCheck reference" icon="code" href="/api-reference/safety-check">
    Full function signature.
  </Card>
</CardGroup>
