Appearance
MCP Integration
within-sdk tracks a vendor MCP server instance. The SDK observes supported MCP request handlers and high-level tool registrations. By default it adds a required context field to advertised tool schemas and adds get_more_tools to the tool list.
Supported servers
- TypeScript/JavaScript: high-level
McpServerand compatible low-level servers from@modelcontextprotocol/sdk1.11+. - Python: official
mcpservers (1.2+ and 2.x — bothFastMCPandMCPServer), community FastMCP v2 and v3 servers, and compatible low-level servers.
Server setup
Create your MCP server normally, register tools, then call track().
ts
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { track } from 'within-sdk';
const server = new McpServer({
name: 'acme',
version: '1.0.0',
});
server.tool(
'search_companies',
'Search for companies by domain, revenue, or competitor.',
SearchCompaniesSchema,
async (args) => searchCompanies(args),
);
track(server, 'acme', {
apiKey: process.env.WITHIN_SDK_API_KEY!,
});
export { server };python
from mcp.server import MCPServer # mcp 1.x: from mcp.server.fastmcp import FastMCP
from within_sdk import track, WithinOptions
server = MCPServer("acme")
@server.tool()
def search_companies(query: str) -> str:
"""Search for companies by domain, revenue, or competitor."""
return search_companies_impl(query)
# api_key is read from the WITHIN_SDK_API_KEY environment variable
track(server, "acme", WithinOptions())What gets instrumented
For supported MCP servers, the SDK records:
initialize,tools/list, andtools/calllifecycle events- catalog updates from
tools/list - tool name, arguments, result, success or error state, and duration
- MCP client and protocol metadata when present
- the locally hashed user ID from
identify()when configured - redacted
identify()user-data traits when configured get_more_toolsfeedback, excluded from SDK lead scoring
All payload fields are redacted and truncated before delivery to the Within API or a vendor-configured exporter (TypeScript SDK only). The SDK uses its configured Within API origin and appends the SDK-managed /v1/ingest/* paths.
Identity
Use identify() when your MCP runtime can derive a stable vendor-local user ID.
ts
track(server, 'acme', {
apiKey: process.env.WITHIN_SDK_API_KEY!,
async identify(_request, extra) {
const account = await accountFromSession(extra?.sessionId);
if (!account) return null;
return {
userId: account.internalAccountId,
userData: {
plan: account.plan,
tier: account.tier,
},
};
},
});python
from within_sdk import UserIdentity
def identify(request, context):
# On HTTP transports, context.request is the incoming HTTP request —
# resolve your account from its headers, session, or verified claims.
account = account_from_request(context)
if not account:
return None
return UserIdentity(
user_id=account.internal_account_id,
user_data={"plan": account.plan, "tier": account.tier},
)
track(server, "acme", WithinOptions(identify=identify))Within hashes the user ID locally with the vendor slug, drops the user name, and sends only redacted user data.
Language note
The TypeScript identify callback may be async and receives pre-verified auth info via extra.authInfo when the server framework provides it. The Python callback is synchronous and receives the request context; on HTTP transports context.request exposes the raw request for claim verification.
Conversions stay explicit
When the same user later becomes a subscriber, report a conversion from trusted server-side checkout, webhook, or account-upgrade code using the same opaque vendor-local ID.
ts
await reportConversion({
vendorSlug: 'acme',
apiKey: process.env.WITHIN_SDK_API_KEY!,
}, {
userId: account.internalAccountId,
plan: { id: 'pro', name: 'Pro', interval: 'month' },
});python
from within_sdk import report_conversion
report_conversion(
"acme",
os.environ["WITHIN_SDK_API_KEY"],
account.internal_account_id,
plan={"id": "pro", "name": "Pro", "interval": "month"},
)The SDK creates the same subject locally in both paths, so Within can connect MCP activity and conversion without receiving the raw user ID. The subject hash is byte-identical across the TypeScript SDK, the Python SDK, and Within connectors — activity captured by one joins outcomes reported by another.
Reporting a conversion records a confirmed conversion and sets the SDK lead to subscriber. It does not report upgrades, churn, renewals, or billing amounts. CRM connectors can report broader outcomes; the Salesforce connector is upcoming.
Pass-through guarantee
The SDK returns the original tool result and rethrows original errors. SDK-injected context is removed before the vendor handler runs, while a vendor-declared context field is passed through unchanged (the SDK skips context injection for tools that already declare context and for complex oneOf/allOf/anyOf schemas). Reporting happens in the background. Within availability does not block the vendor tool call.
If the SDK cannot observe the server adapter safely, it returns the vendor server unchanged, logs the issue when possible, and avoids changing tool behavior. track() never throws into the host server — configuration problems disable analytics and log a warning.
