@getjavelin/scout
v0.0.9
Published
Javelin Scout
Downloads
46
Readme
Javelin Scout
Real-time monitoring for Model Context Protocol (MCP) communication using eBPF technology with Javelin guardrail integration.
Features
- 🔒 Real-time MCP Monitoring: Monitor Model Context Protocol communication using eBPF
- 🛡️ Javelin Guardrail Integration: Real-time security validation and analysis
- 📊 Multiple Transport Support: Stdio, HTTP/HTTPS, and Server-Sent Events
- ⚡ Service Management: Easy installation and management as a system service
- 🐛 Debugging Tools: Troubleshoot MCP integrations with detailed message flow
- 📈 Performance Monitoring: Track message patterns and identify bottlenecks
Installation
Prerequisites
- Linux kernel version 5.15 or later
- Root privileges (required for eBPF)
- Node.js 14.0.0 or later
NPM Package Installation
# Install globally
sudo npm install -g @getjavelin/scout
Usage
Configuration
Before running the service, configure the following environment variables:
JAVELIN_URL → Base URL of your Javelin Core deployment (typically ends with /v1).
To get this: Contact your Javelin administrator or check your Javelin Core deployment documentation.
JAVELIN_API_KEY → Your API Key for authenticating with the Javelin Gateway.
To get this: Log into your Javelin Gateway dashboard and generate an API key from the settings section.
By default, scout will automatically provision an MCP Overwatch application (mcp_overwatch) in your Javelin Gateway when started if it doesn't already exist.
What happens after starting?
Once you start the service, scout will:
- Monitor MCP traffic in real-time using eBPF technology
- Display live logs showing MCP operations, requests, and responses
- Process guardrails we will process the MCP operations and send data to your Javelin Gateway
Running as a Service vs Terminal
Run as Background Service (Recommended)
# Install as system service (prompts for configuration)
scout install
# Start the service
scout start
# Service runs in background - terminal can be closed
# Use scout logs to view output
# Use scout stop to stop the serviceService Management
Javelin Scout can be installed and managed as a system service:
# Install as a system service (prompts for API key and URL)
scout install
# Start the service
scout start
# Show config
scout config show
# Update config (optional)
scout config set
# Stop the service
scout stop
# Restart the service
scout restart
# Check service status
scout status
# View service logs (follow mode)
scout logs
# Show help
scout helpArchitecture
Javelin Scout consists of several key components:
- eBPF Program: Hooks into kernel functions for low-level monitoring
- HTTP Session Manager: Manages HTTP/HTTPS sessions and correlates request/response pairs
- MCP Protocol Parser: Validates JSON-RPC 2.0 message format and parses MCP-specific methods
- Javelin Integration: Message correlation and guardrail processing
- Service Management: NPM package wrapper with Supervisor integration
K8s Deployment
- Download and update the
javelin-chartsinto local
helm repo add javelin-charts "https://getjavelin.github.io/charts"
helm repo update javelin-charts && helm search repo javelin-charts- Create a
value.yamlfile for the helm deployment
image:
repository: "ghcr.io/getjavelin/release-javelin-scout"
pullPolicy: Always
# Overrides the image tag with a specific version.
tag: "latest"
imagePullSecrets:
- name: javelin-registry-secret
secrets:
enabled: true
secretData:
JAVELIN_URL: 'https://be-domain/v1'
JAVELIN_API_KEY: '${JAVELIN_API_KEY}'- Deploy the
javelin-scoutto the kubernetes cluster
kubectl create ns javelin-scout
helm upgrade --install javelin-scout javelin-charts/javelin-scout \
--namespace javelin-scout \
-f value.yaml --timeout=10mLimitations
- Platform: Linux only (kernel 5.15+)
- Buffer Size: Limited to 16KB per message
- Javelin Service: Guardrail processing requires valid Javelin configuration and network connectivity
- Root Privileges: Required for eBPF operations
Example: MCP client that calls DeepWiki
DeepWikiMCP is an MCP server that provides tools to analyze GitHub repository structures and documentation. This example shows how to use it as a test client to generate MCP traffic that scout can monitor.
Below is a minimal Python client that calls the
read_wiki_structuretool on the DeepWiki MCP. Save as deepwiki_call_read_structure.py (or a name you prefer).python deepwiki_call_read_structure.py --repo "getjavelin/ramparts"Use this command to run the deepwiki client and generate MCP traffic that scout will monitor.
#!/usr/bin/env python3
"""
- Install python env
- Install httpx
- Install mcp
Call read_wiki_structure on DeepWiki MCP (minimal, fixed factory)
Usage:
python3 deepwiki_call_read_structure.py --repo "github.com/getjavelin/ramparts" \
[--bearer ABC123] [--transport http|sse]
Defaults:
endpoint: https://mcp.deepwiki.com/mcp
transport: http (streamable HTTP)
"""
import argparse
import asyncio
import json
import logging
from typing import Any, Dict, Optional
import httpx
from mcp import ClientSession
from mcp.client.sse import sse_client
from mcp.client.streamable_http import streamablehttp_client
ENDPOINT_DEFAULT = "https://mcp.deepwiki.com/mcp"
TOOL_NAME = "read_wiki_structure"
def httpx_client_factory_factory(bearer_from_cli: Optional[str] = None, verify_tls: bool = True):
"""
Returns a factory function matching the signature expected by streamablehttp_client:
factory(headers=None, timeout=None, auth=None, **kwargs) -> httpx.AsyncClient
"""
def factory(headers: Optional[Dict[str, str]] = None, timeout: Optional[Any] = None, auth: Optional[Any] = None, **kwargs) -> httpx.AsyncClient:
client_kwargs: Dict[str, Any] = {
"follow_redirects": True,
"verify": verify_tls,
}
# honor provided timeout (httpx.Timeout object or numeric); fallback to 30s
client_kwargs["timeout"] = timeout if timeout is not None else 30.0
# Merge headers: transport headers (if any) + bearer_from_cli header
merged_headers: Dict[str, str] = {}
if headers:
merged_headers.update(headers)
if bearer_from_cli:
# only set Authorization if not already set by transport
merged_headers.setdefault("Authorization", f"Bearer {bearer_from_cli}")
if merged_headers:
client_kwargs["headers"] = merged_headers
if auth is not None:
client_kwargs["auth"] = auth
return httpx.AsyncClient(**client_kwargs)
return factory
async def call_read_wiki_structure_over_http(endpoint: str, headers: Dict[str, str], factory, repo: str):
async with streamablehttp_client(endpoint, httpx_client_factory=factory) as (read_stream, write_stream, _):
async with ClientSession(read_stream, write_stream) as session:
await session.initialize()
result = await session.call_tool(TOOL_NAME, {"repoName": repo})
return result
async def call_read_wiki_structure_over_sse(endpoint: str, repo: str):
async with sse_client(endpoint) as (read_stream, write_stream):
async with ClientSession(read_stream, write_stream) as session:
await session.initialize()
result = await session.call_tool(TOOL_NAME, {"repo": repo})
return result
def pretty_print_result(result):
try:
# If Pydantic-like model with model_dump()
print(json.dumps(result.model_dump(), indent=2)) # type: ignore[attr-defined]
except Exception:
# Fallback: let json try to serialize, else print repr
try:
print(json.dumps(result, default=str, indent=2))
except Exception:
print(repr(result))
async def main_async(args):
endpoint = args.url
repo = args.repo
bearer = args.bearer
transport = args.transport.lower()
# Prepare factory that accepts (headers, timeout, auth, **kwargs)
factory = httpx_client_factory_factory(bearer_from_cli=bearer, verify_tls=not args.insecure)
if transport == "http":
result = await call_read_wiki_structure_over_http(endpoint, {}, factory, repo)
elif transport == "sse":
result = await call_read_wiki_structure_over_sse(endpoint, repo)
else:
raise SystemExit("transport must be 'http' or 'sse'")
pretty_print_result(result)
def parse_args():
p = argparse.ArgumentParser(description="Call read_wiki_structure on DeepWiki MCP")
p.add_argument("--url", default=ENDPOINT_DEFAULT, help="MCP endpoint (default: https://mcp.deepwiki.com/mcp)")
p.add_argument("--repo", required=True, help="Repo identifier (e.g. github.com/org/repo)")
p.add_argument("--bearer", help="Bearer token for Authorization header")
p.add_argument("--transport", choices=["http", "sse"], default="http", help="Transport (http or sse)")
p.add_argument("--insecure", action="store_true", help="Disable TLS verification (useful for self-signed certs)")
return p.parse_args()
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s", datefmt="%H:%M:%S")
args = parse_args()
try:
asyncio.run(main_async(args))
except Exception as exc:
logging.exception("Error during MCP call: %s", exc)
raise