hermes-skills/arifos/arifos-mcp-transport-discovery/SKILL.md
Diagnose and wire MCP servers on arifOS VPS — identifying transport type (streamable-http/SSE/stdio), session requirements, and correct Hermes config entries. Active 2026-05-05.
npx skillsauth add ariffazil/openclaw-workspace arifos-mcp-transport-discoveryInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
| Service | Port | Transport | Tools | MCP Endpoint | Auth |
|---------|------|-----------|-------|--------------|------|
| arifOS | 8080 | streamable-http | 13 | GET /mcp → metadata, POST /mcp → 406 without Accept | Bearer (ARIFOS_API_KEY) |
| GEOX | 8081 | streamable-http | 118 | POST /mcp | Bearer |
| WEALTH | 8082 | streamable-http | 50 | POST /mcp — works without Accept header | None |
| WELL | 8083 | streamable-http | 45 | POST /mcp — works without Accept header | None |
| VAULT999 | 8100 | REST | — | NOT MCP — direct REST | None |
| A-FORGE | 7071 | streamable-http | — | GET /health, POST /mcp | None |
arifOS FastMCP returns HTTP 406 when client sends Accept: */* or no Accept header. GEOX, WEALTH, and WELL do NOT have this issue — they work without any Accept header.
Root cause: GEOX and WELL both have a monkey-patch in server.py that overrides StreamableHTTPServerTransport._check_accept_headers to return (True, True) when json_response=True. arifOS is missing this patch.
Diagnosis:
# arifOS fails without Accept
curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8080/mcp \
-X POST -H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","method":"initialize","id":1,"params":{}}'
# → 406
# WEALTH/GEOX/WELL work without Accept
curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8082/mcp \
-X POST -H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","method":"initialize","id":1,"params":{}}'
# → 200
Two fixes (apply both):
Add to ~/.openclaw/openclaw.json for the arifOS entry:
{
"url": "http://127.0.0.1:8080/mcp",
"transport": "streamable-http",
"headers": {"Accept": "application/json"}
}
Insert before if __name__ == "__main__": in /root/arifOS/arifosmcp/server.py:
# --- Monkey-patch: Fix 406 from Accept header ---
from mcp.server.streamable_http import StreamableHTTPServerTransport
_orig_check = StreamableHTTPServerTransport._check_accept_headers
def _patched_check(self, request):
if getattr(self, 'is_json_response_enabled', False): return True, True
return _orig_check(self, request)
StreamableHTTPServerTransport._check_accept_headers = _patched_check
Apply via SSH (idempotent — safe to re-run):
ssh root@af-forge "python3 -c \"
path = '/root/arifOS/arifosmcp/server.py'
with open(path) as f: c = f.read()
patch = '''# --- Monkey-patch: Fix 406 from Accept header ---
from mcp.server.streamable_http import StreamableHTTPServerTransport
_orig_check = StreamableHTTPServerTransport._check_accept_headers
def _patched_check(self, request):
if getattr(self, 'is_json_response_enabled', False): return True, True
return _orig_check(self, request)
StreamableHTTPServerTransport._check_accept_headers = _patched_check
'''
if 'Monkey-patch: Fix 406' not in c:
c = c.replace('if __name__ == \\\"__main__\\\":', patch + '\nif __name__ == \\\"__main__\\\":')
open(path,'w').write(c)
print('PATCHED')
else:
print('Already patched')
\""
ssh root@af-forge "docker restart arifosmcp"
curl -s http://127.0.0.1:PORT/health
# arifOS: returns server metadata
curl -s http://127.0.0.1:8080/mcp
# WEALTH: returns 405 Method Not Allowed
# GEOX: returns 405 Method Not Allowed
# WELL: returns 405 Method Not Allowed
curl -s -X POST http://127.0.0.1:PORT/mcp \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
Expected responses by transport type:
| Transport | Success Response | Error Response |
|----------|----------------|----------------|
| streamable-http | {"jsonrpc":"2.0","id":1,"result":{"tools":[...]}} | various |
| SSE (session-based) | {"jsonrpc":"2.0","id":"server-error","error":{"code":-32600,"message":"Not Acceptable: Client must accept text/event-stream"}} | needs SSE Accept header |
| Requires session | {"jsonrpc":"2.0","id":"server-error","error":{"code":-32600,"message":"Bad Request: Missing session ID"}} | needs session init |
curl -s -X POST http://127.0.0.1:PORT/mcp \
-H "Accept: application/json, text/event-stream" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'
If still Missing session ID → server requires explicit session initialization handshake before tools/list.
arifosmcp:
name: arifosmcp
url: http://127.0.0.1:8080/mcp
transport: streamable-http
timeout: 30
headers:
Accept: application/json
geox:
name: geox
url: http://127.0.0.1:8081/mcp
transport: streamable-http
timeout: 30
wealth:
name: wealth
url: http://127.0.0.1:8082/mcp
transport: streamable-http
timeout: 30
well:
name: well
url: http://127.0.0.1:8083/mcp
transport: streamable-http
timeout: 30
# For streamable-http servers
curl -s -X POST http://127.0.0.1:PORT/mcp \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \
| python3 -c "import sys,json; d=json.load(sys.stdin); [print(t['name']) for t in d.get('result',{}).get('tools',[])]"
# For SSE servers (may need session first)
curl -s -X POST http://127.0.0.1:PORT/mcp \
-H "Accept: application/json, text/event-stream" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
Accept: application/json header — 406 without it. Fix: openclaw.json header + monkey-patch in server.pyif __name__ == "__main__": in server.py — StreamableHTTPServerTransport._check_accept_headers overridearifOS exposes tools via TWO distinct HTTP interfaces with DIFFERENT calling conventions:
/tools/TOOL_NAME (HTTP GET/POST, query params)POST http://127.0.0.1:8080/tools/arif_sense_observeAccept: application/json header — 406 without itsession_id in bodyRETAK + "Unknown mode: X" in reasons[]surface not query)/mcp with tools/call method (Preferred)POST http://127.0.0.1:8080/mcp{"jsonrpc":"2.0","method":"tools/call","id":N,"params":{"name":"TOOL_NAME","arguments":{...}}}Accept: application/json header{"isError":true,"content":[{"type":"text","text":"2 validation errors..."}]} inside result{"jsonrpc":"2.0","id":N,"result":{"content":[{"type":"text","text":"..."}]}} where text is a JSON stringresult.content[0].text as JSON to get the actual tool response with nine_signal envelopecurl -s -X POST http://127.0.0.1:8080/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{"jsonrpc":"2.0","method":"tools/call","id":1,"params":{"name":"arif_sense_observe","arguments":{}}}' \
| python3 -c "
import json,sys
d=json.load(sys.stdin)
text=d['result']['content'][0]['text']
content=json.loads(text)
print('Status:', content.get('status'))
print('Nine signal:', content.get('nine_signal',{}).get('overall'))
print('Output policy:', content.get('output_policy'))
"
# Step 1: init session
SESSION=$(curl -s -X POST http://127.0.0.1:8080/tools/arif_session_init \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"mode":"init","actor_id":"test-agent","ack_irreversible":false}' \
| python3 -c "import json,sys; d=json.load(sys.stdin); print(d['result']['result']['session']['session_id'])")
# Step 2: use session_id in subsequent calls
curl -s -X POST http://127.0.0.1:8080/mcp \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d "{\"jsonrpc\":\"2.0\",\"method\":\"tools/call\",\"id\":2,\"params\":{\"name\":\"arif_sense_observe\",\"arguments\":{\"session_id\":\"\$SESSION\"}}}"
arif_judge_deliberate (888): Returns empty HTTP body — silent, no errorarif_vault_seal (999): Returns empty HTTP body — silent, no errorarif_heart_critique (666): Returns VOID with nine_signal=null when args missing| Tool | Working arguments |
|------|------------------|
| arif_sense_observe | {} (no args = search mode) |
| arif_mind_reason | {"query": "..."} |
| arif_kernel_route | {} (no args) |
| arif_memory_recall | {"query": "...", "session_id": "SEAL-..."} |
| arif_ops_measure | {} (no args) |
| arif_heart_critique | {} → returns VOID (auth gate, not error) |
# Restart Hermes gateway
hermes gateway restart
# Check gateway state
curl http://127.0.0.1:18000/health 2>/dev/null || \
cat /root/.hermes/gateway_state.json
# List connected tools
hermes tools list 2>/dev/null || \
curl -s http://127.0.0.1:8080/.well-known/mcp/server.json | python3 -m json.tool | grep name
development
Federation-wide gold (XAUUSD) trading capability. Python stack, OANDA broker, backtesting, macro signals, RSI strategy. Every organ has a role.
development
Capital claim state management — tracks claim lifecycle across WEALTH organ.
development
Archived constitutional warga placeholder retained only for audit provenance. Do not use for active work; use the live arifOS governance and constitutional skills instead.
testing
Warga (citizen) agent skills for AAA federation members. See subdirectories for specialized warga skills.