Skip to main content
FrontMcpContext provides per-request state that flows through the entire async execution chain. It enables distributed tracing, timing, request-scoped data storage, context-aware fetch, and transport access.

Overview

Every HTTP request to your FrontMCP server creates a FrontMcpContext that:
  • Propagates through all stages, tools, resources, and prompts via AsyncLocalStorage
  • Provides W3C Trace Context for distributed tracing
  • Stores authentication information after verification
  • Tracks timing marks for performance monitoring
  • Provides request-scoped key-value storage
  • Offers context-aware fetch with auto-injection
  • Enables transport access for elicit requests

Accessing Context

From Tools/Resources/Prompts

Use the context getter for convenient access:
import { Tool } from '@frontmcp/sdk';
import { z } from 'zod';

@Tool({ name: 'my-tool', inputSchema: { query: z.string() } })
class MyTool {
  async execute({ query }) {
    const ctx = this.context;
    // or: const ctx = this.get(FRONTMCP_CONTEXT);

    console.log(`Request ${ctx.requestId} from session ${ctx.sessionId}`);
    return `Processed: ${query}`;
  }
}

Safe Access

Use tryGetContext() when context may not be available (e.g., during initialization or in non-HTTP flows):
const ctx = this.tryGetContext();
if (ctx) {
  console.log(ctx.requestId);
} else {
  console.log('No context available');
}

From CONTEXT-Scoped Providers

CONTEXT-scoped providers can receive FrontMcpContext via factory injection:
import { ProviderScope, FRONTMCP_CONTEXT, FrontMcpContext } from '@frontmcp/sdk';

const requestLoggerProvider = {
  provide: 'RequestLogger',
  scope: ProviderScope.CONTEXT,
  factory: (ctx: FrontMcpContext) => ({
    log: (msg: string) => console.log(`[${ctx.requestId}] ${msg}`),
  }),
  inject: [FRONTMCP_CONTEXT],
};

Context-Aware Fetch

FrontMcpContext provides a fetch() method that automatically injects headers:
const ctx = this.context;

// Automatically injects:
// - Authorization: Bearer <token> (if authInfo.token is available)
// - traceparent: <W3C trace context>
// - x-request-id: <request ID>
// - Custom x-frontmcp-* headers from request metadata
const response = await ctx.fetch('https://api.example.com/data');

Configuration

Configure fetch behavior via context config:
// In FrontMcpContextArgs
{
  config: {
    autoInjectAuthHeaders: true,       // Default: true
    autoInjectTracingHeaders: true,    // Default: true
    requestTimeout: 30000,             // Default: 30000ms
  }
}

Custom Headers

Additional headers can be passed and will be merged:
const response = await ctx.fetch('https://api.example.com/data', {
  headers: {
    'X-Custom-Header': 'value',
  },
});

Transport Access (Elicit)

Access the transport for interactive prompts:
const ctx = this.context;

if (ctx.transport?.supportsElicit) {
  const result = await ctx.transport.elicit('Please confirm your action', schema);

  switch (result.action) {
    case 'accept':
      console.log('User accepted:', result.content);
      break;
    case 'decline':
      console.log('User declined');
      break;
    case 'cancel':
      console.log('User cancelled');
      break;
  }
}

Distributed Tracing

FrontMcpContext automatically parses W3C Trace Context headers for distributed tracing compatibility.

Supported Headers

HeaderDescription
traceparentW3C standard: {version}-{trace-id}-{parent-id}-{flags}
tracestateVendor-specific trace data
x-frontmcp-trace-idFallback for non-W3C clients

Using Trace Context

const ctx = this.context;

// Access trace identifiers
const { traceId, parentId, traceFlags, traceState } = ctx.traceContext;

console.log(`Trace: ${traceId}, Parent: ${parentId}, Flags: ${traceFlags}`);

// Use ctx.fetch() for automatic trace propagation
const response = await ctx.fetch('https://api.example.com/data');

Integration with Observability Tools

FrontMCP’s trace context is compatible with:
  • OpenTelemetry
  • Datadog APM
  • AWS X-Ray
  • Jaeger
  • Zipkin

Timing & Performance

Track execution timing with marks for performance monitoring:
const ctx = this.context;

// Mark stages
ctx.mark('validation-start');
await this.validateInput();
ctx.mark('validation-end');

ctx.mark('db-query-start');
await this.queryDatabase();
ctx.mark('db-query-end');

// Measure elapsed time
console.log(`Validation: ${ctx.elapsed('validation-start', 'validation-end')}ms`);
console.log(`DB Query: ${ctx.elapsed('db-query-start', 'db-query-end')}ms`);
console.log(`Total: ${ctx.elapsed()}ms`); // From request start to now

Performance Logging

// Log all timing marks at the end of request
const marks = ctx.getMarks();
for (const [name, timestamp] of marks) {
  console.log(`${name}: ${timestamp - ctx.timestamp}ms from start`);
}

Context-Scoped Storage

