Skip to main content

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:

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

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)

Source distribution for firstops 0.3.0
File Size Uploaded
firstops-0.3.0.tar.gz 71.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for firstops 0.3.0
File Interpreter ABI Platform
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 log

Release 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

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page