Overview
MCPcat allows you to identify users and associate their sessions with specific user information. This enables you to track usage patterns, understand user behavior, and provide personalized experiences.
User identification happens automatically on the first tool invocation in a session and persists throughout the entire session.
Basic Implementation
To identify users, provide an identify
callback function when tracking your MCP server:
mcpcat.track(mcpServer, "proj_abc123xyz", {
identify: async (request, extra) => {
// Get token from request arguments or auth info
const token = request.params?.arguments?.token ||
extra.authInfo?.token;
// Validate token and fetch user
const user = await validateTokenAndGetUser(token);
return {
userId: user.id,
userName: user.email,
userData: {
role: user.role,
organization: user.orgId
}
};
}
});
User Identity Object
The identify function should return a UserIdentity
object with the following structure:
interface UserIdentity {
userId: string; // Required: Unique identifier
userName?: string; // Optional: Display name
userData?: Record<string, any>; // Optional: Additional metadata
}
Common Patterns
Token-Based Authentication
Extract user information from authentication tokens:
mcpcat.track(mcpServer, "proj_abc123xyz", {
identify: async (request, extra) => {
// Get token from request arguments or auth info
const token = request.params?.arguments?.token ||
extra.authInfo?.token;
// Validate token and fetch user
const user = await validateTokenAndGetUser(token);
return {
userId: user.id,
userName: user.email,
userData: {
role: user.role,
organization: user.orgId
}
};
}
});
API Key Identification
Identify users based on API keys:
mcpcat.track(mcpServer, "proj_abc123xyz", {
identify: async (request, extra) => {
const apiKey = request.params?.arguments?.apiKey;
const account = await getAccountByApiKey(apiKey);
return {
userId: account.id,
userName: account.organizationName,
userData: {
tier: account.tier,
monthlyUsage: account.currentUsage,
region: account.region
}
};
}
});
MCP Authentication
For servers using MCP’s built-in authentication:
mcpcat.track(mcpServer, "proj_abc123xyz", {
identify: async (request, extra) => {
// Access auth token from extra parameter
const authToken = extra.authInfo?.token;
if (!authToken) {
return null; // Anonymous session
}
// Use the MCP auth token to identify user
const user = await getUserFromMCPToken(authToken);
return {
userId: user.id,
userName: user.email,
userData: {
authProvider: 'mcp',
scopes: extra.authInfo?.scopes
}
};
}
});
Error Handling
Handle identification failures gracefully:
mcpcat.track(mcpServer, "proj_abc123xyz", {
identify: async (request, extra) => {
try {
const user = await fetchUserInfo(request);
return {
userId: user.id,
userName: user.name
};
} catch (error) {
console.error('User identification failed:', error);
// Return null to continue with anonymous tracking
return null;
}
}
});
Function Parameters
The identify function receives parameters that vary between the TypeScript and Python SDKs:
The request structure follows the MCP (Model Context Protocol) specification. The specific types and fields available depend on your SDK:
// TypeScript SDK parameters
identify: async (request, extra) => {
// request: MCP request object
// extra: RequestHandlerExtra object
}
request
The MCP request object following the JSON-RPC format:
{
method: string; // The tool/method being called (e.g., "tools/call")
params?: { // Optional parameters
_meta?: { // Optional metadata
progressToken?: string | number; // Token for progress notifications
};
name?: string; // Tool name being invoked
arguments?: { // Tool-specific arguments passed by the client
// Your custom arguments like userId, apiKey, token, etc. passed into tool calls
[key: string]: any;
};
};
}
The MCP RequestHandlerExtra object providing additional context:
{
signal: AbortSignal; // Abort signal for request cancellation
authInfo?: AuthInfo; // Validated access token information
sessionId?: string; // Session ID from the transport
_meta?: RequestMeta; // Metadata from the original request
requestId: RequestId; // JSON-RPC ID of the request (string | number)
// Functions for sending related messages (not typically used in identify)
sendNotification: (notification: Notification) => Promise<void>;
sendRequest: <U>(request: Request, resultSchema: U, options?: RequestOptions) => Promise<z.infer<U>>;
}
Python: context
The MCP RequestContext object providing session and client information:
# Python context object
context.session # ServerSession object
context.session.client_params.clientInfo.name # Client name
context.session.client_params.clientInfo.version # Client version
context.lifespan_context # Application-specific context storage
Python Authentication Access: In Python MCP servers, authentication tokens are accessed via the get_access_token()
function from mcp.server.auth.middleware.auth_context
, not through the context parameter. This is different from the TypeScript SDK where auth info is available in the extra
parameter.
Common Usage Patterns
identify: async (request, extra) => {
// Access tool arguments
const userId = request.params?.arguments?.userId;
const apiKey = request.params?.arguments?.apiKey;
// Access auth information (if using MCP auth)
const authToken = extra.authInfo?.token;
// Tool name being called
const toolName = request.params?.name;
// Check if request was cancelled
if (extra.signal.aborted) {
return null;
}
// Your identification logic here...
}
Important Considerations
The identify function is called only once per session on the first tool invocation. This minimizes overhead while ensuring consistent user tracking throughout the session.
Anonymous Sessions
If you don’t provide an identify function or if it returns null
, sessions will be tracked anonymously. This is useful for:
- Public APIs where user identification isn’t required
- Development and testing environments
- Respecting user privacy preferences