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
Governed intelligence skill for AAA as the abstraction, attestation, and abduction control plane across arifOS, APEX, A-FORGE, GEOX, WEALTH, WELL, and the ariffazil profile repository. Use when the user asks to explain or design AAA, route agentic work, reduce chaos/entropy in an arifOS federation task, create AREP/task declarations, classify risk, plan multi-repo changes, review governance boundaries, or translate human intent into evidence-backed, authority-safe, recursively agentic workflows. Provides deterministic F1-F13 floor checking, bounded abduction, and FederationReceipt composition.
development
Check every skill’s “use when” and “do not use when” clauses for collisions, missing negatives, and vague verbs like “help,” “assist,” or “improve.” Load when linting, reviewing, or validating trigger boundaries.
development
Bootstrap, design, and package new skills. Load when capturing user intent for a new skill or drafting its initial instruction framework.
content-media
Diagnose which federation services are up, down, or drifting. Produce a prioritized remediation plan.