Skip to content

Configuration

track(server, vendorSlug, options) accepts an existing MCP server instance and connects its SDK activity to the Within API.

Option names below are shown in TypeScript's camelCase; the Python SDK exposes the same options in snake_case on WithinOptions (apiKeyapi_key, privacy.maxFieldBytesPrivacyOptions.max_field_bytes, and so on).

Required inputs

InputTypeDescription
serverMCP serverVendor-owned server instance to track.
vendorSlugstringStable Within vendor slug.
options.apiKeystringServer-side SDK API key issued by Within for this vendor.

apiKey may also come from WITHIN_SDK_API_KEY or WITHIN_SDK_INGEST_KEY — in both SDKs.

Within API origin

apiBaseUrl is an origin such as https://api.getwith.in, not a complete endpoint. The SDK appends its managed /v1/ingest/* paths. Most integrations should use the default.

The origin is resolved in this order:

  1. options.apiBaseUrl
  2. WITHIN_SDK_API_URL
  3. WITHIN_SDK_INGEST_BASE_URL
  4. https://api.getwith.in

WITHIN_SDK_INGEST_BASE_URL remains a compatibility fallback despite its older name.

Capture defaults

These defaults are enabled unless explicitly disabled:

OptionDefaultBehavior
enableTracingtrueObserve MCP lifecycle and tool-call activity.
enableToolCallContexttrueInject the SDK context parameter used to understand tool-call intent.
enableReportMissingtrueRegister the get_more_tools feedback tool. Within stores this as feedback and excludes it from SDK lead scoring.

Injected context remains declared alongside additionalProperties: false. The SDK removes only SDK-injected context before calling vendor handlers. A vendor-declared context field is captured after sanitization and passed through unchanged; tools that already declare context and complex oneOf/allOf/anyOf schemas are skipped rather than modified.

Identity

Use identify() to provide a stable vendor-local user ID when your server can derive one from the MCP request.

ts
track(server, 'acme', {
  apiKey: process.env.WITHIN_SDK_API_KEY!,
  async identify(request, extra) {
    const user = await lookupUserFromSession(extra?.sessionId);
    if (!user) return null;
    return {
      userId: user.internalCustomerId,
      userData: {
        plan: user.plan,
        role: user.role,
      },
    };
  },
});
python
from within_sdk import UserIdentity


def identify(request, context):
    user = lookup_user_from_request(context)
    if not user:
        return None
    return UserIdentity(
        user_id=user.internal_customer_id,
        user_data={"plan": user.plan, "role": user.role},
    )


track(server, "acme", WithinOptions(identify=identify))

The SDK hashes the user ID locally with the vendor slug, drops the user name, and redacts user data before enqueueing or posting events. Use opaque internal IDs rather than email, name, phone, or org-domain values when available.

Each request resolves identity independently. If identify() returns null/None, returns an empty ID, or throws, that request remains anonymous even when an earlier request in the same session was identified.

Privacy

FieldTypeDefaultDescription
privacy.maxFieldBytesnumber10000Max bytes for a single string field before truncation.
privacy.maxEventBytesnumber128000Max captured payload size before omission.
privacy.redactKeysstring[]built-in listAdditional key substrings to redact.
redactSensitiveInformationfunctionnoneOptional text redactor that runs before Within privacy sanitization.
ts
track(server, 'acme', {
  apiKey: process.env.WITHIN_SDK_API_KEY!,
  privacy: {
    redactKeys: ['customer_ref'],
    maxFieldBytes: 2_000,
  },
  redactSensitiveInformation: (text) => scrubInternalCodes(text),
});
python
from within_sdk import PrivacyOptions

track(server, "acme", WithinOptions(
    privacy=PrivacyOptions(
        redact_keys=["customer_ref"],
        max_field_bytes=2_000,
    ),
    redact_sensitive_information=scrub_internal_codes,
))

Within privacy sanitization always runs before SDK activity is sent to the Within API or exported to vendor telemetry sinks.

Exporters

Vendor-configured Datadog, Sentry, PostHog, and OTLP exporters are preserved.

TypeScript only

Exporters are currently available in the TypeScript SDK only.

ts
track(server, 'acme', {
  apiKey: process.env.WITHIN_SDK_API_KEY!,
  exporters: {
    datadog: {
      type: 'datadog',
      apiKey: process.env.DATADOG_API_KEY!,
    },
  },
});

Exporters receive the same sanitized event shape sent to the Within API. Raw user IDs, user names, email-like keys, tokens, and direct identity fields are removed first.

Local diagnostics

SDK operational messages are written to ~/within-sdk.log (in Python, when debug mode is enabled) and to the console in edge runtimes. Provide options.log to replace the default destination — useful in containers and serverless environments where a home-directory log file is unreachable. Local diagnostics are never sent over the network and do not control persisted MCP lifecycle events.

Event tags and properties

Use eventTags for low-cardinality tags and eventProperties for additional workflow metadata.

ts
track(server, 'acme', {
  apiKey: process.env.WITHIN_SDK_API_KEY!,
  eventTags: async () => ({ environment: 'production' }),
  eventProperties: async (_request, extra) => ({
    transport: extra?.headers ? 'http' : 'stdio',
  }),
});
python
track(server, "acme", WithinOptions(
    event_tags=lambda request, extra: {"environment": "production"},
    event_properties=lambda request, extra: {"transport": "http"},
))

Tags and properties are redacted and truncated before send.

Conversion reporting

Use the same opaque vendor-local user ID to report a conversion when that user becomes a subscriber.

ts
import { reportConversion } from 'within-sdk';

await reportConversion({
  vendorSlug: process.env.WITHIN_VENDOR_SLUG!,
  apiKey: process.env.WITHIN_SDK_API_KEY!,
}, {
  userId: user.internalCustomerId,
  convertedAt: new Date(),
  plan: {
    id: 'pro',
    name: 'Pro',
    interval: 'month',
  },
});
python
import os
from datetime import datetime, timezone

from within_sdk import report_conversion

report_conversion(
    os.environ["WITHIN_VENDOR_SLUG"],
    os.environ["WITHIN_SDK_API_KEY"],
    user.internal_customer_id,
    converted_at=datetime.now(timezone.utc),
    plan={"id": "pro", "name": "Pro", "interval": "month"},
)

MCP activity and conversion reports are linked by the same locally generated subject. Reporting a conversion sets the SDK lead to subscriber and stores the latest plan summary. It does not report upgrades, churn, renewals, billing amounts, currency, customer IDs, or subscription IDs. CRM connectors can report broader outcomes; the Salesforce connector is upcoming.

Within SDK turns privacy-safe MCP activity into workflow intelligence and SDK leads.