Skip to main content

Intent Declaration

MCPProxy provides intent-based tool splitting - a security feature that enables fine-grained permission control in IDEs like Cursor, Claude Desktop, and other AI coding assistants.

The Problem

With a single call_tool command, IDEs can only offer all-or-nothing permission choices:

MCPProxy Tools:
[x] call_tool → Auto-approve ALL operations? (risky!)
[ ] call_tool → Ask every time? (annoying for reads)

This forces users to choose between security (asking for every operation) and convenience (auto-approving everything, including destructive operations).

The Solution: Tool Splitting

MCPProxy splits tool execution into three variants based on operation type:

Tool VariantPurposeRisk Level
call_tool_readRead-only queriesLow
call_tool_writeCreate/update operationsMedium
call_tool_destructiveDelete/irreversible operationsHigh

This enables granular IDE permission settings:

MCPProxy Tools:
[x] call_tool_read → Auto-approve (safe reads)
[ ] call_tool_write → Ask each time
[ ] call_tool_destructive → Always ask + confirm

How It Works

The tool variant (call_tool_read / write / destructive) automatically determines the operation type. Intent metadata is provided as flat string parameters (not nested objects) for maximum compatibility with AI models:

{
"name": "call_tool_destructive",
"arguments": {
"name": "github:delete_repo",
"args_json": "{\"repo\": \"test-repo\"}",
"intent_data_sensitivity": "private",
"intent_reason": "User requested repository cleanup"
}
}

The operation_type is inferred from the tool variant - agents don't need to specify it explicitly.

Validation Chain

  1. Tool variant determines operation type (call_tool_destructive → "destructive")
  2. Optional intent fields (intent_data_sensitivity, intent_reason) are validated if provided
  3. Server annotation check → validate against destructiveHint/readOnlyHint

Tool Variants

call_tool_read

Execute read-only operations that don't modify state.

{
"name": "github:list_repos",
"args_json": "{\"org\": \"myorg\"}"
}

Or with optional metadata:

{
"name": "github:list_repos",
"args_json": "{\"org\": \"myorg\"}",
"intent_reason": "Listing repositories for project analysis"
}

Validation:

  • operation_type automatically inferred as "read"
  • Rejected if server marks tool as destructiveHint: true

call_tool_write

Execute state-modifying operations that create or update resources.

{
"name": "github:create_issue",
"args_json": "{\"title\": \"Bug report\", \"body\": \"Details...\"}",
"intent_reason": "Creating bug report per user request"
}

Validation:

  • operation_type automatically inferred as "write"
  • Rejected if server marks tool as destructiveHint: true

call_tool_destructive

Execute destructive or irreversible operations.