Store and retrieve data that lives only for the duration of the request:
const ctx = this.context;

// Store data
ctx.set('correlation-id', crypto.randomUUID());
ctx.set('feature-flags', { newUI: true, betaFeatures: false });

// Retrieve data (later in the same request)
const correlationId = ctx.get<string>('correlation-id');
const flags = ctx.get<{ newUI: boolean }>('feature-flags');

// Check existence
if (ctx.has('correlation-id')) {
  // ...
}

// Delete data
ctx.delete('feature-flags');

Request Metadata

Access HTTP request metadata:
const ctx = this.context;
const { metadata } = ctx;

console.log(`User-Agent: ${metadata.userAgent}`);
console.log(`Client IP: ${metadata.clientIp}`);
console.log(`Content-Type: ${metadata.contentType}`);
console.log(`Accept: ${metadata.accept}`);

// Custom x-frontmcp-* headers
console.log(`Custom headers:`, metadata.customHeaders);

Authentication

Access authentication information via the context:
const ctx = this.context;
const { authInfo } = ctx;

// JWT token
if (authInfo.token) {
  console.log(`Token present, expires: ${authInfo.expiresAt}`);
}

// User information
if (authInfo.user) {
  console.log(`User: ${authInfo.user.email}`);
  console.log(`Tenant: ${authInfo.user.tenantId}`);
}

// Session information
console.log(`Session: ${authInfo.sessionId}`);
authInfo is Partial<AuthInfo> because authentication information is progressively populated during the request lifecycle. Fields are fully populated after the authorization stage completes.

Logging

Get a child logger with context attached:
const ctx = this.context;
const logger = ctx.getLogger(this.logger);

// Logger includes requestId and traceId prefix
logger.info('Processing request'); // [abc12345:def67890] Processing request

// Get summary for structured logging
const logContext = ctx.toLogContext();
// {
//   requestId: 'abc12345-...',
//   traceId: 'def67890...',
//   sessionIdHash: 'a1b2c3d4e5f6', // Hashed for privacy
//   scopeId: 'main',
//   flowName: 'tools/call',
//   elapsed: 123,
// }

API Reference

FrontMcpContext Class

PropertyTypeDescription
requestIdstringUnique request identifier (UUID v4)
traceContextTraceContextW3C Trace Context data
sessionIdstringMCP session identifier
authInfoPartial<AuthInfo>Authentication information
scopeIdstringCurrent scope identifier
timestampnumberRequest start timestamp (ms since epoch)
metadataRequestMetadataHTTP request metadata
configFrontMcpContextConfigContext configuration
transportTransportAccessor | undefinedTransport for elicit requests
flowFlowBaseRef | undefinedCurrent flow reference
scopeScopeRef | undefinedCurrent scope reference
sessionMetadataSessionIdPayload | undefinedSession metadata (protocol, platform)
MethodSignatureDescription
markmark(name: string): voidRecord a timing mark
elapsedelapsed(from?: string, to?: string): numberGet elapsed time in ms
getMarksgetMarks(): ReadonlyMap<string, number>Get all timing marks
setset<T>(key: string | symbol, value: T): voidStore context-scoped data
getget<T>(key: string | symbol): T | undefinedRetrieve context-scoped data
hashas(key: string | symbol): booleanCheck if key exists
deletedelete(key: string | symbol): booleanDelete a key
getLoggergetLogger(parent: FrontMcpLogger): FrontMcpLoggerGet child logger with context
toLogContexttoLogContext(): Record<string, unknown>Get summary for logging
fetchfetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>Context-aware fetch
updateAuthInfoupdateAuthInfo(authInfo: Partial<AuthInfo>): voidUpdate auth info (internal)
updateSessionMetadataupdateSessionMetadata(metadata: SessionIdPayload): voidUpdate session metadata (internal)

TraceContext Interface

PropertyTypeDescription
traceIdstring32-character hex trace identifier
parentIdstring | undefined16-character hex parent span ID
traceFlagsnumberTrace flags (e.g., 1 for sampled)
traceStatestring | undefinedVendor-specific trace state
rawstringRaw traceparent header value

RequestMetadata Interface

PropertyTypeDescription
userAgentstring | undefinedUser-Agent header
contentTypestring | undefinedContent-Type header
acceptstring | undefinedAccept header
clientIpstring | undefinedClient IP address
customHeadersRecord<string, string>Headers matching x-frontmcp-*

TransportAccessor Interface

Property/MethodTypeDescription
supportsElicitbooleanWhether transport supports elicit
elicit<T>(message: string, schema: T): Promise<ElicitResult>Send elicit request

Key Features

  1. Unified Context: All request-scoped data in one place
  2. Better Tracing: Access trace IDs alongside auth info
  3. Context-Aware Fetch: Auto-inject headers in outgoing requests
  4. Transport Access: Use elicit directly from context
  5. Timing Integration: Correlate auth with performance metrics
  6. Future-Proof: New features will be added to FrontMcpContext