-
Notifications
You must be signed in to change notification settings - Fork 954
Feature/client level identifiers #666
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
monahk
wants to merge
6
commits into
modelcontextprotocol:main
Choose a base branch
from
monahk:feature/client-level-identifiers
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Feature/client level identifiers #666
monahk
wants to merge
6
commits into
modelcontextprotocol:main
from
monahk:feature/client-level-identifiers
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Implements the proposal from modelcontextprotocol/modelcontextprotocol#801 to enable passing contextual metadata through MCP tool calls, supporting distributed tracing, multi-tenancy, and request correlation across the protocol boundary. This implementation: - Extends the protocol schema by adding an optional `identifiers` field to CallToolRequest for passing key-value string pairs - Introduces client-level identifiers in ClientOptions that automatically apply to all tool calls made through a client instance - Implements merging logic in Client.callTool() that combines client-level and request-level identifiers (with request taking precedence on conflicts) - Adds server-side configuration via IdentifierForwardingConfig to control how identifiers are processed and forwarded - Provides forwardIdentifiersAsHeaders() utility to convert identifiers into standard HTTP headers for downstream requests - Implements EnhancedRequestHandlerExtra interface with helpers for tool implementations to access and forward identifiers Security considerations: - Identifier forwarding is disabled by default and must be explicitly enabled - Server configuration includes options for filtering allowed keys, limiting the number of identifiers, and restricting value length Documentation: - Added comprehensive README with examples and best practices - Added CHANGELOG entry - Created working example demonstrating both client and request-level identifiers This feature enables important cross-cutting concerns like request tracing, multi-tenant isolation, and authorization context propagation without modifying the core protocol or breaking backward compatibility.
Implements the proposal from modelcontextprotocol/modelcontextprotocol#801 to enable passing contextual metadata through MCP tool calls, supporting distributed tracing, multi-tenancy, and request correlation across the protocol boundary. Core Implementation: - Extends CallToolRequest schema with optional `identifiers` field for key-value string pairs - Adds client-level identifiers in ClientOptions that automatically apply to all tool calls - Implements merging logic in Client.callTool() combining client and request identifiers - Provides server-side IdentifierForwardingConfig for controlling identifier processing - Converts identifiers to X-MCP-* HTTP headers with kebab-to-Pascal-Case transformation - Adds EnhancedRequestHandlerExtra interface with helper methods for tool implementations Comprehensive Testing: ✅ Client-level identifiers only (trace-id, tenant-id forwarded correctly) ✅ Request-level identifiers only (request-id, user-id forwarded correctly) ✅ Identifier merging (4 identifiers: client + request combined successfully) ✅ Conflict resolution (request trace-id correctly overrode client value) ✅ Empty identifiers (no headers sent when empty objects provided) ✅ Backward compatibility (existing code works unchanged, no identifiers = no headers) ✅ Edge cases (long values, special characters, various naming patterns handled) ✅ Header format validation (proper X-MCP- prefix, case transformation) ✅ End-to-end HTTP forwarding (7 test scenarios, 5/5 validation tests passed) Security Features: - Identifier forwarding disabled by default, must be explicitly enabled - Server configuration supports allowedKeys filtering, size limits - Input validation and sanitization of identifier values - No sensitive data mixing (identifiers for tracking, not authentication) Documentation: - Comprehensive README with examples, test coverage, and best practices - CHANGELOG entry documenting all new features - Working example demonstrating both client and request-level identifiers - Complete test suite with automated validation This feature enables critical cross-cutting concerns like request tracing, multi-tenant isolation, and context propagation without modifying the core protocol or breaking backward compatibility. All tests pass with 100% success rate.
Implements a comprehensive identifier forwarding system for distributed tracing, multi-tenancy, and request correlation across MCP tool calls. ## Client-Side Features - Add optional `identifiers` field to `ClientOptions` for client-wide identifiers - Add optional `identifiers` field to `CallToolRequest` schema for per-request identifiers - Implement identifier merging logic with request-level precedence over client-level - Only include identifiers field in requests when non-empty (clean protocol) ## Server-Side Features - Add `IdentifierForwardingConfig` to `ServerOptions` (disabled by default for security) - Implement `forwardIdentifiersAsHeaders()` method for HTTP header conversion - Add comprehensive server-side validation and security filtering: - Key format validation (alphanumeric, hyphens, underscores only) - ASCII-only value validation for HTTP header safety - Configurable count limits with deterministic truncation - Configurable value length limits - Optional whitelist filtering via `allowedKeys` - Extend `EnhancedRequestHandlerExtra` interface with identifiers and helper methods ## Security & Performance - Identifier forwarding disabled by default for security - Multi-layer validation (client merging + server truncation + security filtering) - Optimized validation order (cheapest checks first) - Deterministic behavior via alphabetical sorting for cross-platform consistency - Comprehensive input sanitization prevents header injection attacks ## Developer Experience - Zero breaking changes - fully backward compatible - Rich TypeScript types with proper generics - Helper method `applyIdentifiersToRequestOptions()` for easy HTTP forwarding - Comprehensive test suite with 11 test scenarios covering security edge cases - Detailed documentation with usage examples and security best practices ## Example Usage ```typescript // Client with default identifiers const client = new Client(serverInfo, { identifiers: { "trace-id": "abc-123", "tenant-id": "org-456" } }); // Server with forwarding enabled const server = new McpServer(serverInfo, { identifierForwarding: { enabled: true, allowedKeys: ["trace-id", "tenant-id"] } }); // Tool implementation with header forwarding mcpServer.registerTool("api_call", config, async (args, extra) => { const options = extra.applyIdentifiersToRequestOptions({ headers: { "Content-Type": "application/json" } }); return fetch("https://api.example.com", options); });
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary
Implements client-level request identifiers feature that enables passing contextual metadata (trace IDs, tenant context, user info) through MCP tool calls to downstream APIs. This addresses the lack of standardized observability and multi-tenancy support in the current MCP protocol.
Motivation and Context
Currently, there's no standard way to pass request-scoped metadata like trace IDs, user context, or tenant information from MCP clients through servers to downstream APIs. This creates gaps in:
This implementation provides a clean, backward-compatible solution by allowing clients to configure identifiers that automatically flow through as HTTP headers to downstream services.
Related to community discussion: modelcontextprotocol/modelcontextprotocol#801
How Has This Been Tested?
Comprehensive test suite with 11 scenarios and 100% pass rate:
✅ Core Functionality Tests
trace-id
,tenant-id
forwarded correctly)request-id
,user-id
forwarded correctly)trace-id
correctly overrode client value)✅ Edge Case & Compatibility Tests
[email protected]
, numbers, dashes, underscores)✅ Security Validation Tests
\x00
,\x1F
,\x7F
properly rejected)✅ Header Format Tests
X-MCP-
prefix application✅ End-to-End Validation
Test Results: 11 test scenarios executed, 11/11 validation tests passed, all security measures working correctly.
Breaking Changes
None. This is fully backward compatible:
identifiers
fieldTypes of changes
Checklist
Additional context
Key Design Decisions:
Two-level identifier system: Client-level (applies to all calls) + request-level (per-call) with request taking precedence on conflicts
Security-first approach:
HTTP header transformation: Identifiers converted to
X-MCP-{Key}
headers with kebab-case to Pascal-Case transformation (e.g.,trace-id
→X-MCP-Trace-Id
)Comprehensive server-side configuration:
allowedKeys
whitelist for restricting which identifiers can be forwardedmaxIdentifiers
limit (default: 20) with deterministic alphabetical sortingmaxValueLength
limit (default: 256) for preventing abuseheaderPrefix
customization (default:X-MCP-
)Helper utilities: Added
EnhancedRequestHandlerExtra
interface withapplyIdentifiersToRequestOptions()
to make it easy for tool implementations to forward identifiersSecurity Implementation:
Implementation highlights:
ClientOptions
andCallToolRequest
schemasFiles added/modified: