Skip to main content

Research Agent

Web research with fine-grained API access control.

Difficulty: Advanced

What You'll Learn​

  • Annotation-based HTTP policies
  • Internal network blocking
  • Multiple external APIs
  • Per-tool permissions

Prerequisites​

  • AgentVisor CLI installed
  • Docker Compose — brings up Temporal and a local Ollama instance the template depends on
  • jq installed (used below to pretty-print API responses)

Available Tools​

ToolEndpointPolicy
search_wikipediaen.wikipedia.orgAllowed
fetch_weatherwttr.inAllowed
fetch_urlAny URLMost blocked

Security Features​

Internal Network Blocking​

The policy blocks:

  • localhost (except Ollama)
  • 10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12
  • *.internal, *.local domains

Approved External APIs​

Only these are allowed:

  • en.wikipedia.org - Encyclopedia
  • wttr.in - Weather

Setup​

agentvisor template create langgraph/research-agent
cd research-agent
docker compose up -d
agentvisor serve .

The template's LLM calls go through Ollama at a loopback address, which the proxy's SSRF guard blocks by default independently of the policy above — the shipped agentvisor.yaml allowlists it; see Egress Controls for how proxy.ssrf_allowed_cidrs works.

Test It​

THREAD=$(curl -sX POST http://localhost:8090/threads | jq -r '.thread_id')

# Wikipedia (allowed)
curl -sX POST "http://localhost:8090/threads/$THREAD/runs?wait=60s" \
-H "Content-Type: application/json" \
-d '{"input": {"messages": [{"role": "user", "content": "Tell me about quantum computing"}]}}'

# Weather (allowed)
curl -sX POST "http://localhost:8090/threads/$THREAD/runs?wait=60s" \
-H "Content-Type: application/json" \
-d '{"input": {"messages": [{"role": "user", "content": "Whats the weather in London?"}]}}'

# Generic URL (blocked)
curl -sX POST "http://localhost:8090/threads/$THREAD/runs?wait=60s" \
-H "Content-Type: application/json" \
-d '{"input": {"messages": [{"role": "user", "content": "Fetch https://example.com"}]}}'

How It Works​

  1. Discovery: AgentVisor™ detects langgraph.json and selects the LangGraph framework provider
  2. Execution: python3 -m agentvisor.langgraph.runner loads the researcher graph from agent.py
  3. Tool calls: The graph's tools call out over HTTP → AgentVisor proxy → policy engine checks the destination against the annotation-based resource groups below → allowed calls reach Wikipedia/wttr.in, blocked calls are rejected before they leave the sandbox
  4. State persistence: Conversation state is checkpointed via AgentVisorCheckpointer, enabling multi-turn conversation across runs on the same thread

Credential Flow​

Not applicable — the template's LLM calls go through a local Ollama instance, which requires no API key or credential substitution. The proxy's SSRF guard blocks loopback destinations by default; the shipped agentvisor.yaml allowlists Ollama's loopback address directly (see Setup above and Egress Controls for how proxy.ssrf_allowed_cidrs works) rather than brokering a credential.

Policy Highlights​

Annotation-Based Patterns​

resources:
- name: http-research-endpoints
selector:
- "mrn:agentvisor:http:.*"
group: "mrn:agentvisor:resourcegroup:http-research"
annotations:
- name: "allowed_patterns"
value:
- "^en\\.wikipedia\\.org(/.*)?$"
- "^wttr\\.in(/.*)?$"
- name: "blocked_patterns"
value:
- ".*\\.internal$"
- "metadata\\.google\\..*"

Internal Network Block​

is_internal_network if {
regex.match("^10\\..*", target)
}
is_internal_network if {
regex.match("^192\\.168\\..*", target)
}

allow if {
helpers.is_authenticated
is_allowed
not is_blocked
not is_internal_network
}

Project Files​

research-agent/
├── agent.py # LangGraph graph: search_wikipedia, fetch_weather, fetch_url tools
├── langgraph.json # Graph discovery config (auto-detected by AgentVisor)
├── mav-agent-config.yaml # A2A metadata
├── requirements.txt # Python dependencies
├── agentvisor.yaml # Runtime config (Ollama loopback SSRF allowlist)
└── policies/
├── domain.yml # Authorization policies (annotation-based HTTP patterns)
└── test.yml # Policy decision tests

Next Steps​