Version: 0.1.0 (Draft)
Status: Proposed
Authors: Magg Contributors
This specification defines the Model Context Protocol (MCP) Proxy Extension, which enables dynamic access to MCP capabilities through a single, unified tool interface. The proxy pattern allows MCP servers to aggregate, gateway, and dynamically expose capabilities from other servers without requiring clients to manage multiple connections.
This specification is based on the implementation in Magg (MCP Aggregator) and serves as a reference for other MCP servers that want to implement similar proxy functionality. The reference implementation can be found in the magg.proxy package.
The MCP Proxy Extension provides a standardized way for MCP servers to expose capabilities from other servers through a single tool. This enables powerful aggregation scenarios while maintaining the simplicity of the MCP protocol.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
- Proxy Tool: The MCP tool that provides unified access to capabilities
- Capability: An MCP tool, resource, or prompt
- Query Action: Operations that return metadata (list, info)
- Call Action: Operations that execute capabilities
The proxy tool SHOULD be named proxy. Servers MAY use an alternative name (e.g., mcp:proxy) if documented.
The proxy tool MUST accept the following parameters:
- Type: String enumeration
- Values:
"list"|"info"|"call" - Description: The operation to perform
- Type: String enumeration
- Values:
"tool"|"resource"|"prompt" - Description: The type of MCP capability to interact with
- Note: Implementations MAY use parameter aliasing to avoid language keyword conflicts
- Type: String
- Description: Name or URI of the specific capability
- Requirements:
- REQUIRED for
infoandcallactions - MUST NOT be provided for
listaction
- REQUIRED for
- Type: Object (key-value pairs)
- Description: Arguments for the capability being called
- Requirements:
- ONLY allowed for
callaction - MUST NOT be provided for
listandinfoactions
- ONLY allowed for
Servers MUST validate parameters and return clear error messages for:
- Missing required parameters
- Invalid parameter combinations
- Unknown action or type values
Query actions MUST return a list containing a single embedded resource with:
[
{
"type": "resource",
"resource": {
"uri": "<proxy-uri>",
"mimeType": "application/json",
"text": "<json-encoded-capability-data>"
},
"annotations": {
"proxyAction": "<action>",
"proxyType": "<type>",
"proxyPath": "<path>", // Only for info action
"pythonType": "<type-identifier>",
"many": <boolean>
}
}
]Query responses MUST include:
proxyAction: The action performed ("list"or"info")proxyType: The capability type ("tool","resource", or"prompt")proxyPath: The specific capability path (ONLY forinfoaction)
Query responses SHOULD include type preservation annotations:
pythonType: A type identifier for deserialization (language-specific name to be generalized)many: Boolean indicating if the data represents multiple objects
Call actions MUST return the actual result from the called capability with proxy annotations.
Returns a list of content items (TextContent, ImageContent, or EmbeddedResource) with each item annotated:
[
{
"type": "text",
"text": "Result content",
"annotations": {
"proxyType": "tool",
"proxyAction": "call",
"proxyPath": "<tool-name>"
}
}
]Resource results MUST be converted to tool result format (EmbeddedResource) with annotations.
When a text resource can be parsed as JSON, implementations SHOULD:
- Parse the text content as JSON
- Re-encode it with consistent formatting
- Set
mimeTypeto"application/json" - Preserve the original MIME type in a
contentTypefield
Example with objectification:
[
{
"type": "resource",
"resource": {
"uri": "<original-resource-uri>",
"mimeType": "application/json",
"text": "{\"key\":\"value\"}",
"contentType": "text/plain" // Original MIME type preserved
},
"annotations": {
"proxyType": "resource",
"proxyAction": "call",
"proxyPath": "<resource-uri>"
}
}
]Example without objectification (binary or non-JSON):
[
{
"type": "resource",
"resource": {
"uri": "<original-resource-uri>",
"mimeType": "image/png",
"blob": "<base64-encoded-data>"
},
"annotations": {
"proxyType": "resource",
"proxyAction": "call",
"proxyPath": "<resource-uri>"
}
}
]Prompt results MUST be wrapped in an EmbeddedResource with the prompt data JSON-encoded:
[
{
"type": "resource",
"resource": {
"uri": "<prompt-uri>",
"mimeType": "application/json",
"text": "<json-encoded-prompt-result>"
},
"annotations": {
"proxyType": "prompt",
"proxyAction": "call",
"proxyPath": "<prompt-name>",
"pythonType": "GetPromptResult"
}
}
]To enable proper deserialization, implementations SHOULD include type information in annotations.
The current Magg implementation uses:
pythonType: String identifier for the data typemany: Boolean indicating if the data represents multiple objects
Future revisions SHOULD generalize these to language-agnostic names such as:
dataTypeorobjectTypeinstead ofpythonTypeisArrayormultipleinstead ofmany
Type identifiers SHOULD use one of these formats:
- Simple names:
"Tool","Resource","Prompt" - Qualified names:
"mcp.types.Tool","mcp.types.Resource" - Union types:
"Resource|ResourceTemplate"
When converting resources to tool results, implementations MUST preserve type information:
- Original MIME Type: If a resource is objectified (converted to JSON), the original MIME type SHOULD be preserved in a
contentTypefield - Objectification: Text resources that parse as valid JSON SHOULD be re-encoded with
mimeType: "application/json" - Binary Resources: Resources with binary content remain unchanged with their original MIME type
This allows clients to understand both the current format and the original format of the resource.
Implementations MAY add additional type preservation mechanisms using custom annotations:
- Python:
pythonTypeannotation with Python type names - TypeScript:
typescriptTypewith TypeScript type names - Other languages:
<language>Typepattern
The proxy tool SHOULD rely on standard MCP error handling mechanisms. Implementations SHOULD raise exceptions (or language-appropriate error mechanisms) that are automatically converted to MCP protocol errors.
When the proxy tool receives invalid parameters, it SHOULD raise appropriate errors:
- Missing required parameters (e.g.,
pathfor info/call actions) - Invalid parameter combinations (e.g.,
argsprovided for list action) - Unknown action or type values
Errors from proxied capabilities SHOULD be propagated naturally:
- Tool not found
- Resource access errors
- Invalid arguments for the proxied capability
These errors are handled the same way as any other MCP tool error - the implementation raises an exception which the MCP protocol layer converts to a proper error response.
Clients SHOULD check for proxy support by:
- Looking for a tool named
proxyin the tool list - Checking tool description for proxy-related keywords
- Attempting to call the proxy tool with valid parameters
The proxy tool enables dynamic capability discovery without maintaining persistent connections:
- Use
action: "list"to enumerate available capabilities - Use
action: "info"to get detailed metadata - Cache results as appropriate for performance
Proxy implementations SHOULD:
- Respect access controls of proxied servers
- Implement per-capability access policies
- Log proxy operations for auditing
Proxy tools MUST NOT:
- Expose internal server details in error messages
- Include sensitive information in annotations
- Bypass authentication of proxied servers
The proxy extension is designed to be backward compatible:
- Clients unaware of proxy tools can ignore them
- Standard MCP operations continue to work normally
- No changes required to existing MCP tools
Future extensions SHOULD:
- Use new annotation namespaces for additional metadata
- Add new capability types through the existing interface
- Maintain the core parameter structure
Clients supporting proxy tools SHOULD:
- Detect proxy tool availability
- Provide convenience methods for proxy operations
- Handle type preservation based on annotations
- Support transparent mode for drop-in compatibility
Servers implementing proxy tools SHOULD:
- Validate all parameters before processing
- Include comprehensive annotations in responses
- Handle errors gracefully with clear messages
- Optimize for performance with connection pooling
Request arguments:
{
"action": "list",
"type": "tool"
}Response (tool result):
[
{
"type": "resource",
"resource": {
"uri": "proxy:list/tool",
"mimeType": "application/json",
"text": "[{\"name\":\"calculator_add\",\"description\":\"Add two numbers\"}]"
},
"annotations": {
"proxyAction": "list",
"proxyType": "tool",
"pythonType": "Tool",
"many": true
}
}
]Request arguments:
{
"action": "call",
"type": "tool",
"path": "calculator_add",
"args": {"a": 5, "b": 3}
}Response (tool result):
[
{
"type": "text",
"text": "8",
"annotations": {
"proxyType": "tool",
"proxyAction": "call",
"proxyPath": "calculator_add"
}
}
]The reference implementation in Magg includes:
-
Server-side proxy (
magg/proxy/server.pyandmagg/proxy/mixin.py):ProxyFastMCPwrapper class that adds proxy capabilities to FastMCP instancesProxyMCPmixin class for servers that want built-in proxy support- Automatic tool registration and capability aggregation
- Result transformation and annotation
-
Client-side wrapper (
magg/proxy/client.py):ProxyClientclass that provides transparent access to proxied servers- Automatic result unwrapping and type conversion
- Lazy connection management
Future versions MAY support batch operations:
{
"action": "batch",
"operations": [
{"action": "call", "type": "tool", "path": "tool1", "args": {}},
{"action": "call", "type": "tool", "path": "tool2", "args": {}}
]
}Large result sets could benefit from streaming:
- Use HTTP streaming for progressive results
- Add pagination parameters for list operations
- Support partial result delivery
Enhanced discovery through filtering:
{
"action": "list",
"type": "tool",
"filter": {
"prefix": "calculator_",
"tags": ["math", "arithmetic"]
}
}