What Interactive Feedback MCP Actually Is
Most MCP servers are one-directional: a tool gets called, it executes, it returns a result. The AI agent moves on. That model works perfectly for deterministic operations — querying a database, fetching a URL, running a calculation. It falls apart the moment your agent touches anything where a wrong autonomous decision has real consequences.
Interactive Feedback MCP solves this by inserting a human-in-the-loop layer directly into the tool call chain. When an agent invokes a feedback-enabled tool, execution pauses. A prompt surfaces to a human reviewer — in a terminal dialog, a browser UI, or a custom interface — and the agent receives the human's response as structured data before continuing.
The result is an AI workflow that can ask questions, request approval, surface diffs for review, and collect free-form input — all within the standard MCP tool-calling protocol, without custom integration code in your application layer.
In under 60 words: Interactive Feedback MCP is an MCP server that adds bidirectional human interaction to AI agent workflows. Instead of autonomous end-to-end execution, agents can pause at checkpoints, show humans what they're about to do, collect approvals or free-form input, and proceed only when a human confirms. It uses standard JSON-RPC tool calls so it works with any MCP-compatible client.
Why Non-Interactive AI Agents Break in Production
Before getting into setup, it's worth being precise about the failure mode this solves — because if you don't understand the failure, you'll configure the solution wrong.
A non-interactive agent working on a production task (say, refactoring a live codebase or submitting records to an external API) faces a compounding uncertainty problem:
- The model interprets the user's intent — this interpretation may be subtly wrong
- The model selects a plan — the plan may have side effects the user didn't anticipate
- Each tool call builds on the previous result — early errors amplify
- There's no checkpoint to catch drift before it causes damage
This isn't a model capability problem. GPT-4, Claude 3.5, Gemini — all of them will confidently execute a subtly wrong plan to completion if nothing stops them. The interactive feedback layer is that stop.
What changes with Interactive Feedback MCP:
| Scenario | Without Feedback MCP | With Feedback MCP |
|---|---|---|
| Deleting production records | Executes silently | Pauses, shows scope, requires approval |
| Sending 500 emails | Sends all 500 | Shows recipient list, waits for confirm |
| Deploying to prod | Deploys immediately | Diffs shown to human, deploy blocked until approved |
| Ambiguous user request | Agent guesses | Agent asks clarifying question via feedback tool |
| Multi-step refactor | Completes full rewrite | Human reviews each logical chunk |
The table above covers the common cases. The deeper insight is that interactive feedback isn't just a safety mechanism — it's an interface pattern. It lets agents work on genuinely complex, ambiguous tasks that would be too risky to fully automate, by keeping a human meaningfully in the loop rather than just watching logs after the fact.
Want to analyze your API security?
Import your OpenAPI spec and generate a Security Report automatically.
Architecture: How the Feedback Loop Works
┌─────────────────────────────────────────────────────────────────┐
│ MCP Client │
│ (Claude Desktop / Claude Code / Cursor) │
└──────────────────────────┬──────────────────────────────────────┘
│ JSON-RPC tool call
│ tools/call → request_feedback
▼
┌─────────────────────────────────────────────────────────────────┐
│ Interactive Feedback MCP Server │
│ │
│ ┌─────────────────┐ ┌──────────────────┐ │
│ │ Tool Registry │ │ Session Manager │ │
│ │ - request_ │ │ - pending queue │ │
│ │ feedback │ │ - timeout mgr │ │
│ │ - submit_ │ │ - token store │ │
│ │ response │ └──────────────────┘ │
│ └─────────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────────────────────────┐ │
│ │ Transport Layer │ │
│ │ stdio (local) / SSE (remote) │ │
│ └─────────────────────────────────────────┘ │
└──────────────────────────┬──────────────────────────────────────┘
│
┌──────────────┴──────────────┐
▼ ▼
┌─────────────────┐ ┌──────────────────────┐
│ Terminal / TUI │ │ Browser UI (SSE) │
│ (stdio mode) │ │ Human Reviewer │
└────────┬────────┘ └──────────┬───────────┘
│ Human input │ Human input
└──────────────┬──────────────┘
▼
Structured response returned
to agent via JSON-RPC result
Data flow in detail:
- The agent calls
request_feedbackwith a payload describing what it needs (approval, clarification, selection, etc.) - The feedback server registers the request in its pending queue with a unique session ID
- The request is surfaced to the human reviewer via the configured interface (terminal prompt or browser UI)
- The human responds — approves, rejects, or provides free-form input
- The server packages the response into a structured JSON-RPC result and returns it to the agent
- The agent reads the result and continues (or halts, based on the response)
The agent is blocked during step 2–5. From the MCP protocol perspective, this is a long-running tool call — the connection stays open while the human decides. This is why timeout configuration matters.
Prerequisites
Before installing, confirm you have:
- Python 3.10+ (the reference implementation is Python-based)
- uv package manager (strongly recommended over pip for MCP servers)
- At least one MCP-compatible client: Claude Desktop 0.10+, Claude Code, or Cursor 0.40+
- Basic familiarity with MCP server configuration (JSON config files)
If you're new to MCP concepts generally, review the MCP protocol specification before continuing — this guide assumes you understand what tools, resources, and transports are.
Installation
Option 1: Install via uvx (Recommended)
The fastest path to a running server — no virtual environment management required:
# Verify uvx is available
uvx --version
# Test the server starts correctly
uvx interactive-feedback-mcp
uvx runs the package in an isolated environment and resolves dependencies automatically. This is the preferred approach for MCP servers because it avoids dependency conflicts with your project's own Python environment.
Option 2: Install via pip into a virtual environment
Use this if you need to modify the server source or pin specific versions:
# Create and activate a virtual environment
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
# Install the package
pip install interactive-feedback-mcp
# Verify installation
python -m interactive_feedback_mcp --version
Option 3: Install from source
For contributors or teams that need to patch the server:
git clone https://github.com/noopstudios/interactive-feedback-mcp.git
cd interactive-feedback-mcp
# Install with uv
uv sync
# Or with pip
pip install -e .
Configuration Reference
The feedback server accepts configuration through environment variables and a JSON config object passed by the MCP client. Here's the complete configuration surface:
Environment Variables
# Maximum seconds to wait for human response before returning timeout error
FEEDBACK_TIMEOUT_SECONDS=300
# Transport mode: 'stdio' (default) or 'sse'
FEEDBACK_TRANSPORT=stdio
# SSE mode only: port to listen on
FEEDBACK_SSE_PORT=8765
# SSE mode only: host to bind
FEEDBACK_SSE_HOST=127.0.0.1
# Log level: DEBUG, INFO, WARNING, ERROR
FEEDBACK_LOG_LEVEL=INFO
# Enable approval token signing (production)
FEEDBACK_SIGN_TOKENS=true
FEEDBACK_TOKEN_SECRET=your-secret-here
# Allow anonymous submissions (disable in production)
FEEDBACK_ALLOW_ANONYMOUS=false
Server Capabilities Exposed as MCP Tools
The server registers three primary tools:
{
"tools": [
{
"name": "request_feedback",
"description": "Pause execution and request human input. Use for approvals, clarifications, and confirmations before irreversible actions.",
"inputSchema": {
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": ["approval", "input", "selection", "confirmation"],
"description": "The type of human interaction needed"
},
"message": {
"type": "string",
"description": "What to show the human reviewer"
},
"context": {
"type": "object",
"description": "Structured context to display alongside the prompt (diffs, metadata, risk info)"
},
"options": {
"type": "array",
"items": { "type": "string" },
"description": "For 'selection' type: the options to choose from"
},
"default": {
"type": "string",
"description": "Default value if human presses enter without input"
},
"timeout_override": {
"type": "integer",
"description": "Override the global timeout for this specific request"
}
},
"required": ["type", "message"]
}
},
{
"name": "submit_feedback",
"description": "Submit a human response to a pending feedback request. Used by the reviewer UI.",
"inputSchema": {
"type": "object",
"properties": {
"session_id": { "type": "string" },
"response": { "type": "string" },
"approved": { "type": "boolean" }
},
"required": ["session_id", "response"]
}
},
{
"name": "list_pending_feedback",
"description": "List all pending feedback requests awaiting human response.",
"inputSchema": {
"type": "object",
"properties": {}
}
}
]
}
Claude Desktop Integration
Open your Claude Desktop configuration file:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
Minimal Configuration (stdio, local use)
{
"mcpServers": {
"interactive-feedback": {
"command": "uvx",
"args": ["interactive-feedback-mcp"],
"env": {
"FEEDBACK_TIMEOUT_SECONDS": "120",
"FEEDBACK_LOG_LEVEL": "INFO"
}
}
}
}
Production Configuration (stdio, signed tokens)
{
"mcpServers": {
"interactive-feedback": {
"command": "uvx",
"args": ["interactive-feedback-mcp"],
"env": {
"FEEDBACK_TIMEOUT_SECONDS": "300",
"FEEDBACK_SIGN_TOKENS": "true",
"FEEDBACK_TOKEN_SECRET": "${FEEDBACK_SECRET}",
"FEEDBACK_ALLOW_ANONYMOUS": "false",
"FEEDBACK_LOG_LEVEL": "WARNING"
}
}
}
}
Note on secrets: Claude Desktop doesn't support
.envfiles directly. SetFEEDBACK_SECRETas a system environment variable before launching Claude Desktop, or use a secrets manager that injects environment variables at process start.
After Configuration
- Save the config file
- Fully quit Claude Desktop (menu bar → Quit, not just close the window)
- Reopen Claude Desktop
- Open a new conversation and verify the
interactive-feedbackserver appears in the MCP server list
Claude Code Integration
Claude Code uses a different config path and supports project-level MCP server definitions:
Global Configuration
# Add the server globally (available in all Claude Code sessions)
claude mcp add interactive-feedback uvx interactive-feedback-mcp \
--env FEEDBACK_TIMEOUT_SECONDS=180 \
--env FEEDBACK_LOG_LEVEL=INFO
Project-Level Configuration
For team projects where you want everyone to share the same feedback server config:
# In your project root
claude mcp add interactive-feedback uvx interactive-feedback-mcp \
--scope project \
--env FEEDBACK_TIMEOUT_SECONDS=300
This creates a .mcp.json file in your project root. Commit this file to give your whole team the same MCP configuration:
{
"mcpServers": {
"interactive-feedback": {
"command": "uvx",
"args": ["interactive-feedback-mcp"],
"env": {
"FEEDBACK_TIMEOUT_SECONDS": "300",
"FEEDBACK_LOG_LEVEL": "INFO"
}
}
}
}
Verify Claude Code Connection
# List connected MCP servers
claude mcp list
# Check server status
claude mcp get interactive-feedback
You should see the server listed as connected with the three feedback tools available.
Cursor Integration
Cursor uses a ~/.cursor/mcp.json global config or a .cursor/mcp.json project config:
Global Cursor Config
{
"mcpServers": {
"interactive-feedback": {
"command": "uvx",
"args": ["interactive-feedback-mcp"],
"env": {
"FEEDBACK_TIMEOUT_SECONDS": "240",
"FEEDBACK_LOG_LEVEL": "INFO"
}
}
}
}
SSE Mode for Cursor (Remote Teams)
If your team runs a shared feedback server that multiple developers connect to:
{
"mcpServers": {
"interactive-feedback": {
"url": "https://feedback.yourcompany.internal/sse",
"headers": {
"Authorization": "Bearer ${FEEDBACK_API_TOKEN}"
}
}
}
}
The shared server approach makes sense for enterprise deployments where you want a single audit log of all feedback interactions across the team.
Cursor-Specific Consideration
Cursor's Composer agent mode tends to be more aggressive about autonomous execution than Claude. This makes the feedback server especially valuable — you can use Cursor Rules to instruct the agent to always call request_feedback before file deletions, git operations, or external API calls:
# .cursorrules
Before executing any of these operations, you MUST call request_feedback and wait for human approval:
- Deleting or overwriting files
- Running git commit, push, or merge
- Making HTTP requests to external APIs
- Modifying environment variables or configuration files
- Running database migrations
Do NOT proceed with these operations if request_feedback returns approved: false.
Building Human-in-the-Loop Workflows
The installation is straightforward. The interesting engineering is in how you structure your workflow to use feedback checkpoints effectively. Here are the patterns that work in production.
Pattern 1: Pre-Execution Approval
The most common pattern. Before any destructive or irreversible action, the agent asks for approval and shows the human exactly what it plans to do:
# Example agent code calling request_feedback before deletion
result = mcp_client.call_tool(
"request_feedback",
{
"type": "approval",
"message": "I'm about to delete 47 records from the users table that match status='inactive' and last_login < 2023-01-01. This cannot be undone.",
"context": {
"operation": "DELETE FROM users WHERE status='inactive' AND last_login < '2023-01-01'",
"affected_count": 47,
"risk_level": "HIGH",
"reversible": False
}
}
)
if result["approved"]:
execute_deletion()
else:
return {"status": "cancelled", "reason": result["response"]}
Pattern 2: Clarification Before Ambiguous Execution
When the agent's task description is genuinely ambiguous, it asks for clarification rather than guessing:
clarification = mcp_client.call_tool(
"request_feedback",
{
"type": "input",
"message": "The refactoring task mentions 'update all API endpoints'. Should I update the authentication middleware on all routes, or only the public-facing endpoints? Please clarify.",
"context": {
"ambiguous_phrase": "all API endpoints",
"option_a_scope": "127 total routes including internal admin",
"option_b_scope": "34 public-facing routes only"
},
"default": "public-facing only"
}
)
scope = clarification["response"] # Human types their answer
# Agent continues with precise scope
Pattern 3: Progressive Approval for Multi-Step Operations
For long workflows, use a checkpoint at each logical phase rather than one giant approval at the start:
phases = [
{"name": "Schema migration", "risk": "MEDIUM", "reversible": True},
{"name": "Data backfill", "risk": "MEDIUM", "reversible": True},
{"name": "Index rebuild", "risk": "LOW", "reversible": True},
{"name": "Old column drop", "risk": "HIGH", "reversible": False}
]
for phase in phases:
approval = mcp_client.call_tool(
"request_feedback",
{
"type": "approval",
"message": f"Ready to execute phase: {phase['name']}",
"context": phase
}
)
if not approval["approved"]:
handle_phase_rejection(phase, approval["response"])
break
execute_phase(phase)
Pattern 4: Selection for Agent Decision Points
When the agent reaches a fork and multiple valid paths exist, it surfaces the choice to the human rather than picking arbitrarily:
strategy = mcp_client.call_tool(
"request_feedback",
{
"type": "selection",
"message": "The target table has 3 viable indexing strategies. Which should I implement?",
"options": [
"Composite index on (user_id, created_at) — best for time-range queries",
"Partial index on active records only — best for write performance",
"Full-text index on description column — best for search queries"
],
"context": {
"table_size": "4.2GB",
"primary_query_pattern": "time-range filters on user activity"
}
}
)
selected_strategy = strategy["response"] # Returns the selected option text
Approval Token Validation
For workflows where you want cryptographic proof that a human approved an action (useful for compliance and audit trails), enable token signing:
# Generate a signing secret
python -c "import secrets; print(secrets.token_hex(32))"
# → 8f3a2d1e4b7c9f0a2e5d8b3c6f1a4e7d0c3f6a9d2e5b8c1f4a7d0e3b6c9f2
Set this as FEEDBACK_TOKEN_SECRET in your config. When a human approves a request, the server returns a signed token:
{
"approved": true,
"response": "Approved by reviewer",
"approval_token": "eyJhbGciOiJIUzI1NiJ9.eyJzZXNzaW9uX2lkIjoiYWJjMTIzIiwiYXBwcm92ZWQiOnRydWUsInRpbWVzdGFtcCI6MTcwNjYyNDAwMCwicmV2aWV3ZXIiOiJvcGVyYXRvckBleGFtcGxlLmNvbSJ9.signature",
"session_id": "abc123",
"timestamp": 1706624000
}
Your downstream tool can then verify this token before executing:
import jwt
def verify_approval_token(token: str, secret: str) -> dict:
try:
payload = jwt.decode(token, secret, algorithms=["HS256"])
if not payload.get("approved"):
raise ValueError("Token indicates rejection")
return payload
except jwt.ExpiredSignatureError:
raise ValueError("Approval token expired")
except jwt.InvalidTokenError:
raise ValueError("Invalid approval token")
# In your execution function
def execute_with_approval(approval_token: str):
payload = verify_approval_token(approval_token, os.environ["FEEDBACK_TOKEN_SECRET"])
# Token is valid — safe to proceed
do_the_thing()
This creates a verifiable chain: the feedback server issues the token, your execution function validates it, and the audit log shows exactly when and by whom each action was approved.
Security Considerations
Interactive Feedback MCP sits in a sensitive architectural position — it controls whether agents can proceed with actions. Getting the security model wrong means either the human-in-the-loop becomes bypassable, or the server becomes a bottleneck that creates its own vulnerabilities.
What to Harden in Production
1. Never expose the SSE endpoint without authentication
The SSE endpoint allows submitting responses to feedback requests. An unauthenticated endpoint means anyone who can reach it can approve actions. Put it behind a reverse proxy with authentication:
# nginx config for feedback SSE endpoint
location /feedback/sse {
auth_request /auth;
proxy_pass http://127.0.0.1:8765;
proxy_set_header X-Reviewer-Email $upstream_http_x_auth_email;
proxy_buffering off;
proxy_cache off;
}
location /auth {
internal;
proxy_pass https://your-auth-service/validate;
proxy_pass_request_body off;
proxy_set_header Authorization $http_authorization;
}
2. Enable token signing for any production workflow
Without token signing, an agent could theoretically be prompted to fabricate an approval result. Signed tokens make approvals cryptographically verifiable.
3. Log all feedback interactions
Every request_feedback call and every human response should be logged with:
- Timestamp
- Session ID
- What was shown to the reviewer
- What the reviewer responded
- Reviewer identity (if available)
# Example structured log entry
{
"event": "feedback_response",
"session_id": "abc123",
"timestamp": "2025-01-30T14:23:01Z",
"request_type": "approval",
"approved": true,
"reviewer": "engineer@company.com",
"response_latency_seconds": 47,
"context_summary": "DELETE FROM users WHERE status=inactive"
}
4. Set sensible timeouts — and handle them explicitly
A feedback request that never times out is a resource leak and a potential denial-of-service vector. Set FEEDBACK_TIMEOUT_SECONDS and make sure your agent handles timeout errors:
result = mcp_client.call_tool("request_feedback", {...})
if result.get("error") == "timeout":
# Don't proceed — log and escalate
log_timeout_incident(result["session_id"])
notify_on_call_engineer()
return {"status": "aborted", "reason": "reviewer timeout"}
5. Validate that the agent prompt instructs correct feedback use
System prompts matter. An agent that isn't explicitly instructed to use feedback tools for sensitive operations may skip them. Your system prompt should enumerate exactly which operations require a feedback call.
Security Comparison: Interactive vs Non-Interactive MCP
| Security Property | Non-Interactive MCP | Interactive Feedback MCP |
|---|---|---|
| Human oversight | None — audit logs after the fact | Active — human approves before execution |
| Reversibility | Depends on operation | Explicitly surfaced to reviewer |
| Audit trail | Tool call logs | Tool call logs + approval records + reviewer identity |
| Blast radius control | Tool design only | Human judgment + tool design |
| Compliance evidence | Difficult | Approval tokens provide verifiable evidence |
Common Mistakes and How to Fix Them
Mistake 1: Using approval Type When You Need input Type
Symptom: The reviewer can only say yes/no but needs to provide specific parameters.
Fix: Use type: "input" when you need a free-form response, and type: "approval" only when a binary yes/no is genuinely sufficient.
Mistake 2: Message Too Vague for the Reviewer
Symptom: The reviewer approves without understanding what they're approving because the message says "Proceed with database operation?" rather than showing the actual SQL.
Fix: Always put the actual operation in the context object. The reviewer should be able to make an informed decision without switching to another tool to look up what the agent is planning.
# Bad — vague
{"type": "approval", "message": "Proceed with database operation?"}
# Good — specific
{
"type": "approval",
"message": "About to execute a bulk update on the orders table.",
"context": {
"query": "UPDATE orders SET status='archived' WHERE created_at < '2023-01-01' AND status='completed'",
"estimated_rows": 12847,
"estimated_duration_seconds": 45,
"reversible": True,
"backup_created": True
}
}
Mistake 3: Not Handling approved: false
Symptom: Agent proceeds with the action even when the reviewer rejected it.
Fix: Always check the approved field in the response and treat false as a hard stop. This is the most dangerous mistake in feedback-enabled workflows.
result = mcp_client.call_tool("request_feedback", {...})
# WRONG — ignores rejection
execute_operation()
# CORRECT — checks approval
if result.get("approved", False):
execute_operation()
else:
return {"status": "rejected", "reviewer_note": result.get("response")}
Mistake 4: Feedback Timeout Too Short for Complex Reviews
Symptom: Reviewers are frequently seeing timeout errors because they need time to read diffs or consult colleagues.
Fix: Set different timeouts for different risk levels. Use timeout_override in high-stakes requests to give reviewers adequate time:
# High-stakes operation — give the reviewer 10 minutes
{
"type": "approval",
"message": "...",
"timeout_override": 600
}
# Low-stakes confirmation — 2 minutes is fine
{
"type": "confirmation",
"message": "..."
# Uses global FEEDBACK_TIMEOUT_SECONDS
}
Mistake 5: Running the SSE Server Without TLS in Production
Symptom: Approval tokens and reviewer responses transmitted in plaintext.
Fix: Always terminate TLS at a reverse proxy (nginx, Caddy) in front of the SSE server. The feedback server itself doesn't handle TLS — that's the proxy's job.
Mistake 6: Calling request_feedback for Every Trivial Operation
Symptom: Reviewers experience alert fatigue and start approving everything without reading.
Fix: Reserve feedback checkpoints for genuinely consequential operations. Reading data, generating reports, calling read-only APIs — these don't need approval. The signal gets diluted if everything requires human confirmation.
Troubleshooting
Server Fails to Start
# Check if the process is already running
lsof -i :8765 # SSE mode port check
# Run with debug logging
FEEDBACK_LOG_LEVEL=DEBUG uvx interactive-feedback-mcp
# Verify Python version
python --version # Must be 3.10+
Tools Not Appearing in Client
- Confirm the server process is actually running (
ps aux | grep interactive-feedback) - Check the client config file syntax — JSON syntax errors silently prevent server loading
- In Claude Desktop: check the logs at
~/Library/Logs/Claude/mcp*.log(macOS) - In Claude Code: run
claude mcp listand look for error status - Fully restart the client — MCP servers don't hot-reload
Feedback Prompt Not Appearing
In stdio mode, the terminal prompt appears in the terminal window where you're running the MCP server — not in the client UI. If you started the server via client config (which is the normal path), the prompt appears in the client's MCP server output panel.
In SSE mode, open http://localhost:8765/pending to see the pending feedback queue. If requests are queued but the UI isn't showing them, check your frontend connection to the SSE stream.
approved Field Missing from Response
This means the human submitted a response without explicitly setting the approved flag. The submit_feedback tool requires approved to be explicitly true or false. Update your reviewer UI to always send this field:
// In your reviewer frontend
await fetch('/feedback/submit', {
method: 'POST',
body: JSON.stringify({
session_id: sessionId,
response: reviewerComment,
approved: userClickedApprove // boolean, not string
})
})
High Latency in Tool Response
If you're seeing unexpectedly high latency even when no human input is pending:
- Check
FEEDBACK_LOG_LEVEL=DEBUGfor slow operations in the session manager - If using SSE mode, check network latency to the server
- Review whether the pending queue has stale sessions blocking processing
Stale sessions can accumulate if timeout handling isn't working. Clear the queue:
curl -X POST http://localhost:8765/admin/clear-stale-sessions \
-H "Authorization: Bearer $ADMIN_TOKEN"
Performance Optimization
Interactive feedback is inherently latency-bound by human response time — that's the point. But there are parts of the system where engineering choices affect throughput:
Session Manager Cleanup
Don't let timed-out sessions accumulate in memory. Set FEEDBACK_SESSION_CLEANUP_INTERVAL (default: 60 seconds) to aggressively clean expired sessions. Each stale session holds references to the original request payload, which can be large if you're passing diffs.
Payload Size
The context object is serialized and held in memory until the session resolves. If you're passing large diffs or datasets as context, truncate them. A reviewer can't meaningfully evaluate a 50,000-line diff in a feedback dialog anyway.
# Truncate large diffs for the feedback context
def build_diff_context(full_diff: str, max_lines: int = 200) -> dict:
lines = full_diff.splitlines()
if len(lines) <= max_lines:
return {"diff": full_diff, "truncated": False}
return {
"diff": "\n".join(lines[:max_lines]),
"truncated": True,
"total_lines": len(lines),
"note": f"Showing first {max_lines} of {len(lines)} lines"
}
Concurrent Feedback Requests
The server handles multiple pending requests concurrently. But a single reviewer receiving 10 simultaneous approval requests will bottleneck everything. Design workflows to serialize consequential operations through a single checkpoint where possible, rather than fan-out feedback requests that overwhelm the reviewer.
Production Deployment
Running the interactive feedback server in production requires more thought than a local dev setup. The key differences:
Deployment Architecture for Teams
┌─────────────────────┐ ┌─────────────────────┐
│ Developer A │ │ Developer B │
│ (Cursor / Code) │ │ (Claude Desktop) │
└────────┬────────────┘ └──────────┬──────────┘
│ MCP over SSE │ MCP over SSE
└──────────────┬─────────────┘
▼
┌──────────────────┐
│ nginx (TLS) │
│ + auth proxy │
└────────┬─────────┘
▼
┌────────────────────────┐
│ Interactive Feedback │
│ MCP Server (SSE mode) │
│ + Redis session store │
└────────────────────────┘
↑
┌────────────┴────────────┐
│ Reviewer Dashboard │
│ (your team's web UI) │
└─────────────────────────┘
Production Checklist
- TLS termination at reverse proxy (never expose feedback server directly)
- Authentication on SSE endpoint (OAuth, API tokens, or mTLS)
-
FEEDBACK_SIGN_TOKENS=truewith a strong randomly-generated secret -
FEEDBACK_ALLOW_ANONYMOUS=false - Timeout configured and tested (
FEEDBACK_TIMEOUT_SECONDS) - Structured logging enabled and shipped to your log aggregator
- Reviewer UI deployed and accessible to your team
- Health check endpoint monitored (
/health) - Session cleanup interval configured
- Runbook written for: server restart, stale session purge, secret rotation
Health Check Endpoint
The server exposes /health in SSE mode:
curl https://feedback.yourcompany.internal/health
# → {"status": "ok", "pending_sessions": 2, "uptime_seconds": 3847}
Add this to your monitoring stack. A spike in pending_sessions indicates reviewers are backed up or not responding — a leading indicator worth alerting on.
For additional guidance on production MCP deployments, see the Running MCP in Production guide — it covers containerization, process management, and observability patterns that apply equally to the feedback server.
Validating Your Setup with MCPForge Verify
Before you consider your interactive feedback setup production-ready, run it through MCPForge Verify. The tool tests your server against the MCP specification and catches:
- Tool schema validation errors (missing required fields, incorrect types)
- Transport negotiation failures
- Response shape mismatches
- Capability advertisement inconsistencies
- Error response formatting problems
These issues are invisible during casual testing but surface as silent failures in production when the client tries to handle edge cases. A 10-minute verification run before deployment saves significant debugging time later.
If your feedback server passes verification, it's eligible for listing in the MCPForge Verified directory — useful if you're building a shared feedback server for a broader team or open-source project.
Practical Use Cases Worth Building
CI/CD Pipeline Approval Gates
Integrate the feedback server as an approval gate in your CI/CD pipeline. When an agent proposes a deployment to production, the pipeline pauses and routes the approval request to the on-call engineer via the feedback server. The engineer reviews the deployment plan, approves or requests changes, and the pipeline continues only on approval.
Database Migration Oversight
Alembic/Django migrations running through an AI agent workflow can use feedback checkpoints before each destructive migration step. The reviewer sees the migration SQL, affected table sizes, and estimated rollback complexity before approving.
Automated Email / Notification Campaigns
An agent preparing a batch email campaign (personalized outreach, newsletters, alerts) calls request_feedback with a sample of 5 emails and the total recipient count. A human spot-checks the copy and audience before approving the full send.
Legal and Compliance Document Processing
Agents extracting and summarizing legal documents can use feedback loops at decision points: "I've identified these 3 clauses as potentially non-compliant with GDPR. Do you want me to flag them for legal review or auto-redline?"
Infrastructure Provisioning
Terraform plans generated by an AI agent get routed through the feedback server before terraform apply. The reviewer sees the plan diff and approves or requests modifications. Combined with signed tokens, this creates a verifiable audit trail for infrastructure changes.
Interactive vs Non-Interactive: When Each Approach Makes Sense
| Factor | Use Non-Interactive | Use Interactive Feedback |
|---|---|---|
| Operation type | Read-only, idempotent | Write, delete, irreversible |
| Failure cost | Low — easy to retry | High — hard or impossible to undo |
| Ambiguity in task | Well-defined, deterministic | Open-ended, context-dependent |
| Compliance requirements | None | Audit trail required |
| Reviewer availability | Not applicable | Team can respond within SLA |
| Operation frequency | High-volume, repetitive | Low-volume, high-stakes |
| User trust in agent | High — validated workflow | Low — new workflow or sensitive domain |
The decision isn't binary. Most production AI workflows use both: a non-interactive MCP server handles the bulk of deterministic operations while the interactive feedback server handles the checkpoints that require human judgment. This hybrid approach keeps human cognitive load manageable — reviewers only see requests that actually need their attention.
Key Takeaways
- Interactive Feedback MCP is a protocol-native solution for human-in-the-loop AI workflows — no custom middleware needed
- The three feedback types (
approval,input,selection) cover the vast majority of real review scenarios - Security depends on: authentication on the SSE endpoint, token signing, explicit timeout handling, and structured logging
- The biggest mistake is calling
request_feedbackfor everything — alert fatigue defeats the purpose - Production deployments need TLS, authentication, a reviewer UI, health monitoring, and a session cleanup strategy
- Validate your setup with MCPForge Verify before going to production
- The real value isn't just safety — interactive feedback enables AI agents to tackle genuinely ambiguous tasks that would be too risky to fully automate