Convert OpenAPI specifications into native, production-grade LangChain tools.
Project description
langchain-openapi
Convert OpenAPI v3.0 & v3.1 and Swagger 2.0 specifications into native, production-grade LangChain tools.
langchain_openapi is a modern Python library designed to seamlessly convert OpenAPI v3.0, v3.1, and Swagger 2.0 specifications into native, type-safe LangChain tools for AI agents and LLM applications.
No python code generation is requiredโtools are generated dynamically at runtime with strict Pydantic input schemas, prompt optimization options, and production-ready middleware.
Installation & Importing
Install the PyPI package:
pip install langchain-openapi-tools
# or using uv
uv add langchain-openapi-tools
Import in Python:
from langchain_openapi_tools import OpenAPIToolkit, OpenAPIToolkitConfig
Migration Note
# Old (deprecated, but still works for backward compatibility):
from langchain_openapi import OpenAPIToolkit
# New (recommended):
from langchain_openapi_tools import OpenAPIToolkit
Features
- โก Zero-Code Tool Generation: Runtime conversion of OpenAPI specs (YAML/JSON) into LangChain
StructuredTools. - ๐งญ Typed, Generic & Hybrid Toolkits: Choose per-operation typed tools, a constant set of generic
GET/POST/... tools with on-demand endpoint discovery, or a hybrid mix โ all sharing the same execution stack. - ๐ Swagger 2.0 & OpenAPI 3.x: Native normalization of legacy Swagger 2.0 and modern OpenAPI 3.0/3.1 specs.
- ๐๏ธ Prompt Optimization & Filtering: Description modes (
full,compact,minimal), description compression, overrides, callbacks, and operation/tag filtering to drastically reduce context window usage. - ๐ Pluggable Authentication: Built-in support for Bearer Tokens, API Key Headers, Query Parameters, Basic Auth, and custom request providers.
- ๐ก๏ธ Production Middleware: Composable middleware architecture for Retries (exponential backoff), Rate Limiting (token-bucket), Caching (TTL), Pagination aggregation, and Sanitized Logging.
- ๐ฏ Type-Safe Validation: Dynamically generated Pydantic input schemas ensure LLM arguments adhere strictly to specification types before network transport.
- ๐ Async Engine: Non-blocking asynchronous network transport powered by
httpx.AsyncClient.
Supported Specifications
- โ Swagger 2.0 (Automatically normalized to OpenAPI 3.0 via the built-in adapter layer)
- โ OpenAPI 3.0.x (JSON and YAML)
- โ
OpenAPI 3.1.x (JSON and YAML, including union
typearrays,oneOf/anyOf/allOf, andconst)
Note: Swagger 2.0 is commonly referred to as OpenAPI 2.0.
Compatibility Matrix
| Feature | Swagger 2.0 | OpenAPI 3.0 | OpenAPI 3.1 |
|---|---|---|---|
| Path / query / header / cookie params | โ | โ | โ |
$ref resolution (internal) |
โ | โ | โ |
Base URL from host + basePath |
โ | โ | โ |
Base URL from servers[] |
โ | โ | โ |
| Fallback base URL from spec source URL | โ | โ | โ |
application/json request bodies |
โ | โ | โ |
application/x-www-form-urlencoded |
โ | โ | โ |
multipart/form-data (incl. files) |
โ | โ | โ |
text/* and application/xml |
โ | โ | โ |
Vendor +json media types |
โ | โ | โ |
oneOf / anyOf (as Python Union) |
โ | โ | โ |
allOf merge into single model |
โ | โ | โ |
nullable: true (3.0) |
โ | โ | โ |
type: ["string", "null"] (3.1) |
โ | โ | โ |
const |
โ | โ | โ |
readOnly / writeOnly / deprecated |
โ | โ | โ |
| Security: Bearer / API key / Basic | โ | โ | โ |
Async execution (httpx.AsyncClient) |
โ | โ | โ |
Not yet supported: discriminator-driven union routing, patternProperties,
$dynamicRef / $dynamicAnchor, callbacks, links, webhooks, and XML request-body
serialization from Python dicts.
Quick Start
from langchain_openapi_tools import OpenAPIToolkit
# Load spec from remote URL or local file
toolkit = OpenAPIToolkit.from_url("https://api.crossref.org/swagger-docs")
# Extract generated tools
tools = toolkit.get_tools()
print(f"Generated {len(tools)} tools:")
for tool in tools[:3]:
print(f"- {tool.name}: {tool.description}")
Agent Integration
import asyncio
from langchain_openapi_tools import OpenAPIToolkit
async def main():
toolkit = OpenAPIToolkit.from_url("https://api.crossref.org/swagger-docs")
search_tool = toolkit.get_tool("get_works")
if search_tool:
result = await search_tool.ainvoke({"query": "LangGraph"})
print("Search Result:", result)
if __name__ == "__main__":
asyncio.run(main())
Execution Strategies: Typed, Generic & Hybrid
Large APIs can generate hundreds or thousands of typed tools, which blows up
prompts and slows agents. langchain_openapi_tools ships three execution
strategies that all share the same loader / parser / provider / middleware /
executor stack โ only the LangChain interface changes.
| Toolkit | Best For | Tool Count |
|---|---|---|
| Typed | Small & medium APIs, maximum correctness | One per operation |
| Generic | Large APIs, low context usage | Constant (9 tools) |
| Hybrid | Enterprise APIs mixing hot paths and long tails | Typed for selected ops + generic for the rest |
Typed Toolkit (default)
from langchain_openapi_tools import OpenAPIToolkit
toolkit = OpenAPIToolkit.from_url(url)
tools = toolkit.get_tools() # one StructuredTool per operation
Generic Toolkit
from langchain_openapi_tools import GenericOpenAPIToolkit
toolkit = GenericOpenAPIToolkit.from_url(url)
tools = toolkit.get_tools() # constant set of tools
The generic toolkit always exposes:
- HTTP tools โ
GET,POST,PUT,PATCH,DELETE - Discovery tools โ
search_operations,describe_operation,list_operations,list_tags
Intended reasoning flow:
user โ search_operations("books")
โ describe_operation("get_books")
โ GET(endpoint="/books", params={...})
โ response
Nothing is duplicated: authentication providers, retry / rate-limit / cache / logging / pagination middleware, and the async HTTP executor are all reused.
from langchain_openapi_tools import (
BearerAuthProvider,
CacheMiddleware,
GenericOpenAPIToolkit,
InMemoryCacheBackend,
RetryMiddleware,
)
toolkit = GenericOpenAPIToolkit.from_url(
url,
provider=BearerAuthProvider(token),
middleware=[
RetryMiddleware(retries=3),
CacheMiddleware(backend=InMemoryCacheBackend(), ttl=60),
],
timeout=30,
)
Hybrid Toolkit
Mix strategies within the same toolkit โ typed tools for the operations you care about, generic HTTP tools for everything else.
toolkit = GenericOpenAPIToolkit.from_url(url)
tools = toolkit.get_tools(
mode="hybrid",
typed_tags=["Books", "Users"], # only these tags become typed tools
)
The classic OpenAPIToolkit also accepts mode="generic" / mode="hybrid"
and transparently delegates, so existing setups can opt in without switching
classes:
toolkit = OpenAPIToolkit.from_url(url)
tools = toolkit.get_tools(mode="hybrid", typed_tags=["Books"])
Prompt Optimization & Tool Customization
Large OpenAPI specifications can generate extensive tool descriptions that exceed model context windows. langchain_openapi_tools provides full control over description generation and context footprint.
Configuration Object (OpenAPIToolkitConfig)
from langchain_openapi_tools import OpenAPIToolkit, OpenAPIToolkitConfig
config = OpenAPIToolkitConfig(
description_mode="compact",
compress_descriptions=True,
include_tags=["Works"],
tool_description_overrides={
"get_works": "Search scholarly papers registered with Crossref."
},
)
toolkit = OpenAPIToolkit.from_url(
"https://api.crossref.org/swagger-docs", config=config
)
Description Modes (description_mode)
full(default): Complete summary, description, HTTP method, path, and schema parameter details.compact: Summary and short parameter list without response schemas or redundant examples.minimal: A single-sentence summary ideal for large specifications with dozens of tools.
toolkit = OpenAPIToolkit.from_url(url, description_mode="minimal")
Description Compression (compress_descriptions=True)
Removes duplicate text, redundant whitespace, and empty sections without altering tool semantics:
toolkit = OpenAPIToolkit.from_url(url, compress_descriptions=True)
Custom Overrides & Callbacks
Override descriptions for specific tools:
toolkit = OpenAPIToolkit.from_url(
url, tool_description_overrides={"get_works": "Search scholarly papers."}
)
Or pass a custom builder callback:
def my_builder(operation):
return f"Execute {operation.name} on path {operation.path}."
toolkit = OpenAPIToolkit.from_url(url, description_builder=my_builder)
Operation Filtering
Filter tools before they are created to reduce context window overhead:
# Filter by Tags
toolkit = OpenAPIToolkit.from_url(url, include_tags=["Works"], exclude_tags=["Admin"])
# Filter by Operations
toolkit = OpenAPIToolkit.from_url(
url, include_operations=["get_works"], exclude_operations=["delete_work"]
)
Architecture Pipeline
Swagger 2.0 / OpenAPI 3.x
โ
โผ
Swagger Normalizer
โ
โผ
Normalized OpenAPI Model
โ
โผ
Existing Parser
โ
โผ
Internal Operation Models
โ
โผ
Schema Converter
โ
โผ
HTTP Executor
โ
โผ
LangChain StructuredTools
Example:
from langchain_openapi_tools import OpenAPIToolkit
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
toolkit = OpenAPIToolkit.from_url(
"https://api.crossref.org/swagger-docs"
)
model = init_chat_model("openrouter:qwen/qwen3-32b:free")
agent = create_agent(
model=model,
tools=toolkit.get_tools(tags=["Works"]),
)
response = agent.invoke({
"messages": "Find papers about Kashmir"
})
Why langchain-openapi Instead of the Alternatives?
Wiring an LLM up to a real API usually looks like one of these two extremes. Neither works well in production.
โ Option A โ Hand-rolling one function per endpoint
The "just write it yourself" path:
@tool
def list_pets(status: str) -> list[dict]:
r = httpx.get(
f"{BASE}/pets",
params={"status": status},
headers={"Authorization": f"Bearer {TOKEN}"},
)
r.raise_for_status()
return r.json()
# ...repeat 20, 200, or 2,000 times.
What you actually end up building yourself:
- One tool per operation, hand-copied from the docs.
- A Pydantic schema per tool, kept in sync with the spec โ by hand.
- Bearer / API-key / Basic / OAuth2 / cookie plumbing on every call.
- Retry with exponential backoff,
Retry-Afterhandling, jitter. - Token-bucket rate limiting so you do not get banned.
- Response caching with TTLs and cache-key hashing.
- Pagination aggregation across
next,Link,cursor, offset styles. - Log sanitization that strips secrets before they hit disk.
- A test suite that mocks every route with
respx. - A migration every time the vendor bumps the spec.
That is a library, not a feature. langchain-openapi is exactly that
library, already written, already tested against Petstore, Crossref, GitHub,
Stripe, and Kubernetes.
โ Option B โ Dropping the OpenAPI URL into the prompt
The "let the model figure it out" path:
System: Here is the API doc: https://api.example.com/openapi.json
User: Please list all my pets.
Why this fails in practice:
- Context explosion. Real specs are 200 KB โ 5 MB of JSON. That is a cold-start prompt tax on every turn.
- Hallucinated endpoints. Models happily invent
/users/{id}/petswhen the real path is/pet/findByStatus. - No auth. The LLM cannot inject a Bearer token into a request it is only describing. You still have to build an executor.
- No validation. Nothing stops the model from sending
status="MAYBE"when the enum is[available, pending, sold]โ the server just 400s and the agent loops. - No middleware. No retries, no rate limiting, no caching, no sanitized logging. The first 429 kills the run.
- No reproducibility. A doc URL that changes silently changes agent behaviour with zero code diff.
โ
langchain-openapi: the middle path
langchain-openapi treats the OpenAPI spec as the source of truth and
generates a strict, production-grade tool surface at runtime.
| Concern | Hand-rolled | LLM-reads-spec | langchain-openapi |
|---|---|---|---|
| Tool generation | Manual | None | Automatic from spec |
| Pydantic argument validation | You write it | โ | Generated per operation |
| Path/query/header/cookie routing | You write it | โ | Handled by RequestBuilder |
| Bearer / API-Key / Basic / OAuth2 | You write it | โ | Pluggable RequestProviders |
| Retry with backoff | You write it | โ | RetryMiddleware |
| Rate limiting | You write it | โ | RateLimitMiddleware |
| Response caching | You write it | โ | CacheMiddleware |
| Pagination aggregation | You write it | โ | PaginationMiddleware |
| Log sanitization | You write it | โ | Built-in |
| Prompt / context footprint | Grows linearly with endpoints | Grows with the whole spec | Typed / Generic / Hybrid modes |
| Endpoint discovery for large APIs | N/A | Full spec in prompt | search_operations / describe_operation |
| Swagger 2.0 ยท OpenAPI 3.0 ยท 3.1 | You port it | Model guesses | Normalized by the adapter layer |
| Spec changes | Manual diff | Silent drift | Reload โ new tools |
| Testability | You write mocks | โ | Deterministic, respx-friendly |
When to reach for it
- You have an API with more than three endpoints โ the boilerplate savings already pay for themselves.
- You need production-grade networking (auth, retries, rate limits, caching, logging) without hand-rolling middleware.
- You want the agent's tool schema to always match the spec โ no drift, no hallucinated parameters.
- You are targeting a large surface (GitHub, Kubernetes, Stripe) and want a constant prompt footprint via the Generic or Hybrid toolkit.
- You want the same integration to work across Swagger 2.0, OpenAPI 3.0, and OpenAPI 3.1 without a rewrite.
TL;DR
Do not paste the OpenAPI URL into the prompt. Do not write 200 @tool
functions by hand. Point langchain-openapi at the spec and get
type-safe, authenticated, resilient LangChain tools โ with your choice of
one-tool-per-operation, a constant generic surface, or a hybrid of both.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file langchain_openapi_tools-2.0.1.tar.gz.
File metadata
- Download URL: langchain_openapi_tools-2.0.1.tar.gz
- Upload date:
- Size: 1.0 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ed5fab93f30ac1e0640a03a1d67a4054bc94a7a9afef8f046597dab7d550ca00
|
|
| MD5 |
bc0e8362233bde8085c4668581cd4dca
|
|
| BLAKE2b-256 |
2656760af1ba6dadc662662a78e2be8d7c33e9378b736a705f6b7053287d74f2
|
Provenance
The following attestation bundles were made for langchain_openapi_tools-2.0.1.tar.gz:
Publisher:
publish.yml on abhaywani114/langchain-openapi
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
langchain_openapi_tools-2.0.1.tar.gz -
Subject digest:
ed5fab93f30ac1e0640a03a1d67a4054bc94a7a9afef8f046597dab7d550ca00 - Sigstore transparency entry: 2312914696
- Sigstore integration time:
-
Permalink:
abhaywani114/langchain-openapi@834f8aedd3937f933e53e6e31fcc3d3d692f00ef -
Branch / Tag:
refs/tags/v2.0.1 - Owner: https://github.com/abhaywani114
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@834f8aedd3937f933e53e6e31fcc3d3d692f00ef -
Trigger Event:
push
-
Statement type:
File details
Details for the file langchain_openapi_tools-2.0.1-py3-none-any.whl.
File metadata
- Download URL: langchain_openapi_tools-2.0.1-py3-none-any.whl
- Upload date:
- Size: 54.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5353257872b70066b54d45c4b774fd600d1e2ee3935fc94c1d1a5b9e46fdb299
|
|
| MD5 |
598f4214a5d8adb42280c1aa13298311
|
|
| BLAKE2b-256 |
720441c72945276ed473af7c541223216808f7e33406ba0890fafb2f59eccd61
|
Provenance
The following attestation bundles were made for langchain_openapi_tools-2.0.1-py3-none-any.whl:
Publisher:
publish.yml on abhaywani114/langchain-openapi
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
langchain_openapi_tools-2.0.1-py3-none-any.whl -
Subject digest:
5353257872b70066b54d45c4b774fd600d1e2ee3935fc94c1d1a5b9e46fdb299 - Sigstore transparency entry: 2312914700
- Sigstore integration time:
-
Permalink:
abhaywani114/langchain-openapi@834f8aedd3937f933e53e6e31fcc3d3d692f00ef -
Branch / Tag:
refs/tags/v2.0.1 - Owner: https://github.com/abhaywani114
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@834f8aedd3937f933e53e6e31fcc3d3d692f00ef -
Trigger Event:
push
-
Statement type: