retrieve_tools with exclude_destructive=true returned read_text_file (readOnlyHint=true) correctly. 5 non-destructive tools returned including read_text_file, read_file, read_multiple_files, get_edge_function, read_media_file.
{"content":[{"type":"text","text":"Echo: hello"}]}{"content":[{"type":"text","text":"Echo: "}]}{"content":[{"type":"text","text":"Echo: ใใใซใกใฏ ๐"}]}Response contained 'Echo: ' + 1000 'A' characters (1006 total chars). Full content returned in single text block.
Error: 'No client found for server: fake-server. Available servers: [ElevenLabs, mcpproxy, supabase, defillama2, sentry, screenshot-website-fast, perplexity, context7, everything-server, cloudflare-graphql, cloudflare-observability, tavily, kaggle, synapbus, demo-filesystem, hugginface, memory, cloudflare-docs-sse, obsidian-pilot]. IMPORTANT: Use retrieve_tools first to discover tools and their exact server:tool names, or use upstream_servers operation="list" to see all configured servers.'
{"content":[{"type":"text","text":"MCP error -32602: Input validation error: Invalid arguments for tool echo: [{\"code\":\"invalid_type\",\"expected\":\"string\",\"received\":\"undefined\",\"path\":[\"message\"],\"message\":\"Required\"}]"}],"isError":true}retrieve_tools returned 3 results: (1) kaggle:list_competition_data_tree_files (score 0.057), (2) demo-filesystem:list_directory (score 0.053), (3) kaggle:list_dataset_tree_files (score 0.051). Called demo-filesystem:list_directory with path=/tmp - call completed successfully but response content not visible due to MCP connection degradation.
Tool call completed successfully (no error thrown). Server cloudflare-docs-sse confirmed Ready (protocol_version 2025-06-18, server_version 0.4.5, 2 tools, protocol: SSE). Response content not visible due to MCP connection degradation.
Tool discovered via retrieve_tools with correct schema: {a: number (required), b: number (required)} -> Returns the sum of two numbers. Call completed successfully (no error thrown). Response content not visible due to MCP connection degradation.Tool call completed successfully (no error thrown). JSON argument serialization with embedded double quotes, backslashes, and HTML entities was accepted by MCPProxy without parse errors. No errors in server logs. Response content not visible due to MCP connection degradation.
Response format: {success:true, data:{servers:[...]}}. 24 servers returned. 1 quarantined server found: 'mcpproxy' (admin_state='quarantined'). Each server includes quarantined boolean, health.level, health.admin_state, health.summary, and health.action fields. MCP quarantine_security list_quarantined returned empty (no output) which is misleading since mcpproxy IS quarantined but fails to connect.HTTP 401 Unauthorized. Body: {"success":false,"error":"Invalid or missing API key","request_id":"263b9285-41b4-4812-bc8d-9a5904a16698"}. Error response includes request_id for correlation.HTTP 401 Unauthorized. Body: {"success":false,"error":"Invalid or missing API key","request_id":"28707258-dfc0-4c97-9fc3-10f3c271590c"}. Correctly rejects wrong API key with same error format as missing key.HTTP 200. Response: {"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2024-11-05","capabilities":{"tools":{"listChanged":true}},"serverInfo":{"name":"mcpproxy-go","version":"v0.1.0"}}}. MCP endpoint correctly accessible without authentication.16 connected servers found, all with quarantined=false and admin_state='enabled'. 1 quarantined but not connected: 'mcpproxy' (fails to connect with timeout). Tool export for screenshot-website-fast: 3 tools all 'approved'. Tool export for everything-server: 13 tools all 'approved'. Tool export for cloudflare-observability: 10 tools all 'approved'. No pending or changed tools detected across connected servers. Total tool count across connected servers: 249.
Server 'mcpproxy' IS quarantined (admin_state='quarantined', quarantined=true, enabled=true, connected=false). inspect_quarantined returned error: 'Quarantined server mcpproxy failed to connect within 20s timeout. Connection status: connecting=true, last_error=MCP initialize failed for stdio transport: context deadline exceeded'. inspect_tools returned: 'No tool approval records found for server mcpproxy'. The server cannot connect (likely broken/misconfigured stdio command) so quarantine inspec
All endpoints return X-Request-Id header in UUID format. /api/v1/status: X-Request-Id: 92e4555b-4550-45e6-847e-063d142bc819. /api/v1/servers: X-Request-Id: 9d208456-90dc-41e6-8a7d-c8c0f481b89c. /api/v1/activity: X-Request-Id: bea461e7-f3c3-41e4-8b37-a2b117fe5dc5. Error response (401): X-Request-Id: a24ff590-1e20-495e-ab1f-b8bae6a760a6, body includes matching request_id. Also includes X-Correlation-Id header on all responses.
4 policy_decision records found. All have status='blocked' with metadata containing decision='blocked' and reason='Tool description/schema changed since last approval'. Servers affected: everything-server (tool: echo, 1 event), obsidian-pilot (tools: create_note_tool and read_note_tool, 3 events). Records include timestamps, session_id, and has_sensitive_data=false. This confirms the quarantine tool-level change detection is working and logging policy decisions.
All activity records include has_sensitive_data field (boolean). Filter has_sensitive_data=true returned activities that match. Sample record with sensitive data: id=01KMQWMPT9AFE9AZQDYM4JJNY4 (tool_call, everything-server:echo) had has_sensitive_data flagged from a retrieve_tools call containing API key patterns in tool responses. Regular records show has_sensitive_data=false. Total activity records: 19511. Filter parameter works correctly.
CORS headers present on all API responses: Access-Control-Allow-Origin: *, Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS, Access-Control-Allow-Headers: Content-Type, Authorization, X-API-Key. Headers returned on both OPTIONS preflight and regular GET requests. Wildcard origin (*) is used, which allows any origin.
Returned 24 total tool_call activities. All 3 returned records had type=tool_call (e.g., take_screenshot, echo). Each had metadata with intent, content_trust, tool_variant fields.
Returned 108 total system_start records. All 3 had type=system_start, source=api, status=success. Metadata included config_path, listen_address, startup_duration_ms, version fields.
Returned error activities successfully. First record: internal_tool_call retrieve_tools with error 'search query cannot be empty'. Second: internal_tool_call call_tool_read with browser launch error. Third: tool_call take_screenshot with rosetta error. All had status=error and error_message populated.
Returned activities scoped to demo-filesystem. All 3 records had server_name=demo-filesystem. Types were tool_quarantine_change with tool_description_changed status for tools get_file_info, search_files, move_file.
Page 1: 5 records, total=19512, ids=[01KMQWMPT9..., 01KMQWMP3Q..., 01KMQWM9SH..., 01KMQWM5EE..., 01KMQWKKKE...]. Page 2: 5 records, total=19515, ids=[01KMQWM9SH..., 01KMQWM5EE..., 01KMQWKKKE..., 01KMQVBPF6..., 01KMQVBP79...]. Total increased between calls (19512->19515) because new activities were being recorded live; the 3-record overlap is expected on a live system. Pagination mechanics (limit/offset) work correctly.
Response: {success: true, data: {activity: {...}}}. Activity object has 14 fields: arguments, duration_ms, has_sensitive_data, id, metadata, request_id, response, server_name, session_id, source, status, timestamp, tool_name, type. All populated correctly for a tool_call/echo on everything-server.All 10 tool_call activities have metadata with keys [content_trust, intent, tool_variant]. metadata.intent contains {operation_type: 'read'}. Intent tracking working correctly per Spec 018.CSV export returns correct headers: id,type,source,server_name,tool_name,status,error_message,duration_ms,timestamp,session_id,request_id,response_truncated. Data rows present with correct CSV formatting. HTTP 200, Content-Type: text/csv. Note: limit parameter in URL is intentionally ignored by export endpoint (code sets filter.Limit=0 for 'all matching records').
curl activity/export?format=json&limit=5 returned exactly 5 lines (not 19K).
Activity query with start_time/end_time returned HTTP 200 in 214ms (well under 10s timeout). No deadlock.
All 24 servers have non-empty id fields populated (id matches server name).
Health field present on all servers. Healthy servers have: level, admin_state, summary (3 fields). detail and action are omitted (zero-value omitempty). Disabled servers add action='enable'. Error servers (synapbus) have all 5 fields: level='unhealthy', admin_state='enabled', summary='Authentication required', detail=, action='login'. Quarantined server (mcpproxy) has: level='healthy', admin_state='quarantined', summary='Quarantined for review', action='approve'.
Found 5 disabled servers: idea-ide-local, desktop-commander, imagegen, gcore-mcp-server, googledrive-smithery. All have health.admin_state='disabled', health.summary='Disabled', health.action='enable', health.level='healthy'. Verified correctly.
Found 'synapbus' server with health.action='login', health.level='unhealthy', health.admin_state='enabled', health.summary='Authentication required', health.detail containing 'OAuth authentication required' error message. Correct behavior.
QuarantineStats struct exists with pending_count/changed_count fields. Field is omitempty and correctly omitted when counts are 0. Code in httpapi/server.go:964 populates it when pending>0 or changed>0. No servers currently have pending/changed tools so field is absent (correct behavior).
POST /api/v1/servers/everything-server/enable with enabled=false returned HTTP 200 in 52ms (well under 5s).
POST /api/v1/servers/everything-server/enable with enabled=true returned HTTP 200 in 27ms.
POST /api/v1/servers/everything-server/restart returned HTTP 200 in 1608ms.
everything-server has tool_count=13, status=ready, connected=true after restart. Tools fully rediscovered.
Returns 5 canonical config paths for macOS (darwin): (1) Claude Desktop: ~/Library/Application Support/Claude/claude_desktop_config.json (exists=true), (2) Claude Code (User): ~/.claude.json (exists=true), (3) Cursor IDE: ~/.cursor/mcp.json (exists=true), (4) Codex CLI: ~/.codex/config.toml (exists=true), (5) Gemini CLI: ~/.gemini/settings.json (exists=true). Each entry has: name, format, path, exists, os, description. Response is fast and correct.
role=AXMenuBarItem, subrole=AXMenuExtra, role_description='status menu', position={x:956, y:4.5}, size={height:24, width:36}, title='' (icon-only), pid=5871414 top-level items + 24 server submenus + 121 server sub-items = 159 total items. Top-level: version header, stats, Needs Attention (2), 2 attention servers, quarantine count, Servers (24), Add Server..., Open MCPProxy..., Open Web UI, Run at Startup, Check for Updates, Pause MCPProxy Core, Quit MCPProxy
Expected to fail on dev builds per test instructions.
'Needs Attention (2)' header present (disabled/label). Lists 2 problematic servers: 'synapbus - Authentication required' (enabled, clickable) and 'mcpproxy - Quarantined for review' (enabled, clickable). Also shows '1 quarantined server(s)' count label.
All 24 servers verified. Connected servers show: status (e.g., 'Connected (28 tools)'), Protocol, Disable, Restart, View Logs. Disabled servers show: 'Disabled', Protocol, Enable, Restart, View Logs. Auth-required servers additionally show 'Log In (Opens Browser)'. All 24/24 have toggle (Enable/Disable) and Restart.
'Add Server...' item present, enabled=true, shortcut=Cmd+N
'Run at Startup' item present, enabled=true, no shortcut key
'Check for Updates' item present, enabled=true, no shortcut key
click_menu_item returned success. screenshot_window captured /tmp/s69-mcpproxy-window.png (309576 bytes). Window shows MCPProxy dashboard with sidebar (Dashboard, Servers, Activity Log, Secrets, Configuration), stats cards (24 Total Servers, 17 Connected, 252 Total Tools, 1 Quarantined), Servers Needing Attention section, and Recent Activity list.
'Quit MCPProxy' item present, enabled=true, shortcut='Cmd+Q'
{"ok":true,"value":{"result":2}}{"ok":true,"value":{"result":"HELLO"}}{"ok":true,"value":{"result":1}}{"ok":true,"value":{"result":{"ok":true,"result":{"content":[{"type":"text","text":"Echo: from code"}]}}}}{"ok":true,"value":{"result":42}}{"ok":false,"error":{"message":"Error: test error at :1:7(2)","stack":"Error: test error\n\tat :1:7(2)\n","code":"RUNTIME_ERROR"}} {"ok":true,"value":{"first":{"ok":true,"result":{"content":[{"type":"text","text":"Echo: first"}]}},"second":{"ok":true,"result":{"content":[{"type":"text","text":"Echo: second"}]}}}}{"ok":true,"value":{"result":"default"}}{"ok":true,"value":{"result":"1,1,3,4,5"}}{"ok":true,"value":{"result":"Result: 5"}}HTTP 400 returned with JSON response: {"success":false,"error":"Invalid request body: invalid character 'i' looking for beginning of object key string","request_id":"5644fea8-675d-4d8c-9ef2-fb775dbd2eda"}HTTP 404 returned with plain text body: '404 page not found'
HTTP 200. Server caps limit to 100 via ActivityFilter.Validate() (internal/storage/activity_models.go:138-140). Response returned 100 records with total=19516. Server handled gracefully.
HTTP 200. Server clamps negative offset to 0 via ActivityFilter.Validate() (internal/storage/activity_models.go:141-143). Response returned records from offset 0. Handled gracefully.
HTTP 200 returned with JSON: {"success":true,"data":{"query":"'; DROP TABLE--","results":[],"total":0,"took":"0ms"}}. Injection string treated as literal search text. No SQL backend (uses Bleve BM25 index), so inherently safe.HTTP 200 with Content-Type: application/json. Response: {"success":true,"data":{"activities":[],"total":0,...}}. The XSS payload is not reflected back in the response body. Even if it were, the application/json Content-Type header prevents browser HTML interpretation. No server with that name exists, so empty results returned.HTTP 200 returned with JSON: {"success":true,"data":{"query":"ๆฅๆฌ่ชใในใ","results":[],"total":0,"took":"0ms"}}. Unicode properly decoded and echoed back. No crash or encoding errors.HTTP 401 returned with JSON: {"success":false,"error":"Invalid or missing API key","request_id":"d9748513-e4ab-4b2a-b227-2fbc6a11ab3b"}. Empty API key correctly rejected.All 10 parallel requests to /api/v1/servers returned HTTP 200. Server remained responsive after (final check HTTP 200).
curl returned HTTP 000 (timeout) after 1.8ms. Immediately after, /api/v1/status returned HTTP 200 confirming the server remained healthy. The server properly handles client-side disconnections without resource leaks or crashes.
MCPProxy v0.1.0 (personal) darwin/arm64
/tmp/mcpproxy-fixed doctor completed with exit code 0. Reported 2 known issues (screenshot-website-fast connection timeout, synapbus OAuth needed) and deprecated config warnings.
/tmp/mcpproxy-fixed upstream list completed with exit code 0. Listed all 24 servers with correct status, tool counts, and health indicators.
/tmp/mcpproxy-fixed activity list completed with exit code 0. Displayed 29 activity records with correct columns (ID, SRC, TYPE, SERVER, TOOL, INTENT, SENSITIVE, STATUS, DURATION, TIME).
/tmp/mcpproxy-fixed activity summary completed with exit code 0. Showed 50 total calls, 80% success rate, top servers and tools.
Returns summary with period, total_count, success_count
Telemetry Status\n Status: Enabled\n Anonymous ID: 5d04bcb4-51a0-4ca5-a994-b212db7565d5\n Endpoint: https://telemetry.mcpproxy.app/v1
Valid JSON: True, has mcpServers: True, server_count: 24, has_api_key: True, has_listen: True, server_names: ['ElevenLabs', 'cloudflare-docs-sse', 'cloudflare-graphql', ...]
srw-------@ 1 user staff 0 Mar 27 15:57 /Users/user/.mcpproxy/mcpproxy.sock
...MCPProxy Control Panel .........HTTP_CODE:200