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

# Instrument a server

> Add Sedata observability to an existing MCP server.

This guide assumes you already have a working MCP server. You'll add
`instrumentServer` and verify traces in under a minute.

## Add the call

`instrumentServer` must run **before** you register tools — it patches
`server.registerTool` and only the calls made afterward are instrumented.

```ts theme={null}
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
import { instrumentServer } from '@sedata-ai/mcp'

const server = new McpServer({ name: 'my-server', version: '1.0.0' })

const telemetry = instrumentServer(server, {
  serverName: 'my-server',
  serverVersion: '1.0.0',
  exporterEndpoint: process.env.OTLP_ENDPOINT ?? 'https://otel.sedata-ai.tech/v1',
  exporterAuth: { type: 'bearer', token: process.env.SEDATA_TOKEN! },
})

// Now register tools — they will all be instrumented.
server.registerTool('hello', { /* ... */ }, async () => /* ... */)
```

<Tip>
  `instrumentServer` returns an [`ObservabilityInstance`](/api-reference/types/observability-instance)
  — keep the reference around to record custom spans and to call `shutdown()`.
</Tip>

## Pick the right `serverName` / `serverVersion`

These map to `service.name` and `service.version` in OpenTelemetry. Use stable
values that match how you operate the service:

```ts theme={null}
serverName: 'weather-mcp',          // not 'my-server'
serverVersion: process.env.GIT_SHA, // or your release tag
```

## Wire shutdown

The OTel SDK is a long-running thing. Always shut it down on exit so the last
batch of metrics flushes (including session duration):

```ts theme={null}
const exit = async (code = 0) => {
  await telemetry.shutdown()
  process.exit(code)
}

process.on('SIGINT', () => exit(0))
process.on('SIGTERM', () => exit(0))
```

## Confirm it works

Three quick checks:

<AccordionGroup>
  <Accordion title="1. Console exporter (no network)" icon="terminal">
    Set `exporterType: 'console'` and watch spans print on stdout when you call
    a tool:

    ```ts theme={null}
    instrumentServer(server, {
      serverName: 'my-server',
      serverVersion: '1.0.0',
      exporterType: 'console',
    })
    ```

    See [Console debugging](/guides/console-debugging).
  </Accordion>

  <Accordion title="2. Sedata dashboard" icon="gauge">
    With the live exporter pointed at `https://otel.sedata-ai.tech/v1`, run
    a tool from any MCP client. Open
    [app.sedata-ai.tech](https://app.sedata-ai.tech) → **Traces**. Latest
    trace should appear within a few seconds.
  </Accordion>

  <Accordion title="3. Your own collector" icon="server">
    Point `exporterEndpoint` at your collector and tail its logs:

    ```bash theme={null}
    docker run --rm -p 4318:4318 otel/opentelemetry-collector-contrib \
      --config /etc/otelcol-contrib/config.yaml
    ```
  </Accordion>
</AccordionGroup>

## Common pitfalls

<Warning>
  **Calling `instrumentServer` after `registerTool`** — tools registered
  before instrumentation are not patched. Always call `instrumentServer`
  immediately after `new McpServer(...)`.
</Warning>

<Warning>
  **Two versions of `@opentelemetry/api`** — if your project pins a different
  version, your tracer will silently no-op. Run `npm ls @opentelemetry/api`
  and dedupe.
</Warning>

<Warning>
  **Sampling 0 in dev** — if `samplingRate: 0` is in a shared config you'll see
  zero spans. Default is `1.0`.
</Warning>

## Next

<CardGroup cols={2}>
  <Card title="Authentication" icon="key" href="/guides/authentication">
    Bearer, API key, basic.
  </Card>

  <Card title="Custom spans & metrics" icon="code" href="/guides/custom-spans-and-metrics">
    Record domain-specific telemetry.
  </Card>
</CardGroup>