{
"name": "github:delete_repo",
"args_json": "{\"repo\": \"test-repo\"}",
"intent": {
"intent_data_sensitivity": "private",
"intent_reason": "User confirmed deletion of test repository"
}

Validation:

  • operation_type automatically inferred as "destructive"
  • Most permissive - allowed regardless of server annotations

Intent Parameters

Intent metadata is provided as flat string parameters for maximum compatibility with AI models (e.g., Gemini):

ParameterRequiredValuesDescription
intent_data_sensitivityNopublic, internal, private, unknownData classification for audit
intent_reasonNoString (max 1000 chars)Explanation for audit trail

The operation_type is automatically inferred from the tool variant and cannot be overridden.

Examples

Minimal (no intent needed):

{
"name": "dataserver:read_data",
"args_json": "{\"id\": \"123\"}"
}

With optional metadata:

{
"name": "dataserver:write_data",
"args_json": "{\"id\": \"123\", \"value\": \"new\"}",
"intent_data_sensitivity": "private",
"intent_reason": "Updating user profile with personal information"
}

Server Annotation Validation

MCPProxy validates agent intent against server-provided annotations:

Tool VariantServer AnnotationResult
call_tool_readreadOnlyHint: trueALLOW
call_tool_readdestructiveHint: trueREJECT
call_tool_readNo annotationALLOW (trust agent)
call_tool_writereadOnlyHint: trueWARN + ALLOW
call_tool_writedestructiveHint: trueREJECT
call_tool_writeNo annotationALLOW
call_tool_destructiveAnyALLOW (most permissive)

Strict Mode

By default, strict validation is enabled. Configure via mcp_config.json:

{
"intent_declaration": {
"strict_server_validation": true
}
}

When strict_server_validation: false, server annotation mismatches log a warning but allow the call.

Tool Discovery

The retrieve_tools response includes annotations and guidance:

{
"tools": [
{
"name": "github:delete_repo",
"description": "Delete a GitHub repository",
"inputSchema": {...},
"annotations": {
"destructiveHint": true,
"readOnlyHint": false
},
"call_with": "call_tool_destructive"
},
{
"name": "github:list_repos",
"description": "List repositories",
"inputSchema": {...},
"annotations": {
"readOnlyHint": true
},
"call_with": "call_tool_read"
}
]
}

The call_with field recommends which tool variant to use based on server annotations.

CLI Commands

Execute tools via CLI with explicit intent:

# Read operation
mcpproxy call tool-read github:list_repos --args '{"org": "myorg"}'

# Write operation
mcpproxy call tool-write github:create_issue \
--args '{"title": "Bug", "body": "Details"}' \
--reason "Creating bug report"

# Destructive operation
mcpproxy call tool-destructive github:delete_repo \
--args '{"repo": "test"}' \
--sensitivity private \
--reason "User confirmed deletion"

CLI Flags

FlagDescription
--argsTool arguments as JSON
--reasonOptional reason for audit trail
--sensitivityData sensitivity: public, internal, private, unknown

Activity Log Integration

Intent is recorded in every activity log entry:

mcpproxy activity list
ID              TIME                 SERVER      TOOL          INTENT  STATUS  DURATION
01JG2... 2025-01-15 10:30:00 github create_issue write success 245ms
01JG2... 2025-01-15 10:29:45 github list_repos read success 123ms
01JG2... 2025-01-15 10:29:30 github delete_repo destr success 567ms

Filter by intent type:

# Show only destructive operations
mcpproxy activity list --intent-type destructive

# REST API
curl -H "X-API-Key: $KEY" "http://127.0.0.1:8080/api/v1/activity?intent_type=destructive"

Error Messages

Clear error messages help agents self-correct:

Server annotation conflict:

Tool 'github:delete_repo' is marked destructive by server.
Use call_tool_destructive instead of call_tool_read.

Invalid data sensitivity:

Invalid intent.data_sensitivity 'secret': must be public, internal, private, or unknown

Reason too long:

intent.reason exceeds maximum length of 1000 characters

IDE Configuration Examples

Cursor

In Cursor settings, configure MCP tool permissions:

MCPProxy Tools:
call_tool_read [Auto-approve]
call_tool_write [Ask each time]
call_tool_destructive [Always ask]

Claude Desktop

In claude_desktop_config.json:

{
"mcpServers": {
"mcpproxy": {
"permissions": {
"call_tool_read": "auto",
"call_tool_write": "ask",
"call_tool_destructive": "always_ask"
}
}
}
}

Best Practices

  1. Use the right variant: Match your intent to the appropriate tool variant
  2. Provide reasons: Help audit trails with clear explanations
  3. Classify sensitivity: Mark private data operations appropriately
  4. Trust retrieve_tools: Use the call_with recommendation
  5. Configure IDE permissions: Enable auto-approve for reads, require confirmation for destructive

Migration from call_tool

The legacy call_tool has been removed. Update your integrations:

Before:

{
"name": "call_tool",
"arguments": {
"name": "github:create_issue",
"args_json": "{...}"
}
}

After:

{
"name": "call_tool_write",
"arguments": {
"name": "github:create_issue",
"args_json": "{...}"
}
}

Intent parameters are optional - operation_type is automatically inferred from the tool variant. You can add intent_data_sensitivity and intent_reason for audit purposes.

Choosing the Right Variant

When unsure, use call_tool_destructive - it's the most permissive and will always succeed validation. Then refine based on retrieve_tools guidance.