FirstOps Python SDK
Govern what your AI agents do. FirstOps applies identity, policy enforcement, credential brokering, and audit to every LLM call, tool call, and MCP call your agent makes — across LangGraph, the Claude Agent SDK, the OpenAI Agents SDK, and Google ADK, or any custom loop.
Install
pip install "firstops[langgraph]" # LangGraph + LangChain
pip install "firstops[claude]" # Claude Agent SDK
pip install "firstops[openai]" # OpenAI Agents SDK
pip install "firstops[adk]" # Google ADK
pip install "firstops[all]" # all of the above
pip install firstops # core only (management client / custom loops)
Python 3.10+. Core deps are just cryptography and httpx — your agent framework comes in via the extra you pick.
What FirstOps governs
| Surface | How it's wired | What you get |
|---|---|---|
| LLM calls | point the model base_url at the local sidecar |
inspect prompts/responses, scrub PII, block, audit |
| Tool calls | one adapter (or @firstops.tool) |
block / rewrite args / audit — including framework built-ins |
| MCP servers | point the MCP client at the local proxy | server-side policy + credential brokering (the agent never holds the upstream token) |
Every action is evaluated by FirstOps and returns allow / deny / modify — your agent logic doesn't change.
Quick start (LangGraph)
import firstops
from firstops.integrations.langgraph import FirstOpsMiddleware
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
fo = firstops.init(
agent_id="<agent-uuid>", # from the FirstOps dashboard
private_key_pem=open("agent-key.pem").read(),
)
# Route the LLM through FirstOps; wire one middleware to govern every tool call.
llm = ChatOpenAI(model="gpt-4o-mini", base_url=firstops.llm_base_url("openai"), api_key="sk-...")
agent = create_agent(model=llm, tools=[...], middleware=[FirstOpsMiddleware(fo)])
agent.invoke({"messages": [{"role": "user", "content": "..."}]})
The whole integration is init() + a base_url swap + one middleware. See examples/ for runnable agents, including MCP.
Other harnesses
Claude Agent SDK — one PreToolUse hook governs every tool (built-ins, MCP, custom):
from claude_agent_sdk import query, ClaudeAgentOptions
from firstops.integrations.claude import firstops_hooks
options = ClaudeAgentOptions(hooks=firstops_hooks(fo), permission_mode="bypassPermissions")
async for _ in query(prompt="...", options=options):
pass
OpenAI Agents SDK — a guardrail per tool + the model routed through the sidecar:
from agents import Agent, function_tool, set_default_openai_client
from firstops.integrations.openai_agents import firstops_tool_input_guardrail
from openai import AsyncOpenAI
set_default_openai_client(AsyncOpenAI(base_url=firstops.llm_base_url("openai"), api_key="sk-..."))
guard = firstops_tool_input_guardrail(fo)
@function_tool(tool_input_guardrails=[guard])
def send_email(to: str, body: str) -> str: ...
Google ADK — one before_tool_callback governs every tool (block + rewrite args):
from google.adk.agents import LlmAgent
from firstops.integrations.google_adk import firstops_before_tool_callback
agent = LlmAgent(name="assistant", model=..., tools=[...],
before_tool_callback=firstops_before_tool_callback(fo))
Any framework / custom loop — the base API:
@firstops.tool # govern any callable: block / scrub args / audit
def send_email(to: str, body: str): ...
MCP servers
Point your MCP client at the local proxy; FirstOps brokers the upstream credentials.
from langchain_mcp_adapters.client import MultiServerMCPClient
mcp = MultiServerMCPClient({"notion": {"url": firstops.mcp_url("<connection-id>"), "transport": "streamable_http"}})
tools = await mcp.get_tools()
Examples
Runnable agents in examples/ — each governs the LLM and tool calls; the *_mcp variants add a Notion MCP server:
- LangGraph —
langgraph_basic.py,langgraph_notion_mcp.py - Claude Agent SDK —
claude_sdk_basic.py,claude_sdk_mcp.py - OpenAI Agents SDK —
openai_agents_basic.py,openai_agents_mcp.py - Google ADK —
google_adk_basic.py
See examples/README.md for the env vars to run them.
Management client
Provision agents and connections from your backend:
from firstops import FirstOps
admin = FirstOps(api_key="fo_key_...")
agent = admin.agents.create(name="research-bot") # -> id + private_key (shown once)
admin.connections.register(principal_id=agent.id, name="slack", upstream_url="https://mcp.slack.com/sse")
How it works
firstops.init() starts a local sidecar and establishes the agent's identity (a DPoP-bound principal — RFC 9449). Tool and LLM actions are forwarded to the FirstOps gateway, which evaluates them against your policies and returns the verdict; MCP and LLM traffic flow through the sidecar with credentials brokered. Enforcement fails open on infrastructure errors; authentication fails closed.
Documentation
- Docs home
- Guides: LangChain / LangGraph · Claude Agent SDK · OpenAI Agents SDK · Google ADK
- Concepts: Identity · Enforcement · Connections
- Repository
License
MIT
Release files for firstops 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| firstops-0.3.0.tar.gz | 71.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| firstops-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 109.3 kB
Release files / firstops-0.3.0.tar.gz
| Download URL | firstops-0.3.0.tar.gz |
|---|---|
| Size | 71.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6b5271845ac7db4baf8d7c415947219c7dd07fcb18744220d6cd5cb073968339
|
|
BLAKE2b-256 checksum How to use checksums |
6ede4005bbefa3b4076d8de8cbdabbfacfb13ab07d393e83bc97e74c68c74b85
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 15, 2026.
Transparency logRelease files / firstops-0.3.0-py3-none-any.whl
| Download URL | firstops-0.3.0-py3-none-any.whl |
|---|---|
| Size | 38.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5967e6f3b8cbc5e2c40f4c6069ba3d2fefe22f0b68d35d7ab7c6d0716a50d74c
|
|
BLAKE2b-256 checksum How to use checksums |
43a13586f9390a328c6e4243ed79d7d404c92e66a5286d075c43ffa23bcdab16
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 15, 2026.
Transparency log